Compare commits

..

162 Commits
1.2.2 ... 1.2.4

Author SHA1 Message Date
Ajay Ramachandran
f5a4ffabde Merge pull request #234 from ajayyy/hotfix-invidious
Hotfix
2020-01-11 13:42:10 -05:00
Ajay Ramachandran
115b1edf11 Increased version number 2020-01-11 13:41:44 -05:00
Ajay Ramachandran
04942a3a5d Fixed delete button potentially appearing. 2020-01-11 13:35:20 -05:00
Ajay Ramachandran
aee0712ef1 Fixed old sponsortime config being broken. 2020-01-11 13:27:20 -05:00
Ajay Ramachandran
63568aae9c Merge pull request #229 from ajayyy/experimental-ajay
Increase version number
2020-01-10 22:26:22 -05:00
Ajay Ramachandran
bf90d2a8e6 Increase version number 2020-01-10 22:22:55 -05:00
Ajay Ramachandran
d87cb77895 Merge pull request #228 from ajayyy/experimental-ajay
Invidious support fixes
2020-01-10 22:22:24 -05:00
Ajay Ramachandran
36c4ebda65 Added comments to the settimeout on install 2020-01-10 22:16:53 -05:00
Ajay Ramachandran
968df5a2e4 Increased notice width 2020-01-10 22:15:42 -05:00
Ajay Ramachandran
259f7a9439 Added notice info about the Invidious update. TODO: remove this in the future. 2020-01-10 22:15:28 -05:00
Ajay Ramachandran
4f8e1bc827 Fixed formatting. 2020-01-10 20:49:21 -05:00
Ajay Ramachandran
9e8a520d1e Fixed broken voting. 2020-01-10 20:48:16 -05:00
Ajay Ramachandran
7335429541 Added option for auto-vote. 2020-01-10 20:06:16 -05:00
Ajay Ramachandran
5c227f445a Added ublock origin to npm run dev 2020-01-10 19:58:59 -05:00
Ajay Ramachandran
dce90e86bf Added invidious support info to the help page. 2020-01-10 15:46:50 -05:00
Ajay Ramachandran
36d7dcce9b Revert "Removed snopyta.org from the default."
This reverts commit fb974de53b.
2020-01-10 15:17:31 -05:00
Ajay Ramachandran
502bec55c4 Merge pull request #181 from afrmtbl/add-invidious
Initial Invidious support
2020-01-09 22:41:08 -05:00
Ajay Ramachandran
21a61bb238 Fixed options page and manifest. 2020-01-09 22:40:44 -05:00
Ajay Ramachandran
fb974de53b Removed snopyta.org from the default. 2020-01-09 22:34:26 -05:00
Ajay Ramachandran
a5adf73b88 Moved registration removal to a util function. 2020-01-09 22:32:20 -05:00
Ajay Ramachandran
1f4c4c0901 Make content script reregister on firefox every browser restart 2020-01-09 22:13:00 -05:00
Ajay Ramachandran
338fbcea9c Fixed buttons appearing on invidious. 2020-01-09 21:32:56 -05:00
Ajay Ramachandran
a20fa9871e Added support for any invidious instance. 2020-01-09 21:23:25 -05:00
Ajay Ramachandran
25436d9620 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into add-invidious
# Conflicts:
#	background.js
2020-01-09 20:42:31 -05:00
Ajay Ramachandran
8d3a633d85 Merge pull request #226 from ajayyy/ajay-config-listener
Config callback updating
2020-01-09 20:41:18 -05:00
Ajay Ramachandran
f67568e3b6 Fixed indentation. 2020-01-09 20:29:47 -05:00
Ajay Ramachandran
d902cc5efe Made buttons update with the config. 2020-01-09 20:29:20 -05:00
Ajay Ramachandran
9e89eb521a Added config callback support. 2020-01-09 20:09:32 -05:00
Ajay Ramachandran
f4c5f50f8c Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into add-invidious 2020-01-09 19:53:49 -05:00
Ajay Ramachandran
4301a6bfe3 Merge pull request #225 from ajayyy/experimental-ajay
Option page fixes
2020-01-09 19:53:40 -05:00
Ajay Ramachandran
2c5a78947a Added instance display 2020-01-09 19:52:20 -05:00
Ajay Ramachandran
8f7eb82b6e Remove unnecessary code 2020-01-09 19:42:18 -05:00
Ajay Ramachandran
d2e1373e2a Fixed more merging issues. 2020-01-09 19:23:05 -05:00
Ajay Ramachandran
d705610855 Fix merge issues 2020-01-09 19:19:30 -05:00
Ajay Ramachandran
c40b6576d6 Updated gitignore. 2020-01-09 15:02:06 -05:00
Ajay Ramachandran
1c3e2fcdad Fixed help page style issue. 2020-01-09 15:01:42 -05:00
Ajay Ramachandran
7acc6c3329 Added warning message when changing the userID. 2020-01-09 15:00:03 -05:00
Ajay Ramachandran
1715ee327f Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into experimental-ajay 2020-01-09 14:28:40 -05:00
Ajay Ramachandran
0481943737 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into add-invidious
# Conflicts:
#	background.js
#	content.js
#	options/options.js
2020-01-09 14:28:06 -05:00
Ajay Ramachandran
c53bc20294 Merge pull request #219 from OfficialNoob/patch-26
Config proxy [WIP]
2020-01-09 13:24:33 -05:00
Ajay Ramachandran
a8fc22eae8 Reformatted variable name. 2020-01-09 13:17:26 -05:00
Ajay Ramachandran
4ba82f6e00 Set local config right away 2020-01-09 13:16:27 -05:00
Ajay Ramachandran
8fd671d4d3 Added docs and improved consistency. 2020-01-09 12:46:04 -05:00
Ajay Ramachandran
309b1b007e Removed unneeded function 2020-01-09 12:39:48 -05:00
Ajay Ramachandran
d0e7213cc4 Added docs and removed reflection. Also removed inheritance. 2020-01-09 12:38:15 -05:00
Ajay Ramachandran
a2e9688418 Formatting + duplicate code removal. 2020-01-09 12:30:09 -05:00
Ajay Ramachandran
f42c23cd9a Formatting fixes 2020-01-09 12:12:49 -05:00
Official Noob
52f60d70e2 Map support :D 2020-01-09 16:39:23 +00:00
Official Noob
339d05e157 :/ 2020-01-08 23:27:34 +00:00
Official Noob
c0c3640638 Reverted back <Not working> 2020-01-08 23:16:02 +00:00
Official Noob
a314139302 Map storage encoding 2020-01-08 22:22:18 +00:00
Official Noob
bfa0472f84 Reflect 2020-01-08 19:52:41 +00:00
Ajay Ramachandran
fa19e435cc Switched to a listener map. 2020-01-07 22:59:50 -05:00
Ajay Ramachandran
eb4bf89194 Fixed default 2020-01-07 22:12:53 -05:00
Ajay Ramachandran
da8a1376a7 Converted options page to new config system. 2020-01-07 22:02:16 -05:00
Ajay Ramachandran
267132cdde Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into patch-26 2020-01-07 21:24:54 -05:00
Ajay Ramachandran
b8ebe5076b Fixed indentation. 2020-01-07 21:23:59 -05:00
Ajay Ramachandran
cb9877b3b4 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into experimental-ajay 2020-01-06 22:31:17 -05:00
Ajay Ramachandran
c73b9ed5a6 Remove redundant code. 2020-01-06 22:30:35 -05:00
Ajay Ramachandran
1bd0b4349f Fixed build not ignoring ignored folder 2020-01-06 19:51:49 -05:00
Official Noob
d15785146f Update options.js 2020-01-06 23:42:02 +00:00
Official Noob
47d9d93818 Added SB.js to options html 2020-01-06 23:34:33 +00:00
Official Noob
601ff44145 Forgot comma 2020-01-06 23:29:04 +00:00
Official Noob
cbd451949b Added hideDiscordLink, hideDiscordLink 2020-01-06 23:27:07 +00:00
Official Noob
a7dc207c5f Fix format conflict 2020-01-06 23:12:48 +00:00
Official Noob
c20b67d11f Fixed syntax 2020-01-06 21:20:22 +00:00
Official Noob
0b9def800b Update SB.js 2020-01-06 21:17:28 +00:00
Official Noob
d8ae73e96a Update SB.js 2020-01-06 21:14:31 +00:00
Ajay Ramachandran
c99f7925eb Fixed migrate 2020-01-06 16:13:50 -05:00
Official Noob
3627661e1f Backwards compatibility 2020-01-06 21:11:37 +00:00
Official Noob
f1c68a98cf removed SB.config.dontShowNoticeOld 2020-01-06 18:59:38 +00:00
Official Noob
92f10d51aa Removed SB.config.dontShowNoticeOld 2020-01-06 18:58:47 +00:00
Official Noob
bdae68be35 () => 2020-01-06 18:56:37 +00:00
Official Noob
2a4abf958d Map test 2020-01-01 19:20:14 +00:00
Official Noob
1362331a93 Map test 2020-01-01 19:12:15 +00:00
Official Noob
a70aa7723e Map test 2020-01-01 19:11:17 +00:00
Official Noob
a3f5200c9a Map test 2020-01-01 19:10:34 +00:00
Official Noob
1005783034 Update SB.js 2020-01-01 18:02:16 +00:00
Official Noob
278e40207c Create empty array for sponsorTimeKey 2020-01-01 18:00:47 +00:00
Ajay Ramachandran
509b627e88 Made it reenable the permission when an invidious instance is added.
Right now it throws an error
2020-01-01 12:55:35 -05:00
Official Noob
ecd9f6eaff Update content.js 2020-01-01 15:09:13 +00:00
Official Noob
1d2b6b2010 userID 2020-01-01 14:50:05 +00:00
Official Noob
6c4d5c0705 submitTimes async 2020-01-01 14:47:41 +00:00
Official Noob
0533919bde Update SB.js 2020-01-01 14:45:34 +00:00
Official Noob
e02ca1c822 Update SB.js 2020-01-01 14:45:22 +00:00
Official Noob
039c1a178f Update background.js 2020-01-01 14:44:39 +00:00
Official Noob
6f682baa45 Update content.js 2020-01-01 14:30:23 +00:00
Official Noob
0241c0a036 Update SB.js 2020-01-01 14:04:49 +00:00
Official Noob
4ebdcf1cc5 Update content.js 2020-01-01 14:04:18 +00:00
Official Noob
46c3187c89 Update content.js 2020-01-01 13:46:09 +00:00
Official Noob
c65e3c21e3 fix 2020-01-01 13:01:42 +00:00
Official Noob
e35774138f Added run_at document_start 2020-01-01 13:01:18 +00:00
Official Noob
a9b678f0ff dontShowNoticeAgain 2020-01-01 12:36:29 +00:00
Official Noob
32356d711d Update SB.js 2020-01-01 12:35:54 +00:00
Official Noob
477ae3eb2c Update SB.js 2020-01-01 12:27:59 +00:00
Ajay Ramachandran
0b41118232 Added option for custom invidious instances. 2019-12-31 19:09:37 -05:00
Ajay Ramachandran
ea3f9f246e Fixed firefox support. 2019-12-31 18:13:51 -05:00
Official Noob
9dd954e7d8 Added default for trackViewCount 2019-12-31 22:54:02 +00:00
Official Noob
41352a5116 Update content.js 2019-12-31 22:52:41 +00:00
Official Noob
1ac9989288 Use defaults 2019-12-31 22:50:52 +00:00
Ajay Ramachandran
b441cc2123 Added firefox support and support for multiple invidious instances. 2019-12-31 17:48:43 -05:00
Official Noob
5e2bc43722 Update SB.js 2019-12-31 22:48:29 +00:00
Official Noob
da17dd8bae Added addDefaults and resetConfig 2019-12-31 22:46:16 +00:00
Official Noob
87098d1c3e Update content.js 2019-12-31 22:04:40 +00:00
Official Noob
2a1b60596b debug 2019-12-31 21:30:54 +00:00
Official Noob
7bbbe0dcf3 Use SB.config 2019-12-31 20:56:30 +00:00
Official Noob
25672a6496 SB.js content script 2019-12-31 20:17:27 +00:00
Official Noob
796bf6ef45 Added SB.js 2019-12-31 20:10:16 +00:00
Official Noob
6ceeaebd9d Added SB 2019-12-31 20:08:11 +00:00
Official Noob
61b8427270 File used to control the SB object 2019-12-31 20:07:43 +00:00
Official Noob
4450aaa3b3 Moving to separate due to load order 2019-12-31 20:07:03 +00:00
Ajay Ramachandran
b0e0c380dd Added Firefox fixes 2019-12-31 14:50:01 -05:00
Official Noob
8baf11a053 Forgot SB. 2019-12-31 19:20:20 +00:00
Official Noob
67f9697f3f test 2019-12-31 19:17:10 +00:00
Official Noob
a94d941125 Added sync config 2019-12-31 19:16:46 +00:00
Official Noob
2917de6776 Moved localconfig to SB object 2019-12-31 19:06:33 +00:00
Official Noob
272698f97b Update utils.js 2019-12-31 19:03:43 +00:00
Official Noob
3fbb689e0a Moving utils 2019-12-31 19:01:17 +00:00
Ajay Ramachandran
4817af5e4f Removed minimum version 2019-12-31 13:29:59 -05:00
Ajay Ramachandran
aba08a515e Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into add-invidious 2019-12-31 13:18:46 -05:00
Ajay Ramachandran
83801db82e Merge pull request #215 from jplsek/ci4
Add web-ext and ci artifact generation
2019-12-31 13:17:46 -05:00
Official Noob
84e4adbc12 Config proxy [POC]
Having a global SB.config that can be used to store get and set variables easily  
Example: SB.config.userID = "blah"
2019-12-31 14:55:03 +00:00
Ajay Ramachandran
6a37753753 Added defaults to option page. 2019-12-31 02:32:44 -05:00
Ajay Ramachandran
0898c7e28c Added options description. 2019-12-31 02:23:39 -05:00
Ajay Ramachandran
412be37ae5 Fixed channel parsing error. 2019-12-31 02:23:23 -05:00
Ajay Ramachandran
beec376e10 Updated invidious explainer. 2019-12-31 02:17:02 -05:00
Ajay Ramachandran
df30f00347 Moved invidious code to functions and made it check permissions on init. 2019-12-31 02:15:10 -05:00
Ajay Ramachandran
dcfdade927 Added invidio.sh 2019-12-31 02:08:32 -05:00
Ajay Ramachandran
741ddcd8aa Fixed permissions. 2019-12-31 02:06:58 -05:00
Ajay Ramachandran
433db26078 Added option to enable invidious support. 2019-12-30 23:15:29 -05:00
Ajay Ramachandran
fc033cb69d Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into add-invidious 2019-12-30 17:40:32 -05:00
Ajay Ramachandran
bd8c67bc24 Merge branch 'experimental-ajay' of https://github.com/ajayyy/SponsorBlock into add-invidious 2019-12-30 17:39:07 -05:00
Ajay Ramachandran
a80fbc1a04 Merge pull request #216 from ajayyy/options-page
Options Page
2019-12-30 17:37:59 -05:00
Ajay Ramachandran
e347504616 Removed options from popup. 2019-12-30 17:37:02 -05:00
Ajay Ramachandran
94cbf089db Added submission keybind option 2019-12-30 17:23:05 -05:00
Ajay Ramachandran
cb2fb6925b Added keybind option. 2019-12-30 16:41:33 -05:00
Ajay Ramachandran
b3361a473c Removed use of center tag. 2019-12-30 14:44:03 -05:00
Ajay Ramachandran
fcb6ed7676 Added text set option (userID) 2019-12-30 01:20:20 -05:00
Ajay Ramachandran
91f4d7f669 Removed logs 2019-12-30 00:49:23 -05:00
Ajay Ramachandran
2e2ff60c23 Made the options save. 2019-12-30 00:48:59 -05:00
Ajay Ramachandran
13727270d4 Added all toggle buttons and made them set to their values. 2019-12-30 00:39:02 -05:00
Ajay Ramachandran
b27f56bc00 Added basic options panel.
Co-authored-by: Official Noob <31563761+OfficialNoob@users.noreply.github.com>
2019-12-29 23:18:18 -05:00
Ajay Ramachandran
7ad7d793d0 Added info about web-ext run 2019-12-29 20:52:40 -05:00
Ajay Ramachandran
491bef680e Removed unnecessary ignored files. 2019-12-29 20:49:31 -05:00
Ajay Ramachandran
e581dc818f Updated ignore files for build. 2019-12-29 20:26:47 -05:00
Jeremy Plsek
8d0b032eb6 Add web-ext and ci artifact generation 2019-12-29 19:35:02 -05:00
Ajay Ramachandran
9cb4fd6f79 Merge pull request #214 from OfficialNoob/patch-26
getYouTubeVideoID ~ TV support
2019-12-29 16:56:36 -05:00
Official Noob
87abcae249 fix embeds 2019-12-29 21:51:11 +00:00
Ajay Ramachandran
fe608b579e Formatting 2019-12-29 16:48:10 -05:00
Official Noob
f74e25a482 Update utils.js 2019-12-29 21:42:43 +00:00
Official Noob
1db9d25f3b getYouTubeVideoID ~ TV support 2019-12-29 21:39:19 +00:00
Ajay Ramachandran
f25aeefe83 Merge branch 'master' into add-invidious 2019-12-29 00:34:49 -05:00
Ajay Ramachandran
9fc846bd7a Made sure the video player button options are ignored on Invidious. 2019-12-19 01:03:09 -05:00
Ajay Ramachandran
5b628ccbf9 Fixed submit button being shown at the wrong time. 2019-12-19 00:56:52 -05:00
Ajay Ramachandran
5471273673 Fixed getting channel ID for invidious. 2019-12-19 00:48:26 -05:00
Ajay Ramachandran
58c0c6e152 Merge branch 'experimental-ajay' of https://github.com/ajayyy/SponsorBlock into add-invidious 2019-12-19 00:46:52 -05:00
Ajay Ramachandran
7d62c9f575 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into add-invidious 2019-12-19 00:40:32 -05:00
Ajay Ramachandran
45a64fcb03 Prevented upload button from appearing on invidious.
It still appears if the video player controls are disabled.
2019-12-19 00:38:55 -05:00
Ajay Ramachandran
630b099fd6 Fixed formatting and removed whitelisting fix code.
Whitelisting was now fixed in a different way.
2019-12-19 00:36:35 -05:00
afrmtbl
5dc67a386c Fix manifest 2019-12-05 16:13:22 -05:00
afrmtbl
6d442b9e80 Explain additional whitelist check 2019-12-05 15:48:26 -05:00
afrmtbl
2f6ddeb5f1 Initial Invidious support 2019-12-05 15:35:25 -05:00
22 changed files with 9511 additions and 1035 deletions

