Compare commits

...

42 Commits

Author SHA1 Message Date
Ajay Ramachandran
457bd15e17 Merge pull request #298 from ajayyy/experimental
Options Improvements
2020-03-10 23:24:36 -04:00
Ajay Ramachandran
cc1b8ee499 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into experimental 2020-03-10 23:23:30 -04:00
Ajay Ramachandran
4a9ed1348e Increase version number 2020-03-10 23:23:10 -04:00
Ajay Ramachandran
5595420be6 Removed redundant if statement 2020-03-10 23:22:57 -04:00
Ajay Ramachandran
191e9ceb6f Makes sure the playing and play listener both don't get called at the same time.
This led to double notices.
2020-03-10 23:22:17 -04:00
Ajay Ramachandran
1e26faa57c Update README.md 2020-03-10 12:11:08 -04:00
Ajay Ramachandran
030256c9e1 Enable checkbox when the permission prompt is successful 2020-03-10 02:14:00 -04:00
Ajay Ramachandran
77eff12d9b Merge pull request #261 from OfficialNoob/patch-1
Made decodeStoredItem detect item type
2020-03-10 01:21:10 -04:00
Ajay Ramachandran
2967fce013 Update README.md 2020-03-10 00:57:44 -04:00
Ajay Ramachandran
db1def623a Update README.md 2020-03-10 00:56:58 -04:00
Ajay Ramachandran
140e324bf1 Update README.md 2020-03-10 00:55:18 -04:00
Ajay Ramachandran
f0bf051259 Properly ask for permissions when changing the server address 2020-03-10 00:48:53 -04:00
Ajay Ramachandran
2ec47d52cd Added basic options import/export 2020-03-10 00:33:50 -04:00
Ajay Ramachandran
50002cfbbd Fix github token using the wrong key in release workflow 2020-03-09 23:10:59 -04:00
Ajay Ramachandran
6ccd4b8b37 Merge pull request #297 from ajayyy/experimental
Fix non zero second skips
2020-03-09 23:05:45 -04:00
Ajay Ramachandran
c0894afff9 Prevent manual skipping votes from affecting to UI and happening when auto vote is off 2020-03-09 23:03:24 -04:00
Ajay Ramachandran
09f244150c Fixed skipping for non zero second sponsors.
Also now using the playing event to fix issues with mobile YouTube skipping.
2020-03-09 23:00:39 -04:00
Ajay Ramachandran
efec8b320c Increase version num 2020-03-09 18:38:02 -04:00
Ajay Ramachandran
e6ea9f77e9 Fixed skip scheduling for auto skip 2020-03-09 18:34:33 -04:00
Ajay Ramachandran
0813aa4ba3 Prevent release workflow from running multiple times 2020-03-09 18:30:57 -04:00
Ajay Ramachandran
ba575f6b8d Merge pull request #296 from ajayyy/experimental
Prevent manual skips from triggering a view and improved skip schedule for manual skip
2020-03-09 18:20:11 -04:00
Ajay Ramachandran
ff9b2338e0 Fixed scheduling being wrong when manual skip is enabled 2020-03-09 18:12:05 -04:00
Ajay Ramachandran
d2bb4b38e3 Increased version number 2020-03-09 18:07:29 -04:00
Ajay Ramachandran
760c08dd0c Prevent manual skips from triggering a view 2020-03-09 18:07:06 -04:00
Ajay Ramachandran
50517eb462 Switched upload to release action 2020-03-09 11:15:29 -04:00
Ajay Ramachandran
e77425c21e Merge pull request #294 from ajayyy/experimental
Another potential fix for zero second sponsor freezing
2020-03-09 11:04:26 -04:00
Ajay Ramachandran
f63abb053d Revert to only using workflows 2020-03-09 11:02:14 -04:00
Ajay Ramachandran
7b5703aa04 Fixed action format 2020-03-09 10:56:06 -04:00
Ajay Ramachandran
d641066312 Checkout in CI 2020-03-09 10:52:43 -04:00
Ajay Ramachandran
44ca8d47d8 Moved CI into the right place 2020-03-09 10:51:26 -04:00
Ajay Ramachandran
d5f41bf4ad Fixed CI 2020-03-09 10:49:50 -04:00
Ajay Ramachandran
73e8926444 Start skip schedule from skip time to prevent slow video updates from breaking it. 2020-03-09 10:43:13 -04:00
Ajay Ramachandran
5ad694af65 Increase version number 2020-03-08 23:26:46 -04:00
Ajay Ramachandran
d7f7acb219 Fixed release action 2020-03-08 23:20:41 -04:00
Ajay Ramachandran
8d82a6a3e6 Fixed data old format migration. 2020-02-14 23:20:11 -05:00
Ajay Ramachandran
88a8fda566 Moved window.SB creation for security reasons. 2020-02-14 23:16:01 -05:00
Official Noob
995fe072bd Merge pull request #1 from ajayyy/master
Update
2020-02-09 22:15:27 +00:00
Ajay Ramachandran
8cdbebd6de Added the config as a global variable. 2020-02-08 20:16:26 -05:00
Ajay Ramachandran
94af8ab301 Prevent all strings from being parsed as JSON. 2020-02-08 20:15:49 -05:00
Ajay Ramachandran
be3a4a4e91 Added support for old format. 2020-02-08 20:08:34 -05:00
Official Noob
1c17464c94 config => defaults 2020-02-04 23:29:11 +00:00
Official Noob
8896c5707a Made decodeStoredItem detect item type
Not tested because SB.config cant be used anymore :(
2020-02-04 22:16:40 +00:00
10 changed files with 240 additions and 60 deletions

View File

@@ -1,6 +1,8 @@
name: Upload Release Build name: Upload Release Build
on: release on:
release:
types: [published]
jobs: jobs:
@@ -9,22 +11,68 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# Build Artifacts # Initialization
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Build Artifacts - uses: actions/setup-node@v1
uses: ./.github/workflows/ci.yml - run: npm install
- name: Copy configuration
run: cp config.json.example config.json
# Create Chrome artifacts
- name: Create Chrome artifacts
run: npm run build:chrome
- uses: actions/upload-artifact@v1
with:
name: ChromeExtension
path: dist
- run: mkdir ./builds
- uses: montudor/action-zip@v0.1.0
with:
args: zip -qq -r ./builds/ChromeExtension.zip ./dist
# Create Firefox artifacts
- name: Create Firefox artifacts
run: npm run build:firefox
- uses: actions/upload-artifact@v1
with:
name: FirefoxExtension
path: dist
- uses: montudor/action-zip@v0.1.0
with:
args: zip -qq -r ./builds/FirefoxExtension.zip ./dist
# Create Beta artifacts (Builds with the name changed to beta)
- name: Create Chrome Beta artifacts
run: npm run build:chrome -- --env.stream=beta
- uses: actions/upload-artifact@v1
with:
name: ChromeExtensionBeta
path: dist
- uses: montudor/action-zip@v0.1.0
with:
args: zip -qq -r ./builds/ChromeExtensionBeta.zip ./dist
- name: Create Firefox Beta artifacts
run: npm run build:firefox -- --env.stream=beta
- uses: actions/upload-artifact@v1
with:
name: FirefoxExtensionBeta
path: dist
- uses: montudor/action-zip@v0.1.0
with:
args: zip -qq -r ./builds/FirefoxExtensionBeta.zip ./dist
# Upload each release asset # Upload each release asset
- name: Upload to release - name: Upload to release
uses: JasonEtco/upload-to-release@master uses: Shopify/upload-to-release@master
with: with:
args: ./builds/ChromeExtension.zip args: builds/ChromeExtension.zip
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload to release - name: Upload to release
uses: JasonEtco/upload-to-release@master uses: Shopify/upload-to-release@master
with: with:
args: ./builds/FirefoxExtension.zip args: builds/FirefoxExtension.zip
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -40,32 +40,30 @@ The backend server code is available here: https://github.com/ajayyy/SponsorBloc
It is a simple Sqlite database that will hold all the timing data. It is a simple Sqlite database that will hold all the timing data.
To make sure that this project doesn't die, I have made the database publicly downloadable at https://api.sponsor.ajay.app/database.db. So, you can download a backup or get archive.org to take a backup for you if you want. To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. You can download a backup or get archive.org to take a backup for you if you want.
Hopefully this project can be combined with projects like [this](https://github.com/Sponsoff/sponsorship_remover) and use this data to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea. The dataset and API are now being used in some [ports](https://github.com/ajayyy/SponsorBlock/wiki/Unofficial-Ports) as well as a [neural network](https://github.com/andrewzlee/NeuralBlock).
A [previous project](https://github.com/Sponsoff/sponsorship_remover) attempted to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea starting from a crowd-sourced system instead.
# API # API
You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs). You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs).
# Build Yourself # Building
You can load this project as an unpacked extension. Make sure to rename the `config.json.example` file to `config.json` before installing. There are also other build scripts available. Install `npm`, then run `npm install` in the repository to install dependencies.
There are also other build scripts available. Install `npm`, then run `npm install` in the repository. Run `npm run build` to generate a Chrome extension.
Use `npm run build:firefox` to generate a Firefox extension.
The result is in `dist`. This can be loaded as an unpacked extension
## Developing with a clean profile ## Developing with a clean profile
Run `npm run dev` to run the extension using a clean browser profile with hot reloading. Use `npm run dev:firefox` for Firefox. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands). Run `npm run dev` to run the extension using a clean browser profile with hot reloading. Use `npm run dev:firefox` for Firefox. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands).
## Packing
Run `npm run build` to generate a packed Chrome extension.
Use `npm run build:firefox` to generate a Firefox extension.
The result is in `dist`.
# Credit # Credit
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) previously was used. The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) previously was used.