38
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: CI
on: [push, pull_request]
jobs:
build:
name: Create artifacts
runs-on: ubuntu-latest
steps:
# Initialization
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- run: npm install
- name: Copy configuration
run: cp config.js.example config.js
# Create Chrome artifacts
- name: Create Chrome artifacts
run: npm run build
- uses: actions/upload-artifact@v1
with:
name: Chrome Extension
path: web-ext-artifacts
# Create Firefox artifacts
- name: Move manifest
run: mv manifest.json manifest.json.original
- name: Combine manifest for Firefox
run: jq -s '.[0] * .[1]' manifest.json.original firefox_manifest-extra.json > manifest.json
- name: Create Firefox artifacts
run: npm run build
- uses: actions/upload-artifact@v1
with:
name: Firefox Extension
path: web-ext-artifacts

5
.gitignore vendored
View File

@@ -1,3 +1,6 @@
config.js
ignored
.idea/
.idea/
node_modules
web-ext-artifacts
.vscode/

View File

@@ -50,6 +50,16 @@ You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#ap
You can load this project as an unpacked extension. Make sure to rename the `config.js.example` file to `config.js` before installing.
There are also other build scripts available. Install `npm`, then run `npm install` in the repository.
## Developing with a clean profile
Run `npm run dev` to run the extension using a clean browser profile with hot reloading [(by default Firefox)](https://hacks.mozilla.org/2019/10/developing-cross-browser-extensions-with-web-ext-3-2-0/). This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands).
## Packing
Run `npm run build` to generate a packed extension.
# Credit
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) is used to grab the time the video was published.

189
SB.js Normal file
View File

@@ -0,0 +1,189 @@
SB = {
/**
* Callback function when an option is updated
*
* @type {CallableFunction}
*/
configListeners: []
};
// Function setup
Map.prototype.toJSON = function() {
return Array.from(this.entries());
};
class MapIO {
constructor(id) {
this.id = id;
this.map = SB.localConfig[this.id];
}
set(key, value) {
this.map.set(key, value);
SB.config.handler.set(undefined, this.id, encodeStoredItem(this.map));
return this.map;
}
get(key) {
return this.map.get(key);
}
has(key) {
return this.map.has(key);
}
deleteProperty(key) {
if (this.map.has(key)) {
this.map.delete(key);
return true;
} else {
return false;
}
}
size() {
return this.map.size;
}
delete(key) {
this.map.delete(key);
SB.config.handler.set(undefined, this.id, encodeStoredItem(this.map));
}
}
/**
* A Map cannot be stored in the chrome storage.
* This data will be encoded into an array instead as specified by the toJSON function.
*
* @param {*} data
*/
function encodeStoredItem(data) {
if(!(data instanceof Map)) return data;
return JSON.stringify(data);
}
/**
* A Map cannot be stored in the chrome storage.
* This data will be decoded from the array it is stored in
*
* @param {*} data
*/
function decodeStoredItem(data) {
if(typeof data !== "string") return data;
try {
let str = JSON.parse(data);
if(!Array.isArray(str)) return data;
return new Map(str);
} catch(e) {
// If all else fails, return the data
return data;
}
}
function configProxy() {
chrome.storage.onChanged.addListener((changes, namespace) => {
for (const key in changes) {
SB.localConfig[key] = decodeStoredItem(changes[key].newValue);
}
for (const callback of SB.configListeners) {
callback(changes);
}
});
var handler = {
set: function(obj, prop, value) {
SB.localConfig[prop] = value;
chrome.storage.sync.set({
[prop]: encodeStoredItem(value)
});
},
get: function(obj, prop) {
let data = SB.localConfig[prop];
if(data instanceof Map) data = new MapIO(prop);
return obj[prop] || data;
}
};
return new Proxy({handler}, handler);
}
function fetchConfig() {
return new Promise((resolve, reject) => {
chrome.storage.sync.get(null, function(items) {
SB.localConfig = items; // Data is ready
resolve();
});
});
}
function migrateOldFormats() { // Convert sponsorTimes format
for (key in SB.localConfig) {
if (key.startsWith("sponsorTimes") && key !== "sponsorTimes" && key !== "sponsorTimesContributed") {
SB.config.sponsorTimes.set(key.substr(12), SB.config[key]);
chrome.storage.sync.remove(key);
}
}
}
async function setupConfig() {
await fetchConfig();
addDefaults();
convertJSON();
SB.config = configProxy();
migrateOldFormats();
}
SB.defaults = {
"sponsorTimes": new Map(),
"startSponsorKeybind": ";",
"submitKeybind": "'",
"minutesSaved": 0,
"skipCount": 0,
"sponsorTimesContributed": 0,
"disableSkipping": false,
"disableAutoSkip": false,
"trackViewCount": true,
"dontShowNotice": false,
"hideVideoPlayerControls": false,
"hideInfoButtonPlayerControls": false,
"hideDeleteButtonPlayerControls": false,
"hideDiscordLaunches": 0,
"hideDiscordLink": false,
"invidiousInstances": ["invidio.us", "invidiou.sh", "invidious.snopyta.org"],
"invidiousUpdateInfoShowCount": 0,
"autoUpvote": true
}
// Reset config
function resetConfig() {
SB.config = SB.defaults;
};
function convertJSON() {
Object.keys(SB.defaults).forEach(key => {
SB.localConfig[key] = decodeStoredItem(SB.localConfig[key], key);
});
}
// Add defaults
function addDefaults() {
for (const key in SB.defaults) {
if(!SB.localConfig.hasOwnProperty(key)) {
SB.localConfig[key] = SB.defaults[key];
}
}
};
// Sync config
setupConfig();

View File

@@ -332,5 +332,59 @@
},
"userIDChangeWarning": {
"message": "Warning: Changing the UserID is permanent. Are you sure you would like to do this? Make sure to backup your old one just in case."
},
"createdBy": {
"message": "Created By"
},
"autoSkip": {
"message": "Auto Skip"
},
"showSkipNotice": {
"message": "Show Notice After A Sponsor Is Skipped"
},
"keybindCurrentlySet": {
"message": ". It is currently set to:"
},
"supportInvidious": {
"message": "Support Invidious"
},
"supportInvidiousDescription": {
"message": "Invidious (invidio.us) is a third party YouTube client. To enable support, you must accept the extra permissions. This does NOT work in incongnito on chrome and other chromium variants."
},
"optionsInfo": {
"message": "Enable Invidious support, disable autoskip, hide buttons and more."
},
"addInvidiousInstance": {
"message": "Add Invidious Instance"
},
"addInvidiousInstanceDescription": {
"message": "Add a custom instance of Invidious. This must be formatted with JUST the domain. Example: invidious.ajay.app"
},
"add": {
"message": "Add"
},
"addInvidiousInstanceError": {
"message": "This is an invalid domain. This should JUST include the domain part. Example: invidious.ajay.app"
},
"resetInvidiousInstance": {
"message": "Reset Invidious Instance List"
},
"resetInvidiousInstanceAlert": {
"message": "You are about to reset the Invidious instance list"
},
"currentInstances": {
"message": "Current Instances:"
},
"enableAutoUpvote": {
"message": "Auto Upvote"
},
"whatAutoUpvote": {
"message": "With this enabled, the extension will upvote all submissions you view if you do not report them. If the notice is disabled, this will not occur."
},
"invidiousInfo1": {
"message": "Invidious (the 3rd party YouTube site) support has been added!"
},
"invidiousInfo2": {
"message": "You MUST enable it in the options for it to work."
}
}

View File