View File

@@ -1,7 +1,7 @@
{ {
"name": "__MSG_fullName__", "name": "__MSG_fullName__",
"short_name": "__MSG_Name__", "short_name": "__MSG_Name__",
"version": "1.2.18", "version": "1.2.22",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_Description__", "description": "__MSG_Description__",
"content_scripts": [{ "content_scripts": [{

View File

@@ -425,5 +425,20 @@
}, },
"mobileUpdateInfo": { "mobileUpdateInfo": {
"message": "m.youtube.com is now supported" "message": "m.youtube.com is now supported"
},
"exportOptions": {
"message": "Import/Export All Options"
},
"whatExportOptions": {
"message": "This is your entire configuration in JSON. This includes your userID, so be sure to share this wisely."
},
"setOptions": {
"message": "Set Options"
},
"exportOptionsWarning": {
"message": "Warning: Changing the options is permanent and can break your install. Are you sure you would like to do this? Make sure to backup your old one just in case."
},
"incorrectlyFormattedOptions": {
"message": "This JSON is not formatted correctly. Your options have not been changed."
} }
} }

View File

@@ -308,6 +308,32 @@
<br/> <br/>
<br/> <br/>
<div option-type="private-text-change" sync-option="*" confirm-message="exportOptionsWarning">
<div class="option-button trigger-button">
__MSG_exportOptions__
</div>
<br/>
<div class="small-description">__MSG_whatExportOptions__</div>
<div class="option-hidden-section hidden">
<br/>
<input class="option-text-box" type="text">
<br/>
<br/>
<div class="option-button text-change-set">
__MSG_setOptions__
</div>
</div>
</div>
<br/>
<br/>
<div option-type="text-change" sync-option="serverAddress"> <div option-type="text-change" sync-option="serverAddress">
<label class="text-label-container"> <label class="text-label-container">
<div>__MSG_customServerAddress__</div> <div>__MSG_customServerAddress__</div>

View File

@@ -1,5 +1,8 @@
import * as Types from "./types"; import * as Types from "./types";
import Config from "./config"; import Config from "./config";
// Make the config public for debugging purposes
(<any> window).SB = Config;
import Utils from "./utils"; import Utils from "./utils";
var utils = new Utils({ var utils = new Utils({

View File

@@ -84,12 +84,7 @@ class SBMap<T, U> extends Map {
return result; return result;
} }
toJSON() {
return Array.from(this.entries());
} }
}
var Config: SBObject = { var Config: SBObject = {
/** /**
@@ -131,14 +126,14 @@ var Config: SBObject = {
/** /**
* A SBMap cannot be stored in the chrome storage. * A SBMap cannot be stored in the chrome storage.
* This data will be encoded into an array instead as specified by the toJSON function. * This data will be encoded into an array instead
* *
* @param data * @param data
*/ */
function encodeStoredItem(data) { function encodeStoredItem(data) {
// if data is SBMap convert to json for storing // if data is SBMap convert to json for storing
if(!(data instanceof SBMap)) return data; if(!(data instanceof SBMap)) return data;
return JSON.stringify(data); return Array.from(data.entries());
} }
/** /**
@@ -148,19 +143,31 @@ function encodeStoredItem(data) {
* @param {*} data * @param {*} data
*/ */
function decodeStoredItem(id: string, data) { function decodeStoredItem(id: string, data) {
if(typeof data !== "string") return data; if (!Config.defaults[id]) return data;
if (Config.defaults[id] instanceof SBMap) {
try { try {
let str = JSON.parse(data); let jsonData: any = data;
if(!Array.isArray(str)) return data; // Check if data is stored in the old format for SBMap (a JSON string)
return new SBMap(id, str); if (typeof data === "string") {
try {
jsonData = JSON.parse(data);
} catch(e) { } catch(e) {
// Continue normally (out of this if statement)
}
}
if (!Array.isArray(jsonData)) return data;
return new SBMap(id, jsonData);
} catch(e) {
console.error("Failed to parse SBMap: " + id);
}
}
// If all else fails, return the data // If all else fails, return the data
return data; return data;
} }
}
function configProxy(): any { function configProxy(): any {
chrome.storage.onChanged.addListener((changes, namespace) => { chrome.storage.onChanged.addListener((changes, namespace) => {

View File

@@ -45,7 +45,12 @@ var lastPreviewBarUpdate;
var durationListenerSetUp = false; var durationListenerSetUp = false;
// Is the video currently being switched // Is the video currently being switched
var switchingVideos = false; var switchingVideos = null;
// Used by the play and playing listeners to make sure two aren't
// called at the same time
var lastCheckTime = 0;
var lastCheckVideoTime = -1;
//the channel this video is about //the channel this video is about
var channelURL; var channelURL;
@@ -238,6 +243,9 @@ document.onkeydown = function(e: KeyboardEvent){
} }
function resetValues() { function resetValues() {
lastCheckTime = 0;
lastCheckVideoTime = -1;
//reset sponsor times //reset sponsor times
sponsorTimes = null; sponsorTimes = null;
UUIDs = []; UUIDs = [];
@@ -250,6 +258,8 @@ function resetValues() {
//reset sponsor data found check //reset sponsor data found check
sponsorDataFound = false; sponsorDataFound = false;
switchingVideos = true;
} }
async function videoIDChange(id) { async function videoIDChange(id) {
@@ -264,8 +274,6 @@ async function videoIDChange(id) {
//id is not valid //id is not valid
if (!id) return; if (!id) return;
switchingVideos = true;
// Wait for options to be ready // Wait for options to be ready
await utils.wait(() => Config.config !== null, 5000, 1); await utils.wait(() => Config.config !== null, 5000, 1);
@@ -449,7 +457,7 @@ function startSponsorSchedule(currentTime?: number): void {
return; return;
} }
if (currentTime === undefined) currentTime = video.currentTime; if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
let skipInfo = getNextSkipIndex(currentTime); let skipInfo = getNextSkipIndex(currentTime);
@@ -459,11 +467,19 @@ function startSponsorSchedule(currentTime?: number): void {
let timeUntilSponsor = skipTime[0] - currentTime; let timeUntilSponsor = skipTime[0] - currentTime;
let skippingFunction = () => { let skippingFunction = () => {
let forcedSkipTime: number = null;
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) { if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice); skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice);
if (Config.config.disableAutoSkip) {
forcedSkipTime = skipTime[0] + 0.001;
} else {
forcedSkipTime = skipTime[1];
}
} }
startSponsorSchedule(); startSponsorSchedule(forcedSkipTime);
}; };
if (timeUntilSponsor <= 0) { if (timeUntilSponsor <= 0) {
@@ -493,7 +509,23 @@ function sponsorsLookup(id: string, channelIDPromise?) {
video.addEventListener('play', () => { video.addEventListener('play', () => {
switchingVideos = false; switchingVideos = false;
// Make sure it doesn't get double called with the playing event
if (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000) {
lastCheckTime = Date.now();
lastCheckVideoTime = video.currentTime;
startSponsorSchedule(); startSponsorSchedule();
}
});
video.addEventListener('playing', () => {
// Make sure it doesn't get double called with the play event
if (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000) {
lastCheckTime = Date.now();
lastCheckVideoTime = video.currentTime;
startSponsorSchedule();
}
}); });
video.addEventListener('seeked', () => { video.addEventListener('seeked', () => {
if (!video.paused) startSponsorSchedule(); if (!video.paused) startSponsorSchedule();
@@ -848,10 +880,9 @@ function skipToTime(v, index, sponsorTimes, openNotice) {
} }
//send telemetry that a this sponsor was skipped //send telemetry that a this sponsor was skipped
if (Config.config.trackViewCount && !sponsorSkipped[index]) { if (Config.config.trackViewCount && !sponsorSkipped[index] && !Config.config.disableAutoSkip) {
utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID); utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID);
if (!Config.config.disableAutoSkip) {
// Count this as a skip // Count this as a skip
Config.config.minutesSaved = Config.config.minutesSaved + (sponsorTimes[index][1] - sponsorTimes[index][0]) / 60; Config.config.minutesSaved = Config.config.minutesSaved + (sponsorTimes[index][1] - sponsorTimes[index][0]) / 60;
Config.config.skipCount = Config.config.skipCount + 1; Config.config.skipCount = Config.config.skipCount + 1;
@@ -860,7 +891,6 @@ function skipToTime(v, index, sponsorTimes, openNotice) {
} }
} }
} }
}
function unskipSponsorTime(UUID) { function unskipSponsorTime(UUID) {
if (sponsorTimes != null) { if (sponsorTimes != null) {

View File

@@ -1,5 +1,7 @@
'use strict'; 'use strict';
import Config from "../config";
/** /**
* The notice that tells the user that a sponsor was just skipped * The notice that tells the user that a sponsor was just skipped
*/ */
@@ -305,7 +307,7 @@ class SkipNotice {
if (this.manualSkip) { if (this.manualSkip) {
this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle")); this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle"));
this.contentContainer().vote(1, this.UUID, this); if (Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
} }
} }

View File

@@ -1,4 +1,6 @@
import Config from "./config"; import Config from "./config";
// Make the config public for debugging purposes
(<any> window).SB = Config;
import Utils from "./utils"; import Utils from "./utils";
var utils = new Utils(); var utils = new Utils();
@@ -72,7 +74,7 @@ async function init() {
textChangeInput.value = Config.config[textChangeOption]; textChangeInput.value = Config.config[textChangeOption];
textChangeSetButton.addEventListener("click", () => { textChangeSetButton.addEventListener("click", async () => {
// See if anything extra must be done // See if anything extra must be done
switch (textChangeOption) { switch (textChangeOption) {
case "serverAddress": case "serverAddress":
@@ -84,6 +86,18 @@ async function init() {
return; return;
} }
// Permission needed on Firefox
if (utils.isFirefox()) {
let permissionSuccess = await new Promise((resolve, reject) => {
chrome.permissions.request({
origins: [textChangeInput.value + "/"],
permissions: []
}, resolve);
});
if (!permissionSuccess) return;
}
break; break;
} }
@@ -259,6 +273,8 @@ function invidiousOnClick(checkbox: HTMLInputElement, option: string) {
if (!granted) { if (!granted) {
Config.config[option] = false; Config.config[option] = false;
checkbox.checked = false; checkbox.checked = false;
} else {
checkbox.checked = true;
} }
}); });
} else { } else {
@@ -346,15 +362,50 @@ function activatePrivateTextChange(element: HTMLElement) {
return; return;
} }
textBox.value = Config.config[option]; let result = Config.config[option];
// See if anything extra must be done
switch (option) {
case "*":
result = JSON.stringify(Config.localConfig);
break;
}
textBox.value = result;
let setButton = element.querySelector(".text-change-set"); let setButton = element.querySelector(".text-change-set");
setButton.addEventListener("click", () => { setButton.addEventListener("click", () => {
let confirmMessage = element.getAttribute("confirm-message"); let confirmMessage = element.getAttribute("confirm-message");
if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) { if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) {
// See if anything extra must be done
switch (option) {
case "*":
try {
let newConfig = JSON.parse(textBox.value);
for (const key in newConfig) {
Config.config[key] = newConfig[key];
}
init();
if (newConfig.supportInvidious) {
let checkbox = <HTMLInputElement> document.querySelector("#support-invidious > label > label > input");
checkbox.checked = true;
invidiousOnClick(checkbox, "supportInvidious");
}
} catch (e) {
alert(chrome.i18n.getMessage("incorrectlyFormattedOptions"));
}
break;
default:
Config.config[option] = textBox.value; Config.config[option] = textBox.value;
} }
}
}); });
element.querySelector(".option-hidden-section").classList.remove("hidden"); element.querySelector(".option-hidden-section").classList.remove("hidden");