@@ -1,3 +1,15 @@
isBackgroundScript = true;
// Used only on Firefox, which does not support non persistent background pages.
var contentScriptRegistrations = {};
// Register content script if needed
if (isFirefox()) {
wait(() => SB.config !== undefined).then(function() {
if (SB.config.supportInvidious) setupExtraSiteContentScripts();
});
}
chrome.tabs.onUpdated.addListener(function(tabId) {
chrome.tabs.sendMessage(tabId, {
message: 'update',
@@ -6,74 +18,101 @@ chrome.tabs.onUpdated.addListener(function(tabId) {
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
switch(request.message) {
case "submitTimes":
submitTimes(request.videoID, callback);
//this allows the callback to be called later by the submitTimes function
return true;
case "addSponsorTime":
addSponsorTime(request.time, request.videoID, callback);
//this allows the callback to be called later
return true;
case "getSponsorTimes":
getSponsorTimes(request.videoID, function(sponsorTimes) {
callback({
sponsorTimes: sponsorTimes
})
});
//this allows the callback to be called later
return true;
case "submitVote":
submitVote(request.type, request.UUID, callback);
//this allows the callback to be called later
return true;
case "alertPrevious":
chrome.notifications.create("stillThere" + Math.random(), {
type: "basic",
title: chrome.i18n.getMessage("wantToSubmit") + " " + request.previousVideoID + "?",
message: chrome.i18n.getMessage("leftTimes"),
iconUrl: "./icons/LogoSponsorBlocker256px.png"
});
case "submitTimes":
submitTimes(request.videoID, callback);
//this allows the callback to be called later by the submitTimes function
return true;
case "addSponsorTime":
addSponsorTime(request.time, request.videoID, callback);
//this allows the callback to be called later
return true;
case "getSponsorTimes":
getSponsorTimes(request.videoID, function(sponsorTimes) {
callback({
sponsorTimes: sponsorTimes
})
});
//this allows the callback to be called later
return true;
case "submitVote":
submitVote(request.type, request.UUID, callback);
//this allows the callback to be called later
return true;
case "alertPrevious":
chrome.notifications.create("stillThere" + Math.random(), {
type: "basic",
title: chrome.i18n.getMessage("wantToSubmit") + " " + request.previousVideoID + "?",
message: chrome.i18n.getMessage("leftTimes"),
iconUrl: "./icons/LogoSponsorBlocker256px.png"
});
case "registerContentScript":
registerFirefoxContentScript(request);
return false;
case "unregisterContentScript":
contentScriptRegistrations[request.id].unregister();
delete contentScriptRegistrations[request.id];
return false;
}
});
//add help page on install
chrome.runtime.onInstalled.addListener(function (object) {
// This let's the config sync to run fully before checking.
// This is required on Firefox
setTimeout(function() {
chrome.storage.sync.get(["userID"], function(result) {
const userID = result.userID;
const userID = SB.config.userID;
// If there is no userID, then it is the first install.
if (!userID){
//open up the install page
chrome.tabs.create({url: chrome.extension.getURL("/help/index_en.html")});
// If there is no userID, then it is the first install.
if (!userID){
//open up the install page
chrome.tabs.create({url: chrome.extension.getURL("/help/index_en.html")});
//generate a userID
const newUserID = generateUserID();
//save this UUID
chrome.storage.sync.set({
"userID": newUserID
});
}
});
//generate a userID
const newUserID = generateUserID();
//save this UUID
SB.config.userID = newUserID;
//TODO: Remove when invidious support is old
// Don't show this to new users
SB.config.invidiousUpdateInfoShowCount = 6;
}
}, 1500);
});
/**
* Only works on Firefox.
* Firefox requires that it be applied after every extension restart.
*
* @param {JSON} options
*/
function registerFirefoxContentScript(options) {
let oldRegistration = contentScriptRegistrations[options.id];
if (oldRegistration) oldRegistration.unregister();
browser.contentScripts.register({
allFrames: options.allFrames,
js: options.js,
css: options.css,
matches: options.matches
}).then(() => void (contentScriptRegistrations[options.id] = registration));
}
//gets the sponsor times from memory
function getSponsorTimes(videoID, callback) {
let sponsorTimes = [];
let sponsorTimeKey = "sponsorTimes" + videoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimesStorage = result[sponsorTimeKey];
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
sponsorTimes = sponsorTimesStorage;
}
callback(sponsorTimes)
});
let sponsorTimesStorage = SB.config.sponsorTimes.get(videoID);
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
sponsorTimes = sponsorTimesStorage;
}
callback(sponsorTimes);
}
function addSponsorTime(time, videoID, callback) {
@@ -91,111 +130,97 @@ function addSponsorTime(time, videoID, callback) {
}
//save this info
let sponsorTimeKey = "sponsorTimes" + videoID;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, callback);
SB.config.sponsorTimes.set(videoID, sponsorTimes);
callback();
});
}
function submitVote(type, UUID, callback) {
chrome.storage.sync.get(["userID"], function(result) {
let userID = result.userID;
let userID = SB.config.userID;
if (userID == undefined || userID === "undefined") {
//generate one
userID = generateUserID();
chrome.storage.sync.set({
"userID": userID
if (userID == undefined || userID === "undefined") {
//generate one
userID = generateUserID();
SB.config.userID = userID;
}
//publish this vote
sendRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
callback({
successType: 1
});
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) {
//duplicate vote
callback({
successType: 0,
statusCode: xmlhttp.status
});
} else if (error) {
//error while connect
callback({
successType: -1,
statusCode: xmlhttp.status
});
}
//publish this vote
sendRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
callback({
successType: 1
});
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) {
//duplicate vote
callback({
successType: 0,
statusCode: xmlhttp.status
});
} else if (error) {
//error while connect
callback({
successType: -1,
statusCode: xmlhttp.status
});
}
})
})
});
}
function submitTimes(videoID, callback) {
async function submitTimes(videoID, callback) {
//get the video times from storage
let sponsorTimeKey = 'sponsorTimes' + videoID;
chrome.storage.sync.get([sponsorTimeKey, "userID"], async function(result) {
let sponsorTimes = result[sponsorTimeKey];
let userID = result.userID;
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
let durationResult = await new Promise((resolve, reject) => {
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "getVideoDuration"
}, (response) => resolve(response));
});
let sponsorTimes = SB.config.sponsorTimes.get(videoID);
let userID = SB.config.userID;
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
let durationResult = await new Promise((resolve, reject) => {
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "getVideoDuration"
}, (response) => resolve(response));
});
});
//check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i][1] > durationResult.duration) {
sponsorTimes[i][1] = durationResult.duration;
}
}
//submit these times
for (let i = 0; i < sponsorTimes.length; i++) {
//to prevent it from happeneing twice
let increasedContributionAmount = false;
//submit the sponsorTime
sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
+ "&userID=" + userID, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && !error) {
callback({
statusCode: xmlhttp.status
});
if (xmlhttp.status == 200) {
//add these to the storage log
chrome.storage.sync.get(["sponsorTimesContributed"], function(result) {
let currentContributionAmount = 0;
if (result.sponsorTimesContributed != undefined) {
//current contribution amount is known
currentContributionAmount = result.sponsorTimesContributed;
}
//save the amount contributed
if (!increasedContributionAmount) {
increasedContributionAmount = true;
chrome.storage.sync.set({"sponsorTimesContributed": currentContributionAmount + sponsorTimes.length});
}
});
}
} else if (error) {
callback({
statusCode: -1
});
}
});
//check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i][1] > durationResult.duration) {
sponsorTimes[i][1] = durationResult.duration;
}
}
});
//submit these times
for (let i = 0; i < sponsorTimes.length; i++) {
//to prevent it from happeneing twice
let increasedContributionAmount = false;
//submit the sponsorTime
sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
+ "&userID=" + userID, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && !error) {
callback({
statusCode: xmlhttp.status
});
if (xmlhttp.status == 200) {
//add these to the storage log
currentContributionAmount = SB.config.sponsorTimesContributed;
//save the amount contributed
if (!increasedContributionAmount) {
increasedContributionAmount = true;
SB.config.sponsorTimesContributed = currentContributionAmount + sponsorTimes.length;
}
}
} else if (error) {
callback({
statusCode: -1
});
}
});
}
}
}
function sendRequestToServer(type, address, callback) {
@@ -215,4 +240,4 @@ function sendRequestToServer(type, address, callback) {
//submit this request
xmlhttp.send();
}
}

View File

@@ -71,7 +71,7 @@
}
.sponsorSkipNotice {
min-width: 300px;
min-width: 350px;
background-color: rgba(28, 28, 28, 0.9);
position: absolute;
right: 5px;

View File

@@ -58,11 +58,6 @@ var lastSponsorTimeSkippedUUID = null;
//if showing the start sponsor button or the end sponsor button on the player
var showingStartSponsor = true;
//should the video controls buttons be added
var hideVideoPlayerControls = false;
var hideInfoButtonPlayerControls = false;
var hideDeleteButtonPlayerControls = false;
//the sponsor times being prepared to be submitted
var sponsorTimesSubmitting = [];
@@ -70,158 +65,103 @@ var sponsorTimesSubmitting = [];
//this is used to close the popup on YouTube when the other popup opens
var popupInitialised = false;
//should skips happen at all
var disableSkipping = false;
chrome.storage.sync.get(["disableSkipping"], function(result) {
let disableSkippingStorage = result.disableSkipping;
if (disableSkippingStorage != undefined) {
disableSkipping = disableSkippingStorage;
}
});
//should skips be manual
var disableAutoSkip = false;
chrome.storage.sync.get(["disableAutoSkip"], function(result) {
let disableAutoSkipStorage = result.disableAutoSkip;
if (disableAutoSkipStorage != undefined) {
disableAutoSkip = disableAutoSkipStorage;
}
});
//should view counts be tracked
var trackViewCount = false;
chrome.storage.sync.get(["trackViewCount"], function(result) {
let trackViewCountStorage = result.trackViewCount;
if (trackViewCountStorage != undefined) {
trackViewCount = trackViewCountStorage;
} else {
trackViewCount = true;
}
});
//if the notice should not be shown
//happens when the user click's the "Don't show notice again" button
//option renamed when new notice was made
var dontShowNotice = false;
chrome.storage.sync.get(["dontShowNotice"], function(result) {
let dontShowNoticeAgain = result.dontShowNotice;
if (dontShowNoticeAgain != undefined) {
dontShowNotice = dontShowNoticeAgain;
}
});
//load the legacy option to hide the notice
var dontShowNoticeOld = false;
chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) {
let dontShowNoticeAgain = result.dontShowNoticeAgain;
if (dontShowNoticeAgain != undefined) {
dontShowNoticeOld = dontShowNoticeAgain;
}
});
//get messages from the background script and the popup
chrome.runtime.onMessage.addListener(messageListener);
function messageListener(request, sender, sendResponse) {
//messages from popup script
switch(request.message){
case "update":
videoIDChange(getYouTubeVideoID(document.URL));
//messages from popup script
switch(request.message){
case "update":
videoIDChange(getYouTubeVideoID(document.URL));
break;
case "sponsorStart":
sponsorMessageStarted(sendResponse);
break;
case "sponsorStart":
sponsorMessageStarted(sendResponse);
break;
case "sponsorDataChanged":
updateSponsorTimesSubmitting();
break;
case "sponsorDataChanged":
updateSponsorTimesSubmitting();
break;
case "isInfoFound":
//send the sponsor times along with if it's found
sendResponse({
found: sponsorDataFound,
sponsorTimes: sponsorTimes,
hiddenSponsorTimes: hiddenSponsorTimes,
UUIDs: UUIDs
});
break;
case "isInfoFound":
//send the sponsor times along with if it's found
sendResponse({
found: sponsorDataFound,
sponsorTimes: sponsorTimes,
hiddenSponsorTimes: hiddenSponsorTimes,
UUIDs: UUIDs
});
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
//the popup should be closed now that another is opening
closeInfoMenu();
}
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
//the popup should be closed now that another is opening
closeInfoMenu();
}
popupInitialised = true;
break;
case "getVideoID":
sendResponse({
videoID: sponsorVideoID
});
popupInitialised = true;
break;
case "getVideoID":
sendResponse({
videoID: sponsorVideoID
});
break;
case "getVideoDuration":
sendResponse({
duration: v.duration
});
break;
case "getVideoDuration":
sendResponse({
duration: v.duration
});
break;
case "skipToTime":
v.currentTime = request.time;
return
case "getCurrentTime":
sendResponse({
currentTime: v.currentTime
});
break;
case "skipToTime":
v.currentTime = request.time;
return
case "getCurrentTime":
sendResponse({
currentTime: v.currentTime
});
break;
case "getChannelURL":
sendResponse({
channelURL: channelURL
});
break;
case "getChannelURL":
sendResponse({
channelURL: channelURL
});
break;
case "isChannelWhitelisted":
sendResponse({
value: channelWhitelisted
});
break;
case "isChannelWhitelisted":
sendResponse({
value: channelWhitelisted
});
break;
case "whitelistChange":
channelWhitelisted = request.value;
sponsorsLookup(sponsorVideoID);
break;
case "whitelistChange":
channelWhitelisted = request.value;
sponsorsLookup(sponsorVideoID);
break;
case "changeStartSponsorButton":
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
break;
case "dontShowNotice":
dontShowNotice = false;
break;
case "changeStartSponsorButton":
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
break;
case "showNoticeAgain":
dontShowNotice = false;
break;
case "changeVideoPlayerControlsVisibility":
hideVideoPlayerControls = request.value;
updateVisibilityOfPlayerControlsButton();
break;
case "changeInfoButtonPlayerControlsVisibility":
hideInfoButtonPlayerControls = request.value;
updateVisibilityOfPlayerControlsButton();
break;
case "changeDeleteButtonPlayerControlsVisibility":
hideDeleteButtonPlayerControls = request.value;
updateVisibilityOfPlayerControlsButton();
break;
case "trackViewCount":
trackViewCount = request.value;
break;
}
}
/**
* Called when the config is updated
*
* @param {String} changes
*/
function contentConfigUpdateListener(changes) {
for (const key in changes) {
switch(key) {
case "hideVideoPlayerControls":
case "hideInfoButtonPlayerControls":
case "hideDeleteButtonPlayerControls":
updateVisibilityOfPlayerControlsButton()
break;
}
}
}
if (!SB.configListeners.includes(contentConfigUpdateListener)) {
SB.configListeners.push(contentConfigUpdateListener);
}
//check for hotkey pressed
@@ -231,19 +171,9 @@ document.onkeydown = async function(e){
let video = document.getElementById("movie_player");
let startSponsorKey = await new Promise((resolve, reject) => {
chrome.storage.sync.get(["startSponsorKeybind"], (result) => resolve(result));
});
let submitKey = await new Promise((resolve, reject) => {
chrome.storage.sync.get(["submitKeybind"], (result) => resolve(result));
});
let startSponsorKey = SB.config.startSponsorKeybind;
if (startSponsorKey.startSponsorKeybind === undefined) {
startSponsorKey.startSponsorKeybind = ";"
}
if (submitKey.submitKeybind === undefined) {
submitKey.submitKeybind = "'"
}
let submitKey = SB.config.submitKeybind;
//is the video in focus, otherwise they could be typing a comment
if (document.activeElement === video) {
@@ -294,29 +224,39 @@ function videoIDChange(id) {
if (previewBar == null) {
//create it
wait(getControls).then(result => {
let progressBar = document.getElementsByClassName("ytp-progress-bar-container")[0] || document.getElementsByClassName("no-model cue-range-markers")[0];
previewBar = new PreviewBar(progressBar);
const progressElementSelectors = [
// For YouTube
"ytp-progress-bar-container",
"no-model cue-range-markers",
// For Invidious/VideoJS
"vjs-progress-holder"
];
for (const selector of progressElementSelectors) {
const el = document.getElementsByClassName(selector);
if (el && el.length && el[0]) {
previewBar = new PreviewBar(el[0]);
break;
}
}
});
}
//warn them if they had unsubmitted times
if (previousVideoID != null) {
//get the sponsor times from storage
let sponsorTimeKey = 'sponsorTimes' + previousVideoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimes = result[sponsorTimeKey];
let sponsorTimes = SB.config.sponsorTimes.get(previousVideoID);
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//warn them that they have unsubmitted sponsor times
chrome.runtime.sendMessage({
message: "alertPrevious",
previousVideoID: previousVideoID
})
}
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//warn them that they have unsubmitted sponsor times
chrome.runtime.sendMessage({
message: "alertPrevious",
previousVideoID: previousVideoID
})
}
//set the previous video id to the currentID
previousVideoID = id;
});
//set the previous video id to the currentID
previousVideoID = id;
} else {
//set the previous id now, don't wait for chrome.storage.get
previousVideoID = id;
@@ -358,30 +298,10 @@ function videoIDChange(id) {
}
});
});
//see if video controls buttons should be added
chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) {
if (result.hideVideoPlayerControls != undefined) {
hideVideoPlayerControls = result.hideVideoPlayerControls;
}
if (!onInvidious) {
updateVisibilityOfPlayerControlsButton();
});
chrome.storage.sync.get(["hideInfoButtonPlayerControls"], function(result) {
if (result.hideInfoButtonPlayerControls != undefined) {
hideInfoButtonPlayerControls = result.hideInfoButtonPlayerControls;
}
updateVisibilityOfPlayerControlsButton();
});
chrome.storage.sync.get(["hideDeleteButtonPlayerControls"], function(result) {
if (result.hideDeleteButtonPlayerControls != undefined) {
hideDeleteButtonPlayerControls = result.hideDeleteButtonPlayerControls;
}
updateVisibilityOfPlayerControlsButton(false);
});
}
}
function sponsorsLookup(id, channelIDPromise) {
@@ -463,7 +383,7 @@ function sponsorsLookup(id, channelIDPromise) {
});
//add the event to run on the videos "ontimeupdate"
if (!disableSkipping) {
if (!SB.config.disableSkipping) {
v.ontimeupdate = function () {
sponsorCheck();
};
@@ -503,6 +423,9 @@ function getChannelID() {
channelURLContainer = document.querySelector("#channel-name > #container > #text-container > #text");
if (channelURLContainer !== null) {
channelURLContainer = channelURLContainer.firstElementChild;
} else if (onInvidious) {
// Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers...
channelURLContainer = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a");
} else {
//old YouTube theme
let channelContainers = document.getElementsByClassName("yt-user-info");
@@ -521,6 +444,9 @@ function getChannelID() {
let currentTitle = "";
if (titleInfoContainer != null) {
currentTitle = titleInfoContainer.firstElementChild.firstElementChild.querySelector(".title").firstElementChild.innerText;
} else if (onInvidious) {
// Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers...
currentTitle = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a > div > span").textContent;
} else {
//old YouTube theme
currentTitle = document.getElementById("eow-title").innerText;
@@ -542,20 +468,16 @@ function getChannelID() {
//checks if this channel is whitelisted, should be done only after the channelID has been loaded
function whitelistCheck() {
//see if this is a whitelisted channel
chrome.storage.sync.get(["whitelistedChannels"], function(result) {
let whitelistedChannels = result.whitelistedChannels;
let whitelistedChannels = SB.config.whitelistedChannels;
console.log(channelURL)
if (whitelistedChannels != undefined && whitelistedChannels.includes(channelURL)) {
channelWhitelisted = true;
}
});
if (whitelistedChannels != undefined && whitelistedChannels.includes(channelURL)) {
channelWhitelisted = true;
}
}
//video skipping
function sponsorCheck() {
if (disableSkipping) {
if (SB.config.disableSkipping) {
// Make sure this isn't called again
v.ontimeupdate = null;
return;
@@ -621,7 +543,7 @@ function checkIfTimeToSkip(currentVideoTime, startTime, endTime) {
//skip fromt he start time to the end time for a certain index sponsor time
function skipToTime(v, index, sponsorTimes, openNotice) {
if (!disableAutoSkip) {
if (!SB.config.disableAutoSkip) {
v.currentTime = sponsorTimes[index][1];
}
@@ -632,42 +554,31 @@ function skipToTime(v, index, sponsorTimes, openNotice) {
if (openNotice) {
//send out the message saying that a sponsor message was skipped
if (!dontShowNotice) {
let skipNotice = new SkipNotice(this, currentUUID, disableAutoSkip);
if (!SB.config.dontShowNotice) {
let skipNotice = new SkipNotice(this, currentUUID, SB.config.disableAutoSkip);
if (dontShowNoticeOld) {
//show why this notice is showing
skipNotice.addNoticeInfoMessage(chrome.i18n.getMessage("noticeUpdate"), chrome.i18n.getMessage("noticeUpdate2"));
//TODO: Remove this when Invidious support is old
if (SB.config.invidiousUpdateInfoShowCount < 5) {
skipNotice.addNoticeInfoMessage(chrome.i18n.getMessage("invidiousInfo1"), chrome.i18n.getMessage("invidiousInfo2"));
//remove this setting
chrome.storage.sync.remove(["dontShowNoticeAgain"]);
dontShowNoticeOld = false;
SB.config.invidiousUpdateInfoShowCount += 1;
}
//auto-upvote this sponsor
if (trackViewCount && !disableAutoSkip) {
if (SB.config.trackViewCount && !SB.config.disableAutoSkip && SB.config.autoUpvote) {
vote(1, currentUUID, null);
}
}
}
//send telemetry that a this sponsor was skipped
if (trackViewCount && !sponsorSkipped[index]) {
if (SB.config.trackViewCount && !sponsorSkipped[index]) {
sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID);
if (!disableAutoSkip) {
if (!SB.config.disableAutoSkip) {
// Count this as a skip
chrome.storage.sync.get(["minutesSaved"], function(result) {
if (result.minutesSaved === undefined) result.minutesSaved = 0;
chrome.storage.sync.set({"minutesSaved": result.minutesSaved + (sponsorTimes[index][1] - sponsorTimes[index][0]) / 60 });
});
chrome.storage.sync.get(["skipCount"], function(result) {
if (result.skipCount === undefined) result.skipCount = 0;
chrome.storage.sync.set({"skipCount": result.skipCount + 1 });
});
SB.config.minutesSaved = SB.config.minutesSaved + (sponsorTimes[index][1] - sponsorTimes[index][0]) / 60;
SB.config.skipCount = SB.config.skipCount + 1;
sponsorSkipped[index] = true;
}
}
@@ -687,13 +598,6 @@ function reskipSponsorTime(UUID) {
}
}
function removePlayerControlsButton() {
if (!sponsorVideoID) return;
document.getElementById("startSponsorButton").style.display = "none";
document.getElementById("submitButton").style.display = "none";
}
function createButton(baseID, title, callback, imageName, isDraggable=false) {
if (document.getElementById(baseID + "Button") != null) return;
@@ -721,7 +625,14 @@ function createButton(baseID, title, callback, imageName, isDraggable=false) {
function getControls() {
let controls = document.getElementsByClassName("ytp-right-controls");
return (!controls || controls.length === 0) ? false : controls[controls.length - 1]
if (!controls || controls.length === 0) {
// The invidious video element's controls element
controls = document.getElementsByClassName("vjs-control-bar");
return (!controls || controls.length === 0) ? false : controls[controls.length - 1];
} else {
return controls[controls.length - 1];
}
};
//adds all the player controls buttons
@@ -744,14 +655,21 @@ async function updateVisibilityOfPlayerControlsButton() {
await createButtons();
if (hideVideoPlayerControls) {
removePlayerControlsButton();
if (SB.config.hideVideoPlayerControls || onInvidious) {
document.getElementById("startSponsorButton").style.display = "none";
document.getElementById("submitButton").style.display = "none";
} else {
document.getElementById("startSponsorButton").style.removeProperty("display");
}
//don't show the info button on embeds
if (hideInfoButtonPlayerControls || document.URL.includes("/embed/")) {
if (SB.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) {
document.getElementById("infoButton").style.display = "none";
} else {
document.getElementById("infoButton").style.removeProperty("display");
}
if (hideDeleteButtonPlayerControls) {
if (SB.config.hideDeleteButtonPlayerControls || onInvidious) {
document.getElementById("deleteButton").style.display = "none";
}
}
@@ -803,7 +721,7 @@ async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
await wait(isSubmitButtonLoaded);
//if it isn't visible, there is no data
let shouldHide = (uploadButtonVisible && !hideDeleteButtonPlayerControls) ? "unset" : "none"
let shouldHide = (uploadButtonVisible && !(SB.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
document.getElementById("deleteButton").style.display = shouldHide;
if (showStartSponsor) {
@@ -811,7 +729,7 @@ async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
document.getElementById("startSponsorImage").src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png");
document.getElementById("startSponsorButton").setAttribute("title", chrome.i18n.getMessage("sponsorStart"));
if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !hideInfoButtonPlayerControls) {
if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !SB.config.hideInfoButtonPlayerControls) {
document.getElementById("submitButton").style.display = "unset";
} else if (!uploadButtonVisible) {
//disable submit button
@@ -906,28 +824,24 @@ function clearSponsorTimes() {
let currentVideoID = sponsorVideoID;
let sponsorTimeKey = 'sponsorTimes' + currentVideoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimes = result[sponsorTimeKey];
let sponsorTimes = SB.config.sponsorTimes.get(currentVideoID);
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
let confirmMessage = chrome.i18n.getMessage("clearThis") + getSponsorTimesMessage(sponsorTimes);
confirmMessage += chrome.i18n.getMessage("confirmMSG")
if(!confirm(confirmMessage)) return;
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
let confirmMessage = chrome.i18n.getMessage("clearThis") + getSponsorTimesMessage(sponsorTimes);
confirmMessage += chrome.i18n.getMessage("confirmMSG")
if(!confirm(confirmMessage)) return;
//clear the sponsor times
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
chrome.storage.sync.set({[sponsorTimeKey]: []});
//clear the sponsor times
SB.config.sponsorTimes.delete(currentVideoID);
//clear sponsor times submitting
sponsorTimesSubmitting = [];
//clear sponsor times submitting
sponsorTimesSubmitting = [];
updatePreviewBar();
updatePreviewBar();
//set buttons to be correct
changeStartSponsorButton(true, false);
}
});
//set buttons to be correct
changeStartSponsorButton(true, false);
}
}
//if skipNotice is null, it will not affect the UI
@@ -949,17 +863,12 @@ function vote(type, UUID, skipNotice) {
sponsorSkipped[sponsorIndex] = false;
}
// Count this as a skip
chrome.storage.sync.get(["minutesSaved"], function(result) {
if (result.minutesSaved === undefined) result.minutesSaved = 0;
// Count this as a skip
SB.config.minutesSaved = SB.config.minutesSaved + factor * (sponsorTimes[sponsorIndex][1] - sponsorTimes[sponsorIndex][0]) / 60;
SB.config.skipCount = 0;
chrome.storage.sync.set({"minutesSaved": result.minutesSaved + factor * (sponsorTimes[sponsorIndex][1] - sponsorTimes[sponsorIndex][0]) / 60 });
});
chrome.storage.sync.get(["skipCount"], function(result) {
if (result.skipCount === undefined) result.skipCount = 0;
chrome.storage.sync.set({"skipCount": result.skipCount + factor * 1 });
});
SB.config.skipCount = SB.config.skipCount + factor * 1;
}
chrome.runtime.sendMessage({
@@ -997,10 +906,7 @@ function closeAllSkipNotices(){
}
function dontShowNoticeAgain() {
chrome.storage.sync.set({"dontShowNotice": true});
dontShowNotice = true;
SB.config.dontShowNotice = true;
closeAllSkipNotices();
}
@@ -1027,30 +933,27 @@ function submitSponsorTimes() {
let currentVideoID = sponsorVideoID;
let sponsorTimeKey = 'sponsorTimes' + currentVideoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimes = result[sponsorTimeKey];
let sponsorTimes = SB.config.sponsorTimes.get(currentVideoID);
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i][1] > v.duration) {
sponsorTimes[i][1] = v.duration;
}
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i][1] > v.duration) {
sponsorTimes[i][1] = v.duration;
}
//update sponsorTimes
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes});
//update sponsorTimesSubmitting
sponsorTimesSubmitting = sponsorTimes;
let confirmMessage = chrome.i18n.getMessage("submitCheck") + "\n\n" + getSponsorTimesMessage(sponsorTimes)
+ "\n\n" + chrome.i18n.getMessage("confirmMSG") + "\n\n" + chrome.i18n.getMessage("guildlinesSummary");
if(!confirm(confirmMessage)) return;
sendSubmitMessage();
}
});
//update sponsorTimes
SB.config.sponsorTimes.set(currentVideoID, sponsorTimes);
//update sponsorTimesSubmitting
sponsorTimesSubmitting = sponsorTimes;
let confirmMessage = chrome.i18n.getMessage("submitCheck") + "\n\n" + getSponsorTimesMessage(sponsorTimes)
+ "\n\n" + chrome.i18n.getMessage("confirmMSG") + "\n\n" + chrome.i18n.getMessage("guildlinesSummary");
if(!confirm(confirmMessage)) return;
sendSubmitMessage();
}
}
@@ -1085,8 +988,7 @@ function sendSubmitMessage(){
submitButton.addEventListener("animationend", animationEndListener);
//clear the sponsor times
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
chrome.storage.sync.set({[sponsorTimeKey]: []});
SB.config.sponsorTimes.delete(currentVideoID);
//add submissions to current sponsors list
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);

View File

@@ -1,8 +1,7 @@
{
"browser_specific_settings": {
"gecko": {
"id": "sponsorBlocker@ajay.app",
"strict_min_version": "57.0"
"id": "sponsorBlocker@ajay.app"
}
}
}

View File

@@ -13,7 +13,7 @@
<center>
<p class="createdBy">Created By <a href="https://ajay.app">Ajay Ramachandran</a></p>
<p class="createdBy">Created By <a href="https://ajay.app">Ajay Ramachandran</a> <img src="https://ajay.app/newprofilepic.jpg" height="30" class="profilepiccircle"/></p>
<p>
Thanks for installing SponsorBlock. Here are some quick tips for getting started. Please join the Discord if you have any questions or suggestions.
@@ -27,6 +27,12 @@
Come contribute, make some suggestions and help out in the Discord: <a href="https://discord.gg/QnmVMpU">https://discord.gg/QnmVMpU</a>
</p>
<a class="bigText" href="/options/options.html">Enable Invidious Support</a>
<p>
Invidious is a third-party YouTube viewer. SponsorBlock now supports invidious along with YouTube. Please visit the options page to make sure everything is how you want it to be.
</p>
<h1>How skipping works</h1>
<p class="projectPreview">

View File

@@ -1,4 +1,8 @@
:not(.hljs-keyword):not(.hljs-comment):not(.hljs-number):not(.hljs-string):not(pre):not(code) {
.bigText {
font-size: 50px;
}
body {
background-color: #333333;
}
@@ -83,6 +87,12 @@
vertical-align: middle;
}
.profilepiccircle {
vertical-align: middle;
overflow: hidden;
border-radius: 50%;
}
a {
text-decoration: underline;
color: inherit;
@@ -116,7 +126,7 @@ a {
text-decoration: none;
}
p,li {
p,li,a {
font-family: sans-serif;
font-size: 20;
color: #c4c4c4;

BIN
icons/newprofilepic.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -1,11 +1,12 @@
{
"name": "__MSG_fullName__",
"short_name": "__MSG_Name__",
"version": "1.2.2",
"version": "1.2.4",
"default_locale": "en",
"description": "__MSG_Description__",
"content_scripts": [
{
"run_at": "document_start",
"matches": [
"https://*.youtube.com/*",
"https://www.youtube-nocookie.com/embed/*"
@@ -13,6 +14,7 @@
"all_frames": true,
"js": [
"config.js",
"SB.js",
"utils/previewBar.js",
"utils/skipNotice.js",
"utils.js",
@@ -46,14 +48,19 @@
"notifications",
"https://sponsor.ajay.app/*"
],
"optional_permissions": [
"*://*/*",
"declarativeContent"
],
"browser_action": {
"default_title": "__MSG_Name__",
"default_popup": "popup.html"
},
"background": {
"scripts":[
"utils.js",
"config.js",
"SB.js",
"utils.js",
"background.js"
],
"persistent": false
@@ -65,5 +72,9 @@
"128": "icons/LogoSponsorBlocker128px.png",
"256": "icons/LogoSponsorBlocker256px.png"
},
"options_ui": {
"page": "options/options.html",
"open_in_tab": true
},
"manifest_version": 2
}

327
options/options.css Normal file
View File

@@ -0,0 +1,327 @@
/* Options page CSS */
body {
font-family: Sans-Serif;
}
.center {
text-align: center;
}
.inline {
display: inline-block;
}
.bold {
font-weight: bold;
}
.hidden {
display: none !important;
}
.keybind-status {
display: inline;
}
.small-description {
color: white;
font-size: 13;
}
.medium-description {
color: white;
font-size: 15;
}
.option-text-box {
width: 300px;
}
.option-button {
cursor: pointer;
background-color: #c00000;
padding: 10px;
color: white;
border-radius: 5px;
font-size: 14px;
width: max-content;
}
.option-button:hover {
background-color: #fc0303;
}
.option-button.disabled {
cursor: default;
background-color: #520000;
color: grey;
}
#options {
max-width: 60%;
text-align: left;
display: inline-block;
}
.switch-container:after {
content: attr(label-name);
position: absolute;
padding: 4px;
width: max-content;
font-size: 14px;
color: white;
}
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #707070;
}
.animated * {
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
background-color: white;
}
.animated .slider:before {
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #fc0303;
}
input:checked + .slider:before {
-webkit-transform: translateX(16px);
-ms-transform: translateX(16px);
transform: translateX(16px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
/* Boilerplate CSS from https://ajay.app */
body {
background-color: #333333;
}
.projectPreview {
position: relative;
}
.projectPreviewImage {
position: absolute;
left: -90;
width: 80;
top: 50%;
transform: translateY(-50%);
}
.projectPreviewImageLarge {
position: absolute;
left: -210;
width: 200;
top: 50%;
transform: translateY(-20%);
}
.projectPreviewImageLargeRight {
position: absolute;
right: -210;
width: 200;
top: 50%;
transform: translateY(-50%);
}
.createdBy {
font-size: 14px;
text-align: center;
padding-top: 0px;
padding-bottom: 0px;
display: inline-block;
}
#title {
background-color: #636363;
text-align: center;
vertical-align: middle;
font-family: sans-serif;
font-size: 50;
color: #212121;
/* height: 100; */
padding: 20;
text-decoration: none;
transition: font-size 1s;
}
#title:hover {
font-size: 60;
transition: font-size 1s;
}
.subtitle {
font-family: sans-serif;
font-size: 40;
color: #dad8d8;
padding-top: 10;
transition: font-size 0.4s;
}
.subtitle:hover {
font-size: 45;
transition: font-size 0.4s;
}
.profilepic {
background-color: #636363 !important;
vertical-align: middle;
}
.profilepiccircle {
vertical-align: middle;
overflow: hidden;
border-radius: 50%;
}
a {
text-decoration: underline;
color: inherit;
}
.link {
padding: 20;
height: 80px;
transition: height 0.2s;
}
.link:hover {
height: 95px;
transition: height 0.2s;
}
#contact,.smalllink {
font-family: sans-serif;
font-size: 25;
color: #e8e8e8;
text-align: center;
padding: 10;
}
#contact {
text-decoration: none;
}
p,li {
font-family: sans-serif;
font-size: 20;
color: #c4c4c4;
padding: 10;
}
p,li,code,a {
max-width: 60%;
text-align: left;
overflow-wrap: break-word;
}
@media screen and (orientation:portrait) {
p,li,code,a {
max-width: 100%;
}
.projectPreviewImage {
position: unset;
width: 130;
display: block;
margin: auto;
transform: none;
}
}
.previewImage {
max-height: 200px;
}
img {
max-width: 100%;
text-align: center;
}
#recentPostTitle {
font-family: sans-serif;
font-size: 30;
color: #dad8d8;
}
#recentPostDate {
font-family: sans-serif;
font-size: 15;
color: #dad8d8;
}
h1,h2,h3,h4,h5,h6 {
font-family: sans-serif;
color: #dad8d8;
}
svg {
text-decoration: none;
}

260
options/options.html Normal file
View File

@@ -0,0 +1,260 @@
<head>
<title>Options - SponsorBlock</title>
<link href="options.css" rel="stylesheet"/>
<script src="../utils.js"></script>
<script src="../SB.js"></script>
<script src="options.js"></script>
</head>
<body class="sponsorBlockPageBody">
<div id="title">
<img src="../icons/LogoSponsorBlocker256px.png" height="80" class="profilepic"/>
SponsorBlock
</div>
<div class="center">
<p class="createdBy">__MSG_createdBy__ <a href="https://ajay.app">Ajay Ramachandran</a> <img src="../icons/newprofilepic.jpg" height="30" class="profilepiccircle"/></p>
<h1>__MSG_Options__</h1>
<div id="options" class="hidden">
<div id="support-invidious" option-type="toggle" sync-option="supportInvidious">
<label class="switch-container" label-name="__MSG_supportInvidious__">
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_supportInvidiousDescription__</div>
</div>
<br/>
<br/>
<div option-type="text-change" sync-option="invidiousInstances">
<div class="option-button trigger-button">
__MSG_addInvidiousInstance__
</div>
<br/>
<div class="small-description">__MSG_addInvidiousInstanceDescription__</div>
<div class="option-hidden-section hidden">
<br/>
<input class="option-text-box" type="text">
<br/>
<br/>
<div class="option-button text-change-set inline">
__MSG_add__
</div>
<div class="option-button invidious-instance-reset inline">
__MSG_resetInvidiousInstance__
</div>
<br/>
<br/>
<span class="small-description">__MSG_currentInstances__</span>
<span class="small-description" option-type="display" sync-option="invidiousInstances"></span>
</div>
</div>
<br/>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="disableAutoSkip">
<label class="switch-container" label-name="__MSG_autoSkip__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_autoSkipDescription__</div>
</div>
<br/>
<br/>
<div option-type="keybind-change" sync-option="startSponsorKeybind">
<div class="option-button trigger-button">
__MSG_setStartSponsorShortcut__
</div>
<div class="option-hidden-section hidden">
<br/>
<div class="medium-description keybind-status">
__MSG_keybindDescription__
</div>
<span class="medium-description bold keybind-status-key">
</span>
</div>
</div>
<br/>
<br/>
<div option-type="keybind-change" sync-option="submitKeybind">
<div class="option-button trigger-button">
__MSG_setSubmitKeybind__
</div>
<div class="option-hidden-section hidden">
<br/>
<div class="medium-description keybind-status">
__MSG_keybindDescription__
</div>
<span class="medium-description bold keybind-status-key">
</span>
</div>
</div>
<br/>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="hideVideoPlayerControls">
<label class="switch-container" label-name="__MSG_showButtons__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_hideButtonsDescription__</div>
</div>
<br/>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="hideInfoButtonPlayerControls">
<label class="switch-container" label-name="__MSG_showInfoButton__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_whatInfoButton__</div>
</div>
<br/>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="hideDeleteButtonPlayerControls">
<label class="switch-container" label-name="__MSG_showDeleteButton__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_whatDeleteButton__</div>
</div>
<br/>
<br/>
<div option-type="toggle" sync-option="autoUpvote">
<label class="switch-container" label-name="__MSG_enableAutoUpvote__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_whatAutoUpvote__</div>
</div>
<br/>
<br/>
<div option-type="toggle" sync-option="trackViewCount">
<label class="switch-container" label-name="__MSG_enableViewTracking__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
<br/>
<br/>
<div class="small-description">__MSG_whatViewTracking__</div>
</div>
<br/>
<br/>
<div option-type="text-change" sync-option="userID" confirm-message="userIDChangeWarning">
<div class="option-button trigger-button">
__MSG_changeUserID__
</div>
<br/>
<div class="small-description">__MSG_whatChangeUserID__</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_setUserID__
</div>
</div>
</div>
<br/>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="dontShowNotice">
<label class="switch-container" label-name="__MSG_showSkipNotice__">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</label>
</div>
</div>
</div>
</body>

285
options/options.js Normal file
View File

@@ -0,0 +1,285 @@
window.addEventListener('DOMContentLoaded', init);
async function init() {
localizeHtmlPage();
if (!SB.configListeners.includes(optionsConfigUpdateListener)) {
SB.configListeners.push(optionsConfigUpdateListener);
}
await wait(() => SB.config !== undefined);
// Set all of the toggle options to the correct option
let optionsContainer = document.getElementById("options");
let optionsElements = optionsContainer.querySelectorAll("*");
for (let i = 0; i < optionsElements.length; i++) {
switch (optionsElements[i].getAttribute("option-type")) {
case "toggle":
let option = optionsElements[i].getAttribute("sync-option");
let optionResult = SB.config[option];
let checkbox = optionsElements[i].querySelector("input");
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
if (optionResult != undefined) {
checkbox.checked = optionResult;
if (reverse) {
optionsElements[i].querySelector("input").checked = !optionResult;
}
}
// See if anything extra should be run first time
switch (option) {
case "supportInvidious":
invidiousInit(checkbox, option);
break;
}
// Add click listener
checkbox.addEventListener("click", () => {
SB.config[option] = reverse ? !checkbox.checked : checkbox.checked;
// See if anything extra must be run
switch (option) {
case "supportInvidious":
invidiousOnClick(checkbox, option);
break;
}
});
break;
case "text-change":
let button = optionsElements[i].querySelector(".trigger-button");
button.addEventListener("click", () => activateTextChange(optionsElements[i]));
let textChangeOption = optionsElements[i].getAttribute("sync-option");
// See if anything extra must be done
switch (textChangeOption) {
case "invidiousInstances":
invidiousInstanceAddInit(optionsElements[i], textChangeOption);
}
break;
case "keybind-change":
let keybindButton = optionsElements[i].querySelector(".trigger-button");
keybindButton.addEventListener("click", () => activateKeybindChange(optionsElements[i]));
break;
case "display":
updateDisplayElement(optionsElements[i])
}
}
optionsContainer.classList.remove("hidden");
optionsContainer.classList.add("animated");
}
/**
* Called when the config is updated
*
* @param {String} element
*/
function optionsConfigUpdateListener(changes) {
let optionsContainer = document.getElementById("options");
let optionsElements = optionsContainer.querySelectorAll("*");
for (let i = 0; i < optionsElements.length; i++) {
switch (optionsElements[i].getAttribute("option-type")) {
case "display":
updateDisplayElement(optionsElements[i])
}
}
}
/**
* Will set display elements to the proper text
*
* @param {HTMLElement} element
*/
function updateDisplayElement(element) {
let displayOption = element.getAttribute("sync-option")
let displayText = SB.config[displayOption];
element.innerText = displayText;
// See if anything extra must be run
switch (displayOption) {
case "invidiousInstances":
element.innerText = displayText.join(', ');
break;
}
}
/**
* Initializes the option to add Invidious instances
*
* @param {HTMLElement} element
* @param {String} option
*/
function invidiousInstanceAddInit(element, option) {
let textBox = element.querySelector(".option-text-box");
let button = element.querySelector(".trigger-button");
let setButton = element.querySelector(".text-change-set");
setButton.addEventListener("click", async function(e) {
if (textBox.value == "" || textBox.value.includes("/") || textBox.value.includes("http") || textBox.value.includes(":")) {
alert(chrome.i18n.getMessage("addInvidiousInstanceError"));
} else {
// Add this
let instanceList = SB.config[option];
if (!instanceList) instanceList = [];
instanceList.push(textBox.value);
SB.config[option] = instanceList;
let checkbox = document.querySelector("#support-invidious input");
checkbox.checked = true;
invidiousOnClick(checkbox, "supportInvidious");
textBox.value = "";
// Hide this section again
element.querySelector(".option-hidden-section").classList.add("hidden");
button.classList.remove("disabled");
}
});
let resetButton = element.querySelector(".invidious-instance-reset");
resetButton.addEventListener("click", function(e) {
if (confirm(chrome.i18n.getMessage("resetInvidiousInstanceAlert"))) {
// Set to a clone of the default
SB.config[option] = SB.defaults[option].slice(0);
}
});
}
/**
* Run when the invidious button is being initialized
*
* @param {HTMLElement} checkbox
* @param {string} option
*/
function invidiousInit(checkbox, option) {
let permissions = ["declarativeContent"];
if (isFirefox()) permissions = [];
chrome.permissions.contains({
origins: getInvidiousInstancesRegex(),
permissions: permissions
}, function (result) {
if (result != checkbox.checked) {
SB.config[option] = result;
checkbox.checked = result;
}
});
}
/**
* Run whenever the invidious checkbox is clicked
*
* @param {HTMLElement} checkbox
* @param {string} option
*/
function invidiousOnClick(checkbox, option) {
if (checkbox.checked) {
setupExtraSitePermissions(function (granted) {
if (!granted) {
SB.config[option] = false;
checkbox.checked = false;
}
});
} else {
removeExtraSiteRegistration();
}
}
/**
* Will trigger the container to ask the user for a keybind.
*
* @param {HTMLElement} element
*/
function activateKeybindChange(element) {
let button = element.querySelector(".trigger-button");
if (button.classList.contains("disabled")) return;
button.classList.add("disabled");
let option = element.getAttribute("sync-option");
let currentlySet = SB.config[option] !== null ? chrome.i18n.getMessage("keybindCurrentlySet") : "";
let status = element.querySelector(".option-hidden-section > .keybind-status");
status.innerText = chrome.i18n.getMessage("keybindDescription") + currentlySet;
if (SB.config[option] !== null) {
let statusKey = element.querySelector(".option-hidden-section > .keybind-status-key");
statusKey.innerText = SB.config[option];
}
element.querySelector(".option-hidden-section").classList.remove("hidden");
document.addEventListener("keydown", (e) => keybindKeyPressed(element, e), {once: true});
}
/**
* Called when a key is pressed in an activiated keybind change option.
*
* @param {HTMLElement} element
* @param {KeyboardEvent} e
*/
function keybindKeyPressed(element, e) {
e = e || window.event;
var key = e.key;
let option = element.getAttribute("sync-option");
SB.config[option] = key;
let status = element.querySelector(".option-hidden-section > .keybind-status");
status.innerText = chrome.i18n.getMessage("keybindDescriptionComplete");
let statusKey = element.querySelector(".option-hidden-section > .keybind-status-key");
statusKey.innerText = key;
let button = element.querySelector(".trigger-button");
button.classList.remove("disabled");
}
/**
* Will trigger the textbox to appear to be able to change an option's text.
*
* @param {HTMLElement} element
*/
function activateTextChange(element) {
let button = element.querySelector(".trigger-button");
if (button.classList.contains("disabled")) return;
button.classList.add("disabled");
let textBox = element.querySelector(".option-text-box");
let option = element.getAttribute("sync-option");
// See if anything extra must be done
switch (option) {
case "invidiousInstances":
element.querySelector(".option-hidden-section").classList.remove("hidden");
return;
}
textBox.value = SB.config[option];
let setButton = element.querySelector(".text-change-set");
setButton.addEventListener("click", () => {
let confirmMessage = element.getAttribute("confirm-message");
if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) {
SB.config[option] = textBox.value;
}
});
element.querySelector(".option-hidden-section").classList.remove("hidden");
}

7588
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

22
package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "sponsorblock",
"version": "1.0.0",
"description": "",
"main": "background.js",
"dependencies": {},
"devDependencies": {
"web-ext": "^4.0.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "web-ext run --start-url https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm",
"build": "web-ext build --overwrite-dest -i \"*(package-lock.json|README.md|package.json|config.js.example|firefox_manifest-extra.json|manifest.json.original|ignored|crowdin.yml)\""
},
"repository": {
"type": "git",
"url": "git+https://github.com/ajayyy/SponsorBlock.git"
},
"author": "Ajay Ramachandran",
"license": "GPL-3.0-only",
"private": true
}

View File

@@ -1,13 +1,14 @@
<html>
<head>
<title>__MSG_openPopup__</title>
<script src="SB.js"></script>
<link id="sponorBlockPopupFont" rel="stylesheet" type="text/css" href="/libs/Source+Sans+Pro.css"/>
<link id="sponorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/>
</head>
<body class="popupBody">
<center>
<div id="app" class="popupBody">
<div id="app" class="popupBody sponsorBlockPageBody">
<h1 class="popupElement">
<img src="icons/IconSponsorBlocker256px.png" height="32px" id="sponsorBlockPopupLogo"/>
__MSG_Name__
@@ -193,100 +194,17 @@
<br/>
<button id="optionsButton" class="dangerButton popupElement">__MSG_Options__</button>
<br/>
<sub class="popupElement">
__MSG_optionsInfo__
</sub>
<br/>
</div>
<div id="options" class="popupElement" style="display: none">
<br/>
<h3>__MSG_Options__</h3>
<button id="disableAutoSkip" class="warningButton popupElement">__MSG_disableAutoSkip__</button>
<button id="enableAutoSkip" style="display: none" class="warningButton popupElement">__MSG_enableAutoSkip__</button>
<br/>
<sub class="popupElement">
__MSG_autoSkipDescription__
</sub>
<br/>
<br/>
<span id="keybindButtons">
<button id="setStartSponsorKeybind" class="warningButton popupElement">__MSG_setStartSponsorShortcut__</button>
<br/>
<br/>
<button id="setSubmitKeybind" class="warningButton popupElement">__MSG_setSubmitKeybind__</button>
<br/>
</span>
<h2 id="keybindDescription" style="display: none" class="popupElement">__MSG_keybindDescription__</h2>
<br/>
<br/>
<button id="hideVideoPlayerControls" class="warningButton popupElement">__MSG_hideButtons__</button>
<button id="showVideoPlayerControls" style="display: none" class="warningButton popupElement">__MSG_showButtons__</button>
<br/>
<sub class="popupElement">
__MSG_hideButtonsDescription__
</sub>
<br/>
<br/>
<button id="hideInfoButtonPlayerControls" class="warningButton popupElement">__MSG_hideInfoButton__</button>
<button id="showInfoButtonPlayerControls" style="display: none" class="warningButton popupElement">__MSG_showInfoButton__</button>
<br/>
<sub class="popupElement">
__MSG_whatInfoButton__
</sub>
<br/>
<br/>
<button id="hideDeleteButtonPlayerControls" class="warningButton popupElement">__MSG_hideDeleteButton__</button>
<button id="showDeleteButtonPlayerControls" style="display: none" class="warningButton popupElement">__MSG_showDeleteButton__</button>
<br/>
<sub class="popupElement">
__MSG_whatDeleteButton__
</sub>
<br/>
<br/>
<button id="changeUserIDButton" class="warningButton popupElement">__MSG_changeUserID__</button>
<br/>
<sub class="popupElement">
__MSG_whatChangeUserID__
</sub>
<div id="changeUserID" class="popupElement" style="display: none">
<br/>
<br/>
<input id="userIDInput" hint="userID"></input>
<br/>
<br/>
<button id="setUserID" class="warningButton popupElement">__MSG_setUserID__</button>
</div>
<br/>
<br/>
<button id="disableSponsorViewTracking" class="warningButton popupElement">__MSG_disableViewTracking__</button>
<button id="enableSponsorViewTracking" style="display: none" class="warningButton popupElement">__MSG_enableViewTracking__</button>
<br/>
<sub class="popupElement">
__MSG_whatViewTracking__
</sub>
<br/>
<br/>
<button id="showNoticeAgain" style="display: none" class="dangerButton popupElement">__MSG_showNotice__</button>
</div>
<button id="showNoticeAgain" style="display: none" class="dangerButton popupElement">__MSG_showNotice__</button>
</div>
</center>
</body>

615
popup.js
View File

@@ -1,29 +1,27 @@
//make this a function to allow this to run on the content page
function runThePopup() {
async function runThePopup() {
localizeHtmlPage();
//is it in the popup or content script
var inPopup = true;
if (chrome.tabs == undefined) {
//this is on the content script, use direct communication
chrome.tabs = {};
chrome.tabs.sendMessage = function(id, request, callback) {
messageListener(request, null, callback);
}
//add a dummy query method
chrome.tabs.query = function(config, callback) {
callback([{
url: document.URL,
id: -1
}]);
}
inPopup = false;
//this is on the content script, use direct communication
chrome.tabs = {};
chrome.tabs.sendMessage = function(id, request, callback) {
messageListener(request, null, callback);
}
//add a dummy query method
chrome.tabs.query = function(config, callback) {
callback([{
url: document.URL,
id: -1
}]);
}
inPopup = false;
}
var SB = {};
await wait(() => SB.config !== undefined);
["sponsorStart",
// Top toggles
@@ -31,22 +29,12 @@ function runThePopup() {
"unwhitelistChannel",
"disableSkipping",
"enableSkipping",
// Options
"showNoticeAgain",
"optionsButton",
// More controls
"clearTimes",
"submitTimes",
// options
"showNoticeAgain",
"disableAutoSkip",
"enableAutoSkip",
"hideVideoPlayerControls",
"showVideoPlayerControls",
"hideInfoButtonPlayerControls",
"showInfoButtonPlayerControls",
"hideDeleteButtonPlayerControls",
"showDeleteButtonPlayerControls",
"disableSponsorViewTracking",
"enableSponsorViewTracking",
"optionsButton",
"reportAnIssue",
// sponsorTimesContributions
"sponsorTimesContributionsContainer",
@@ -82,11 +70,6 @@ function runThePopup() {
"setUsername",
"usernameInput",
"submitUsername",
// UserID
"changeUserID",
"changeUserIDButton",
"userIDInput",
"setUserID",
// More
"submissionSection",
"mainControls",
@@ -94,10 +77,6 @@ function runThePopup() {
"videoFound",
"sponsorMessageTimes",
"downloadedSponsorMessageTimes",
// Keybinds
"setStartSponsorKeybind",
"setSubmitKeybind",
"keybindDescription"
].forEach(id => SB[id] = document.getElementById(id));
//setup click listeners
@@ -109,26 +88,12 @@ function runThePopup() {
SB.clearTimes.addEventListener("click", clearTimes);
SB.submitTimes.addEventListener("click", submitTimes);
SB.showNoticeAgain.addEventListener("click", showNoticeAgain);
SB.disableAutoSkip.addEventListener("click", () => setAutoSkip(true));
SB.enableAutoSkip.addEventListener("click", () => setAutoSkip(false));
SB.setStartSponsorKeybind.addEventListener("click", () => setKeybind(true));
SB.setSubmitKeybind.addEventListener("click", () => setKeybind(false));
SB.hideVideoPlayerControls.addEventListener("click", hideVideoPlayerControls);
SB.showVideoPlayerControls.addEventListener("click", showVideoPlayerControls);
SB.hideInfoButtonPlayerControls.addEventListener("click", hideInfoButtonPlayerControls);
SB.showInfoButtonPlayerControls.addEventListener("click", showInfoButtonPlayerControls);
SB.hideDeleteButtonPlayerControls.addEventListener("click", hideDeleteButtonPlayerControls);
SB.showDeleteButtonPlayerControls.addEventListener("click", showDeleteButtonPlayerControls);
SB.disableSponsorViewTracking.addEventListener("click", disableSponsorViewTracking);
SB.enableSponsorViewTracking.addEventListener("click", enableSponsorViewTracking);
SB.setUsernameButton.addEventListener("click", setUsernameButton);
SB.submitUsername.addEventListener("click", submitUsername);
SB.changeUserIDButton.addEventListener("click", changeUserIDButton);
SB.setUserID.addEventListener("click", setUserID);
SB.optionsButton.addEventListener("click", openOptions);
SB.reportAnIssue.addEventListener("click", reportAnIssue);
SB.hideDiscordButton.addEventListener("click", hideDiscordButton);
//if true, the button now selects the end time
let startTimeChosen = false;
@@ -138,178 +103,114 @@ function runThePopup() {
//current video ID of this tab
let currentVideoID = null;
//is this a YouTube tab?
let isYouTubeTab = false;
// Is the start sponsor keybind currently being set
let setStartSponsorKeybind = false;
//see if discord link can be shown
chrome.storage.sync.get(["hideDiscordLink"], function(result) {
let hideDiscordLink = result.hideDiscordLink;
if (hideDiscordLink == undefined || !hideDiscordLink) {
chrome.storage.sync.get(["hideDiscordLaunches"], function(result) {
let hideDiscordLaunches = result.hideDiscordLaunches;
//only if less than 10 launches
if (hideDiscordLaunches == undefined || hideDiscordLaunches < 10) {
SB.discordButtonContainer.style.display = null;
if (hideDiscordLaunches == undefined) {
hideDiscordLaunches = 1;
}
chrome.storage.sync.set({"hideDiscordLaunches": hideDiscordLaunches + 1});
let hideDiscordLink = SB.config.hideDiscordLink;
if (hideDiscordLink == undefined || !hideDiscordLink) {
let hideDiscordLaunches = SB.config.hideDiscordLaunches;
//only if less than 10 launches
if (hideDiscordLaunches == undefined || hideDiscordLaunches < 10) {
SB.discordButtonContainer.style.display = null;
if (hideDiscordLaunches == undefined) {
hideDiscordLaunches = 1;
}
});
}
});
SB.config.hideDiscordLaunches = hideDiscordLaunches + 1;
}
}
//show proper disable skipping button
chrome.storage.sync.get(["disableSkipping"], function(result) {
let disableSkipping = result.disableSkipping;
if (disableSkipping != undefined && disableSkipping) {
SB.disableSkipping.style.display = "none";
SB.enableSkipping.style.display = "unset";
}
});
let disableSkipping = SB.config.disableSkipping;
if (disableSkipping != undefined && disableSkipping) {
SB.disableSkipping.style.display = "none";
SB.enableSkipping.style.display = "unset";
}
//if the don't show notice again variable is true, an option to
// disable should be available
chrome.storage.sync.get(["dontShowNotice"], function(result) {
let dontShowNotice = result.dontShowNotice;
if (dontShowNotice != undefined && dontShowNotice) {
SB.showNoticeAgain.style.display = "unset";
}
});
let dontShowNotice = SB.config.dontShowNotice;
if (dontShowNotice != undefined && dontShowNotice) {
SB.showNoticeAgain.style.display = "unset";
}
//show proper auto skip option
chrome.storage.sync.get(["disableAutoSkip"], function(result) {
let disableAutoSkip = result.disableAutoSkip;
if (disableAutoSkip != undefined && disableAutoSkip) {
SB.disableAutoSkip.style.display = "none";
SB.enableAutoSkip.style.display = "unset";
}
});
//show proper video player controls options
chrome.storage.sync.get(["hideVideoPlayerControls"], function(result) {
let hideVideoPlayerControls = result.hideVideoPlayerControls;
if (hideVideoPlayerControls != undefined && hideVideoPlayerControls) {
SB.hideVideoPlayerControls.style.display = "none";
SB.showVideoPlayerControls.style.display = "unset";
}
});
chrome.storage.sync.get(["hideInfoButtonPlayerControls"], function(result) {
let hideInfoButtonPlayerControls = result.hideInfoButtonPlayerControls;
if (hideInfoButtonPlayerControls != undefined && hideInfoButtonPlayerControls) {
SB.hideInfoButtonPlayerControls.style.display = "none";
SB.showInfoButtonPlayerControls.style.display = "unset";
}
});
chrome.storage.sync.get(["hideDeleteButtonPlayerControls"], function(result) {
let hideDeleteButtonPlayerControls = result.hideDeleteButtonPlayerControls;
if (hideDeleteButtonPlayerControls != undefined && hideDeleteButtonPlayerControls) {
SB.hideDeleteButtonPlayerControls.style.display = "none";
SB.showDeleteButtonPlayerControls.style.display = "unset";
}
});
//show proper tracking option
chrome.storage.sync.get(["trackViewCount"], function(result) {
let trackViewCount = result.trackViewCount;
if (trackViewCount != undefined && !trackViewCount) {
SB.disableSponsorViewTracking.style.display = "none";
SB.enableSponsorViewTracking.style.display = "unset";
}
});
//get the amount of times this user has contributed and display it to thank them
chrome.storage.sync.get(["sponsorTimesContributed"], function(result) {
if (result.sponsorTimesContributed != undefined) {
if (result.sponsorTimesContributed > 1) {
SB.sponsorTimesContributionsDisplayEndWord.innerText = chrome.i18n.getMessage("Sponsors");
} else {
SB.sponsorTimesContributionsDisplayEndWord.innerText = chrome.i18n.getMessage("Sponsor");
}
SB.sponsorTimesContributionsDisplay.innerText = result.sponsorTimesContributed;
SB.sponsorTimesContributionsContainer.style.display = "unset";
//get the userID
chrome.storage.sync.get(["userID"], function(result) {
let userID = result.userID;
if (userID != undefined) {
//there are probably some views on these submissions then
//get the amount of views from the sponsors submitted
sendRequestToServer("GET", "/api/getViewsForUser?userID=" + userID, function(xmlhttp) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let viewCount = JSON.parse(xmlhttp.responseText).viewCount;
if (viewCount != 0) {
if (viewCount > 1) {
SB.sponsorTimesViewsDisplayEndWord.innerText = chrome.i18n.getMessage("Segments");
} else {
SB.sponsorTimesViewsDisplayEndWord.innerText = chrome.i18n.getMessage("Segment");
}
SB.sponsorTimesViewsDisplay.innerText = viewCount;
SB.sponsorTimesViewsContainer.style.display = "unset";
}
}
});
//get this time in minutes
sendRequestToServer("GET", "/api/getSavedTimeForUser?userID=" + userID, function(xmlhttp) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let minutesSaved = JSON.parse(xmlhttp.responseText).timeSaved;
if (minutesSaved != 0) {
if (minutesSaved != 1) {
SB.sponsorTimesOthersTimeSavedEndWord.innerText = chrome.i18n.getMessage("minsLower");
} else {
SB.sponsorTimesOthersTimeSavedEndWord.innerText = chrome.i18n.getMessage("minLower");
}
SB.sponsorTimesOthersTimeSavedDisplay.innerText = getFormattedHours(minutesSaved);
SB.sponsorTimesOthersTimeSavedContainer.style.display = "unset";
}
}
});
}
});
if (SB.config.sponsorTimesContributed != undefined) {
if (SB.config.sponsorTimesContributed > 1) {
SB.sponsorTimesContributionsDisplayEndWord.innerText = chrome.i18n.getMessage("Sponsors");
} else {
SB.sponsorTimesContributionsDisplayEndWord.innerText = chrome.i18n.getMessage("Sponsor");
}
});
SB.sponsorTimesContributionsDisplay.innerText = SB.config.sponsorTimesContributed;
SB.sponsorTimesContributionsContainer.style.display = "unset";
//get the userID
let userID = SB.config.userID;
if (userID != undefined) {
//there are probably some views on these submissions then
//get the amount of views from the sponsors submitted
sendRequestToServer("GET", "/api/getViewsForUser?userID=" + userID, function(xmlhttp) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let viewCount = JSON.parse(xmlhttp.responseText).viewCount;
if (viewCount != 0) {
if (viewCount > 1) {
SB.sponsorTimesViewsDisplayEndWord.innerText = chrome.i18n.getMessage("Segments");
} else {
SB.sponsorTimesViewsDisplayEndWord.innerText = chrome.i18n.getMessage("Segment");
}
SB.sponsorTimesViewsDisplay.innerText = viewCount;
SB.sponsorTimesViewsContainer.style.display = "unset";
}
}
});
//get this time in minutes
sendRequestToServer("GET", "/api/getSavedTimeForUser?userID=" + userID, function(xmlhttp) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let minutesSaved = JSON.parse(xmlhttp.responseText).timeSaved;
if (minutesSaved != 0) {
if (minutesSaved != 1) {
SB.sponsorTimesOthersTimeSavedEndWord.innerText = chrome.i18n.getMessage("minsLower");
} else {
SB.sponsorTimesOthersTimeSavedEndWord.innerText = chrome.i18n.getMessage("minLower");
}
SB.sponsorTimesOthersTimeSavedDisplay.innerText = getFormattedHours(minutesSaved);
SB.sponsorTimesOthersTimeSavedContainer.style.display = "unset";
}
}
});
}
}
//get the amount of times this user has skipped a sponsor
chrome.storage.sync.get(["skipCount"], function(result) {
if (result.skipCount != undefined) {
if (result.skipCount != 1) {
SB.sponsorTimesSkipsDoneEndWord.innerText = chrome.i18n.getMessage("Sponsors");
} else {
SB.sponsorTimesSkipsDoneEndWord.innerText = chrome.i18n.getMessage("Sponsor");
}
SB.sponsorTimesSkipsDoneDisplay.innerText = result.skipCount;
SB.sponsorTimesSkipsDoneContainer.style.display = "unset";
if (SB.config.skipCount != undefined) {
if (SB.config.skipCount != 1) {
SB.sponsorTimesSkipsDoneEndWord.innerText = chrome.i18n.getMessage("Sponsors");
} else {
SB.sponsorTimesSkipsDoneEndWord.innerText = chrome.i18n.getMessage("Sponsor");
}
});
SB.sponsorTimesSkipsDoneDisplay.innerText = SB.config.skipCount;
SB.sponsorTimesSkipsDoneContainer.style.display = "unset";
}
//get the amount of time this user has saved.
chrome.storage.sync.get(["minutesSaved"], function(result) {
if (result.minutesSaved != undefined) {
if (result.minutesSaved != 1) {
SB.sponsorTimeSavedEndWord.innerText = chrome.i18n.getMessage("minsLower");
} else {
SB.sponsorTimeSavedEndWord.innerText = chrome.i18n.getMessage("minLower");
}
SB.sponsorTimeSavedDisplay.innerText = getFormattedHours(result.minutesSaved);
SB.sponsorTimeSavedContainer.style.display = "unset";
if (SB.config.minutesSaved != undefined) {
if (SB.config.minutesSaved != 1) {
SB.sponsorTimeSavedEndWord.innerText = chrome.i18n.getMessage("minsLower");
} else {
SB.sponsorTimeSavedEndWord.innerText = chrome.i18n.getMessage("minLower");
}
});
SB.sponsorTimeSavedDisplay.innerText = getFormattedHours(SB.config.minutesSaved);
SB.sponsorTimeSavedContainer.style.display = "unset";
}
chrome.tabs.query({
active: true,
currentWindow: true
}, onTabs);
function onTabs(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {message: 'getVideoID'}, function(result) {
if (result != undefined && result.videoID) {
@@ -330,25 +231,22 @@ function runThePopup() {
}
//load video times for this video
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimesStorage = result[sponsorTimeKey];
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
if (sponsorTimesStorage[sponsorTimesStorage.length - 1] != undefined && sponsorTimesStorage[sponsorTimesStorage.length - 1].length < 2) {
startTimeChosen = true;
SB.sponsorStart.innerHTML = chrome.i18n.getMessage("sponsorEnd");
}
sponsorTimes = sponsorTimesStorage;
displaySponsorTimes();
//show submission section
SB.submissionSection.style.display = "unset";
showSubmitTimesIfNecessary();
let sponsorTimesStorage = SB.config.sponsorTimes.get(currentVideoID);
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
if (sponsorTimesStorage[sponsorTimesStorage.length - 1] != undefined && sponsorTimesStorage[sponsorTimesStorage.length - 1].length < 2) {
startTimeChosen = true;
SB.sponsorStart.innerHTML = chrome.i18n.getMessage("sponsorEnd");
}
});
sponsorTimes = sponsorTimesStorage;
displaySponsorTimes();
//show submission section
SB.submissionSection.style.display = "unset";
showSubmitTimesIfNecessary();
}
//check if this video's sponsors are known
chrome.tabs.sendMessage(
@@ -405,13 +303,6 @@ function runThePopup() {
);
}
function setVideoID(request) {
//if request is undefined, then the page currently being browsed is not YouTube
if (request != undefined) {
videoID = request.videoID;
}
}
function sendSponsorStartMessage() {
//the content script will get the message if a YouTube page is open
chrome.tabs.query({
@@ -434,10 +325,9 @@ function runThePopup() {
}
sponsorTimes[sponsorTimesIndex][startTimeChosen ? 1 : 0] = response.time;
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
let localStartTimeChosen = startTimeChosen;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, function() {
SB.config.sponsorTimes.set(currentVideoID, sponsorTimes);
//send a message to the client script
if (localStartTimeChosen) {
chrome.tabs.query({
@@ -450,7 +340,6 @@ function runThePopup() {
);
});
}
});
updateStartTimeChosen();
@@ -770,8 +659,7 @@ function runThePopup() {
sponsorTimes[index][1] = getSponsorTimeEditTimes("endTime", index);
//save this
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, function() {
SB.config.sponsorTimes.set(currentVideoID, sponsorTimes);
chrome.tabs.query({
active: true,
currentWindow: true
@@ -781,7 +669,6 @@ function runThePopup() {
{message: "sponsorDataChanged"}
);
});
});
if (closeEditMode) {
displaySponsorTimes();
@@ -811,8 +698,7 @@ function runThePopup() {
sponsorTimes.splice(index, 1);
//save this
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, function() {
SB.config.sponsorTimes.set(currentVideoID, sponsorTimes);
chrome.tabs.query({
active: true,
currentWindow: true
@@ -822,7 +708,6 @@ function runThePopup() {
{message: "sponsorDataChanged"}
);
});
});
//update display
displaySponsorTimes();
@@ -863,9 +748,8 @@ function runThePopup() {
//reset sponsorTimes
sponsorTimes = [];
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, function() {
SB.config.sponsorTimes.set(currentVideoID, sponsorTimes);
chrome.tabs.query({
active: true,
currentWindow: true
@@ -875,7 +759,6 @@ function runThePopup() {
{message: "sponsorDataChanged"}
);
});
});
displaySponsorTimes();
@@ -913,171 +796,11 @@ function runThePopup() {
}
function showNoticeAgain() {
chrome.storage.sync.set({"dontShowNotice": false});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "showNoticeAgain"
});
});
SB.config.dontShowNotice = false;
SB.showNoticeAgain.style.display = "none";
}
function setAutoSkip(value) {
chrome.storage.sync.set({"disableAutoSkip": value});
if (value) {
// If it isn't shown, they can't manually skip
showNoticeAgain();
SB.disableAutoSkip.style.display = "none";
SB.enableAutoSkip.style.display = "unset";
} else {
SB.enableAutoSkip.style.display = "none";
SB.disableAutoSkip.style.display = "unset";
}
}
function hideVideoPlayerControls() {
chrome.storage.sync.set({"hideVideoPlayerControls": true});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "changeVideoPlayerControlsVisibility",
value: true
});
});
SB.hideVideoPlayerControls.style.display = "none";
SB.showVideoPlayerControls.style.display = "unset";
}
function showVideoPlayerControls() {
chrome.storage.sync.set({"hideVideoPlayerControls": false});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "changeVideoPlayerControlsVisibility",
value: false
});
});
SB.hideVideoPlayerControls.style.display = "unset";
SB.showVideoPlayerControls.style.display = "none";
}
function hideInfoButtonPlayerControls() {
chrome.storage.sync.set({"hideInfoButtonPlayerControls": true});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "changeInfoButtonPlayerControlsVisibility",
value: true
});
});
SB.hideInfoButtonPlayerControls.style.display = "none";
SB.showInfoButtonPlayerControls.style.display = "unset";
}
function showInfoButtonPlayerControls() {
chrome.storage.sync.set({"hideInfoButtonPlayerControls": false});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "changeVideoPlayerCochangeInfoButtonPlayerControlsVisibilityntrolsVisibility",
value: false
});
});
SB.hideInfoButtonPlayerControls.style.display = "unset";
SB.showInfoButtonPlayerControls.style.display = "none";
}
function hideDeleteButtonPlayerControls() {
chrome.storage.sync.set({"hideDeleteButtonPlayerControls": true});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "changeDeleteButtonPlayerControlsVisibility",
value: true
});
});
SB.hideDeleteButtonPlayerControls.style.display = "none";
SB.showDeleteButtonPlayerControls.style.display = "unset";
}
function showDeleteButtonPlayerControls() {
chrome.storage.sync.set({"hideDeleteButtonPlayerControls": false});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "changeVideoPlayerCochangeDeleteButtonPlayerControlsVisibilityntrolsVisibility",
value: false
});
});
SB.hideDeleteButtonPlayerControls.style.display = "unset";
SB.showDeleteButtonPlayerControls.style.display = "none";
}
function disableSponsorViewTracking() {
chrome.storage.sync.set({"trackViewCount": false});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "trackViewCount",
value: false
});
});
SB.disableSponsorViewTracking.style.display = "none";
SB.enableSponsorViewTracking.style.display = "unset";
}
function enableSponsorViewTracking() {
chrome.storage.sync.set({"trackViewCount": true});
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "trackViewCount",
value: true
});
});
SB.enableSponsorViewTracking.style.display = "none";
SB.disableSponsorViewTracking.style.display = "unset";
}
function updateStartTimeChosen() {
//update startTimeChosen letiable
if (!startTimeChosen) {
@@ -1108,16 +831,13 @@ function runThePopup() {
//make the options div visible
function openOptions() {
document.getElementById("optionsButtonContainer").style.display = "none";
document.getElementById("options").style.display = "unset";
chrome.runtime.openOptionsPage();
}
//make the options username setting option visible
function setUsernameButton() {
//get the userID
chrome.storage.sync.get(["userID"], function(result) {
//get username from the server
sendRequestToServer("GET", "/api/getUsername?userID=" + result.userID, function (xmlhttp, error) {
sendRequestToServer("GET", "/api/getUsername?userID=" + SB.config.userID, function (xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
SB.usernameInput.value = JSON.parse(xmlhttp.responseText).userName;
@@ -1137,7 +857,6 @@ function runThePopup() {
SB.setUsernameStatus.innerText = getErrorMessage(xmlhttp.status);
}
});
});
}
//submit the new username
@@ -1147,8 +866,7 @@ function runThePopup() {
SB.setUsernameStatus.innerText = "Loading...";
//get the userID
chrome.storage.sync.get(["userID"], function(result) {
sendRequestToServer("POST", "/api/setUsername?userID=" + result.userID + "&username=" + SB.usernameInput.value, function (xmlhttp, error) {
sendRequestToServer("POST", "/api/setUsername?userID=" + SB.config.userID + "&username=" + SB.usernameInput.value, function (xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//submitted
SB.submitUsername.style.display = "none";
@@ -1159,29 +877,12 @@ function runThePopup() {
SB.setUsernameStatus.innerText = getErrorMessageI(xmlhttp.status);
}
});
});
SB.setUsernameContainer.style.display = "none";
SB.setUsername.style.display = "unset";
}
function changeUserIDButton() {
//get the user ID
chrome.storage.sync.get(["userID"], function(result) {
SB.userIDInput.value = result.userID;
SB.setUserID.style.display = "unset";
SB.userIDInput.style.display = "unset";
SB.changeUserID.style.display = "unset";
});
}
function setUserID() {
if (!confirm(chrome.i18n.getMessage("userIDChangeWarning"))) return;
chrome.storage.sync.set({"userID": SB.userIDInput.value});
}
//this is not a YouTube video page
function displayNoVideo() {
document.getElementById("loadingIndicator").innerText = chrome.i18n.getMessage("noVideoID");
@@ -1217,10 +918,8 @@ function runThePopup() {
type: type,
UUID: UUID
}, function(response) {
console.log(response)
if (response != undefined) {
//see if it was a success or failure
console.log(response)
if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) {
//success (treat rate limits as a success)
addVoteMessage(chrome.i18n.getMessage("voted"), UUID)
@@ -1235,8 +934,7 @@ function runThePopup() {
}
function hideDiscordButton() {
chrome.storage.sync.set({"hideDiscordLink": true});
SB.config.hideDiscordLink = true;
SB.discordButtonContainer.style.display = "none";
}
@@ -1265,8 +963,7 @@ function runThePopup() {
{message: 'getChannelURL'},
function(response) {
//get whitelisted channels
chrome.storage.sync.get(["whitelistedChannels"], function(result) {
let whitelistedChannels = result.whitelistedChannels;
let whitelistedChannels = SB.config.whitelistedChannels;
if (whitelistedChannels == undefined) {
whitelistedChannels = [];
}
@@ -1282,7 +979,7 @@ function runThePopup() {
SB.downloadedSponsorMessageTimes.style.fontWeight = "bold";
//save this
chrome.storage.sync.set({whitelistedChannels: whitelistedChannels});
SB.config.whitelistedChannels = whitelistedChannels;
//send a message to the client
chrome.tabs.query({
@@ -1296,7 +993,6 @@ function runThePopup() {
});
}
);
});
}
);
});
@@ -1313,8 +1009,7 @@ function runThePopup() {
{message: 'getChannelURL'},
function(response) {
//get whitelisted channels
chrome.storage.sync.get(["whitelistedChannels"], function(result) {
let whitelistedChannels = result.whitelistedChannels;
let whitelistedChannels = SB.config.whitelistedChannels;
if (whitelistedChannels == undefined) {
whitelistedChannels = [];
}
@@ -1331,7 +1026,7 @@ function runThePopup() {
SB.downloadedSponsorMessageTimes.style.fontWeight = "unset";
//save this
chrome.storage.sync.set({whitelistedChannels: whitelistedChannels});
SB.config.whitelistedChannels = whitelistedChannels;
//send a message to the client
chrome.tabs.query({
@@ -1345,7 +1040,6 @@ function runThePopup() {
});
}
);
});
}
);
});
@@ -1355,7 +1049,7 @@ function runThePopup() {
* Should skipping be disabled (visuals stay)
*/
function toggleSkipping(disabled) {
chrome.storage.sync.set({"disableSkipping": disabled});
SB.config.disableSkipping = disabled;
let hiddenButton = SB.disableSkipping;
let shownButton = SB.enableSkipping;
@@ -1369,34 +1063,6 @@ function runThePopup() {
hiddenButton.style.display = "none";
}
function setKeybind(startSponsorKeybind) {
document.getElementById("keybindButtons").style.display = "none";
document.getElementById("keybindDescription").style.display = "initial";
document.getElementById("keybindDescription").innerText = chrome.i18n.getMessage("keybindDescription");
setStartSponsorKeybind = startSponsorKeybind;
document.addEventListener("keydown", onKeybindSet)
}
function onKeybindSet(e) {
e = e || window.event;
var key = e.key;
if (setStartSponsorKeybind) {
chrome.storage.sync.set({"startSponsorKeybind": key});
} else {
chrome.storage.sync.set({"submitKeybind": key});
}
document.removeEventListener("keydown", onKeybindSet);
document.getElementById("keybindDescription").innerText = chrome.i18n.getMessage("keybindDescriptionComplete") + " " + key;
document.getElementById("keybindButtons").style.display = "unset";
}
//converts time in seconds to minutes
function getTimeInMinutes(seconds) {
let minutes = Math.floor(seconds / 60);
@@ -1452,7 +1118,6 @@ function runThePopup() {
if (chrome.tabs != undefined) {
//add the width restriction (because Firefox)
document.getElementById("sponorBlockStyleSheet").sheet.insertRule('.popupBody { width: 325 }', 0);
//this means it is actually opened in the popup
runThePopup();
}

206
utils.js
View File

@@ -1,3 +1,6 @@
var isBackgroundScript = false;
var onInvidious = false;
// Function that can be used to wait for a condition before returning
async function wait(condition, timeout = 5000, check = 100) {
return await new Promise((resolve, reject) => {
@@ -19,21 +22,33 @@ async function wait(condition, timeout = 5000, check = 100) {
}
function getYouTubeVideoID(url) {
// For YouTube TV support
if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", "");
//Attempt to parse url
let urlObject = null;
try {
urlObject = new URL(url);
urlObject = new URL(url);
} catch (e) {
console.error("[SB] Unable to parse URL: " + url);
return false;
console.error("[SB] Unable to parse URL: " + url);
return false;
}
//Check if valid hostname
if(!["www.youtube.com","www.youtube-nocookie.com"].includes(urlObject.host)) return false;
if (SB.config && SB.config.invidiousInstances.includes(urlObject.host)) {
onInvidious = true;
} else if (!["www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) {
if (!SB.config) {
// Call this later, in case this is an Invidious tab
wait(() => SB.config !== undefined).then(() => videoIDChange(getYouTubeVideoID(url)));
}
return false
}
//Get ID from searchParam
if ((urlObject.pathname == "/watch" || urlObject.pathname == "/watch/") && urlObject.searchParams.has("v")) {
id = urlObject.searchParams.get("v");
if (urlObject.searchParams.has("v") && ["/watch", "/watch/"].includes(urlObject.pathname) || urlObject.pathname.startsWith("/tv/watch")) {
id = urlObject.searchParams.get("v");
return id.length == 11 ? id : false;
} else if (urlObject.pathname.startsWith("/embed/")) {
try {
@@ -42,30 +57,172 @@ function getYouTubeVideoID(url) {
console.error("[SB] Video ID not valid for " + url);
return false;
}
}
}
return false;
}
/**
* Asks for the optional permissions required for all extra sites.
* It also starts the content script registrations.
*
* For now, it is just SB.config.invidiousInstances.
*
* @param {CallableFunction} callback
*/
function setupExtraSitePermissions(callback) {
// Request permission
let permissions = ["declarativeContent"];
if (isFirefox()) permissions = [];
chrome.permissions.request({
origins: getInvidiousInstancesRegex(),
permissions: permissions
}, async function (granted) {
if (granted) {
setupExtraSiteContentScripts();
} else {
removeExtraSiteRegistration();
}
callback(granted);
});
}
/**
* Registers the content scripts for the extra sites.
* Will use a different method depending on the browser.
* This is called by setupExtraSitePermissions().
*
* For now, it is just SB.config.invidiousInstances.
*/
function setupExtraSiteContentScripts() {
let js = [
"config.js",
"SB.js",
"utils/previewBar.js",
"utils/skipNotice.js",
"utils.js",
"content.js",
"popup.js"
];
let css = [
"content.css",
"./libs/Source+Sans+Pro.css",
"popup.css"
];
if (isFirefox()) {
let firefoxJS = [];
for (const file of js) {
firefoxJS.push({file});
}
let firefoxCSS = [];
for (const file of css) {
firefoxCSS.push({file});
}
let registration = {
message: "registerContentScript",
id: "invidious",
allFrames: true,
js: firefoxJS,
css: firefoxCSS,
matches: getInvidiousInstancesRegex()
};
if (isBackgroundScript) {
registerFirefoxContentScript(registration);
} else {
chrome.runtime.sendMessage(registration);
}
} else {
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() {
let conditions = [];
for (const regex of getInvidiousInstancesRegex()) {
conditions.push(new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlMatches: regex }
}));
}
// Add page rule
let rule = {
id: "invidious",
conditions,
actions: [new chrome.declarativeContent.RequestContentScript({
allFrames: true,
js,
css
})]
};
chrome.declarativeContent.onPageChanged.addRules([rule]);
});
}
}
/**
* Removes the permission and content script registration.
*/
function removeExtraSiteRegistration() {
if (isFirefox()) {
let id = "invidious";
if (isBackgroundScript) {
if (contentScriptRegistrations[id]) {
contentScriptRegistrations[id].unregister();
delete contentScriptRegistrations[id];
}
} else {
chrome.runtime.sendMessage({
message: "unregisterContentScript",
id: id
});
}
} else {
chrome.declarativeContent.onPageChanged.removeRules(["invidious"]);
}
chrome.permissions.remove({
origins: getInvidiousInstancesRegex()
});
}
function localizeHtmlPage() {
//Localize by replacing __MSG_***__ meta tags
var objects = document.getElementsByClassName("popupBody")[0].children;
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
for (var j = 0; j < objects.length; j++) {
var obj = objects[j];
var valStrH = obj.innerHTML.toString();
var valNewH = valStrH.replace(/__MSG_(\w+)__/g, function(match, v1)
{
return v1 ? chrome.i18n.getMessage(v1) : "";
});
if(valNewH != valStrH)
{
obj.innerHTML = valNewH;
}
let localizedMessage = getLocalizedMessage(obj.innerHTML.toString());
if (localizedMessage) obj.innerHTML = localizedMessage;
}
}
function getLocalizedMessage(text) {
var valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) {
return v1 ? chrome.i18n.getMessage(v1) : "";
});
if(valNewH != text) {
return valNewH;
} else {
return false;
}
}
/**
* @returns {String[]} Invidious Instances in regex form
*/
function getInvidiousInstancesRegex() {
var invidiousInstancesRegex = [];
for (const url of SB.config.invidiousInstances) {
invidiousInstancesRegex.push("https://*." + url + "/*");
invidiousInstancesRegex.push("http://*." + url + "/*");
}
return invidiousInstancesRegex;
}
function generateUserID(length = 36) {
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
@@ -104,4 +261,11 @@ function getErrorMessage(statusCode) {
}
return errorMessage;
}
}
/**
* Is this Firefox (web-extensions)
*/
function isFirefox() {
return typeof(browser) !== "undefined";
}

View File

@@ -166,7 +166,7 @@ class SkipNotice {
noticeElement.appendChild(secondRow);
//get reference node
let referenceNode = document.getElementById("movie_player");
let referenceNode = document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
if (referenceNode == null) {
//for embeds
let player = document.getElementById("player");
@@ -425,4 +425,4 @@ class SkipNotice {
if (this.countdownInterval != -1) clearInterval(this.countdownInterval);
}
}
}