mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-16 16:37:18 +03:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31b76553dc | ||
|
|
eff73548e3 | ||
|
|
2ca98ad97b | ||
|
|
4e9b5ca0bc | ||
|
|
3d7d291d9a | ||
|
|
195ed1f5fc | ||
|
|
74f14b3bf8 | ||
|
|
290dff25f9 | ||
|
|
64ab6b5768 | ||
|
|
1b2bc6def4 | ||
|
|
18c7be8161 | ||
|
|
638439a671 | ||
|
|
9fafb9cf54 | ||
|
|
0223aa8307 | ||
|
|
07f1106579 | ||
|
|
2f78f31874 | ||
|
|
74a4ef0692 | ||
|
|
2d55ea0fc5 | ||
|
|
a50f030a3b | ||
|
|
ae690f0c65 | ||
|
|
e2128f7ae3 | ||
|
|
80fe28a952 | ||
|
|
be74ebe7bc | ||
|
|
e085163dfd | ||
|
|
adef65b878 | ||
|
|
b7870cbd74 | ||
|
|
cd03218940 | ||
|
|
6abf6a0044 | ||
|
|
6ef5dd4522 | ||
|
|
9f87c839b5 | ||
|
|
85c1a45c8b | ||
|
|
963fb58321 | ||
|
|
d1d4dcdc9c | ||
|
|
24dd98a98f | ||
|
|
5abc0bedd4 | ||
|
|
e1e570fb18 | ||
|
|
93c0a0c003 | ||
|
|
93f82de7fd | ||
|
|
f6945b56d8 | ||
|
|
55e17ceb60 | ||
|
|
2a432490bc | ||
|
|
0115a6df13 | ||
|
|
a5e9ceda60 | ||
|
|
09f53c80f0 | ||
|
|
8134b5a67e | ||
|
|
ebd6c9c952 | ||
|
|
37e2fb0972 | ||
|
|
7af44eae66 | ||
|
|
62c50d77c6 | ||
|
|
bac9029a28 | ||
|
|
48a614943d | ||
|
|
ec9f1efd55 | ||
|
|
59c6455298 | ||
|
|
d7a7476cd1 | ||
|
|
36981af95a | ||
|
|
d4d5e4743e | ||
|
|
3afde08a6e | ||
|
|
6ea87d7cd0 | ||
|
|
b6c243236b | ||
|
|
6fa67088bc | ||
|
|
d37abcfa9f | ||
|
|
5575eda7b1 | ||
|
|
e17eb60b4d | ||
|
|
e055a66342 | ||
|
|
72c98923f6 | ||
|
|
8ecea87c52 | ||
|
|
7727cd56db | ||
|
|
242fbf8009 | ||
|
|
24f2ce4a32 | ||
|
|
0d08e11b1d | ||
|
|
513a140754 | ||
|
|
f100ee4738 | ||
|
|
37662138df | ||
|
|
037d1089a3 | ||
|
|
1df123de6d | ||
|
|
3063591a4c | ||
|
|
a182354254 | ||
|
|
a02aef591e | ||
|
|
1a92265e65 | ||
|
|
92a6065c98 | ||
|
|
d7ca56941a | ||
|
|
da6ccb561d | ||
|
|
c526a812e0 | ||
|
|
ccbc0456f9 | ||
|
|
0d9b624fd5 | ||
|
|
008c9380b1 |
10
README.md
10
README.md
@@ -34,13 +34,17 @@ SponsorBlock is an extension that will skip over sponsored segments of YouTube v
|
|||||||
|
|
||||||
Also support Invidio.us.
|
Also support Invidio.us.
|
||||||
|
|
||||||
|
# Important Links
|
||||||
|
|
||||||
|
See the [Wiki](https://github.com/ajayyy/SponsorBlock/wiki) for important links.
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
|
|
||||||
The backend server code is available here: https://github.com/ajayyy/SponsorBlockServer
|
The backend server code is available here: https://github.com/ajayyy/SponsorBlockServer
|
||||||
|
|
||||||
It is a simple Sqlite database that will hold all the timing data.
|
It is a simple SQLite database that will hold all the timing data.
|
||||||
|
|
||||||
To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. You can download a backup or get archive.org to take a backup for you if you want.
|
To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. If you are planning on using the database in another project, please read the [API Docs](https://github.com/ajayyy/SponsorBlock/wiki/API-Docs) page for more information.
|
||||||
|
|
||||||
The dataset and API are now being used in some [ports](https://github.com/ajayyy/SponsorBlock/wiki/Unofficial-Ports) as well as a [neural network](https://github.com/andrewzlee/NeuralBlock).
|
The dataset and API are now being used in some [ports](https://github.com/ajayyy/SponsorBlock/wiki/Unofficial-Ports) as well as a [neural network](https://github.com/andrewzlee/NeuralBlock).
|
||||||
|
|
||||||
@@ -66,7 +70,7 @@ Run `npm run dev` to run the extension using a clean browser profile with hot re
|
|||||||
|
|
||||||
# Credit
|
# Credit
|
||||||
|
|
||||||
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) previously was used.
|
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) was previously used.
|
||||||
|
|
||||||
Originally forked from [YTSponsorSkip](https://github.com/OfficialNoob/YTSponsorSkip), but zero code remains.
|
Originally forked from [YTSponsorSkip](https://github.com/OfficialNoob/YTSponsorSkip), but zero code remains.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
"serverAddress": "https://sponsor.ajay.app",
|
"serverAddress": "https://sponsor.ajay.app",
|
||||||
"serverAddressComment": "This specifies the default SponsorBlock server to conect to"
|
"testingServerAddress": "https://sponsor.ajay.app/test",
|
||||||
|
"serverAddressComment": "This specifies the default SponsorBlock server to conect to",
|
||||||
|
"categoryList": ["sponsor", "intro", "outro", "interaction", "selfpromo", "offtopic"]
|
||||||
}
|
}
|
||||||
11
crowdin.yml
11
crowdin.yml
@@ -1,10 +1,3 @@
|
|||||||
files:
|
files:
|
||||||
- source: /_locales/en/*
|
- source: /public/_locales/en/*
|
||||||
translation: /_locales/%two_letters_code%/%original_file_name%
|
translation: /public/_locales/%two_letters_code%/%original_file_name%
|
||||||
languages_mapping:
|
|
||||||
two_letters_code:
|
|
||||||
pl-PL: "pl_PL"
|
|
||||||
pr-BR: "pt_BR"
|
|
||||||
pr-PT: "pt_PT"
|
|
||||||
zh-CN: "zh_CH"
|
|
||||||
zh-TW: "zh_TW"
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "__MSG_fullName__",
|
"name": "__MSG_fullName__",
|
||||||
"short_name": "__MSG_Name__",
|
"short_name": "__MSG_Name__",
|
||||||
"version": "1.2.24",
|
"version": "1.2.26",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"description": "__MSG_Description__",
|
"description": "__MSG_Description__",
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
"icons/downvote.png",
|
"icons/downvote.png",
|
||||||
"icons/report.png",
|
"icons/report.png",
|
||||||
"icons/close.png",
|
"icons/close.png",
|
||||||
|
"icons/beep.ogg",
|
||||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||||
"popup.html",
|
"popup.html",
|
||||||
|
|||||||
925
package-lock.json
generated
925
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -4,7 +4,15 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "background.js",
|
"main": "background.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"concurrently": "^5.1.0"
|
"@types/react": "^16.9.22",
|
||||||
|
"@types/react-dom": "^16.9.5",
|
||||||
|
"babel": "^6.23.0",
|
||||||
|
"babel-core": "^6.26.3",
|
||||||
|
"babel-loader": "^8.0.6",
|
||||||
|
"babel-preset-env": "^1.7.0",
|
||||||
|
"concurrently": "^5.1.0",
|
||||||
|
"react": "^16.12.0",
|
||||||
|
"react-dom": "^16.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"web-ext": "^4.0.0",
|
"web-ext": "^4.0.0",
|
||||||
|
|||||||
1
public/_locales/af/messages.json
Normal file
1
public/_locales/af/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/am/messages.json
Normal file
1
public/_locales/am/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/ar/messages.json
Normal file
1
public/_locales/ar/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/bg/messages.json
Normal file
1
public/_locales/bg/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/bn/messages.json
Normal file
1
public/_locales/bn/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/ca/messages.json
Normal file
1
public/_locales/ca/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/cs/messages.json
Normal file
1
public/_locales/cs/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/da/messages.json
Normal file
1
public/_locales/da/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -1,20 +1,8 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Name of the extension."
|
|
||||||
},
|
|
||||||
"fullName": {
|
|
||||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
|
||||||
"description": "Name of the extension."
|
|
||||||
},
|
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Überspringe die gesponserten Inhalte in YouTube-Videos. Melde gesponsorte Inhalte in den von dir angesehenen Videos und erspare anderen die Zeit.",
|
"message": "Überspringe die gesponserten Inhalte in YouTube-Videos. Melde gesponsorte Inhalte in den von dir angesehenen Videos und erspare anderen die Zeit.",
|
||||||
"description": "Description of the extension."
|
"description": "Description of the extension."
|
||||||
},
|
},
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
|
||||||
"400": {
|
"400": {
|
||||||
"message": "Ungültige Anforderung"
|
"message": "Ungültige Anforderung"
|
||||||
},
|
},
|
||||||
|
|||||||
1
public/_locales/el/messages.json
Normal file
1
public/_locales/el/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -291,6 +291,12 @@
|
|||||||
"autoSkipDescription": {
|
"autoSkipDescription": {
|
||||||
"message": "Auto skip will skip sponsors for you. If disabled, a notice will appear asking if you'd like to skip."
|
"message": "Auto skip will skip sponsors for you. If disabled, a notice will appear asking if you'd like to skip."
|
||||||
},
|
},
|
||||||
|
"audioNotification": {
|
||||||
|
"message": "Audio Notification On Skip"
|
||||||
|
},
|
||||||
|
"audioNotificationDescription": {
|
||||||
|
"message": "Audio notification on skip will play a sound whenever a sponsor is skipped. If disabled (or auto skip is disabled), no sound will be played."
|
||||||
|
},
|
||||||
"youHaveSkipped": {
|
"youHaveSkipped": {
|
||||||
"message": "You have skipped "
|
"message": "You have skipped "
|
||||||
},
|
},
|
||||||
@@ -441,6 +447,24 @@
|
|||||||
"incorrectlyFormattedOptions": {
|
"incorrectlyFormattedOptions": {
|
||||||
"message": "This JSON is not formatted correctly. Your options have not been changed."
|
"message": "This JSON is not formatted correctly. Your options have not been changed."
|
||||||
},
|
},
|
||||||
|
"confirmNoticeTitle" : {
|
||||||
|
"message": "Submit Segment"
|
||||||
|
},
|
||||||
|
"submit": {
|
||||||
|
"message": "Submit"
|
||||||
|
},
|
||||||
|
"cancel": {
|
||||||
|
"message": "Cancel"
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"message": "Delete"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"message": "Preview"
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"message": "Edit"
|
||||||
|
},
|
||||||
"copyDebugInformation": {
|
"copyDebugInformation": {
|
||||||
"message": "Copy Debug Information To Clipboard"
|
"message": "Copy Debug Information To Clipboard"
|
||||||
},
|
},
|
||||||
@@ -461,5 +485,51 @@
|
|||||||
},
|
},
|
||||||
"keyAlreadyUsed": {
|
"keyAlreadyUsed": {
|
||||||
"message": "is bound to another action. Please select another key."
|
"message": "is bound to another action. Please select another key."
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"message": "to",
|
||||||
|
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||||
|
},
|
||||||
|
"category_sponsor": {
|
||||||
|
"message": "Sponsor"
|
||||||
|
},
|
||||||
|
"category_intro": {
|
||||||
|
"message": "Intro"
|
||||||
|
},
|
||||||
|
"category_outro": {
|
||||||
|
"message": "Outro"
|
||||||
|
},
|
||||||
|
"category_interaction": {
|
||||||
|
"message": "Interaction (Redundant Like, Subscribe, Follow, etc.)"
|
||||||
|
},
|
||||||
|
"category_selfpromo": {
|
||||||
|
"message": "Self-Promotion and Merchandise"
|
||||||
|
},
|
||||||
|
"category_offtopic": {
|
||||||
|
"message": "Offtopic tangent (Subjective)"
|
||||||
|
},
|
||||||
|
"disable": {
|
||||||
|
"message": "Disable"
|
||||||
|
},
|
||||||
|
"manualSkip": {
|
||||||
|
"message": "Manual Skip"
|
||||||
|
},
|
||||||
|
"showOverlay": {
|
||||||
|
"message": "Show In Seek Bar"
|
||||||
|
},
|
||||||
|
"enableTestingServer": {
|
||||||
|
"message": "Enable Beta Testing Server"
|
||||||
|
},
|
||||||
|
"whatEnableTestingServer": {
|
||||||
|
"message": "Your submissions and votes WILL NOT COUNT towards the main server. Only use this for testing."
|
||||||
|
},
|
||||||
|
"testingServerWarning": {
|
||||||
|
"message": "All submissions and votes WILL NOT COUNT towards the main server while connecting to the test server. Make sure to disable this when you want to make real submissions."
|
||||||
|
},
|
||||||
|
"bracketNow": {
|
||||||
|
"message": "(Now)"
|
||||||
|
},
|
||||||
|
"moreCategories": {
|
||||||
|
"message": "More Categories"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
public/_locales/es/messages.json
Normal file
1
public/_locales/es/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/et/messages.json
Normal file
1
public/_locales/et/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/fa/messages.json
Normal file
1
public/_locales/fa/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/fi/messages.json
Normal file
1
public/_locales/fi/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/fil/messages.json
Normal file
1
public/_locales/fil/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -1,20 +1,12 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Name of the extension."
|
|
||||||
},
|
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "SponsorBlock pour YouTube - Supprime les messages commerciaux et publicités intégrées",
|
"message": "SponsorBlock pour YouTube - Supprime les messages commerciaux et publicités intégrées",
|
||||||
"description": "Name of the extension."
|
"description": "Name of the extension."
|
||||||
},
|
},
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Passe automatiquement les messages commerciaux intégrés dans les vidéos YouTube. Soumettez les segments commerciaux dans les vidéos que vous regardez pour aidez les autres.",
|
"message": "Passe automatiquement les messages commerciaux intégrés dans les vidéos YouTube. Soumettez les segments commerciaux dans les vidéos que vous regardez pour aidez les autres.",
|
||||||
"description": "Description of the extension."
|
"description": "Description of the extension."
|
||||||
},
|
},
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
|
||||||
"400": {
|
"400": {
|
||||||
"message": "Soumission invalide"
|
"message": "Soumission invalide"
|
||||||
},
|
},
|
||||||
@@ -25,7 +17,7 @@
|
|||||||
"message": "Déja soumis"
|
"message": "Déja soumis"
|
||||||
},
|
},
|
||||||
"channelWhitelisted": {
|
"channelWhitelisted": {
|
||||||
"message": "Cette chaîne est sur la liste blanche !"
|
"message": "Chaîne mise sur liste blanche !"
|
||||||
},
|
},
|
||||||
"Sponsor": {
|
"Sponsor": {
|
||||||
"message": "message commercial"
|
"message": "message commercial"
|
||||||
@@ -43,16 +35,16 @@
|
|||||||
"message": "Message commercial passé"
|
"message": "Message commercial passé"
|
||||||
},
|
},
|
||||||
"reportButtonTitle": {
|
"reportButtonTitle": {
|
||||||
"message": "Incorrect"
|
"message": "Signaler"
|
||||||
},
|
},
|
||||||
"reportButtonInfo": {
|
"reportButtonInfo": {
|
||||||
"message": "Signaler que ce segment commercial est incorrect ou n'existe pas."
|
"message": "Signaler que ce segment commercial est incorrect."
|
||||||
},
|
},
|
||||||
"Dismiss": {
|
"Dismiss": {
|
||||||
"message": "Fermer"
|
"message": "Fermer"
|
||||||
},
|
},
|
||||||
"Loading": {
|
"Loading": {
|
||||||
"message": "Chargement en cours..."
|
"message": "Chargement..."
|
||||||
},
|
},
|
||||||
"Mins": {
|
"Mins": {
|
||||||
"message": "Minutes"
|
"message": "Minutes"
|
||||||
@@ -85,10 +77,10 @@
|
|||||||
"message": "Une erreur s'est produite lors de la soumission, veuillez ré-essayer plus tard."
|
"message": "Une erreur s'est produite lors de la soumission, veuillez ré-essayer plus tard."
|
||||||
},
|
},
|
||||||
"sponsorFound": {
|
"sponsorFound": {
|
||||||
"message": "Les messages commerciaux sont déjà dans notre base de donnée pour cette vidéo !"
|
"message": "Les messages commerciaux pour cette vidéo sont déjà dans notre base de donnée !"
|
||||||
},
|
},
|
||||||
"sponsor404": {
|
"sponsor404": {
|
||||||
"message": "Pas de messages commerciaux trouvés"
|
"message": "Pas de sponsors trouvés"
|
||||||
},
|
},
|
||||||
"sponsorStart": {
|
"sponsorStart": {
|
||||||
"message": "Début du message commercial"
|
"message": "Début du message commercial"
|
||||||
@@ -138,9 +130,6 @@
|
|||||||
"removeFromWhitelist": {
|
"removeFromWhitelist": {
|
||||||
"message": "Supprimer la chaîne de la liste blanche"
|
"message": "Supprimer la chaîne de la liste blanche"
|
||||||
},
|
},
|
||||||
"whitelistDescription": {
|
|
||||||
"message": "Ajouter à la liste blanche les chaînes qui publient des messages commerciaux de façon éthique pour encourager les bons comportements, ou qui publient des messages commerciaux divertissants ou drôles. Ou pas, c'est votre choix."
|
|
||||||
},
|
|
||||||
"voteOnTime": {
|
"voteOnTime": {
|
||||||
"message": "Voter sur un segment commercial"
|
"message": "Voter sur un segment commercial"
|
||||||
},
|
},
|
||||||
@@ -187,7 +176,7 @@
|
|||||||
"message": "Cacher"
|
"message": "Cacher"
|
||||||
},
|
},
|
||||||
"Options": {
|
"Options": {
|
||||||
"message": "Options"
|
"message": "Paramètres"
|
||||||
},
|
},
|
||||||
"showButtons": {
|
"showButtons": {
|
||||||
"message": "Montrer les boutons sur le lecteur YouTube"
|
"message": "Montrer les boutons sur le lecteur YouTube"
|
||||||
@@ -259,5 +248,147 @@
|
|||||||
},
|
},
|
||||||
"keybindDescriptionComplete": {
|
"keybindDescriptionComplete": {
|
||||||
"message": "Le raccourci choisi est : "
|
"message": "Le raccourci choisi est : "
|
||||||
|
},
|
||||||
|
"0": {
|
||||||
|
"message": "Délai de connexion dépassé. Vérifiez votre connexion internet. Si votre connexion internet fonctionne, le serveur est probablement surchargé ou hors service."
|
||||||
|
},
|
||||||
|
"disableSkipping": {
|
||||||
|
"message": "Désactiver SponsorBlock"
|
||||||
|
},
|
||||||
|
"enableSkipping": {
|
||||||
|
"message": "Activer SponsorBlock"
|
||||||
|
},
|
||||||
|
"yourWork": {
|
||||||
|
"message": "Votre travail",
|
||||||
|
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||||
|
},
|
||||||
|
"502": {
|
||||||
|
"message": "Le serveur semble être surchargé. Réessayez dans quelques secondes."
|
||||||
|
},
|
||||||
|
"errorCode": {
|
||||||
|
"message": "Code d'erreur : "
|
||||||
|
},
|
||||||
|
"noticeTitleNotSkipped": {
|
||||||
|
"message": "Passer le sponsor ?"
|
||||||
|
},
|
||||||
|
"skip": {
|
||||||
|
"message": "Passer"
|
||||||
|
},
|
||||||
|
"disableAutoSkip": {
|
||||||
|
"message": "Désactiver le passage automatique"
|
||||||
|
},
|
||||||
|
"enableAutoSkip": {
|
||||||
|
"message": "Activer le passage automatique"
|
||||||
|
},
|
||||||
|
"autoSkipDescription": {
|
||||||
|
"message": "Le passage automatique passera automatiquement les sponsors pour vous. Si désactivé, un avis apparaîtra vous demandant si vous souhaitez passer."
|
||||||
|
},
|
||||||
|
"audioNotification": {
|
||||||
|
"message": "Notification audio lors du passage"
|
||||||
|
},
|
||||||
|
"audioNotificationDescription": {
|
||||||
|
"message": "La notification audio lors du passage jouera un son à chaque fois qu'un sponsor est ignoré. Si désactivé (ou si le passage automatique est désactivé), aucun son ne sera joué."
|
||||||
|
},
|
||||||
|
"youHaveSkipped": {
|
||||||
|
"message": "Vous avez passé "
|
||||||
|
},
|
||||||
|
"youHaveSaved": {
|
||||||
|
"message": "Vous avez économisé "
|
||||||
|
},
|
||||||
|
"minLower": {
|
||||||
|
"message": "minute"
|
||||||
|
},
|
||||||
|
"minsLower": {
|
||||||
|
"message": "minutes"
|
||||||
|
},
|
||||||
|
"hourLower": {
|
||||||
|
"message": "heure"
|
||||||
|
},
|
||||||
|
"hoursLower": {
|
||||||
|
"message": "heures"
|
||||||
|
},
|
||||||
|
"youHaveSavedTime": {
|
||||||
|
"message": "Vous avez économisé"
|
||||||
|
},
|
||||||
|
"youHaveSavedTimeEnd": {
|
||||||
|
"message": " aux autres."
|
||||||
|
},
|
||||||
|
"guildlinesSummary": {
|
||||||
|
"message": "- Assurez-vous que votre segment ne contient que des segments de promotion payante, rien d'autre.\n- Assurez-vous que passer ce segment ne sautera pas de contenu important\n- Si la vidéo entière est un sponsor, s'il vous plaît, ne le signalez pas. Un système complet de reportage vidéo sortira bientôt.\n- Veuillez ne pas signaler les avertissements qui pourraient montrer des biais (si une vidéo de revue est sponsorisée, ne sautez pas quand ils le mentionnent)."
|
||||||
|
},
|
||||||
|
"statusReminder": {
|
||||||
|
"message": "Vérifiez status.sponsor.ajay.app pour le status du serveur."
|
||||||
|
},
|
||||||
|
"changeUserID": {
|
||||||
|
"message": "Importer/Exporter votre ID d'utilisateur"
|
||||||
|
},
|
||||||
|
"whatChangeUserID": {
|
||||||
|
"message": "Gardez ça privé. C'est comme un mot de passe et ne devrait pas être partagé avec quiconque. Si quelqu'un l'obtiens, il peut vous usurper."
|
||||||
|
},
|
||||||
|
"setUserID": {
|
||||||
|
"message": "Définir l'ID utilisateur"
|
||||||
|
},
|
||||||
|
"userIDChangeWarning": {
|
||||||
|
"message": "AVERTISSEMENT : La modification de l'ID d'utilisateur est permanente. Êtes-vous sûr de vouloir faire ça ? Assurez-vous de sauvegarder votre ancien au cas où."
|
||||||
|
},
|
||||||
|
"createdBy": {
|
||||||
|
"message": "Créé par"
|
||||||
|
},
|
||||||
|
"autoSkip": {
|
||||||
|
"message": "Passage automatique"
|
||||||
|
},
|
||||||
|
"showSkipNotice": {
|
||||||
|
"message": "Afficher l'avis après le passage d'un sponsor"
|
||||||
|
},
|
||||||
|
"keybindCurrentlySet": {
|
||||||
|
"message": ". Il est actuellement réglé sur :"
|
||||||
|
},
|
||||||
|
"supportInvidious": {
|
||||||
|
"message": "Soutenir Invidious"
|
||||||
|
},
|
||||||
|
"supportInvidiousDescription": {
|
||||||
|
"message": "Invidious (invidio.us) est un client YouTube tiers. Pour l'activer, vous devez accepter les autorisations supplémentaires. Cela ne fonctionne PAS en mode incongnito sur Chrome et d'autres variantes de Chromium."
|
||||||
|
},
|
||||||
|
"optionsInfo": {
|
||||||
|
"message": "Activer Invidious, désactiver le passage automatique, masquer les boutons et plus encore."
|
||||||
|
},
|
||||||
|
"addInvidiousInstance": {
|
||||||
|
"message": "Ajouter une instance Invidious"
|
||||||
|
},
|
||||||
|
"addInvidiousInstanceDescription": {
|
||||||
|
"message": "Ajouter une instance Invidious personnalisée. Doit être formaté avec SEULEMENT le domaine. Exemple: invidious.ajay.app"
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
"message": "Ajouter"
|
||||||
|
},
|
||||||
|
"addInvidiousInstanceError": {
|
||||||
|
"message": "Ce domaine n'est pas valide. Il devrait JUSTE inclure le domaine. Exemple: invidious.ajay.app"
|
||||||
|
},
|
||||||
|
"resetInvidiousInstance": {
|
||||||
|
"message": "Réinitialiser la liste d'instances Invidious"
|
||||||
|
},
|
||||||
|
"resetInvidiousInstanceAlert": {
|
||||||
|
"message": "Vous êtes sur le point de réinitialiser la liste des instances Invidious"
|
||||||
|
},
|
||||||
|
"currentInstances": {
|
||||||
|
"message": "Instances actuelles:"
|
||||||
|
},
|
||||||
|
"enableAutoUpvote": {
|
||||||
|
"message": "Vote automatique"
|
||||||
|
},
|
||||||
|
"whatAutoUpvote": {
|
||||||
|
"message": "Si cette option est activée, l'extension votera en faveur de tous les segments que vous visualiserez si vous ne les signalez pas. Si l'avis est désactivé, cela ne se produira pas."
|
||||||
|
},
|
||||||
|
"minDuration": {
|
||||||
|
"message": "Durée minimale (en secondes):"
|
||||||
|
},
|
||||||
|
"minDurationDescription": {
|
||||||
|
"message": "Les segments sponsorisés plus courts que la valeur définie ne seront pas passé ni affichés dans le lecteur."
|
||||||
|
},
|
||||||
|
"shortCheck": {
|
||||||
|
"message": "Le segment suivant est plus court que votre option de durée minimale. Cela pourrait signifier qu'il est déjà soumis, et just ignoré par cette option. Êtes-vous sûr de vouloir soumettre ?"
|
||||||
|
},
|
||||||
|
"reset": {
|
||||||
|
"message": "Réinitialiser"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
public/_locales/gu/messages.json
Normal file
1
public/_locales/gu/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/he/messages.json
Normal file
1
public/_locales/he/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/hi/messages.json
Normal file
1
public/_locales/hi/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/hr/messages.json
Normal file
1
public/_locales/hr/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/hu/messages.json
Normal file
1
public/_locales/hu/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -1,20 +1,12 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Name of the extension."
|
|
||||||
},
|
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "SponsorBlock per YouTube - Salta gli sponsor",
|
"message": "SponsorBlock per YouTube - Salta gli sponsor",
|
||||||
"description": "Name of the extension."
|
"description": "Name of the extension."
|
||||||
},
|
},
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Salta i contenuti sponsorizzati nei video di YouTube. Segnala gli annunci incorporati nei video che guardi per far risparmiare tempo agli altri.",
|
"message": "Salta i contenuti sponsorizzati nei video di YouTube. Segnala gli annunci incorporati nei video che guardi per far risparmiare tempo agli altri.",
|
||||||
"description": "Description of the extension."
|
"description": "Description of the extension."
|
||||||
},
|
},
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
|
||||||
"400": {
|
"400": {
|
||||||
"message": "Richiesta non valida"
|
"message": "Richiesta non valida"
|
||||||
},
|
},
|
||||||
@@ -84,7 +76,6 @@
|
|||||||
"Unknown": {
|
"Unknown": {
|
||||||
"message": "Si è verificato un errore durante l'invio dello spezzone sponsorizzato, per favore riprova più tardi."
|
"message": "Si è verificato un errore durante l'invio dello spezzone sponsorizzato, per favore riprova più tardi."
|
||||||
},
|
},
|
||||||
|
|
||||||
"sponsorFound": {
|
"sponsorFound": {
|
||||||
"message": "I contenuti sponsorizzati di questo video sono nel database!"
|
"message": "I contenuti sponsorizzati di questo video sono nel database!"
|
||||||
},
|
},
|
||||||
@@ -139,9 +130,6 @@
|
|||||||
"removeFromWhitelist": {
|
"removeFromWhitelist": {
|
||||||
"message": "Rimuovi Canale dalla Whitelist"
|
"message": "Rimuovi Canale dalla Whitelist"
|
||||||
},
|
},
|
||||||
"whitelistDescription": {
|
|
||||||
"message": "Aggiungi alla whitelist i canali che sponsorizzano eticamente per incoraggiare ad un comportamento corretto, oppure se sono semplicemente intrattenenti e divertenti. Oppure non farlo, decidi tu."
|
|
||||||
},
|
|
||||||
"voteOnTime": {
|
"voteOnTime": {
|
||||||
"message": "Vota uno Spezzone Sponsorizzato"
|
"message": "Vota uno Spezzone Sponsorizzato"
|
||||||
},
|
},
|
||||||
|
|||||||
1
public/_locales/ja/messages.json
Normal file
1
public/_locales/ja/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/kn/messages.json
Normal file
1
public/_locales/kn/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/ko/messages.json
Normal file
1
public/_locales/ko/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/lt/messages.json
Normal file
1
public/_locales/lt/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/lv/messages.json
Normal file
1
public/_locales/lv/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/ml/messages.json
Normal file
1
public/_locales/ml/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/mr/messages.json
Normal file
1
public/_locales/mr/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/ms/messages.json
Normal file
1
public/_locales/ms/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/nl/messages.json
Normal file
1
public/_locales/nl/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/no/messages.json
Normal file
1
public/_locales/no/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -1,19 +1,11 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Nazwa rozszerzenia."
|
|
||||||
},
|
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
||||||
"description": "Nazwa rozszerzenia."
|
"description": "Name of the extension."
|
||||||
},
|
},
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
||||||
"description": "Opis rozszerzenia."
|
"description": "Description of the extension."
|
||||||
},
|
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||||
@@ -27,9 +19,6 @@
|
|||||||
"channelWhitelisted": {
|
"channelWhitelisted": {
|
||||||
"message": "Kanał dodany do wyjątków!"
|
"message": "Kanał dodany do wyjątków!"
|
||||||
},
|
},
|
||||||
"Sponsor": {
|
|
||||||
"message": "sponsor"
|
|
||||||
},
|
|
||||||
"Sponsors": {
|
"Sponsors": {
|
||||||
"message": "sponsorzy"
|
"message": "sponsorzy"
|
||||||
},
|
},
|
||||||
@@ -227,23 +216,23 @@
|
|||||||
},
|
},
|
||||||
"longDescription": {
|
"longDescription": {
|
||||||
"message": "SponsorBlock jest rozszerzeniem które przewinie segmenty sponsorów w filmach na YouTube. SponsorBlock jest opartym na crowdsourcing rozszerzeniem które pozwala każdemu zgłaszać początek i koniec segmentu reklamowego w filmach na YouTube. Kiedy ktoś zgłosi taki fragment zostanie on pominięty przez innych użytkowników rozszerzenia.",
|
"message": "SponsorBlock jest rozszerzeniem które przewinie segmenty sponsorów w filmach na YouTube. SponsorBlock jest opartym na crowdsourcing rozszerzeniem które pozwala każdemu zgłaszać początek i koniec segmentu reklamowego w filmach na YouTube. Kiedy ktoś zgłosi taki fragment zostanie on pominięty przez innych użytkowników rozszerzenia.",
|
||||||
"description": "Pełny opis rozszerzenia na stronie w sklepie."
|
"description": "Full description of the extension on the store pages."
|
||||||
},
|
},
|
||||||
"website": {
|
"website": {
|
||||||
"message": "Strona",
|
"message": "Strona",
|
||||||
"description": "Używane w sklepie Firefoxa"
|
"description": "Used on Firefox Store Page"
|
||||||
},
|
},
|
||||||
"sourceCode": {
|
"sourceCode": {
|
||||||
"message": "Kod źródłowy",
|
"message": "Kod źródłowy",
|
||||||
"description": "Używane w sklepie Firefoxa"
|
"description": "Used on Firefox Store Page"
|
||||||
},
|
},
|
||||||
"noticeUpdate": {
|
"noticeUpdate": {
|
||||||
"message": "Informacje zostały zaktualizowane!",
|
"message": "Informacje zostały zaktualizowane!",
|
||||||
"description": "Pierwsza linia po aktualizacji informacji."
|
"description": "The first line of the message displayed after the notice was upgraded."
|
||||||
},
|
},
|
||||||
"noticeUpdate2": {
|
"noticeUpdate2": {
|
||||||
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
||||||
"description": "Druga linia po aktualizacji informacji."
|
"description": "The second line of the message displayed after the notice was upgraded."
|
||||||
},
|
},
|
||||||
"setStartSponsorShortcut": {
|
"setStartSponsorShortcut": {
|
||||||
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
||||||
@@ -268,7 +257,7 @@
|
|||||||
},
|
},
|
||||||
"yourWork": {
|
"yourWork": {
|
||||||
"message": "Twój wkład",
|
"message": "Twój wkład",
|
||||||
"description": "Nagłowek sekcji ze statystykami użytkownika."
|
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||||
},
|
},
|
||||||
"502": {
|
"502": {
|
||||||
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
||||||
@@ -380,11 +369,5 @@
|
|||||||
},
|
},
|
||||||
"whatAutoUpvote": {
|
"whatAutoUpvote": {
|
||||||
"message": "To ustawienie sprawia, że wszystkie przewinięte przez ciebie a nie zgłoszone jako błąd segmenty reklamowe zostaną potwierdzone jako prawidłowe. Ta opcja nie działa jeśli okienko z informacją o przewinięciu jest ukryte."
|
"message": "To ustawienie sprawia, że wszystkie przewinięte przez ciebie a nie zgłoszone jako błąd segmenty reklamowe zostaną potwierdzone jako prawidłowe. Ta opcja nie działa jeśli okienko z informacją o przewinięciu jest ukryte."
|
||||||
},
|
|
||||||
"invidiousInfo1": {
|
|
||||||
"message": "Invidious (nieoficjalny klient YouTube) została dodana do wspieranych!"
|
|
||||||
},
|
|
||||||
"invidiousInfo2": {
|
|
||||||
"message": "Musisz odblokować to w opcjach aby móc to zrobić."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Nome da extensão."
|
|
||||||
},
|
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "SponsorBlock para YouTube - Pule patrocínios",
|
"message": "SponsorBlock para YouTube - Pule patrocínios",
|
||||||
"description": "Nome da extensão."
|
"description": "Name of the extension."
|
||||||
},
|
},
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Pule patrocinadores em vídeos do YouTube. Reporte patrocinadores em videos que você assiste para salvar o tempo dos outros.",
|
"message": "Pule patrocinadores em vídeos do YouTube. Reporte patrocinadores em videos que você assiste para salvar o tempo dos outros.",
|
||||||
"description": "Descrição da extensão."
|
"description": "Description of the extension."
|
||||||
},
|
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"message": "O servidor disse que esse pedido foi inválido"
|
"message": "O servidor disse que esse pedido foi inválido"
|
||||||
@@ -84,7 +76,6 @@
|
|||||||
"Unknown": {
|
"Unknown": {
|
||||||
"message": "Teve um erro ao enviar seus segmentos, tente novamente depois."
|
"message": "Teve um erro ao enviar seus segmentos, tente novamente depois."
|
||||||
},
|
},
|
||||||
|
|
||||||
"sponsorFound": {
|
"sponsorFound": {
|
||||||
"message": "Os patrocinadores desse vídeo estão no banco de dados!"
|
"message": "Os patrocinadores desse vídeo estão no banco de dados!"
|
||||||
},
|
},
|
||||||
@@ -139,9 +130,6 @@
|
|||||||
"removeFromWhitelist": {
|
"removeFromWhitelist": {
|
||||||
"message": "Remover canal da Whitelist"
|
"message": "Remover canal da Whitelist"
|
||||||
},
|
},
|
||||||
"whitelistDescription": {
|
|
||||||
"message": "Colocar na Whitelist canais com patrocínios éticos que encoragem boas atitude, ou simplesmente canais com patrocínios engraçados. Ou não, é consigo."
|
|
||||||
},
|
|
||||||
"voteOnTime": {
|
"voteOnTime": {
|
||||||
"message": "Vote num intervalo de patrocínio"
|
"message": "Vote num intervalo de patrocínio"
|
||||||
},
|
},
|
||||||
@@ -231,14 +219,14 @@
|
|||||||
},
|
},
|
||||||
"longDescription": {
|
"longDescription": {
|
||||||
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
||||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
"description": "Full description of the extension on the store pages."
|
||||||
},
|
},
|
||||||
"website": {
|
"website": {
|
||||||
"message": "Site",
|
"message": "Site",
|
||||||
"description": "Usado na pagina da loja do Firefox"
|
"description": "Used on Firefox Store Page"
|
||||||
},
|
},
|
||||||
"sourceCode": {
|
"sourceCode": {
|
||||||
"message": "Código fonte",
|
"message": "Código fonte",
|
||||||
"description": "Usado na pagina da loja do Firefox"
|
"description": "Used on Firefox Store Page"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,11 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Nome da extensão."
|
|
||||||
},
|
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "SponsorBlock para o YouTube - Salte patrocínios",
|
"message": "SponsorBlock para o YouTube - Salte patrocínios",
|
||||||
"description": "Nome da extensão."
|
"description": "Name of the extension."
|
||||||
},
|
},
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Salte patrocinadores em vídeos do YouTube. Reporte patrocinadores em vídeos que assista para poupar tempo a outros.",
|
"message": "Salte patrocinadores em vídeos do YouTube. Reporte patrocinadores em vídeos que assista para poupar tempo a outros.",
|
||||||
"description": "Descrição da extensão."
|
"description": "Description of the extension."
|
||||||
},
|
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"message": "O servidor disse que este pedido foi inválido"
|
"message": "O servidor disse que este pedido foi inválido"
|
||||||
@@ -138,9 +130,6 @@
|
|||||||
"removeFromWhitelist": {
|
"removeFromWhitelist": {
|
||||||
"message": "Remover canal da Whitelist"
|
"message": "Remover canal da Whitelist"
|
||||||
},
|
},
|
||||||
"whitelistDescription": {
|
|
||||||
"message": "Colocar na Whitelist canais com patrocínios éticos que encoragem boas atitude, ou simplesmente canais com patrocínios engraçados. Ou não, é consigo."
|
|
||||||
},
|
|
||||||
"voteOnTime": {
|
"voteOnTime": {
|
||||||
"message": "Vote num intervalo de patrocínio"
|
"message": "Vote num intervalo de patrocínio"
|
||||||
},
|
},
|
||||||
@@ -230,14 +219,14 @@
|
|||||||
},
|
},
|
||||||
"longDescription": {
|
"longDescription": {
|
||||||
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
||||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
"description": "Full description of the extension on the store pages."
|
||||||
},
|
},
|
||||||
"website": {
|
"website": {
|
||||||
"message": "Site",
|
"message": "Site",
|
||||||
"description": "Usado na pagina da loja do Firefox"
|
"description": "Used on Firefox Store Page"
|
||||||
},
|
},
|
||||||
"sourceCode": {
|
"sourceCode": {
|
||||||
"message": "Código fonte",
|
"message": "Código fonte",
|
||||||
"description": "Usado na pagina da loja do Firefox"
|
"description": "Used on Firefox Store Page"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
public/_locales/ro/messages.json
Normal file
1
public/_locales/ro/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -1,19 +1,11 @@
|
|||||||
{
|
{
|
||||||
"Name": {
|
|
||||||
"message": "SponsorBlock",
|
|
||||||
"description": "Название расширения, не переводится."
|
|
||||||
},
|
|
||||||
"fullName": {
|
"fullName": {
|
||||||
"message": "SponsorBlock для YouTube - Пропускайте спонсорские вставки",
|
"message": "SponsorBlock для YouTube - Пропускайте спонсорские вставки",
|
||||||
"description": "Название расширения."
|
"description": "Name of the extension."
|
||||||
},
|
},
|
||||||
|
|
||||||
"Description": {
|
"Description": {
|
||||||
"message": "Пропускайте спонсорские вставки в видео на YouTube. Сообщайте о спонсорских вставках в видео, которые Вы смотрите, чтобы сэкономить время других пользователей.",
|
"message": "Пропускайте спонсорские вставки в видео на YouTube. Сообщайте о спонсорских вставках в видео, которые Вы смотрите, чтобы сэкономить время других пользователей.",
|
||||||
"description": "Описание раширения."
|
"description": "Description of the extension."
|
||||||
},
|
|
||||||
"helpPage": {
|
|
||||||
"message": "index_en.html"
|
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"message": "Сервер отклонил этот запрос."
|
"message": "Сервер отклонил этот запрос."
|
||||||
@@ -84,7 +76,6 @@
|
|||||||
"Unknown": {
|
"Unknown": {
|
||||||
"message": "При отправке отчета о спонсорском сегменте произошла ошибка. Попытайтесь отправить его позже."
|
"message": "При отправке отчета о спонсорском сегменте произошла ошибка. Попытайтесь отправить его позже."
|
||||||
},
|
},
|
||||||
|
|
||||||
"sponsorFound": {
|
"sponsorFound": {
|
||||||
"message": "Спонсоры этого видео уже находятся в базе данных!"
|
"message": "Спонсоры этого видео уже находятся в базе данных!"
|
||||||
},
|
},
|
||||||
@@ -219,15 +210,15 @@
|
|||||||
},
|
},
|
||||||
"longDescription": {
|
"longDescription": {
|
||||||
"message": "SponsorBlock — это расширение, которое пропускает спонсорские вставки в видео на YouTube. SponsorBlock — это краудсорсинговое расширение, которое позволяет каждому отправить время начала и конца спонсорских сегментов в видео на YouTube. После того, как кто-нибудь отправляет эту информацию, все остальные пользователи расширения будут автоматически пропускать спонсорские сегменты.",
|
"message": "SponsorBlock — это расширение, которое пропускает спонсорские вставки в видео на YouTube. SponsorBlock — это краудсорсинговое расширение, которое позволяет каждому отправить время начала и конца спонсорских сегментов в видео на YouTube. После того, как кто-нибудь отправляет эту информацию, все остальные пользователи расширения будут автоматически пропускать спонсорские сегменты.",
|
||||||
"description": "Полное описание расширения на страницах магазинов."
|
"description": "Full description of the extension on the store pages."
|
||||||
},
|
},
|
||||||
"website": {
|
"website": {
|
||||||
"message": "Сайт",
|
"message": "Сайт",
|
||||||
"description": "Используется на странице магазина Firefox"
|
"description": "Used on Firefox Store Page"
|
||||||
},
|
},
|
||||||
"sourceCode": {
|
"sourceCode": {
|
||||||
"message": "Исходный код",
|
"message": "Исходный код",
|
||||||
"description": "Используется на странице магазина Firefox"
|
"description": "Used on Firefox Store Page"
|
||||||
},
|
},
|
||||||
"noticeUpdate": {
|
"noticeUpdate": {
|
||||||
"message": "Уведомление было обновлено!",
|
"message": "Уведомление было обновлено!",
|
||||||
|
|||||||
1
public/_locales/sk/messages.json
Normal file
1
public/_locales/sk/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/sl/messages.json
Normal file
1
public/_locales/sl/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/sr/messages.json
Normal file
1
public/_locales/sr/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/sv/messages.json
Normal file
1
public/_locales/sv/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/sw/messages.json
Normal file
1
public/_locales/sw/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/ta/messages.json
Normal file
1
public/_locales/ta/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/te/messages.json
Normal file
1
public/_locales/te/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/th/messages.json
Normal file
1
public/_locales/th/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/tr/messages.json
Normal file
1
public/_locales/tr/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/uk/messages.json
Normal file
1
public/_locales/uk/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/vi/messages.json
Normal file
1
public/_locales/vi/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/zh_CN/messages.json
Normal file
1
public/_locales/zh_CN/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
1
public/_locales/zh_TW/messages.json
Normal file
1
public/_locales/zh_TW/messages.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -80,13 +80,15 @@
|
|||||||
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
animation: fadeIn 0.5s;
|
|
||||||
|
|
||||||
border-spacing: 5px 10px;
|
border-spacing: 5px 10px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sponsorSkipNoticeFadeIn {
|
||||||
|
animation: fadeIn 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
.sponsorSkipNoticeFadeOut {
|
.sponsorSkipNoticeFadeOut {
|
||||||
animation: fadeOut 3s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
animation: fadeOut 3s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
}
|
}
|
||||||
@@ -312,3 +314,65 @@
|
|||||||
position:relative;
|
position:relative;
|
||||||
top:1px;
|
top:1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Submission Notice */
|
||||||
|
|
||||||
|
.sponsorTimeDisplay {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeEditButton {
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeEdit > input::-webkit-outer-spin-button,
|
||||||
|
input::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeMessagesRow {
|
||||||
|
max-height: 300px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeEdit {
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeEditMinutes {
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeEditSeconds {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorNowButton {
|
||||||
|
font-size: 11px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorTimeCategories {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
background-color: rgba(28, 28, 28, 0.9);
|
||||||
|
border-color: rgb(130,0,0,0.9);
|
||||||
|
color: white;
|
||||||
|
border-width: 3px;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
BIN
public/icons/beep.ogg
Normal file
BIN
public/icons/beep.ogg
Normal file
Binary file not shown.
@@ -324,3 +324,26 @@ svg {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* React styles */
|
||||||
|
|
||||||
|
.categoryTableElement {
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categoryTableElement > * {
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categoryOptionsSelector {
|
||||||
|
background-color: #c00000;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
@@ -24,6 +24,13 @@
|
|||||||
|
|
||||||
<div id="options" class="hidden">
|
<div id="options" class="hidden">
|
||||||
|
|
||||||
|
<div id="category-type" option-type="react-CategoryChooserComponent">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<div id="support-invidious" option-type="toggle" sync-option="supportInvidious">
|
<div id="support-invidious" option-type="toggle" sync-option="supportInvidious">
|
||||||
<label class="switch-container" label-name="__MSG_supportInvidious__">
|
<label class="switch-container" label-name="__MSG_supportInvidious__">
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
@@ -77,24 +84,6 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<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 option-type="keybind-change" sync-option="startSponsorKeybind">
|
||||||
<div class="option-button trigger-button">
|
<div class="option-button trigger-button">
|
||||||
__MSG_setStartSponsorShortcut__
|
__MSG_setStartSponsorShortcut__
|
||||||
@@ -231,6 +220,23 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
<div option-type="toggle" sync-option="audioNotificationOnSkip">
|
||||||
|
<label class="switch-container" label-name="__MSG_audioNotification__">
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<div class="small-description">__MSG_audioNotificationDescription__</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<div option-type="toggle" sync-option="autoUpvote">
|
<div option-type="toggle" sync-option="autoUpvote">
|
||||||
<label class="switch-container" label-name="__MSG_enableAutoUpvote__">
|
<label class="switch-container" label-name="__MSG_enableAutoUpvote__">
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
@@ -347,6 +353,22 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
<div option-type="toggle" sync-option="testingServer" confirm-message="testingServerWarning">
|
||||||
|
<label class="switch-container" label-name="__MSG_enableTestingServer__">
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<div class="small-description">__MSG_whatEnableTestingServer__</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<div option-type="text-change" sync-option="serverAddress">
|
<div option-type="text-change" sync-option="serverAddress">
|
||||||
<label class="text-label-container">
|
<label class="text-label-container">
|
||||||
|
|||||||
@@ -39,29 +39,15 @@
|
|||||||
|
|
||||||
<div id="submissionSection" class="popupElement" style="display: none">
|
<div id="submissionSection" class="popupElement" style="display: none">
|
||||||
<h3 class="popupElement">__MSG_lastTimes__</h3>
|
<h3 class="popupElement">__MSG_lastTimes__</h3>
|
||||||
<b>
|
|
||||||
<div id="sponsorMessageTimes" class="popupElement">
|
|
||||||
|
|
||||||
</div>
|
<b>Sponsor Editing has been moved and will appear after you click submit</b>
|
||||||
</b>
|
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<button id="clearTimes" class="smallButton popupElement">__MSG_clearTimesButton__</button>
|
|
||||||
|
|
||||||
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<button id="submitTimes" class="smallButton popupElement">__MSG_submitTimesButton__</button>
|
<button id="submitTimes" class="smallButton popupElement">__MSG_submitTimesButton__</button>
|
||||||
|
|
||||||
<div id="submitTimesInfoMessageContainer" class="popupElement" style="display: none">
|
|
||||||
<h3 id="submitTimesInfoMessage" class="popupElement">
|
|
||||||
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -184,13 +184,13 @@ function submitVote(type, UUID, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitTimes(videoID, callback) {
|
async function submitTimes(videoID: string, callback) {
|
||||||
//get the video times from storage
|
//get the video times from storage
|
||||||
let sponsorTimes = Config.config.sponsorTimes.get(videoID);
|
let sponsorTimes = Config.config.sponsorTimes.get(videoID);
|
||||||
let userID = Config.config.userID;
|
let userID = Config.config.userID;
|
||||||
|
|
||||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||||
let durationResult = <Types.videoDurationResponse> await new Promise((resolve, reject) => {
|
let durationResult = <Types.VideoDurationResponse> await new Promise((resolve, reject) => {
|
||||||
chrome.tabs.query({
|
chrome.tabs.query({
|
||||||
active: true,
|
active: true,
|
||||||
currentWindow: true
|
currentWindow: true
|
||||||
@@ -218,21 +218,24 @@ async function submitTimes(videoID, callback) {
|
|||||||
+ "&userID=" + userID, function(xmlhttp, error) {
|
+ "&userID=" + userID, function(xmlhttp, error) {
|
||||||
if (xmlhttp.readyState == 4 && !error) {
|
if (xmlhttp.readyState == 4 && !error) {
|
||||||
callback({
|
callback({
|
||||||
statusCode: xmlhttp.status
|
statusCode: xmlhttp.status,
|
||||||
|
responseText: xmlhttp.responseText
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (xmlhttp.status == 200) {
|
if (xmlhttp.status == 200) {
|
||||||
//save the amount contributed
|
//save the amount contributed
|
||||||
if (!increasedContributionAmount) {
|
if (!increasedContributionAmount) {
|
||||||
increasedContributionAmount = true;
|
increasedContributionAmount = true;
|
||||||
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimes.length;
|
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimes.length;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
callback({
|
callback({
|
||||||
statusCode: -1
|
statusCode: -1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
src/components/CategoryChooserComponent.tsx
Normal file
53
src/components/CategoryChooserComponent.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import Config from "../config"
|
||||||
|
import * as CompileConfig from "../../config.json";
|
||||||
|
import CategorySkipOptionsComponent from "./CategorySkipOptionsComponent";
|
||||||
|
|
||||||
|
export interface CategoryChooserProps {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryChooserState {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class CategoryChooserComponent extends React.Component<CategoryChooserProps, CategoryChooserState> {
|
||||||
|
|
||||||
|
constructor(props: CategoryChooserProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
// Setup state
|
||||||
|
this.state = {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<table id="categoryChooserTable"
|
||||||
|
className="categoryChooserTable">
|
||||||
|
<tbody>
|
||||||
|
{this.getCategorySkipOptions()}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategorySkipOptions(): JSX.Element[] {
|
||||||
|
let elements: JSX.Element[] = [];
|
||||||
|
|
||||||
|
for (const category of CompileConfig.categoryList) {
|
||||||
|
elements.push(
|
||||||
|
<CategorySkipOptionsComponent category={category}
|
||||||
|
defaultColor={"00d400"}
|
||||||
|
key={category}>
|
||||||
|
</CategorySkipOptionsComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CategoryChooserComponent;
|
||||||
130
src/components/CategorySkipOptionsComponent.tsx
Normal file
130
src/components/CategorySkipOptionsComponent.tsx
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import Config from "../config"
|
||||||
|
import { CategorySkipOption } from "../types";
|
||||||
|
|
||||||
|
export interface CategorySkipOptionsProps {
|
||||||
|
category: string;
|
||||||
|
defaultColor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategorySkipOptionsState {
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsProps, CategorySkipOptionsState> {
|
||||||
|
|
||||||
|
constructor(props: CategorySkipOptionsProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
// Setup state
|
||||||
|
this.state = {
|
||||||
|
color: props.defaultColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let defaultOption = "disable";
|
||||||
|
// Set the default opton properly
|
||||||
|
for (const categorySelection of Config.config.categorySelections) {
|
||||||
|
if (categorySelection.name === this.props.category) {
|
||||||
|
switch (categorySelection.option) {
|
||||||
|
case CategorySkipOption.ShowOverlay:
|
||||||
|
defaultOption = "showOverlay";
|
||||||
|
break;
|
||||||
|
case CategorySkipOption.ManualSkip:
|
||||||
|
defaultOption = "manualSkip";
|
||||||
|
break;
|
||||||
|
case CategorySkipOption.AutoSkip:
|
||||||
|
defaultOption = "autoSkip";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr id={this.props.category + "OptionsRow"}
|
||||||
|
className="categoryTableElement">
|
||||||
|
<td id={this.props.category + "OptionName"}
|
||||||
|
className="categoryTableLabel">
|
||||||
|
{chrome.i18n.getMessage("category_" + this.props.category)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td id={this.props.category + "SkipOption"}>
|
||||||
|
<select
|
||||||
|
className="categoryOptionsSelector"
|
||||||
|
defaultValue={defaultOption}
|
||||||
|
onChange={this.skipOptionSelected.bind(this)}>
|
||||||
|
{this.getCategorySkipOptions()}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{/* TODO: Add colour chooser */}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipOptionSelected(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
let option: CategorySkipOption;
|
||||||
|
|
||||||
|
this.removeCurrentCategorySelection();
|
||||||
|
|
||||||
|
switch (event.target.value) {
|
||||||
|
case "disable":
|
||||||
|
return;
|
||||||
|
case "showOverlay":
|
||||||
|
option = CategorySkipOption.ShowOverlay;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "manualSkip":
|
||||||
|
option = CategorySkipOption.ManualSkip;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "autoSkip":
|
||||||
|
option = CategorySkipOption.AutoSkip;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.config.categorySelections.push({
|
||||||
|
name: this.props.category,
|
||||||
|
option: option
|
||||||
|
});
|
||||||
|
|
||||||
|
// Forces the Proxy to send this to the chrome storage API
|
||||||
|
Config.config.categorySelections = Config.config.categorySelections;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes this category from the config list of category selections */
|
||||||
|
removeCurrentCategorySelection(): void {
|
||||||
|
// Remove it if it exists
|
||||||
|
for (let i = 0; i < Config.config.categorySelections.length; i++) {
|
||||||
|
if (Config.config.categorySelections[i].name === this.props.category) {
|
||||||
|
Config.config.categorySelections.splice(i, 1);
|
||||||
|
|
||||||
|
// Forces the Proxy to send this to the chrome storage API
|
||||||
|
Config.config.categorySelections = Config.config.categorySelections;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategorySkipOptions(): JSX.Element[] {
|
||||||
|
let elements: JSX.Element[] = [];
|
||||||
|
""
|
||||||
|
let optionNames = ["disable", "showOverlay", "manualSkip", "autoSkip"];
|
||||||
|
|
||||||
|
for (const optionName of optionNames) {
|
||||||
|
elements.push(
|
||||||
|
<option key={optionName} value={optionName}>
|
||||||
|
{chrome.i18n.getMessage(optionName)}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CategorySkipOptionsComponent;
|
||||||
246
src/components/NoticeComponent.tsx
Normal file
246
src/components/NoticeComponent.tsx
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export interface NoticeProps {
|
||||||
|
noticeTitle: string,
|
||||||
|
|
||||||
|
maxCountdownTime?: () => number,
|
||||||
|
amountOfPreviousNotices?: number,
|
||||||
|
timed?: boolean,
|
||||||
|
idSuffix?: string,
|
||||||
|
|
||||||
|
fadeIn?: boolean,
|
||||||
|
|
||||||
|
// Callback for when this is closed
|
||||||
|
closeListener: () => void,
|
||||||
|
|
||||||
|
zIndex?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoticeState {
|
||||||
|
noticeTitle: string,
|
||||||
|
|
||||||
|
maxCountdownTime?: () => number,
|
||||||
|
|
||||||
|
countdownTime: number,
|
||||||
|
countdownText: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||||
|
countdownInterval: NodeJS.Timeout;
|
||||||
|
idSuffix: any;
|
||||||
|
|
||||||
|
amountOfPreviousNotices: number;
|
||||||
|
|
||||||
|
constructor(props: NoticeProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
let maxCountdownTime = () => {
|
||||||
|
if (this.props.maxCountdownTime) return this.props.maxCountdownTime();
|
||||||
|
else return 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
//the id for the setInterval running the countdown
|
||||||
|
this.countdownInterval = null;
|
||||||
|
|
||||||
|
this.amountOfPreviousNotices = props.amountOfPreviousNotices || 0;
|
||||||
|
|
||||||
|
this.idSuffix = props.idSuffix || "";
|
||||||
|
|
||||||
|
// Setup state
|
||||||
|
this.state = {
|
||||||
|
noticeTitle: props.noticeTitle,
|
||||||
|
|
||||||
|
maxCountdownTime,
|
||||||
|
|
||||||
|
//the countdown until this notice closes
|
||||||
|
countdownTime: maxCountdownTime(),
|
||||||
|
countdownText: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.startCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let noticeStyle: React.CSSProperties = {
|
||||||
|
zIndex: this.props.zIndex || (50 + this.amountOfPreviousNotices)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table id={"sponsorSkipNotice" + this.idSuffix}
|
||||||
|
className={"sponsorSkipObject sponsorSkipNotice" + (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")}
|
||||||
|
style={noticeStyle}
|
||||||
|
onMouseEnter={this.pauseCountdown.bind(this)}
|
||||||
|
onMouseLeave={this.startCountdown.bind(this)}>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
{/* First row */}
|
||||||
|
<tr id={"sponsorSkipNoticeFirstRow" + this.idSuffix}>
|
||||||
|
{/* Left column */}
|
||||||
|
<td>
|
||||||
|
{/* Logo */}
|
||||||
|
<img id={"sponsorSkipLogo" + this.idSuffix}
|
||||||
|
className="sponsorSkipLogo sponsorSkipObject"
|
||||||
|
src={chrome.extension.getURL("icons/IconSponsorBlocker256px.png")}>
|
||||||
|
</img>
|
||||||
|
|
||||||
|
<span id={"sponsorSkipMessage" + this.idSuffix}
|
||||||
|
className="sponsorSkipMessage sponsorSkipObject">
|
||||||
|
|
||||||
|
{this.state.noticeTitle}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{/* Right column */}
|
||||||
|
<td className="sponsorSkipNoticeRightSection"
|
||||||
|
style={{top: "11px"}}>
|
||||||
|
|
||||||
|
{/* Time left */}
|
||||||
|
{this.props.timed ? (
|
||||||
|
<span id={"sponsorSkipNoticeTimeLeft" + this.idSuffix}
|
||||||
|
className="sponsorSkipObject sponsorSkipNoticeTimeLeft">
|
||||||
|
|
||||||
|
{this.state.countdownText || (this.state.countdownTime + "s")}
|
||||||
|
</span>
|
||||||
|
) : ""}
|
||||||
|
|
||||||
|
|
||||||
|
{/* Close button */}
|
||||||
|
<img src={chrome.extension.getURL("icons/close.png")}
|
||||||
|
className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton sponsorSkipNoticeRightButton"
|
||||||
|
onClick={() => this.close()}>
|
||||||
|
</img>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{this.props.children}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//called every second to lower the countdown before hiding the notice
|
||||||
|
countdown() {
|
||||||
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
|
let countdownTime = this.state.countdownTime - 1;
|
||||||
|
|
||||||
|
if (countdownTime <= 0) {
|
||||||
|
//remove this from setInterval
|
||||||
|
clearInterval(this.countdownInterval);
|
||||||
|
|
||||||
|
//time to close this notice
|
||||||
|
this.close();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countdownTime == 3) {
|
||||||
|
//start fade out animation
|
||||||
|
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||||
|
notice.style.removeProperty("animation");
|
||||||
|
notice.classList.add("sponsorSkipNoticeFadeOut");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
countdownTime
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pauseCountdown() {
|
||||||
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
|
//remove setInterval
|
||||||
|
clearInterval(this.countdownInterval);
|
||||||
|
this.countdownInterval = null;
|
||||||
|
|
||||||
|
//reset countdown and inform the user
|
||||||
|
this.setState({
|
||||||
|
countdownTime: this.state.maxCountdownTime(),
|
||||||
|
countdownText: chrome.i18n.getMessage("paused")
|
||||||
|
});
|
||||||
|
|
||||||
|
//remove the fade out class if it exists
|
||||||
|
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||||
|
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
||||||
|
notice.style.animation = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
startCountdown() {
|
||||||
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
|
//if it has already started, don't start it again
|
||||||
|
if (this.countdownInterval !== null) return;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
countdownTime: this.state.maxCountdownTime(),
|
||||||
|
countdownText: null
|
||||||
|
});
|
||||||
|
|
||||||
|
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetCountdown() {
|
||||||
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
countdownTime: this.state.maxCountdownTime(),
|
||||||
|
countdownText: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param silent If true, the close listener will not be called
|
||||||
|
*/
|
||||||
|
close(silent?: boolean) {
|
||||||
|
//remove setInterval
|
||||||
|
if (this.countdownInterval !== null) clearInterval(this.countdownInterval);
|
||||||
|
|
||||||
|
if (!silent) this.props.closeListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
changeNoticeTitle(title) {
|
||||||
|
this.setState({
|
||||||
|
noticeTitle: title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addNoticeInfoMessage(message: string, message2: string = "") {
|
||||||
|
//TODO: Replace
|
||||||
|
|
||||||
|
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
||||||
|
if (previousInfoMessage != null) {
|
||||||
|
//remove it
|
||||||
|
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2");
|
||||||
|
if (previousInfoMessage2 != null) {
|
||||||
|
//remove it
|
||||||
|
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//add info
|
||||||
|
let thanksForVotingText = document.createElement("p");
|
||||||
|
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
|
||||||
|
thanksForVotingText.className = "sponsorTimesInfoMessage";
|
||||||
|
thanksForVotingText.innerText = message;
|
||||||
|
|
||||||
|
//add element to div
|
||||||
|
document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||||
|
|
||||||
|
if (message2 !== undefined) {
|
||||||
|
let thanksForVotingText2 = document.createElement("p");
|
||||||
|
thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2";
|
||||||
|
thanksForVotingText2.className = "sponsorTimesInfoMessage";
|
||||||
|
thanksForVotingText2.innerText = message2;
|
||||||
|
|
||||||
|
//add element to div
|
||||||
|
document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoticeComponent;
|
||||||
28
src/components/NoticeTextSectionComponent.tsx
Normal file
28
src/components/NoticeTextSectionComponent.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export interface NoticeTextSelectionProps {
|
||||||
|
text: string,
|
||||||
|
idSuffix: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoticeTextSelectionState {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoticeTextSelectionComponent extends React.Component<NoticeTextSelectionProps, NoticeTextSelectionState> {
|
||||||
|
|
||||||
|
constructor(props: NoticeTextSelectionProps) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<p id={"sponsorTimesInfoMessage" + this.props.idSuffix}
|
||||||
|
className="sponsorTimesInfoMessage">
|
||||||
|
{this.props.text}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoticeTextSelectionComponent;
|
||||||
321
src/components/SkipNoticeComponent.tsx
Normal file
321
src/components/SkipNoticeComponent.tsx
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import Config from "../config"
|
||||||
|
import { ContentContainer } from "../types";
|
||||||
|
|
||||||
|
import Utils from "../utils";
|
||||||
|
var utils = new Utils();
|
||||||
|
|
||||||
|
import NoticeComponent from "./NoticeComponent";
|
||||||
|
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||||
|
|
||||||
|
|
||||||
|
export interface SkipNoticeProps {
|
||||||
|
UUID: string;
|
||||||
|
autoSkip: boolean;
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: ContentContainer;
|
||||||
|
|
||||||
|
closeListener: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SkipNoticeState {
|
||||||
|
noticeTitle: string,
|
||||||
|
|
||||||
|
messages: string[],
|
||||||
|
|
||||||
|
countdownTime: number,
|
||||||
|
maxCountdownTime: () => number;
|
||||||
|
countdownText: string,
|
||||||
|
|
||||||
|
unskipText: string,
|
||||||
|
unskipCallback: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
|
||||||
|
UUID: string;
|
||||||
|
autoSkip: boolean;
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: ContentContainer;
|
||||||
|
|
||||||
|
amountOfPreviousNotices: number;
|
||||||
|
audio: HTMLAudioElement;
|
||||||
|
|
||||||
|
idSuffix: any;
|
||||||
|
|
||||||
|
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||||
|
|
||||||
|
constructor(props: SkipNoticeProps) {
|
||||||
|
super(props);
|
||||||
|
this.noticeRef = React.createRef();
|
||||||
|
|
||||||
|
this.UUID = props.UUID;
|
||||||
|
this.autoSkip = props.autoSkip;
|
||||||
|
this.contentContainer = props.contentContainer;
|
||||||
|
this.audio = null;
|
||||||
|
|
||||||
|
let noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||||
|
|
||||||
|
if (!this.autoSkip) {
|
||||||
|
noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped");
|
||||||
|
}
|
||||||
|
|
||||||
|
//add notice
|
||||||
|
this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||||
|
|
||||||
|
//this is the suffix added at the end of every id
|
||||||
|
this.idSuffix = this.UUID + this.amountOfPreviousNotices;
|
||||||
|
|
||||||
|
if (this.amountOfPreviousNotices > 0) {
|
||||||
|
//another notice exists
|
||||||
|
|
||||||
|
let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
||||||
|
previousNotice.classList.add("secondSkipNotice")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup state
|
||||||
|
this.state = {
|
||||||
|
noticeTitle,
|
||||||
|
messages: [],
|
||||||
|
|
||||||
|
//the countdown until this notice closes
|
||||||
|
maxCountdownTime: () => 4,
|
||||||
|
countdownTime: 4,
|
||||||
|
countdownText: null,
|
||||||
|
|
||||||
|
unskipText: chrome.i18n.getMessage("unskip"),
|
||||||
|
unskipCallback: this.unskip.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.autoSkip) {
|
||||||
|
Object.assign(this.state, this.getUnskippedModeInfo(chrome.i18n.getMessage("skip")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (Config.config.audioNotificationOnSkip && this.audio) {
|
||||||
|
this.audio.volume = this.contentContainer().v.volume * 0.1;
|
||||||
|
this.audio.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let noticeStyle: React.CSSProperties = {
|
||||||
|
zIndex: 50 + this.amountOfPreviousNotices
|
||||||
|
}
|
||||||
|
if (this.contentContainer().onMobileYouTube) {
|
||||||
|
noticeStyle.bottom = "4em";
|
||||||
|
noticeStyle.transform = "scale(0.8) translate(10%, 10%)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NoticeComponent noticeTitle={this.state.noticeTitle}
|
||||||
|
amountOfPreviousNotices={this.amountOfPreviousNotices}
|
||||||
|
idSuffix={this.idSuffix}
|
||||||
|
fadeIn={true}
|
||||||
|
timed={true}
|
||||||
|
maxCountdownTime={this.state.maxCountdownTime}
|
||||||
|
ref={this.noticeRef}
|
||||||
|
closeListener={this.props.closeListener}>
|
||||||
|
|
||||||
|
{(Config.config.audioNotificationOnSkip) && <audio ref={(source) => { this.audio = source; }}>
|
||||||
|
<source src={chrome.extension.getURL("icons/beep.ogg")} type="audio/ogg"></source>
|
||||||
|
</audio>}
|
||||||
|
|
||||||
|
{/* Text Boxes */}
|
||||||
|
{this.getMessageBoxes()}
|
||||||
|
|
||||||
|
{/* Last Row */}
|
||||||
|
<tr id={"sponsorSkipNoticeSecondRow" + this.idSuffix}>
|
||||||
|
|
||||||
|
{/* Vote Button Container */}
|
||||||
|
<td id={"sponsorTimesVoteButtonsContainer" + this.idSuffix}
|
||||||
|
className="sponsorTimesVoteButtonsContainer">
|
||||||
|
|
||||||
|
{/* Report Text */}
|
||||||
|
<span id={"sponsorTimesReportText" + this.idSuffix}
|
||||||
|
className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
|
||||||
|
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||||
|
style={{marginRight: "5px"}}>
|
||||||
|
|
||||||
|
{chrome.i18n.getMessage("reportButtonTitle")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* Report Button */}
|
||||||
|
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
|
||||||
|
className="sponsorSkipObject voteButton"
|
||||||
|
src={chrome.extension.getURL("icons/report.png")}
|
||||||
|
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||||
|
onClick={() => this.contentContainer().vote(0, this.UUID, this)}>
|
||||||
|
|
||||||
|
</img>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{/* Unskip Button */}
|
||||||
|
<td className="sponsorSkipNoticeUnskipSection">
|
||||||
|
<button id={"sponsorSkipUnskipButton" + this.idSuffix}
|
||||||
|
className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||||
|
style={{marginLeft: "4px"}}
|
||||||
|
onClick={this.state.unskipCallback}>
|
||||||
|
|
||||||
|
{this.state.unskipText}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{/* Never show button if autoSkip is enabled */}
|
||||||
|
{!this.autoSkip ? "" :
|
||||||
|
<td className="sponsorSkipNoticeRightSection">
|
||||||
|
<button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"
|
||||||
|
onClick={this.contentContainer().dontShowNoticeAgain}>
|
||||||
|
|
||||||
|
{chrome.i18n.getMessage("Hide")}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</NoticeComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMessageBoxes(): JSX.Element[] | JSX.Element {
|
||||||
|
if (this.state.messages.length === 0) {
|
||||||
|
// Add a spacer if there is no text
|
||||||
|
return (
|
||||||
|
<tr id={"sponsorSkipNoticeSpacer" + this.idSuffix}
|
||||||
|
className="sponsorBlockSpacer">
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let elements: JSX.Element[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.state.messages.length; i++) {
|
||||||
|
elements.push(
|
||||||
|
<NoticeTextSelectionComponent idSuffix={this.idSuffix}
|
||||||
|
text={this.state.messages[i]}
|
||||||
|
key={i}>
|
||||||
|
</NoticeTextSelectionComponent>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
unskip() {
|
||||||
|
this.contentContainer().unskipSponsorTime(this.UUID);
|
||||||
|
|
||||||
|
this.unskippedMode(chrome.i18n.getMessage("reskip"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets up notice to be not skipped yet */
|
||||||
|
unskippedMode(buttonText: string) {
|
||||||
|
//setup new callback and reset countdown
|
||||||
|
this.setState(this.getUnskippedModeInfo(buttonText), () => {
|
||||||
|
this.noticeRef.current.resetCountdown();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnskippedModeInfo(buttonText: string) {
|
||||||
|
let maxCountdownTime = function() {
|
||||||
|
let sponsorTime = utils.getSponsorTimeFromUUID(this.contentContainer().sponsorTimes, this.UUID);
|
||||||
|
let duration = Math.round((sponsorTime.segment[1] - this.contentContainer().v.currentTime) * (1 / this.contentContainer().v.playbackRate));
|
||||||
|
|
||||||
|
return Math.max(duration, 4);
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
return {
|
||||||
|
unskipText: buttonText,
|
||||||
|
|
||||||
|
unskipCallback: this.reskip.bind(this),
|
||||||
|
|
||||||
|
//change max duration to however much of the sponsor is left
|
||||||
|
maxCountdownTime: maxCountdownTime,
|
||||||
|
|
||||||
|
countdownTime: maxCountdownTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reskip() {
|
||||||
|
this.contentContainer().reskipSponsorTime(this.UUID);
|
||||||
|
|
||||||
|
//reset countdown
|
||||||
|
this.setState({
|
||||||
|
unskipText: chrome.i18n.getMessage("unskip"),
|
||||||
|
unskipCallback: this.unskip.bind(this),
|
||||||
|
|
||||||
|
maxCountdownTime: () => 4,
|
||||||
|
countdownTime: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
// See if the title should be changed
|
||||||
|
if (!this.autoSkip) {
|
||||||
|
this.setState({
|
||||||
|
noticeTitle: chrome.i18n.getMessage("noticeTitle")
|
||||||
|
});
|
||||||
|
|
||||||
|
if(Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afterDownvote() {
|
||||||
|
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||||
|
this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
|
||||||
|
|
||||||
|
//remove this sponsor from the sponsors looked up
|
||||||
|
//find which one it is
|
||||||
|
for (let i = 0; i < this.contentContainer().sponsorTimes.length; i++) {
|
||||||
|
if (this.contentContainer().sponsorTimes[i].UUID == this.UUID) {
|
||||||
|
//this one is the one to hide
|
||||||
|
|
||||||
|
//add this as a hidden sponsorTime
|
||||||
|
this.contentContainer().hiddenSponsorTimes.push(i);
|
||||||
|
|
||||||
|
this.contentContainer().updatePreviewBar();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setNoticeInfoMessage(...messages: string[]) {
|
||||||
|
this.setState({
|
||||||
|
messages
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
addVoteButtonInfo(message) {
|
||||||
|
this.resetVoteButtonInfo();
|
||||||
|
|
||||||
|
//hide report button and text for it
|
||||||
|
let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
|
||||||
|
if (downvoteButton != null) {
|
||||||
|
downvoteButton.style.display = "none";
|
||||||
|
}
|
||||||
|
let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
|
||||||
|
if (downvoteButtonText != null) {
|
||||||
|
downvoteButtonText.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
//add info
|
||||||
|
let thanksForVotingText = document.createElement("td");
|
||||||
|
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
|
||||||
|
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
||||||
|
thanksForVotingText.innerText = message;
|
||||||
|
|
||||||
|
//add element to div
|
||||||
|
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetVoteButtonInfo() {
|
||||||
|
let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
|
||||||
|
if (previousInfoMessage != null) {
|
||||||
|
//remove it
|
||||||
|
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
//show button again
|
||||||
|
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SkipNoticeComponent;
|
||||||
324
src/components/SponsorTimeEditComponent.tsx
Normal file
324
src/components/SponsorTimeEditComponent.tsx
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import Config from "../config";
|
||||||
|
import * as CompileConfig from "../../config.json";
|
||||||
|
|
||||||
|
import Utils from "../utils";
|
||||||
|
import { ContentContainer, SponsorTime } from "../types";
|
||||||
|
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||||
|
var utils = new Utils();
|
||||||
|
|
||||||
|
export interface SponsorTimeEditProps {
|
||||||
|
index: number,
|
||||||
|
|
||||||
|
idSuffix: string,
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: ContentContainer,
|
||||||
|
|
||||||
|
submissionNotice: SubmissionNoticeComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SponsorTimeEditState {
|
||||||
|
editing: boolean;
|
||||||
|
sponsorTimeEdits: string[][];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, SponsorTimeEditState> {
|
||||||
|
|
||||||
|
idSuffix: string;
|
||||||
|
|
||||||
|
categoryOptionRef: React.RefObject<HTMLSelectElement>;
|
||||||
|
|
||||||
|
constructor(props: SponsorTimeEditProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.categoryOptionRef = React.createRef();
|
||||||
|
|
||||||
|
this.idSuffix = this.props.idSuffix;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
editing: false,
|
||||||
|
sponsorTimeEdits: [[null, null], [null, null]]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// Prevent inputs from triggering key events
|
||||||
|
document.getElementById("sponsorTimesContainer" + this.idSuffix).addEventListener('keydown', function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let style: React.CSSProperties = {
|
||||||
|
textAlign: "center"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.props.index != 0) {
|
||||||
|
style.marginTop = "15px";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create time display
|
||||||
|
let timeDisplay: JSX.Element;
|
||||||
|
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||||
|
let segment = sponsorTime.segment;
|
||||||
|
if (this.state.editing) {
|
||||||
|
timeDisplay = (
|
||||||
|
<div id={"sponsorTimesContainer" + this.idSuffix}
|
||||||
|
className="sponsorTimeDisplay">
|
||||||
|
|
||||||
|
<span id={"nowButton0" + this.idSuffix}
|
||||||
|
className="sponsorNowButton"
|
||||||
|
onClick={() => this.setTimeToNow(0)}>
|
||||||
|
{chrome.i18n.getMessage("bracketNow")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input id={"submittingTimeMinutes0" + this.idSuffix}
|
||||||
|
className="sponsorTimeEdit sponsorTimeEditMinutes"
|
||||||
|
type="number"
|
||||||
|
value={this.state.sponsorTimeEdits[0][0]}
|
||||||
|
onChange={(e) => {
|
||||||
|
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||||
|
sponsorTimeEdits[0][0] = e.target.value;
|
||||||
|
|
||||||
|
this.setState({sponsorTimeEdits});
|
||||||
|
}}>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<input id={"submittingTimeSeconds0" + this.idSuffix}
|
||||||
|
className="sponsorTimeEdit sponsorTimeEditSeconds"
|
||||||
|
type="number"
|
||||||
|
value={this.state.sponsorTimeEdits[0][1]}
|
||||||
|
onChange={(e) => {
|
||||||
|
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||||
|
sponsorTimeEdits[0][1] = e.target.value;
|
||||||
|
|
||||||
|
this.setState({sponsorTimeEdits});
|
||||||
|
}}>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{" " + chrome.i18n.getMessage("to") + " "}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input id={"submittingTimeMinutes1" + this.idSuffix}
|
||||||
|
className="sponsorTimeEdit sponsorTimeEditMinutes"
|
||||||
|
type="text"
|
||||||
|
value={this.state.sponsorTimeEdits[1][0]}
|
||||||
|
onChange={(e) => {
|
||||||
|
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||||
|
sponsorTimeEdits[1][0] = e.target.value;
|
||||||
|
|
||||||
|
this.setState({sponsorTimeEdits});
|
||||||
|
}}>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<input id={"submittingTimeSeconds1" + this.idSuffix}
|
||||||
|
className="sponsorTimeEdit sponsorTimeEditSeconds"
|
||||||
|
type="text"
|
||||||
|
value={this.state.sponsorTimeEdits[1][1]}
|
||||||
|
onChange={(e) => {
|
||||||
|
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||||
|
sponsorTimeEdits[1][1] = e.target.value;
|
||||||
|
|
||||||
|
this.setState({sponsorTimeEdits});
|
||||||
|
}}>
|
||||||
|
</input>
|
||||||
|
|
||||||
|
<span id={"nowButton1" + this.idSuffix}
|
||||||
|
className="sponsorNowButton"
|
||||||
|
onClick={() => this.setTimeToNow(1)}>
|
||||||
|
{chrome.i18n.getMessage("bracketNow")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
timeDisplay = (
|
||||||
|
<div id={"sponsorTimesContainer" + this.idSuffix}
|
||||||
|
className="sponsorTimeDisplay"
|
||||||
|
onClick={this.toggleEditTime.bind(this)}>
|
||||||
|
{utils.getFormattedTime(segment[0], true) +
|
||||||
|
((!isNaN(segment[1])) ? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segment[1], true) : "")}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={style}>
|
||||||
|
|
||||||
|
{timeDisplay}
|
||||||
|
|
||||||
|
{/* Category */}
|
||||||
|
|
||||||
|
<select id={"sponsorTimeCategories" + this.idSuffix}
|
||||||
|
className="sponsorTimeCategories"
|
||||||
|
defaultValue={sponsorTime.category}
|
||||||
|
ref={this.categoryOptionRef}
|
||||||
|
onChange={this.categorySelectionChange.bind(this)}>
|
||||||
|
{this.getCategoryOptions()}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
{/* Editing Tools */}
|
||||||
|
|
||||||
|
<span id={"sponsorTimeDeleteButton" + this.idSuffix}
|
||||||
|
className="sponsorTimeEditButton"
|
||||||
|
onClick={this.deleteTime.bind(this)}>
|
||||||
|
{chrome.i18n.getMessage("delete")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{(!isNaN(segment[1])) ? (
|
||||||
|
<span id={"sponsorTimePreviewButton" + this.idSuffix}
|
||||||
|
className="sponsorTimeEditButton"
|
||||||
|
onClick={this.previewTime.bind(this)}>
|
||||||
|
{chrome.i18n.getMessage("preview")}
|
||||||
|
</span>
|
||||||
|
): ""}
|
||||||
|
|
||||||
|
{(!isNaN(segment[1])) ? (
|
||||||
|
<span id={"sponsorTimeEditButton" + this.idSuffix}
|
||||||
|
className="sponsorTimeEditButton"
|
||||||
|
onClick={this.toggleEditTime.bind(this)}>
|
||||||
|
{this.state.editing ? chrome.i18n.getMessage("save") : chrome.i18n.getMessage("edit")}
|
||||||
|
</span>
|
||||||
|
): ""}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategoryOptions() {
|
||||||
|
let elements = [];
|
||||||
|
|
||||||
|
for (const category of Config.config.categorySelections) {
|
||||||
|
elements.push(
|
||||||
|
<option value={category.name}
|
||||||
|
key={category.name}>
|
||||||
|
{chrome.i18n.getMessage("category_" + category.name)}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elements.length < CompileConfig.categoryList.length) {
|
||||||
|
// Add show more button
|
||||||
|
elements.push(
|
||||||
|
<option value={"moreCategories"}
|
||||||
|
key={"moreCategories"}>
|
||||||
|
{chrome.i18n.getMessage("moreCategories")}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
|
// See if show more categories was pressed
|
||||||
|
if (event.target.value === "moreCategories") {
|
||||||
|
// Open options page
|
||||||
|
chrome.runtime.sendMessage({"message": "openConfig"});
|
||||||
|
|
||||||
|
// Reset option to previous
|
||||||
|
event.target.value = this.props.contentContainer().sponsorTimesSubmitting[this.props.index].category;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveEditTimes();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeToNow(index: number) {
|
||||||
|
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||||
|
|
||||||
|
sponsorTime.segment[index] =
|
||||||
|
this.props.contentContainer().v.currentTime;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||||
|
}, this.saveEditTimes);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleEditTime(): void {
|
||||||
|
if (this.state.editing) {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
editing: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.saveEditTimes();
|
||||||
|
} else {
|
||||||
|
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
editing: true,
|
||||||
|
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an array in the sponsorTimeEdits form (minutes and seconds) from a normal seconds sponsor time */
|
||||||
|
getFormattedSponsorTimesEdits(sponsorTime: SponsorTime): string[][] {
|
||||||
|
return [[String(utils.getFormattedMinutes(sponsorTime.segment[0])), String(utils.getFormattedSeconds(sponsorTime.segment[0]))],
|
||||||
|
[String(utils.getFormattedMinutes(sponsorTime.segment[1])), String(utils.getFormattedSeconds(sponsorTime.segment[1]))]];
|
||||||
|
}
|
||||||
|
|
||||||
|
saveEditTimes() {
|
||||||
|
let sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||||
|
|
||||||
|
if (this.state.editing) {
|
||||||
|
sponsorTimesSubmitting[this.props.index].segment =
|
||||||
|
[utils.getRawSeconds(parseFloat(this.state.sponsorTimeEdits[0][0]), parseFloat(this.state.sponsorTimeEdits[0][1])),
|
||||||
|
utils.getRawSeconds(parseFloat(this.state.sponsorTimeEdits[1][0]), parseFloat(this.state.sponsorTimeEdits[1][1]))];
|
||||||
|
}
|
||||||
|
|
||||||
|
sponsorTimesSubmitting[this.props.index].category = this.categoryOptionRef.current.value;
|
||||||
|
|
||||||
|
Config.config.sponsorTimes.set(this.props.contentContainer().sponsorVideoID, utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting));
|
||||||
|
|
||||||
|
this.props.contentContainer().updatePreviewBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
previewTime(): void {
|
||||||
|
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||||
|
let index = this.props.index;
|
||||||
|
|
||||||
|
let skipTime = sponsorTimes[index].segment[0];
|
||||||
|
|
||||||
|
if (this.state.editing) {
|
||||||
|
// Save edits before previewing
|
||||||
|
this.saveEditTimes();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.contentContainer().previewTime(skipTime - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTime(): void {
|
||||||
|
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||||
|
let index = this.props.index;
|
||||||
|
|
||||||
|
//if it is not a complete sponsor time
|
||||||
|
if (sponsorTimes[index].segment.length < 2) {
|
||||||
|
//update video player
|
||||||
|
this.props.contentContainer().changeStartSponsorButton(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sponsorTimes.splice(index, 1);
|
||||||
|
|
||||||
|
//save this
|
||||||
|
Config.config.sponsorTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimes);
|
||||||
|
|
||||||
|
this.props.contentContainer().updatePreviewBar();
|
||||||
|
|
||||||
|
//if they are all removed
|
||||||
|
if (sponsorTimes.length == 0) {
|
||||||
|
this.props.submissionNotice.cancel();
|
||||||
|
|
||||||
|
//update video player
|
||||||
|
this.props.contentContainer().changeStartSponsorButton(true, false);
|
||||||
|
} else {
|
||||||
|
//update display
|
||||||
|
this.props.submissionNotice.forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SponsorTimeEditComponent;
|
||||||
176
src/components/SubmissionNoticeComponent.tsx
Normal file
176
src/components/SubmissionNoticeComponent.tsx
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import Config from "../config"
|
||||||
|
import { ContentContainer } from "../types";
|
||||||
|
|
||||||
|
import NoticeComponent from "./NoticeComponent";
|
||||||
|
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||||
|
import SponsorTimeEditComponent from "./SponsorTimeEditComponent";
|
||||||
|
|
||||||
|
export interface SubmissionNoticeProps {
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: ContentContainer;
|
||||||
|
|
||||||
|
callback: () => any;
|
||||||
|
|
||||||
|
closeListener: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubmissionNoticeeState {
|
||||||
|
noticeTitle: string,
|
||||||
|
messages: string[],
|
||||||
|
idSuffix: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, SubmissionNoticeeState> {
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: ContentContainer;
|
||||||
|
|
||||||
|
callback: () => any;
|
||||||
|
|
||||||
|
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||||
|
timeEditRefs: React.RefObject<SponsorTimeEditComponent>[];
|
||||||
|
|
||||||
|
videoObserver: MutationObserver;
|
||||||
|
|
||||||
|
constructor(props: SubmissionNoticeProps) {
|
||||||
|
super(props);
|
||||||
|
this.noticeRef = React.createRef();
|
||||||
|
|
||||||
|
this.contentContainer = props.contentContainer;
|
||||||
|
this.callback = props.callback;
|
||||||
|
|
||||||
|
let noticeTitle = chrome.i18n.getMessage("confirmNoticeTitle");
|
||||||
|
|
||||||
|
// Setup state
|
||||||
|
this.state = {
|
||||||
|
noticeTitle,
|
||||||
|
messages: [],
|
||||||
|
idSuffix: "SubmissionNotice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// Catch and rerender when the video size changes
|
||||||
|
//TODO: Use ResizeObserver when it is supported in TypeScript
|
||||||
|
this.videoObserver = new MutationObserver(() => {
|
||||||
|
this.forceUpdate();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.videoObserver.observe(this.contentContainer().v, {
|
||||||
|
attributes: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.videoObserver) {
|
||||||
|
this.videoObserver.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<NoticeComponent noticeTitle={this.state.noticeTitle}
|
||||||
|
idSuffix={this.state.idSuffix}
|
||||||
|
ref={this.noticeRef}
|
||||||
|
closeListener={this.cancel.bind(this)}
|
||||||
|
zIndex={50000}>
|
||||||
|
|
||||||
|
{/* Text Boxes */}
|
||||||
|
{this.getMessageBoxes()}
|
||||||
|
|
||||||
|
{/* Sponsor Time List */}
|
||||||
|
<tr id={"sponsorSkipNoticeMiddleRow" + this.state.idSuffix}
|
||||||
|
className="sponsorTimeMessagesRow"
|
||||||
|
style={{maxHeight: (this.contentContainer().v.offsetHeight - 200) + "px"}}>
|
||||||
|
<td style={{width: "100%"}}>
|
||||||
|
{this.getSponsorTimeMessages()}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{/* Last Row */}
|
||||||
|
<tr id={"sponsorSkipNoticeSecondRow" + this.state.idSuffix}>
|
||||||
|
|
||||||
|
<td className="sponsorSkipNoticeRightSection"
|
||||||
|
style={{position: "relative"}}>
|
||||||
|
|
||||||
|
{/* Cancel Button */}
|
||||||
|
<button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"
|
||||||
|
onClick={this.cancel.bind(this)}>
|
||||||
|
|
||||||
|
{chrome.i18n.getMessage("cancel")}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Submit Button */}
|
||||||
|
<button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"
|
||||||
|
onClick={this.submit.bind(this)}>
|
||||||
|
|
||||||
|
{chrome.i18n.getMessage("submit")}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</NoticeComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSponsorTimeMessages(): JSX.Element[] | JSX.Element {
|
||||||
|
let elements: JSX.Element[] = [];
|
||||||
|
this.timeEditRefs = [];
|
||||||
|
|
||||||
|
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||||
|
|
||||||
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
|
let timeRef = React.createRef<SponsorTimeEditComponent>();
|
||||||
|
|
||||||
|
elements.push(
|
||||||
|
<SponsorTimeEditComponent key={i}
|
||||||
|
idSuffix={this.state.idSuffix + i}
|
||||||
|
index={i}
|
||||||
|
contentContainer={this.props.contentContainer}
|
||||||
|
submissionNotice={this}
|
||||||
|
ref={timeRef}>
|
||||||
|
</SponsorTimeEditComponent>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.timeEditRefs.push(timeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMessageBoxes(): JSX.Element[] | JSX.Element {
|
||||||
|
let elements: JSX.Element[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.state.messages.length; i++) {
|
||||||
|
elements.push(
|
||||||
|
<NoticeTextSelectionComponent idSuffix={this.state.idSuffix + i}
|
||||||
|
text={this.state.messages[i]}
|
||||||
|
key={i}>
|
||||||
|
</NoticeTextSelectionComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.noticeRef.current.close(true);
|
||||||
|
|
||||||
|
this.contentContainer().resetSponsorSubmissionNotice();
|
||||||
|
|
||||||
|
this.props.closeListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
// save all items
|
||||||
|
for (const ref of this.timeEditRefs) {
|
||||||
|
ref.current.saveEditTimes();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.callback();
|
||||||
|
|
||||||
|
this.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SubmissionNoticeComponent;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as CompileConfig from "../config.json";
|
import * as CompileConfig from "../config.json";
|
||||||
|
import { CategorySelection, CategorySkipOption } from "./types";
|
||||||
|
|
||||||
interface SBConfig {
|
interface SBConfig {
|
||||||
userID: string,
|
userID: string,
|
||||||
@@ -10,7 +11,6 @@ interface SBConfig {
|
|||||||
skipCount: number,
|
skipCount: number,
|
||||||
sponsorTimesContributed: number,
|
sponsorTimesContributed: number,
|
||||||
disableSkipping: boolean,
|
disableSkipping: boolean,
|
||||||
disableAutoSkip: boolean,
|
|
||||||
trackViewCount: boolean,
|
trackViewCount: boolean,
|
||||||
dontShowNotice: boolean,
|
dontShowNotice: boolean,
|
||||||
hideVideoPlayerControls: boolean,
|
hideVideoPlayerControls: boolean,
|
||||||
@@ -24,8 +24,13 @@ interface SBConfig {
|
|||||||
supportInvidious: boolean,
|
supportInvidious: boolean,
|
||||||
serverAddress: string,
|
serverAddress: string,
|
||||||
minDuration: number,
|
minDuration: number,
|
||||||
|
audioNotificationOnSkip,
|
||||||
checkForUnlistedVideos: boolean,
|
checkForUnlistedVideos: boolean,
|
||||||
mobileUpdateShowCount: number
|
mobileUpdateShowCount: number,
|
||||||
|
testingServer: boolean,
|
||||||
|
|
||||||
|
// What categories should be skipped
|
||||||
|
categorySelections: CategorySelection[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SBObject {
|
interface SBObject {
|
||||||
@@ -105,7 +110,6 @@ var Config: SBObject = {
|
|||||||
skipCount: 0,
|
skipCount: 0,
|
||||||
sponsorTimesContributed: 0,
|
sponsorTimesContributed: 0,
|
||||||
disableSkipping: false,
|
disableSkipping: false,
|
||||||
disableAutoSkip: false,
|
|
||||||
trackViewCount: true,
|
trackViewCount: true,
|
||||||
dontShowNotice: false,
|
dontShowNotice: false,
|
||||||
hideVideoPlayerControls: false,
|
hideVideoPlayerControls: false,
|
||||||
@@ -119,8 +123,15 @@ var Config: SBObject = {
|
|||||||
supportInvidious: false,
|
supportInvidious: false,
|
||||||
serverAddress: CompileConfig.serverAddress,
|
serverAddress: CompileConfig.serverAddress,
|
||||||
minDuration: 0,
|
minDuration: 0,
|
||||||
|
audioNotificationOnSkip: false,
|
||||||
checkForUnlistedVideos: false,
|
checkForUnlistedVideos: false,
|
||||||
mobileUpdateShowCount: 0
|
mobileUpdateShowCount: 0,
|
||||||
|
testingServer: false,
|
||||||
|
|
||||||
|
categorySelections: [{
|
||||||
|
name: "sponsor",
|
||||||
|
option: CategorySkipOption.AutoSkip
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
localConfig: null,
|
localConfig: null,
|
||||||
config: null,
|
config: null,
|
||||||
@@ -225,11 +236,14 @@ function fetchConfig() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function migrateOldFormats() { // Convert sponsorTimes format
|
function migrateOldFormats() {
|
||||||
for (const key in Config.localConfig) {
|
if (Config.config["disableAutoSkip"]) {
|
||||||
if (key.startsWith("sponsorTimes") && key !== "sponsorTimes" && key !== "sponsorTimesContributed") {
|
for (const selection of Config.config.categorySelections) {
|
||||||
Config.config.sponsorTimes.set(key.substr(12), Config.config[key]);
|
if (selection.name === "sponsor") {
|
||||||
delete Config.config[key];
|
selection.option = CategorySkipOption.ManualSkip;
|
||||||
|
|
||||||
|
chrome.storage.sync.remove("disableAutoSkip");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
501
src/content.ts
501
src/content.ts
@@ -1,24 +1,28 @@
|
|||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
|
|
||||||
|
import { SponsorTime, CategorySkipOption, CategorySelection, VideoID } from "./types";
|
||||||
|
|
||||||
|
import { ContentContainer } from "./types";
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
var utils = new Utils();
|
var utils = new Utils();
|
||||||
|
|
||||||
import runThePopup from "./popup";
|
import runThePopup from "./popup";
|
||||||
|
|
||||||
import PreviewBar from "./js-components/previewBar";
|
import PreviewBar from "./js-components/previewBar";
|
||||||
import SkipNotice from "./js-components/skipNotice";
|
import SkipNotice from "./render/SkipNotice";
|
||||||
|
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||||
|
import SubmissionNotice from "./render/SubmissionNotice";
|
||||||
|
|
||||||
// Hack to get the CSS loaded on permission-based sites (Invidious)
|
// Hack to get the CSS loaded on permission-based sites (Invidious)
|
||||||
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
||||||
|
|
||||||
//was sponsor data found when doing SponsorsLookup
|
//was sponsor data found when doing SponsorsLookup
|
||||||
var sponsorDataFound = false;
|
var sponsorDataFound = false;
|
||||||
var previousVideoID = null;
|
var previousVideoID: VideoID = null;
|
||||||
//the actual sponsorTimes if loaded and UUIDs associated with them
|
//the actual sponsorTimes if loaded and UUIDs associated with them
|
||||||
var sponsorTimes: number[][] = null;
|
var sponsorTimes: SponsorTime[] = null;
|
||||||
var UUIDs = [];
|
|
||||||
//what video id are these sponsors for
|
//what video id are these sponsors for
|
||||||
var sponsorVideoID = null;
|
var sponsorVideoID: VideoID = null;
|
||||||
|
|
||||||
// Skips are scheduled to ensure precision.
|
// Skips are scheduled to ensure precision.
|
||||||
// Skips are rescheduled every seeking event.
|
// Skips are rescheduled every seeking event.
|
||||||
@@ -27,10 +31,10 @@ var currentSkipSchedule: NodeJS.Timeout = null;
|
|||||||
var seekListenerSetUp = false
|
var seekListenerSetUp = false
|
||||||
|
|
||||||
//these are sponsors that have been downvoted
|
//these are sponsors that have been downvoted
|
||||||
var hiddenSponsorTimes = [];
|
var hiddenSponsorTimes: number[] = [];
|
||||||
|
|
||||||
/** @type {Array[boolean]} Has the sponsor been skipped */
|
/** @type {Array[boolean]} Has the sponsor been skipped */
|
||||||
var sponsorSkipped = [];
|
var sponsorSkipped: boolean[] = [];
|
||||||
|
|
||||||
//the video
|
//the video
|
||||||
var video: HTMLVideoElement;
|
var video: HTMLVideoElement;
|
||||||
@@ -83,32 +87,39 @@ var sponsorLookupRetries = 0;
|
|||||||
|
|
||||||
//the last time in the video a sponsor was skipped
|
//the last time in the video a sponsor was skipped
|
||||||
//used for the go back button
|
//used for the go back button
|
||||||
var lastSponsorTimeSkipped = null;
|
var lastSponsorTimeSkipped: number = null;
|
||||||
//used for ratings
|
//used for ratings
|
||||||
var lastSponsorTimeSkippedUUID = null;
|
var lastSponsorTimeSkippedUUID: string = null;
|
||||||
|
|
||||||
//if showing the start sponsor button or the end sponsor button on the player
|
//if showing the start sponsor button or the end sponsor button on the player
|
||||||
var showingStartSponsor = true;
|
var showingStartSponsor = true;
|
||||||
|
|
||||||
//the sponsor times being prepared to be submitted
|
//the sponsor times being prepared to be submitted
|
||||||
var sponsorTimesSubmitting = [];
|
var sponsorTimesSubmitting: SponsorTime[] = [];
|
||||||
|
|
||||||
//becomes true when isInfoFound is called
|
//becomes true when isInfoFound is called
|
||||||
//this is used to close the popup on YouTube when the other popup opens
|
//this is used to close the popup on YouTube when the other popup opens
|
||||||
var popupInitialised = false;
|
var popupInitialised = false;
|
||||||
|
|
||||||
|
var submissionNotice: SubmissionNotice = null;
|
||||||
|
|
||||||
// Contains all of the functions and variables needed by the skip notice
|
// Contains all of the functions and variables needed by the skip notice
|
||||||
var skipNoticeContentContainer = () => ({
|
var skipNoticeContentContainer: ContentContainer = () => ({
|
||||||
vote,
|
vote,
|
||||||
dontShowNoticeAgain,
|
dontShowNoticeAgain,
|
||||||
unskipSponsorTime,
|
unskipSponsorTime,
|
||||||
sponsorTimes,
|
sponsorTimes,
|
||||||
UUIDs,
|
sponsorTimesSubmitting,
|
||||||
v: video,
|
|
||||||
reskipSponsorTime,
|
|
||||||
hiddenSponsorTimes,
|
hiddenSponsorTimes,
|
||||||
|
v: video,
|
||||||
|
sponsorVideoID,
|
||||||
|
reskipSponsorTime,
|
||||||
updatePreviewBar,
|
updatePreviewBar,
|
||||||
onMobileYouTube
|
onMobileYouTube,
|
||||||
|
sponsorSubmissionNotice: submissionNotice,
|
||||||
|
resetSponsorSubmissionNotice,
|
||||||
|
changeStartSponsorButton,
|
||||||
|
previewTime
|
||||||
});
|
});
|
||||||
|
|
||||||
//get messages from the background script and the popup
|
//get messages from the background script and the popup
|
||||||
@@ -133,8 +144,7 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
|||||||
sendResponse({
|
sendResponse({
|
||||||
found: sponsorDataFound,
|
found: sponsorDataFound,
|
||||||
sponsorTimes: sponsorTimes,
|
sponsorTimes: sponsorTimes,
|
||||||
hiddenSponsorTimes: hiddenSponsorTimes,
|
hiddenSponsorTimes: hiddenSponsorTimes
|
||||||
UUIDs: UUIDs
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
|
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
|
||||||
@@ -198,6 +208,10 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
|||||||
case "changeStartSponsorButton":
|
case "changeStartSponsorButton":
|
||||||
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
|
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "submitTimes":
|
||||||
|
submitSponsorTimes();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +265,6 @@ function resetValues() {
|
|||||||
|
|
||||||
//reset sponsor times
|
//reset sponsor times
|
||||||
sponsorTimes = null;
|
sponsorTimes = null;
|
||||||
UUIDs = [];
|
|
||||||
sponsorLookupRetries = 0;
|
sponsorLookupRetries = 0;
|
||||||
|
|
||||||
//empty the preview bar
|
//empty the preview bar
|
||||||
@@ -341,36 +354,21 @@ async function videoIDChange(id) {
|
|||||||
sponsorsLookup(id, channelIDPromise);
|
sponsorsLookup(id, channelIDPromise);
|
||||||
|
|
||||||
//make sure everything is properly added
|
//make sure everything is properly added
|
||||||
updateVisibilityOfPlayerControlsButton();
|
updateVisibilityOfPlayerControlsButton().then(() => {
|
||||||
|
|
||||||
//reset sponsor times submitting
|
|
||||||
sponsorTimesSubmitting = [];
|
|
||||||
|
|
||||||
//see if the onvideo control image needs to be changed
|
//see if the onvideo control image needs to be changed
|
||||||
utils.wait(getControls).then(result => {
|
let segments = Config.config.sponsorTimes.get(sponsorVideoID);
|
||||||
chrome.runtime.sendMessage({
|
if (segments != null && segments.length > 0 && segments[segments.length - 1].length >= 2) {
|
||||||
message: "getSponsorTimes",
|
|
||||||
videoID: id
|
|
||||||
}, function(response) {
|
|
||||||
if (response != undefined) {
|
|
||||||
let sponsorTimes = response.sponsorTimes;
|
|
||||||
if (sponsorTimes != null && sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length >= 2) {
|
|
||||||
changeStartSponsorButton(true, true);
|
changeStartSponsorButton(true, true);
|
||||||
} else if (sponsorTimes != null && sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
|
} else if (segments != null && segments.length > 0 && segments[segments.length - 1].length < 2) {
|
||||||
changeStartSponsorButton(false, true);
|
changeStartSponsorButton(false, true);
|
||||||
} else {
|
} else {
|
||||||
changeStartSponsorButton(true, false);
|
changeStartSponsorButton(true, false);
|
||||||
}
|
|
||||||
|
|
||||||
//see if this data should be saved in the sponsorTimesSubmitting variable
|
|
||||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
|
||||||
sponsorTimesSubmitting = sponsorTimes;
|
|
||||||
|
|
||||||
updatePreviewBar();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
//reset sponsor times submitting
|
||||||
|
sponsorTimesSubmitting = [];
|
||||||
|
updateSponsorTimesSubmitting();
|
||||||
|
|
||||||
//see if video controls buttons should be added
|
//see if video controls buttons should be added
|
||||||
if (!onInvidious) {
|
if (!onInvidious) {
|
||||||
@@ -383,9 +381,9 @@ function handleMobileControlsMutations(): void {
|
|||||||
|
|
||||||
updateVisibilityOfPlayerControlsButton().then((createdButtons) => {
|
updateVisibilityOfPlayerControlsButton().then((createdButtons) => {
|
||||||
if (createdButtons) {
|
if (createdButtons) {
|
||||||
if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].length >= 2) {
|
if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length >= 2) {
|
||||||
changeStartSponsorButton(true, true);
|
changeStartSponsorButton(true, true);
|
||||||
} else if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].length < 2) {
|
} else if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length < 2) {
|
||||||
changeStartSponsorButton(false, true);
|
changeStartSponsorButton(false, true);
|
||||||
} else {
|
} else {
|
||||||
changeStartSponsorButton(true, false);
|
changeStartSponsorButton(true, false);
|
||||||
@@ -458,7 +456,7 @@ function cancelSponsorSchedule(): void {
|
|||||||
*
|
*
|
||||||
* @param currentTime Optional if you don't want to use the actual current time
|
* @param currentTime Optional if you don't want to use the actual current time
|
||||||
*/
|
*/
|
||||||
function startSponsorSchedule(currentTime?: number): void {
|
function startSponsorSchedule(includeIntersectingSegments: boolean = false, currentTime?: number): void {
|
||||||
cancelSponsorSchedule();
|
cancelSponsorSchedule();
|
||||||
if (video.paused) return;
|
if (video.paused) return;
|
||||||
|
|
||||||
@@ -468,27 +466,34 @@ function startSponsorSchedule(currentTime?: number): void {
|
|||||||
|
|
||||||
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
||||||
|
|
||||||
let skipInfo = getNextSkipIndex(currentTime);
|
let skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments);
|
||||||
|
|
||||||
if (skipInfo.index === -1) return;
|
if (skipInfo.index === -1) return;
|
||||||
|
|
||||||
let skipTime = skipInfo.array[skipInfo.index];
|
let currentSkip = skipInfo.array[skipInfo.index];
|
||||||
|
let skipTime: number[] = [currentSkip.segment[0], skipInfo.array[skipInfo.endIndex].segment[1]];
|
||||||
let timeUntilSponsor = skipTime[0] - currentTime;
|
let timeUntilSponsor = skipTime[0] - currentTime;
|
||||||
|
|
||||||
|
// Don't skip if this category should not be skipped
|
||||||
|
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ShowOverlay) return;
|
||||||
|
|
||||||
let skippingFunction = () => {
|
let skippingFunction = () => {
|
||||||
let forcedSkipTime: number = null;
|
let forcedSkipTime: number = null;
|
||||||
|
let forcedIncludeIntersectingSegments = false;
|
||||||
|
|
||||||
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
|
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
|
||||||
// Double check that the videoID is correct
|
// Double check that the videoID is correct
|
||||||
// TODO: Remove this bug catching if statement when the bug is found
|
// TODO: Remove this bug catching if statement when the bug is found
|
||||||
let currentVideoID = getYouTubeVideoID(document.URL);
|
let currentVideoID = getYouTubeVideoID(document.URL);
|
||||||
if (currentVideoID == sponsorVideoID) {
|
if (currentVideoID == sponsorVideoID) {
|
||||||
skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice);
|
skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice);
|
||||||
|
|
||||||
if (Config.config.disableAutoSkip) {
|
// TODO: Know the autoSkip settings for ALL items being skipped
|
||||||
|
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) {
|
||||||
forcedSkipTime = skipTime[0] + 0.001;
|
forcedSkipTime = skipTime[0] + 0.001;
|
||||||
} else {
|
} else {
|
||||||
forcedSkipTime = skipTime[1];
|
forcedSkipTime = skipTime[1];
|
||||||
|
forcedIncludeIntersectingSegments = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Something has really gone wrong
|
// Something has really gone wrong
|
||||||
@@ -500,7 +505,7 @@ function startSponsorSchedule(currentTime?: number): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startSponsorSchedule(forcedSkipTime);
|
startSponsorSchedule(forcedIncludeIntersectingSegments, forcedSkipTime);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (timeUntilSponsor <= 0) {
|
if (timeUntilSponsor <= 0) {
|
||||||
@@ -588,61 +593,70 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
|||||||
//check database for sponsor times
|
//check database for sponsor times
|
||||||
//made true once a setTimeout has been created to try again after a server error
|
//made true once a setTimeout has been created to try again after a server error
|
||||||
let recheckStarted = false;
|
let recheckStarted = false;
|
||||||
utils.sendRequestToServer('GET', "/api/getVideoSponsorTimes?videoID=" + id, function(xmlhttp) {
|
// Create categories list
|
||||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
let categories: string[] = [];
|
||||||
|
for (const categorySelection of Config.config.categorySelections) {
|
||||||
|
categories.push(categorySelection.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.asyncRequestToServer('GET', "/api/skipSegments", {
|
||||||
|
videoID: id,
|
||||||
|
categories
|
||||||
|
}).then(async (response: Response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
let recievedSegments: SponsorTime[] = await response.json();
|
||||||
|
if (!recievedSegments.length) {
|
||||||
|
console.error("[SponsorBlock] Server returned malformed response: " + JSON.stringify(recievedSegments));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sponsorDataFound = true;
|
sponsorDataFound = true;
|
||||||
|
|
||||||
let recievedSponsorTimes = JSON.parse(xmlhttp.responseText).sponsorTimes;
|
|
||||||
let recievedUUIDs = JSON.parse(xmlhttp.responseText).UUIDs;
|
|
||||||
|
|
||||||
// Check if any old submissions should be kept
|
// Check if any old submissions should be kept
|
||||||
for (let i = 0; i < UUIDs.length; i++) {
|
if (sponsorTimes !== null) {
|
||||||
if (UUIDs[i] === null) {
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
|
if (sponsorTimes[i].UUID === null) {
|
||||||
// This is a user submission, keep it
|
// This is a user submission, keep it
|
||||||
recievedSponsorTimes.push(sponsorTimes[i]);
|
recievedSegments.push(sponsorTimes[i]);
|
||||||
recievedUUIDs.push(UUIDs[i]);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sponsorTimes = recievedSponsorTimes;
|
sponsorTimes = recievedSegments;
|
||||||
UUIDs = recievedUUIDs;
|
|
||||||
|
|
||||||
// Remove all submissions smaller than the minimum duration
|
// Remove all submissions smaller than the minimum duration
|
||||||
if (Config.config.minDuration !== 0) {
|
if (Config.config.minDuration !== 0) {
|
||||||
let smallSponsors = [];
|
let smallSegments: SponsorTime[] = [];
|
||||||
let smallUUIDs = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
if (sponsorTimes[i][1] - sponsorTimes[i][0] >= Config.config.minDuration) {
|
if (sponsorTimes[i].segment[1] - sponsorTimes[i].segment[0] >= Config.config.minDuration) {
|
||||||
smallSponsors.push(sponsorTimes[i]);
|
smallSegments.push(sponsorTimes[i]);
|
||||||
smallUUIDs.push(UUIDs[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sponsorTimes = smallSponsors;
|
sponsorTimes = smallSegments;
|
||||||
UUIDs = smallUUIDs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!switchingVideos) {
|
if (!switchingVideos) {
|
||||||
// See if there are any starting sponsors
|
// See if there are any starting sponsors
|
||||||
let startingSponsor: number = -1;
|
let startingSponsor: number = -1;
|
||||||
for (const time of sponsorTimes) {
|
for (const time of sponsorTimes) {
|
||||||
if (time[0] <= video.currentTime && time[0] > startingSponsor && time[1] > video.currentTime) {
|
if (time[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
|
||||||
startingSponsor = time[0];
|
startingSponsor = time.segment[0];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!startingSponsor) {
|
if (!startingSponsor) {
|
||||||
for (const time of sponsorTimesSubmitting) {
|
for (const time of sponsorTimesSubmitting) {
|
||||||
if (time[0] <= video.currentTime && time[0] > startingSponsor && time[1] > video.currentTime) {
|
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
|
||||||
startingSponsor = time[0];
|
startingSponsor = time.segment[0];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startingSponsor !== -1) {
|
if (startingSponsor !== -1) {
|
||||||
startSponsorSchedule(startingSponsor);
|
startSponsorSchedule(false, startingSponsor);
|
||||||
} else {
|
} else {
|
||||||
startSponsorSchedule();
|
startSponsorSchedule();
|
||||||
}
|
}
|
||||||
@@ -660,7 +674,7 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sponsorLookupRetries = 0;
|
sponsorLookupRetries = 0;
|
||||||
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 404) {
|
} else if (response.status === 404) {
|
||||||
sponsorDataFound = false;
|
sponsorDataFound = false;
|
||||||
|
|
||||||
//check if this video was uploaded recently
|
//check if this video was uploaded recently
|
||||||
@@ -685,7 +699,7 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
sponsorLookupRetries = 0;
|
sponsorLookupRetries = 0;
|
||||||
} else if (xmlhttp.readyState == 4 && sponsorLookupRetries < 90 && !recheckStarted) {
|
} else if (sponsorLookupRetries < 90 && !recheckStarted) {
|
||||||
recheckStarted = true;
|
recheckStarted = true;
|
||||||
|
|
||||||
//TODO lower when server becomes better (back to 1 second)
|
//TODO lower when server becomes better (back to 1 second)
|
||||||
@@ -798,6 +812,8 @@ function updatePreviewBarPositionMobile(parent: Element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updatePreviewBar() {
|
function updatePreviewBar() {
|
||||||
|
if (previewBar === null || video === null) return;
|
||||||
|
|
||||||
let localSponsorTimes = sponsorTimes;
|
let localSponsorTimes = sponsorTimes;
|
||||||
if (localSponsorTimes == null) localSponsorTimes = [];
|
if (localSponsorTimes == null) localSponsorTimes = [];
|
||||||
|
|
||||||
@@ -807,17 +823,17 @@ function updatePreviewBar() {
|
|||||||
let types = [];
|
let types = [];
|
||||||
for (let i = 0; i < localSponsorTimes.length; i++) {
|
for (let i = 0; i < localSponsorTimes.length; i++) {
|
||||||
if (!hiddenSponsorTimes.includes(i)) {
|
if (!hiddenSponsorTimes.includes(i)) {
|
||||||
types.push("sponsor");
|
types.push(localSponsorTimes[i].category);
|
||||||
} else {
|
} else {
|
||||||
// Don't show this sponsor
|
// Don't show this sponsor
|
||||||
types.push(null);
|
types.push(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
||||||
types.push("previewSponsor");
|
types.push("preview-" + sponsorTimesSubmitting[i].category);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.wait(() => previewBar !== null).then((result) => previewBar.set(allSponsorTimes, types, video.duration));
|
previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration)
|
||||||
|
|
||||||
//update last video id
|
//update last video id
|
||||||
lastPreviewBarUpdate = sponsorVideoID;
|
lastPreviewBarUpdate = sponsorVideoID;
|
||||||
@@ -836,33 +852,80 @@ function whitelistCheck() {
|
|||||||
/**
|
/**
|
||||||
* Returns info about the next upcoming sponsor skip
|
* Returns info about the next upcoming sponsor skip
|
||||||
*/
|
*/
|
||||||
function getNextSkipIndex(currentTime: number): {array: number[][], index: number, openNotice: boolean} {
|
function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean):
|
||||||
let sponsorStartTimes = getStartTimes(sponsorTimes);
|
{array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} {
|
||||||
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, currentTime, true);
|
|
||||||
|
let sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments);
|
||||||
|
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, currentTime, true);
|
||||||
|
|
||||||
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
||||||
|
let endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex);
|
||||||
|
|
||||||
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting);
|
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments);
|
||||||
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, currentTime, false);
|
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, currentTime, false);
|
||||||
|
|
||||||
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
|
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
|
||||||
|
let previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex);
|
||||||
|
|
||||||
if ((minPreviewSponsorTimeIndex === -1 && minSponsorTimeIndex !== -1) ||
|
if ((minPreviewSponsorTimeIndex === -1 && minSponsorTimeIndex !== -1) ||
|
||||||
sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) {
|
sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) {
|
||||||
return {
|
return {
|
||||||
array: sponsorTimes,
|
array: sponsorTimes,
|
||||||
index: minSponsorTimeIndex,
|
index: minSponsorTimeIndex,
|
||||||
|
endIndex: endTimeIndex,
|
||||||
openNotice: true
|
openNotice: true
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
array: sponsorTimesSubmitting,
|
array: sponsorTimesSubmitting,
|
||||||
index: minPreviewSponsorTimeIndex,
|
index: minPreviewSponsorTimeIndex,
|
||||||
|
endIndex: previewEndTimeIndex,
|
||||||
openNotice: false
|
openNotice: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This returns index if the skip option is not AutoSkip
|
||||||
|
*
|
||||||
|
* Finds the last endTime that occurs in a segment that the given
|
||||||
|
* segment skips into that is part of an AutoSkip category.
|
||||||
|
*
|
||||||
|
* Used to find where a segment should truely skip to if there are intersecting submissions due to
|
||||||
|
* them having different categories.
|
||||||
|
*
|
||||||
|
* @param sponsorTimes
|
||||||
|
* @param index Index of the given sponsor
|
||||||
|
* @param hideHiddenSponsors
|
||||||
|
*/
|
||||||
|
function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideHiddenSponsors: boolean = true): number {
|
||||||
|
// Only combine segments for AutoSkip
|
||||||
|
if (index == -1 ||
|
||||||
|
utils.getCategorySelection(sponsorTimes[index].category).option !== CategorySkipOption.AutoSkip) return index;
|
||||||
|
|
||||||
|
// Default to the normal endTime
|
||||||
|
let latestEndTimeIndex = index;
|
||||||
|
|
||||||
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
|
let currentSegment = sponsorTimes[i].segment;
|
||||||
|
let latestEndTime = sponsorTimes[latestEndTimeIndex].segment[1];
|
||||||
|
|
||||||
|
if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime
|
||||||
|
&& (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))
|
||||||
|
&& utils.getCategorySelection(sponsorTimes[i].category).option === CategorySkipOption.AutoSkip) {
|
||||||
|
// Overlapping segment
|
||||||
|
latestEndTimeIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep going if required
|
||||||
|
if (latestEndTimeIndex !== index) {
|
||||||
|
latestEndTimeIndex = getLatestEndTimeIndex(sponsorTimes, latestEndTimeIndex, hideHiddenSponsors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return latestEndTimeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets just the start times from a sponsor times array.
|
* Gets just the start times from a sponsor times array.
|
||||||
* Optionally specify a minimum
|
* Optionally specify a minimum
|
||||||
@@ -870,50 +933,76 @@ function getNextSkipIndex(currentTime: number): {array: number[][], index: numbe
|
|||||||
* @param sponsorTimes
|
* @param sponsorTimes
|
||||||
* @param minimum
|
* @param minimum
|
||||||
* @param hideHiddenSponsors
|
* @param hideHiddenSponsors
|
||||||
|
* @param includeIntersectingSegments If true, it will include segments that start before
|
||||||
|
* the current time, but end after
|
||||||
*/
|
*/
|
||||||
function getStartTimes(sponsorTimes: number[][], minimum?: number, hideHiddenSponsors: boolean = false): number[] {
|
function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, minimum?: number,
|
||||||
|
hideHiddenSponsors: boolean = false): number[] {
|
||||||
if (sponsorTimes === null) return [];
|
if (sponsorTimes === null) return [];
|
||||||
|
|
||||||
let startTimes: number[] = [];
|
let startTimes: number[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
if ((minimum === undefined || sponsorTimes[i][0] >= minimum) && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) {
|
if ((minimum === undefined || (sponsorTimes[i].segment[0] >= minimum || (includeIntersectingSegments && sponsorTimes[i].segment[1] > minimum)))
|
||||||
startTimes.push(sponsorTimes[i][0]);
|
&& (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) {
|
||||||
|
startTimes.push(sponsorTimes[i].segment[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return startTimes;
|
return startTimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
//skip from the start time to the end time for a certain index sponsor time
|
/**
|
||||||
function skipToTime(v, index, sponsorTimes, openNotice) {
|
* Skip to exact time in a video and autoskips
|
||||||
if (!Config.config.disableAutoSkip || previewResetter !== null) {
|
*
|
||||||
v.currentTime = sponsorTimes[index][1];
|
* @param time
|
||||||
|
*/
|
||||||
|
function previewTime(time: number) {
|
||||||
|
video.currentTime = time;
|
||||||
|
|
||||||
|
// Unpause the video if needed
|
||||||
|
if (video.paused){
|
||||||
|
video.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSponsorTimeSkipped = sponsorTimes[index][0];
|
// Start preview resetter
|
||||||
|
if (previewResetter !== null){
|
||||||
|
clearTimeout(previewResetter);
|
||||||
|
}
|
||||||
|
|
||||||
let currentUUID = UUIDs[index];
|
previewResetter = setTimeout(() => previewResetter = null, 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//skip from the start time to the end time for a certain index sponsor time
|
||||||
|
function skipToTime(v: HTMLVideoElement, index: number, sponsorTimes: SponsorTime[], openNotice: boolean) {
|
||||||
|
let autoSkip: boolean = utils.getCategorySelection(sponsorTimes[index].category).option === CategorySkipOption.AutoSkip;
|
||||||
|
|
||||||
|
if (autoSkip || previewResetter !== null) {
|
||||||
|
v.currentTime = sponsorTimes[index].segment[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSponsorTimeSkipped = sponsorTimes[index].segment[0];
|
||||||
|
|
||||||
|
let currentUUID: string = sponsorTimes[index].UUID;
|
||||||
lastSponsorTimeSkippedUUID = currentUUID;
|
lastSponsorTimeSkippedUUID = currentUUID;
|
||||||
|
|
||||||
if (openNotice) {
|
if (openNotice) {
|
||||||
//send out the message saying that a sponsor message was skipped
|
//send out the message saying that a sponsor message was skipped
|
||||||
if (!Config.config.dontShowNotice) {
|
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||||
|
let skipNotice = new SkipNotice(currentUUID, autoSkip, skipNoticeContentContainer);
|
||||||
let skipNotice = new SkipNotice(this, currentUUID, Config.config.disableAutoSkip, skipNoticeContentContainer);
|
|
||||||
|
|
||||||
//auto-upvote this sponsor
|
//auto-upvote this sponsor
|
||||||
if (Config.config.trackViewCount && !Config.config.disableAutoSkip && Config.config.autoUpvote) {
|
if (Config.config.trackViewCount && autoSkip && Config.config.autoUpvote) {
|
||||||
vote(1, currentUUID, null);
|
vote(1, currentUUID, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//send telemetry that a this sponsor was skipped
|
//send telemetry that a this sponsor was skipped
|
||||||
if (Config.config.trackViewCount && !sponsorSkipped[index] && !Config.config.disableAutoSkip) {
|
if (Config.config.trackViewCount && !sponsorSkipped[index] && autoSkip) {
|
||||||
utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID);
|
utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID);
|
||||||
|
|
||||||
// Count this as a skip
|
// Count this as a skip
|
||||||
Config.config.minutesSaved = Config.config.minutesSaved + (sponsorTimes[index][1] - sponsorTimes[index][0]) / 60;
|
Config.config.minutesSaved = Config.config.minutesSaved + (sponsorTimes[index].segment[1] - sponsorTimes[index].segment[0]) / 60;
|
||||||
Config.config.skipCount = Config.config.skipCount + 1;
|
Config.config.skipCount = Config.config.skipCount + 1;
|
||||||
|
|
||||||
sponsorSkipped[index] = true;
|
sponsorSkipped[index] = true;
|
||||||
@@ -924,17 +1013,31 @@ function skipToTime(v, index, sponsorTimes, openNotice) {
|
|||||||
function unskipSponsorTime(UUID) {
|
function unskipSponsorTime(UUID) {
|
||||||
if (sponsorTimes != null) {
|
if (sponsorTimes != null) {
|
||||||
//add a tiny bit of time to make sure it is not skipped again
|
//add a tiny bit of time to make sure it is not skipped again
|
||||||
video.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][0] + 0.001;
|
video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[0] + 0.001;
|
||||||
|
|
||||||
|
checkIfInsideSegment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reskipSponsorTime(UUID) {
|
function reskipSponsorTime(UUID) {
|
||||||
if (sponsorTimes != null) {
|
if (sponsorTimes != null) {
|
||||||
//add a tiny bit of time to make sure it is not skipped again
|
video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1];
|
||||||
video.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][1];
|
|
||||||
|
// See if any skips need to be done if this is inside of another segment
|
||||||
|
startSponsorSchedule(true, utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if currently inside a segment and will trigger
|
||||||
|
* a skip schedule if true.
|
||||||
|
*
|
||||||
|
* This is used for when a manual skip is finished or a reskip is complete
|
||||||
|
*/
|
||||||
|
function checkIfInsideSegment() {
|
||||||
|
// for
|
||||||
|
}
|
||||||
|
|
||||||
function createButton(baseID, title, callback, imageName, isDraggable=false): boolean {
|
function createButton(baseID, title, callback, imageName, isDraggable=false): boolean {
|
||||||
if (document.getElementById(baseID + "Button") != null) return false;
|
if (document.getElementById(baseID + "Button") != null) return false;
|
||||||
|
|
||||||
@@ -1046,36 +1149,57 @@ function startSponsorClicked() {
|
|||||||
|
|
||||||
toggleStartSponsorButton();
|
toggleStartSponsorButton();
|
||||||
|
|
||||||
//send back current time with message
|
//add to sponsorTimes
|
||||||
chrome.runtime.sendMessage({
|
if (sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length < 2) {
|
||||||
message: "addSponsorTime",
|
//it is an end time
|
||||||
time: video.currentTime,
|
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment[1] = video.currentTime;
|
||||||
videoID: sponsorVideoID
|
} else {
|
||||||
}, function(response) {
|
//it is a start time
|
||||||
//see if the sponsorTimesSubmitting needs to be updated
|
sponsorTimesSubmitting.push({
|
||||||
updateSponsorTimesSubmitting();
|
segment: [video.currentTime],
|
||||||
|
UUID: null,
|
||||||
|
// Default to sponsor
|
||||||
|
category: "sponsor"
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create raw segment list
|
||||||
|
let segments: number[][] = [];
|
||||||
|
for (const sponsorTime of sponsorTimesSubmitting) {
|
||||||
|
segments.push(sponsorTime.segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
//save this info
|
||||||
|
Config.config.sponsorTimes.set(sponsorVideoID, segments);
|
||||||
|
|
||||||
|
updateSponsorTimesSubmitting(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSponsorTimesSubmitting() {
|
function updateSponsorTimesSubmitting(getFromConfig: boolean = true) {
|
||||||
chrome.runtime.sendMessage({
|
let segments = Config.config.sponsorTimes.get(sponsorVideoID);
|
||||||
message: "getSponsorTimes",
|
|
||||||
videoID: sponsorVideoID
|
|
||||||
}, function(response) {
|
|
||||||
if (response != undefined) {
|
|
||||||
let sponsorTimes = response.sponsorTimes;
|
|
||||||
|
|
||||||
//see if this data should be saved in the sponsorTimesSubmitting variable
|
//see if this data should be saved in the sponsorTimesSubmitting variable
|
||||||
if (sponsorTimes != undefined) {
|
if (getFromConfig && segments != undefined) {
|
||||||
sponsorTimesSubmitting = sponsorTimes;
|
sponsorTimesSubmitting = [];
|
||||||
|
|
||||||
|
for (const segment of segments) {
|
||||||
|
sponsorTimesSubmitting.push({
|
||||||
|
segment: segment,
|
||||||
|
UUID: null,
|
||||||
|
// Default to sponsor
|
||||||
|
category: "sponsor"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updatePreviewBar();
|
updatePreviewBar();
|
||||||
|
|
||||||
// Restart skipping schedule
|
// Restart skipping schedule
|
||||||
startSponsorSchedule();
|
if (video !== null) startSponsorSchedule();
|
||||||
|
|
||||||
|
if (submissionNotice !== null) {
|
||||||
|
submissionNotice.update();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
|
async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
|
||||||
@@ -1190,7 +1314,7 @@ function clearSponsorTimes() {
|
|||||||
let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID);
|
let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID);
|
||||||
|
|
||||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||||
let confirmMessage = chrome.i18n.getMessage("clearThis") + getSponsorTimesMessage(sponsorTimes)
|
let confirmMessage = chrome.i18n.getMessage("clearThis") + getSegmentsMessage(sponsorTimes)
|
||||||
+ "\n" + chrome.i18n.getMessage("confirmMSG")
|
+ "\n" + chrome.i18n.getMessage("confirmMSG")
|
||||||
if(!confirm(confirmMessage)) return;
|
if(!confirm(confirmMessage)) return;
|
||||||
|
|
||||||
@@ -1208,14 +1332,17 @@ function clearSponsorTimes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//if skipNotice is null, it will not affect the UI
|
//if skipNotice is null, it will not affect the UI
|
||||||
function vote(type, UUID, skipNotice) {
|
function vote(type, UUID, skipNotice?: SkipNoticeComponent) {
|
||||||
if (skipNotice != null) {
|
if (skipNotice !== null && skipNotice !== undefined) {
|
||||||
//add loading info
|
//add loading info
|
||||||
skipNotice.addVoteButtonInfo.bind(skipNotice)("Loading...")
|
skipNotice.addVoteButtonInfo.bind(skipNotice)("Loading...")
|
||||||
skipNotice.resetNoticeInfoMessage.bind(skipNotice)();
|
skipNotice.setNoticeInfoMessage.bind(skipNotice)();
|
||||||
}
|
}
|
||||||
|
|
||||||
let sponsorIndex = UUIDs.indexOf(UUID);
|
let sponsorIndex = utils.getSponsorIndexFromUUID(sponsorTimes, UUID);
|
||||||
|
|
||||||
|
// Don't vote for preview sponsors
|
||||||
|
if (sponsorIndex == -1 || sponsorTimes[sponsorIndex].UUID === null) return;
|
||||||
|
|
||||||
// See if the local time saved count and skip count should be saved
|
// See if the local time saved count and skip count should be saved
|
||||||
if (type == 0 && sponsorSkipped[sponsorIndex] || type == 1 && !sponsorSkipped[sponsorIndex]) {
|
if (type == 0 && sponsorSkipped[sponsorIndex] || type == 1 && !sponsorSkipped[sponsorIndex]) {
|
||||||
@@ -1227,7 +1354,7 @@ function vote(type, UUID, skipNotice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Count this as a skip
|
// Count this as a skip
|
||||||
Config.config.minutesSaved = Config.config.minutesSaved + factor * (sponsorTimes[sponsorIndex][1] - sponsorTimes[sponsorIndex][0]) / 60;
|
Config.config.minutesSaved = Config.config.minutesSaved + factor * (sponsorTimes[sponsorIndex].segment[1] - sponsorTimes[sponsorIndex].segment[0]) / 60;
|
||||||
|
|
||||||
Config.config.skipCount = Config.config.skipCount + factor;
|
Config.config.skipCount = Config.config.skipCount + factor;
|
||||||
}
|
}
|
||||||
@@ -1247,10 +1374,10 @@ function vote(type, UUID, skipNotice) {
|
|||||||
}
|
}
|
||||||
} else if (response.successType == 0) {
|
} else if (response.successType == 0) {
|
||||||
//failure: duplicate vote
|
//failure: duplicate vote
|
||||||
skipNotice.addNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail"))
|
skipNotice.setNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail"))
|
||||||
skipNotice.resetVoteButtonInfo.bind(skipNotice)();
|
skipNotice.resetVoteButtonInfo.bind(skipNotice)();
|
||||||
} else if (response.successType == -1) {
|
} else if (response.successType == -1) {
|
||||||
skipNotice.addNoticeInfoMessage.bind(skipNotice)(utils.getErrorMessage(response.statusCode))
|
skipNotice.setNoticeInfoMessage.bind(skipNotice)(utils.getErrorMessage(response.statusCode))
|
||||||
skipNotice.resetVoteButtonInfo.bind(skipNotice)();
|
skipNotice.resetVoteButtonInfo.bind(skipNotice)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1283,71 +1410,67 @@ function sponsorMessageStarted(callback) {
|
|||||||
toggleStartSponsorButton();
|
toggleStartSponsorButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for the submission notice to clear itself when it closes
|
||||||
|
*/
|
||||||
|
function resetSponsorSubmissionNotice() {
|
||||||
|
submissionNotice = null;
|
||||||
|
}
|
||||||
|
|
||||||
function submitSponsorTimes() {
|
function submitSponsorTimes() {
|
||||||
if (document.getElementById("submitButton").style.display == "none") {
|
if (submissionNotice !== null) return;
|
||||||
//don't submit, not ready
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//it can't update to this info yet
|
//it can't update to this info yet
|
||||||
closeInfoMenu();
|
closeInfoMenu();
|
||||||
|
|
||||||
let currentVideoID = sponsorVideoID;
|
let currentVideoID = sponsorVideoID;
|
||||||
|
|
||||||
let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID);
|
if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) {
|
||||||
|
submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage);
|
||||||
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] > video.duration) {
|
|
||||||
sponsorTimes[i][1] = video.duration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update sponsorTimes
|
|
||||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
|
||||||
|
|
||||||
//update sponsorTimesSubmitting
|
|
||||||
sponsorTimesSubmitting = sponsorTimes;
|
|
||||||
|
|
||||||
// Check to see if any of the submissions are below the minimum duration set
|
|
||||||
if (Config.config.minDuration > 0) {
|
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
|
||||||
if (sponsorTimes[i][1] - sponsorTimes[i][0] < Config.config.minDuration) {
|
|
||||||
let confirmShort = chrome.i18n.getMessage("shortCheck") + "\n\n" + getSponsorTimesMessage(sponsorTimes);
|
|
||||||
|
|
||||||
if(!confirm(confirmShort)) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//send the message to the background js
|
//send the message to the background js
|
||||||
//called after all the checks have been made that it's okay to do so
|
//called after all the checks have been made that it's okay to do so
|
||||||
function sendSubmitMessage(){
|
async function sendSubmitMessage(){
|
||||||
//add loading animation
|
//add loading animation
|
||||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png");
|
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png");
|
||||||
document.getElementById("submitButton").style.animation = "rotate 1s 0s infinite";
|
document.getElementById("submitButton").style.animation = "rotate 1s 0s infinite";
|
||||||
|
|
||||||
let currentVideoID = sponsorVideoID;
|
//check if a sponsor exceeds the duration of the video
|
||||||
|
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
||||||
|
if (sponsorTimesSubmitting[i].segment[1] > video.duration) {
|
||||||
|
sponsorTimesSubmitting[i].segment[1] = video.duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chrome.runtime.sendMessage({
|
//update sponsorTimes
|
||||||
message: "submitTimes",
|
Config.config.sponsorTimes.set(sponsorVideoID, utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting));
|
||||||
videoID: currentVideoID
|
|
||||||
}, function(response) {
|
// Check to see if any of the submissions are below the minimum duration set
|
||||||
if (response != undefined) {
|
if (Config.config.minDuration > 0) {
|
||||||
if (response.statusCode == 200) {
|
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
||||||
|
if (sponsorTimesSubmitting[i].segment[1] - sponsorTimesSubmitting[i].segment[0] < Config.config.minDuration) {
|
||||||
|
let confirmShort = chrome.i18n.getMessage("shortCheck") + "\n\n" +
|
||||||
|
getSegmentsMessage(utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting));
|
||||||
|
|
||||||
|
if(!confirm(confirmShort)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await utils.asyncRequestToServer("POST", "/api/skipSegments", {
|
||||||
|
videoID: sponsorVideoID,
|
||||||
|
userID: Config.config.userID,
|
||||||
|
segments: sponsorTimesSubmitting
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
//hide loading message
|
//hide loading message
|
||||||
let submitButton = document.getElementById("submitButton");
|
let submitButton = document.getElementById("submitButton");
|
||||||
//finish this animation
|
|
||||||
submitButton.style.animation = "rotate 1s";
|
submitButton.style.animation = "rotate 1s";
|
||||||
|
//finish this animation
|
||||||
//when the animation is over, hide the button
|
//when the animation is over, hide the button
|
||||||
let animationEndListener = function() {
|
let animationEndListener = function() {
|
||||||
changeStartSponsorButton(true, false);
|
changeStartSponsorButton(true, false);
|
||||||
@@ -1360,16 +1483,12 @@ function sendSubmitMessage(){
|
|||||||
submitButton.addEventListener("animationend", animationEndListener);
|
submitButton.addEventListener("animationend", animationEndListener);
|
||||||
|
|
||||||
//clear the sponsor times
|
//clear the sponsor times
|
||||||
Config.config.sponsorTimes.delete(currentVideoID);
|
Config.config.sponsorTimes.delete(sponsorVideoID);
|
||||||
|
|
||||||
//add submissions to current sponsors list
|
//add submissions to current sponsors list
|
||||||
if (sponsorTimes === null) sponsorTimes = [];
|
if (sponsorTimes === null) sponsorTimes = [];
|
||||||
|
|
||||||
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);
|
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);
|
||||||
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
|
||||||
// Add placeholder IDs
|
|
||||||
UUIDs.push(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty the submitting times
|
// Empty the submitting times
|
||||||
sponsorTimesSubmitting = [];
|
sponsorTimesSubmitting = [];
|
||||||
@@ -1380,19 +1499,17 @@ function sendSubmitMessage(){
|
|||||||
document.getElementById("submitButton").style.animation = "unset";
|
document.getElementById("submitButton").style.animation = "unset";
|
||||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png");
|
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png");
|
||||||
|
|
||||||
alert(utils.getErrorMessage(response.statusCode));
|
alert(utils.getErrorMessage(response.status) + "\n\n" + (await response.text()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the message that visually displays the video times
|
//get the message that visually displays the video times
|
||||||
function getSponsorTimesMessage(sponsorTimes) {
|
function getSegmentsMessage(segments: number[][]): string {
|
||||||
let sponsorTimesMessage = "";
|
let sponsorTimesMessage = "";
|
||||||
|
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
for (let i = 0; i < segments.length; i++) {
|
||||||
for (let s = 0; s < sponsorTimes[i].length; s++) {
|
for (let s = 0; s < segments[i].length; s++) {
|
||||||
let timeMessage = getFormattedTime(sponsorTimes[i][s]);
|
let timeMessage = utils.getFormattedTime(segments[i][s]);
|
||||||
//if this is an end time
|
//if this is an end time
|
||||||
if (s == 1) {
|
if (s == 1) {
|
||||||
timeMessage = " to " + timeMessage;
|
timeMessage = " to " + timeMessage;
|
||||||
@@ -1455,22 +1572,6 @@ function addCSS() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//converts time in seconds to minutes:seconds
|
|
||||||
function getFormattedTime(seconds) {
|
|
||||||
let minutes = Math.floor(seconds / 60);
|
|
||||||
let secondsNum: number = Math.round(seconds - minutes * 60);
|
|
||||||
let secondsDisplay: string = String(secondsNum);
|
|
||||||
|
|
||||||
if (secondsNum < 10) {
|
|
||||||
//add a zero
|
|
||||||
secondsDisplay = "0" + secondsNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
let formatted = minutes + ":" + secondsDisplay;
|
|
||||||
|
|
||||||
return formatted;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendRequestToCustomServer(type, fullAddress, callback) {
|
function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||||
let xmlhttp = new XMLHttpRequest();
|
let xmlhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,55 @@
|
|||||||
let barTypes = {
|
let barTypes = {
|
||||||
"undefined": {
|
"undefined": {
|
||||||
color: "#00d400",
|
color: "#00d400",
|
||||||
opacity: "0.5"
|
opacity: "0.7"
|
||||||
},
|
},
|
||||||
"sponsor": {
|
"sponsor": {
|
||||||
color: "#00d400",
|
color: "#00d400",
|
||||||
opacity: "0.5"
|
opacity: "0.7"
|
||||||
},
|
},
|
||||||
"previewSponsor": {
|
"preview-sponsor": {
|
||||||
color: "#0000d4",
|
color: "#007800",
|
||||||
opacity: "0.5"
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"intro": {
|
||||||
|
color: "#00ffff",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"preview-intro": {
|
||||||
|
color: "#008080",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"outro": {
|
||||||
|
color: "#0202ed",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"preview-outro": {
|
||||||
|
color: "#000070",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"interaction": {
|
||||||
|
color: "#cc00ff",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"preview-interaction": {
|
||||||
|
color: "#6c0087",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"selfpromo": {
|
||||||
|
color: "#ffff00",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"preview-selfpromo": {
|
||||||
|
color: "#bfbf35",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"offtopic": {
|
||||||
|
color: "#ff9900",
|
||||||
|
opacity: "0.7"
|
||||||
|
},
|
||||||
|
"preview-offtopic": {
|
||||||
|
color: "#a6634a",
|
||||||
|
opacity: "0.7"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,444 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import Config from "../config";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The notice that tells the user that a sponsor was just skipped
|
|
||||||
*/
|
|
||||||
class SkipNotice {
|
|
||||||
parent: HTMLElement;
|
|
||||||
UUID: string;
|
|
||||||
manualSkip: boolean;
|
|
||||||
// Contains functions and variables from the content script needed by the skip notice
|
|
||||||
contentContainer: () => any;
|
|
||||||
|
|
||||||
maxCountdownTime: () => number;
|
|
||||||
countdownTime: any;
|
|
||||||
countdownInterval: NodeJS.Timeout;
|
|
||||||
unskipCallback: any;
|
|
||||||
idSuffix: any;
|
|
||||||
|
|
||||||
constructor(parent: HTMLElement, UUID: string, manualSkip: boolean = false, contentContainer) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.UUID = UUID;
|
|
||||||
this.manualSkip = manualSkip;
|
|
||||||
this.contentContainer = contentContainer;
|
|
||||||
|
|
||||||
let noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
|
||||||
|
|
||||||
if (manualSkip) {
|
|
||||||
noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.maxCountdownTime = () => 4;
|
|
||||||
//the countdown until this notice closes
|
|
||||||
this.countdownTime = this.maxCountdownTime();
|
|
||||||
//the id for the setInterval running the countdown
|
|
||||||
this.countdownInterval = null;
|
|
||||||
|
|
||||||
//the unskip button's callback
|
|
||||||
this.unskipCallback = this.unskip.bind(this);
|
|
||||||
|
|
||||||
//add notice
|
|
||||||
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
|
||||||
|
|
||||||
//this is the suffix added at the end of every id
|
|
||||||
this.idSuffix = this.UUID + amountOfPreviousNotices;
|
|
||||||
|
|
||||||
if (amountOfPreviousNotices > 0) {
|
|
||||||
//already exists
|
|
||||||
|
|
||||||
let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
|
||||||
previousNotice.classList.add("secondSkipNotice")
|
|
||||||
}
|
|
||||||
|
|
||||||
let noticeElement = document.createElement("div");
|
|
||||||
//what sponsor time this is about
|
|
||||||
noticeElement.id = "sponsorSkipNotice" + this.idSuffix;
|
|
||||||
noticeElement.classList.add("sponsorSkipObject");
|
|
||||||
noticeElement.classList.add("sponsorSkipNotice");
|
|
||||||
noticeElement.style.zIndex = String(50 + amountOfPreviousNotices);
|
|
||||||
if (contentContainer().onMobileYouTube) {
|
|
||||||
noticeElement.style.bottom = "4em";
|
|
||||||
noticeElement.style.transform = "scale(0.8) translate(10%, 10%)";
|
|
||||||
}
|
|
||||||
|
|
||||||
//add mouse enter and leave listeners
|
|
||||||
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
|
|
||||||
noticeElement.addEventListener("mouseleave", this.startCountdown.bind(this));
|
|
||||||
|
|
||||||
//the row that will contain the info
|
|
||||||
let firstRow = document.createElement("tr");
|
|
||||||
firstRow.id = "sponsorSkipNoticeFirstRow" + this.idSuffix;
|
|
||||||
|
|
||||||
let logoColumn = document.createElement("td");
|
|
||||||
|
|
||||||
let logoElement = document.createElement("img");
|
|
||||||
logoElement.id = "sponsorSkipLogo" + this.idSuffix;
|
|
||||||
logoElement.className = "sponsorSkipLogo sponsorSkipObject";
|
|
||||||
logoElement.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png");
|
|
||||||
|
|
||||||
let noticeMessage = document.createElement("span");
|
|
||||||
noticeMessage.id = "sponsorSkipMessage" + this.idSuffix;
|
|
||||||
noticeMessage.classList.add("sponsorSkipMessage");
|
|
||||||
noticeMessage.classList.add("sponsorSkipObject");
|
|
||||||
noticeMessage.innerText = noticeTitle;
|
|
||||||
|
|
||||||
//create the first column
|
|
||||||
logoColumn.appendChild(logoElement);
|
|
||||||
logoColumn.appendChild(noticeMessage);
|
|
||||||
|
|
||||||
//add the x button
|
|
||||||
let closeButtonContainer = document.createElement("td");
|
|
||||||
closeButtonContainer.className = "sponsorSkipNoticeRightSection";
|
|
||||||
closeButtonContainer.style.top = "11px";
|
|
||||||
|
|
||||||
let timeLeft = document.createElement("span");
|
|
||||||
timeLeft.id = "sponsorSkipNoticeTimeLeft" + this.idSuffix;
|
|
||||||
timeLeft.innerText = this.countdownTime + "s";
|
|
||||||
timeLeft.className = "sponsorSkipObject sponsorSkipNoticeTimeLeft";
|
|
||||||
|
|
||||||
let hideButton = document.createElement("img");
|
|
||||||
hideButton.src = chrome.extension.getURL("icons/close.png");
|
|
||||||
hideButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton sponsorSkipNoticeRightButton";
|
|
||||||
hideButton.addEventListener("click", this.close.bind(this));
|
|
||||||
|
|
||||||
closeButtonContainer.appendChild(timeLeft);
|
|
||||||
closeButtonContainer.appendChild(hideButton);
|
|
||||||
|
|
||||||
//add all objects to first row
|
|
||||||
firstRow.appendChild(logoColumn);
|
|
||||||
firstRow.appendChild(closeButtonContainer);
|
|
||||||
|
|
||||||
let spacer = document.createElement("hr");
|
|
||||||
spacer.id = "sponsorSkipNoticeSpacer" + this.idSuffix;
|
|
||||||
spacer.className = "sponsorBlockSpacer";
|
|
||||||
|
|
||||||
//the row that will contain the buttons
|
|
||||||
let secondRow = document.createElement("tr");
|
|
||||||
secondRow.id = "sponsorSkipNoticeSecondRow" + this.idSuffix;
|
|
||||||
|
|
||||||
//thumbs up and down buttons
|
|
||||||
let voteButtonsContainer = document.createElement("td");
|
|
||||||
voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer" + this.idSuffix;
|
|
||||||
voteButtonsContainer.className = "sponsorTimesVoteButtonsContainer"
|
|
||||||
|
|
||||||
let reportText = document.createElement("span");
|
|
||||||
reportText.id = "sponsorTimesReportText" + this.idSuffix;
|
|
||||||
reportText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
|
||||||
reportText.innerText = chrome.i18n.getMessage("reportButtonTitle");
|
|
||||||
reportText.style.marginRight = "5px";
|
|
||||||
reportText.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
|
|
||||||
|
|
||||||
let downvoteButton = document.createElement("img");
|
|
||||||
downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + this.idSuffix;
|
|
||||||
downvoteButton.className = "sponsorSkipObject voteButton";
|
|
||||||
downvoteButton.src = chrome.extension.getURL("icons/report.png");
|
|
||||||
downvoteButton.addEventListener("click", () => this.contentContainer().vote(0, this.UUID, this));
|
|
||||||
downvoteButton.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
|
|
||||||
|
|
||||||
//add downvote and report text to container
|
|
||||||
voteButtonsContainer.appendChild(reportText);
|
|
||||||
voteButtonsContainer.appendChild(downvoteButton);
|
|
||||||
|
|
||||||
//add unskip button
|
|
||||||
let unskipContainer = document.createElement("td");
|
|
||||||
unskipContainer.className = "sponsorSkipNoticeUnskipSection";
|
|
||||||
|
|
||||||
let unskipButton = document.createElement("button");
|
|
||||||
unskipButton.id = "sponsorSkipUnskipButton" + this.idSuffix;
|
|
||||||
unskipButton.innerText = chrome.i18n.getMessage("unskip");
|
|
||||||
unskipButton.className = "sponsorSkipObject sponsorSkipNoticeButton";
|
|
||||||
unskipButton.addEventListener("click", this.unskipCallback);
|
|
||||||
|
|
||||||
unskipButton.style.marginLeft = "4px";
|
|
||||||
|
|
||||||
unskipContainer.appendChild(unskipButton);
|
|
||||||
|
|
||||||
//add don't show again button
|
|
||||||
let dontshowContainer = document.createElement("td");
|
|
||||||
dontshowContainer.className = "sponsorSkipNoticeRightSection";
|
|
||||||
|
|
||||||
let dontShowAgainButton = document.createElement("button");
|
|
||||||
dontShowAgainButton.innerText = chrome.i18n.getMessage("Hide");
|
|
||||||
dontShowAgainButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton";
|
|
||||||
dontShowAgainButton.addEventListener("click", this.contentContainer().dontShowNoticeAgain);
|
|
||||||
|
|
||||||
// Don't let them hide it if manually skipping
|
|
||||||
if (!this.manualSkip) {
|
|
||||||
dontshowContainer.appendChild(dontShowAgainButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add to row
|
|
||||||
secondRow.appendChild(voteButtonsContainer);
|
|
||||||
secondRow.appendChild(unskipContainer);
|
|
||||||
secondRow.appendChild(dontshowContainer);
|
|
||||||
|
|
||||||
noticeElement.appendChild(firstRow);
|
|
||||||
noticeElement.appendChild(spacer);
|
|
||||||
noticeElement.appendChild(secondRow);
|
|
||||||
|
|
||||||
//get reference node
|
|
||||||
let referenceNode = document.getElementById("player-container-id")
|
|
||||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
|
||||||
if (referenceNode == null) {
|
|
||||||
//for embeds
|
|
||||||
let player = document.getElementById("player");
|
|
||||||
referenceNode = <HTMLElement> player.firstChild;
|
|
||||||
let index = 1;
|
|
||||||
|
|
||||||
//find the child that is the video player (sometimes it is not the first)
|
|
||||||
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
|
||||||
referenceNode = <HTMLElement> player.children[index];
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
referenceNode.prepend(noticeElement);
|
|
||||||
|
|
||||||
if (manualSkip) {
|
|
||||||
this.unskippedMode(chrome.i18n.getMessage("skip"));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startCountdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
//called every second to lower the countdown before hiding the notice
|
|
||||||
countdown() {
|
|
||||||
this.countdownTime--;
|
|
||||||
|
|
||||||
if (this.countdownTime <= 0) {
|
|
||||||
//remove this from setInterval
|
|
||||||
clearInterval(this.countdownInterval);
|
|
||||||
|
|
||||||
//time to close this notice
|
|
||||||
this.close();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.countdownTime == 3) {
|
|
||||||
//start fade out animation
|
|
||||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
|
||||||
notice.style.removeProperty("animation");
|
|
||||||
notice.classList.add("sponsorSkipNoticeFadeOut");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateTimerDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
pauseCountdown() {
|
|
||||||
//remove setInterval
|
|
||||||
clearInterval(this.countdownInterval);
|
|
||||||
this.countdownInterval = null;
|
|
||||||
|
|
||||||
//reset countdown
|
|
||||||
this.countdownTime = this.maxCountdownTime();
|
|
||||||
|
|
||||||
//inform the user
|
|
||||||
let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix);
|
|
||||||
timeLeft.innerText = chrome.i18n.getMessage("paused");
|
|
||||||
|
|
||||||
//remove the fade out class if it exists
|
|
||||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
|
||||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
|
||||||
notice.style.animation = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
startCountdown() {
|
|
||||||
//if it has already started, don't start it again
|
|
||||||
if (this.countdownInterval !== null) return;
|
|
||||||
|
|
||||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
|
||||||
|
|
||||||
this.updateTimerDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTimerDisplay() {
|
|
||||||
//update the timer display
|
|
||||||
let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix);
|
|
||||||
timeLeft.innerText = this.countdownTime + "s";
|
|
||||||
}
|
|
||||||
|
|
||||||
unskip() {
|
|
||||||
this.contentContainer().unskipSponsorTime(this.UUID);
|
|
||||||
|
|
||||||
this.unskippedMode(chrome.i18n.getMessage("reskip"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets up notice to be not skipped yet */
|
|
||||||
unskippedMode(buttonText) {
|
|
||||||
//change unskip button to a reskip button
|
|
||||||
let unskipButton = this.changeUnskipButton(buttonText);
|
|
||||||
|
|
||||||
//setup new callback
|
|
||||||
this.unskipCallback = this.reskip.bind(this);
|
|
||||||
unskipButton.addEventListener("click", this.unskipCallback);
|
|
||||||
|
|
||||||
//change max duration to however much of the sponsor is left
|
|
||||||
this.maxCountdownTime = function() {
|
|
||||||
let sponsorTime = this.contentContainer().sponsorTimes[this.contentContainer().UUIDs.indexOf(this.UUID)];
|
|
||||||
let duration = Math.round(sponsorTime[1] - this.contentContainer().v.currentTime);
|
|
||||||
|
|
||||||
return Math.max(duration, 4);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.countdownTime = this.maxCountdownTime();
|
|
||||||
this.updateTimerDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
reskip() {
|
|
||||||
this.contentContainer().reskipSponsorTime(this.UUID);
|
|
||||||
|
|
||||||
//change reskip button to a unskip button
|
|
||||||
let unskipButton = this.changeUnskipButton(chrome.i18n.getMessage("unskip"));
|
|
||||||
|
|
||||||
//setup new callback
|
|
||||||
this.unskipCallback = this.unskip.bind(this);
|
|
||||||
unskipButton.addEventListener("click", this.unskipCallback);
|
|
||||||
|
|
||||||
//reset duration
|
|
||||||
this.maxCountdownTime = () => 4;
|
|
||||||
this.countdownTime = this.maxCountdownTime();
|
|
||||||
this.updateTimerDisplay();
|
|
||||||
|
|
||||||
// See if the title should be changed
|
|
||||||
if (this.manualSkip) {
|
|
||||||
this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle"));
|
|
||||||
|
|
||||||
if (Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the text on the reskip button
|
|
||||||
*
|
|
||||||
* @param {string} text
|
|
||||||
* @returns {HTMLElement} unskipButton
|
|
||||||
*/
|
|
||||||
changeUnskipButton(text) {
|
|
||||||
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
|
|
||||||
unskipButton.innerText = text;
|
|
||||||
unskipButton.removeEventListener("click", this.unskipCallback);
|
|
||||||
|
|
||||||
return unskipButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
afterDownvote() {
|
|
||||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
|
||||||
this.addNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
|
|
||||||
|
|
||||||
//remove this sponsor from the sponsors looked up
|
|
||||||
//find which one it is
|
|
||||||
for (let i = 0; i < this.contentContainer().sponsorTimes.length; i++) {
|
|
||||||
if (this.contentContainer().UUIDs[i] == this.UUID) {
|
|
||||||
//this one is the one to hide
|
|
||||||
|
|
||||||
//add this as a hidden sponsorTime
|
|
||||||
this.contentContainer().hiddenSponsorTimes.push(i);
|
|
||||||
|
|
||||||
this.contentContainer().updatePreviewBar();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changeNoticeTitle(title) {
|
|
||||||
let noticeElement = document.getElementById("sponsorSkipMessage" + this.idSuffix);
|
|
||||||
|
|
||||||
noticeElement.innerText = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
addNoticeInfoMessage(message: string, message2: string = "") {
|
|
||||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
|
||||||
if (previousInfoMessage != null) {
|
|
||||||
//remove it
|
|
||||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2");
|
|
||||||
if (previousInfoMessage2 != null) {
|
|
||||||
//remove it
|
|
||||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add info
|
|
||||||
let thanksForVotingText = document.createElement("p");
|
|
||||||
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
|
|
||||||
thanksForVotingText.className = "sponsorTimesInfoMessage";
|
|
||||||
thanksForVotingText.innerText = message;
|
|
||||||
|
|
||||||
//add element to div
|
|
||||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
|
||||||
|
|
||||||
if (message2 !== undefined) {
|
|
||||||
let thanksForVotingText2 = document.createElement("p");
|
|
||||||
thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2";
|
|
||||||
thanksForVotingText2.className = "sponsorTimesInfoMessage";
|
|
||||||
thanksForVotingText2.innerText = message2;
|
|
||||||
|
|
||||||
//add element to div
|
|
||||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resetNoticeInfoMessage() {
|
|
||||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
|
||||||
if (previousInfoMessage != null) {
|
|
||||||
//remove it
|
|
||||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addVoteButtonInfo(message) {
|
|
||||||
this.resetVoteButtonInfo();
|
|
||||||
|
|
||||||
//hide report button and text for it
|
|
||||||
let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
|
|
||||||
if (downvoteButton != null) {
|
|
||||||
downvoteButton.style.display = "none";
|
|
||||||
}
|
|
||||||
let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
|
|
||||||
if (downvoteButtonText != null) {
|
|
||||||
downvoteButtonText.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
//add info
|
|
||||||
let thanksForVotingText = document.createElement("td");
|
|
||||||
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
|
|
||||||
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
|
||||||
thanksForVotingText.innerText = message;
|
|
||||||
|
|
||||||
//add element to div
|
|
||||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
|
|
||||||
}
|
|
||||||
|
|
||||||
resetVoteButtonInfo() {
|
|
||||||
let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
|
|
||||||
if (previousInfoMessage != null) {
|
|
||||||
//remove it
|
|
||||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
//show button again
|
|
||||||
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
|
|
||||||
}
|
|
||||||
|
|
||||||
//close this notice
|
|
||||||
close() {
|
|
||||||
//reset message
|
|
||||||
this.resetNoticeInfoMessage();
|
|
||||||
|
|
||||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
|
||||||
if (notice != null) {
|
|
||||||
notice.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove setInterval
|
|
||||||
if (this.countdownInterval !== null) clearInterval(this.countdownInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SkipNotice;
|
|
||||||
@@ -5,6 +5,7 @@ import * as CompileConfig from "../config.json";
|
|||||||
(<any> window).SB = Config;
|
(<any> window).SB = Config;
|
||||||
|
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
|
import CategoryChooser from "./render/CategoryChooser";
|
||||||
var utils = new Utils();
|
var utils = new Utils();
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', init);
|
window.addEventListener('DOMContentLoaded', init);
|
||||||
@@ -31,6 +32,8 @@ async function init() {
|
|||||||
let checkbox = optionsElements[i].querySelector("input");
|
let checkbox = optionsElements[i].querySelector("input");
|
||||||
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
||||||
|
|
||||||
|
let confirmMessage = optionsElements[i].getAttribute("confirm-message");
|
||||||
|
|
||||||
if (optionResult != undefined) {
|
if (optionResult != undefined) {
|
||||||
checkbox.checked = optionResult;
|
checkbox.checked = optionResult;
|
||||||
|
|
||||||
@@ -48,6 +51,12 @@ async function init() {
|
|||||||
|
|
||||||
// Add click listener
|
// Add click listener
|
||||||
checkbox.addEventListener("click", () => {
|
checkbox.addEventListener("click", () => {
|
||||||
|
// Confirm if required
|
||||||
|
if (checkbox.checked && confirmMessage && !confirm(chrome.i18n.getMessage(confirmMessage))){
|
||||||
|
checkbox.checked = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Config.config[option] = reverse ? !checkbox.checked : checkbox.checked;
|
Config.config[option] = reverse ? !checkbox.checked : checkbox.checked;
|
||||||
|
|
||||||
// See if anything extra must be run
|
// See if anything extra must be run
|
||||||
@@ -164,6 +173,9 @@ async function init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case "react-CategoryChooserComponent":
|
||||||
|
new CategoryChooser(optionsElements[i]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
95
src/popup.ts
95
src/popup.ts
@@ -1,6 +1,7 @@
|
|||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
|
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
|
import { SponsorTime } from "./types";
|
||||||
var utils = new Utils();
|
var utils = new Utils();
|
||||||
|
|
||||||
interface MessageListener {
|
interface MessageListener {
|
||||||
@@ -56,7 +57,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
"showNoticeAgain",
|
"showNoticeAgain",
|
||||||
"optionsButton",
|
"optionsButton",
|
||||||
// More controls
|
// More controls
|
||||||
"clearTimes",
|
|
||||||
"submitTimes",
|
"submitTimes",
|
||||||
"reportAnIssue",
|
"reportAnIssue",
|
||||||
// sponsorTimesContributions
|
// sponsorTimesContributions
|
||||||
@@ -82,9 +82,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
// discordButtons
|
// discordButtons
|
||||||
"discordButtonContainer",
|
"discordButtonContainer",
|
||||||
"hideDiscordButton",
|
"hideDiscordButton",
|
||||||
// submitTimesInfoMessage
|
|
||||||
"submitTimesInfoMessageContainer",
|
|
||||||
"submitTimesInfoMessage",
|
|
||||||
// Username
|
// Username
|
||||||
"setUsernameContainer",
|
"setUsernameContainer",
|
||||||
"setUsernameButton",
|
"setUsernameButton",
|
||||||
@@ -108,7 +105,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel);
|
PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel);
|
||||||
PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true));
|
PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true));
|
||||||
PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false));
|
PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false));
|
||||||
PageElements.clearTimes.addEventListener("click", clearTimes);
|
|
||||||
PageElements.submitTimes.addEventListener("click", submitTimes);
|
PageElements.submitTimes.addEventListener("click", submitTimes);
|
||||||
PageElements.showNoticeAgain.addEventListener("click", showNoticeAgain);
|
PageElements.showNoticeAgain.addEventListener("click", showNoticeAgain);
|
||||||
PageElements.setUsernameButton.addEventListener("click", setUsernameButton);
|
PageElements.setUsernameButton.addEventListener("click", setUsernameButton);
|
||||||
@@ -263,8 +259,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
|
|
||||||
sponsorTimes = sponsorTimesStorage;
|
sponsorTimes = sponsorTimesStorage;
|
||||||
|
|
||||||
displaySponsorTimes();
|
|
||||||
|
|
||||||
//show submission section
|
//show submission section
|
||||||
PageElements.submissionSection.style.display = "unset";
|
PageElements.submissionSection.style.display = "unset";
|
||||||
|
|
||||||
@@ -279,7 +273,7 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function infoFound(request) {
|
function infoFound(request: {found: boolean, sponsorTimes: SponsorTime[], hiddenSponsorTimes: number[]}) {
|
||||||
if(chrome.runtime.lastError) {
|
if(chrome.runtime.lastError) {
|
||||||
//This page doesn't have the injected content script, or at least not yet
|
//This page doesn't have the injected content script, or at least not yet
|
||||||
displayNoVideo();
|
displayNoVideo();
|
||||||
@@ -363,28 +357,14 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
|
|
||||||
updateStartTimeChosen();
|
updateStartTimeChosen();
|
||||||
|
|
||||||
//display video times on screen
|
|
||||||
displaySponsorTimes();
|
|
||||||
|
|
||||||
//show submission section
|
//show submission section
|
||||||
PageElements.submissionSection.style.display = "unset";
|
PageElements.submissionSection.style.display = "unset";
|
||||||
|
|
||||||
showSubmitTimesIfNecessary();
|
showSubmitTimesIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
//display the video times from the array
|
|
||||||
function displaySponsorTimes() {
|
|
||||||
//remove all children
|
|
||||||
while (PageElements.sponsorMessageTimes.firstChild) {
|
|
||||||
PageElements.sponsorMessageTimes.removeChild(PageElements.sponsorMessageTimes.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add sponsor times
|
|
||||||
PageElements.sponsorMessageTimes.appendChild(getSponsorTimesMessageDiv(sponsorTimes));
|
|
||||||
}
|
|
||||||
|
|
||||||
//display the video times from the array at the top, in a different section
|
//display the video times from the array at the top, in a different section
|
||||||
function displayDownloadedSponsorTimes(request) {
|
function displayDownloadedSponsorTimes(request: {found: boolean, sponsorTimes: SponsorTime[], hiddenSponsorTimes: number[]}) {
|
||||||
if (request.sponsorTimes != undefined) {
|
if (request.sponsorTimes != undefined) {
|
||||||
//set it to the message
|
//set it to the message
|
||||||
if (PageElements.downloadedSponsorMessageTimes.innerText != chrome.i18n.getMessage("channelWhitelisted")) {
|
if (PageElements.downloadedSponsorMessageTimes.innerText != chrome.i18n.getMessage("channelWhitelisted")) {
|
||||||
@@ -403,11 +383,11 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
extraInfo = " (hidden)";
|
extraInfo = " (hidden)";
|
||||||
}
|
}
|
||||||
|
|
||||||
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i][0]) + " to " + getFormattedTime(request.sponsorTimes[i][1]) + extraInfo;
|
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i].segment[0]) + " to " + getFormattedTime(request.sponsorTimes[i].segment[1]) + extraInfo;
|
||||||
|
|
||||||
let votingButtons = document.createElement("div");
|
let votingButtons = document.createElement("div");
|
||||||
|
|
||||||
let UUID = request.UUIDs[i];
|
let UUID = request.sponsorTimes[i].UUID;
|
||||||
|
|
||||||
//thumbs up and down buttons
|
//thumbs up and down buttons
|
||||||
let voteButtonsContainer = document.createElement("div");
|
let voteButtonsContainer = document.createElement("div");
|
||||||
@@ -451,12 +431,12 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the message that visually displays the video times
|
//get the message that visually displays the video times
|
||||||
function getSponsorTimesMessage(sponsorTimes) {
|
function getSponsorTimesMessage(sponsorTimes: SponsorTime[]) {
|
||||||
let sponsorTimesMessage = "";
|
let sponsorTimesMessage = "";
|
||||||
|
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
for (let s = 0; s < sponsorTimes[i].length; s++) {
|
for (let s = 0; s < sponsorTimes[i].segment.length; s++) {
|
||||||
let timeMessage = getFormattedTime(sponsorTimes[i][s]);
|
let timeMessage = getFormattedTime(sponsorTimes[i].segment[s]);
|
||||||
//if this is an end time
|
//if this is an end time
|
||||||
if (s == 1) {
|
if (s == 1) {
|
||||||
timeMessage = " to " + timeMessage;
|
timeMessage = " to " + timeMessage;
|
||||||
@@ -692,8 +672,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (closeEditMode) {
|
if (closeEditMode) {
|
||||||
displaySponsorTimes();
|
|
||||||
|
|
||||||
showSubmitTimesIfNecessary();
|
showSubmitTimesIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -721,9 +699,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
//save this
|
//save this
|
||||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
||||||
|
|
||||||
//update display
|
|
||||||
displaySponsorTimes();
|
|
||||||
|
|
||||||
//if they are all removed
|
//if they are all removed
|
||||||
if (sponsorTimes.length == 0) {
|
if (sponsorTimes.length == 0) {
|
||||||
//update chrome tab
|
//update chrome tab
|
||||||
@@ -753,67 +728,17 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearTimes() {
|
function submitTimes() {
|
||||||
//send new sponsor time state to tab
|
|
||||||
if (sponsorTimes.length > 0) {
|
if (sponsorTimes.length > 0) {
|
||||||
messageHandler.query({
|
|
||||||
active: true,
|
|
||||||
currentWindow: true
|
|
||||||
}, function(tabs) {
|
|
||||||
messageHandler.sendMessage(tabs[0].id, {
|
|
||||||
message: "changeStartSponsorButton",
|
|
||||||
showStartSponsor: true,
|
|
||||||
uploadButtonVisible: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset sponsorTimes
|
|
||||||
sponsorTimes = [];
|
|
||||||
|
|
||||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
|
||||||
messageHandler.query({
|
messageHandler.query({
|
||||||
active: true,
|
active: true,
|
||||||
currentWindow: true
|
currentWindow: true
|
||||||
}, tabs => {
|
}, tabs => {
|
||||||
messageHandler.sendMessage(
|
messageHandler.sendMessage(
|
||||||
tabs[0].id,
|
tabs[0].id,
|
||||||
{message: "sponsorDataChanged"}
|
{message: 'submitTimes'},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
displaySponsorTimes();
|
|
||||||
|
|
||||||
//hide submission section
|
|
||||||
document.getElementById("submissionSection").style.display = "none";
|
|
||||||
|
|
||||||
resetStartTimeChosen();
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitTimes() {
|
|
||||||
//make info message say loading
|
|
||||||
PageElements.submitTimesInfoMessage.innerText = chrome.i18n.getMessage("Loading");
|
|
||||||
PageElements.submitTimesInfoMessageContainer.style.display = "unset";
|
|
||||||
|
|
||||||
if (sponsorTimes.length > 0) {
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
message: "submitTimes",
|
|
||||||
videoID: currentVideoID
|
|
||||||
}, function(response) {
|
|
||||||
if (response != undefined) {
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
//hide loading message
|
|
||||||
PageElements.submitTimesInfoMessageContainer.style.display = "none";
|
|
||||||
|
|
||||||
clearTimes();
|
|
||||||
} else {
|
|
||||||
document.getElementById("submitTimesInfoMessage").innerText = utils.getErrorMessage(response.statusCode);
|
|
||||||
document.getElementById("submitTimesInfoMessageContainer").style.display = "unset";
|
|
||||||
|
|
||||||
PageElements.submitTimesInfoMessageContainer.style.display = "unset";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
src/render/CategoryChooser.tsx
Normal file
15
src/render/CategoryChooser.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
import CategoryChooserComponent from "../components/CategoryChooserComponent";
|
||||||
|
|
||||||
|
class CategoryChooser {
|
||||||
|
|
||||||
|
constructor(element: Element) {
|
||||||
|
ReactDOM.render(
|
||||||
|
<CategoryChooserComponent/>,
|
||||||
|
element
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CategoryChooser;
|
||||||
61
src/render/SkipNotice.tsx
Normal file
61
src/render/SkipNotice.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
|
import SkipNoticeComponent from "../components/SkipNoticeComponent";
|
||||||
|
|
||||||
|
class SkipNotice {
|
||||||
|
UUID: string;
|
||||||
|
autoSkip: boolean;
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: () => any;
|
||||||
|
|
||||||
|
noticeElement: HTMLDivElement;
|
||||||
|
|
||||||
|
constructor(UUID: string, autoSkip: boolean = false, contentContainer) {
|
||||||
|
this.UUID = UUID;
|
||||||
|
this.autoSkip = autoSkip;
|
||||||
|
this.contentContainer = contentContainer;
|
||||||
|
|
||||||
|
//get reference node
|
||||||
|
let referenceNode = document.getElementById("player-container-id")
|
||||||
|
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||||
|
if (referenceNode == null) {
|
||||||
|
//for embeds
|
||||||
|
let player = document.getElementById("player");
|
||||||
|
referenceNode = player.firstChild as HTMLElement;
|
||||||
|
let index = 1;
|
||||||
|
|
||||||
|
//find the child that is the video player (sometimes it is not the first)
|
||||||
|
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
||||||
|
referenceNode = player.children[index] as HTMLElement;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||||
|
//this is the suffix added at the end of every id
|
||||||
|
let idSuffix = this.UUID + amountOfPreviousNotices;
|
||||||
|
|
||||||
|
this.noticeElement = document.createElement("div");
|
||||||
|
this.noticeElement.id = "sponsorSkipNoticeContainer" + idSuffix;
|
||||||
|
|
||||||
|
referenceNode.prepend(this.noticeElement);
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<SkipNoticeComponent UUID={UUID}
|
||||||
|
autoSkip={autoSkip}
|
||||||
|
contentContainer={contentContainer}
|
||||||
|
closeListener={() => this.close()} />,
|
||||||
|
this.noticeElement
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||||
|
|
||||||
|
this.noticeElement.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SkipNotice;
|
||||||
65
src/render/SubmissionNotice.tsx
Normal file
65
src/render/SubmissionNotice.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
|
import SubmissionNoticeComponent from "../components/SubmissionNoticeComponent";
|
||||||
|
|
||||||
|
class SubmissionNotice {
|
||||||
|
// Contains functions and variables from the content script needed by the skip notice
|
||||||
|
contentContainer: () => any;
|
||||||
|
|
||||||
|
callback: () => any;
|
||||||
|
|
||||||
|
noticeRef: React.MutableRefObject<SubmissionNoticeComponent>;
|
||||||
|
|
||||||
|
noticeElement: HTMLDivElement;
|
||||||
|
|
||||||
|
constructor(contentContainer: () => any, callback: () => any) {
|
||||||
|
this.noticeRef = React.createRef();
|
||||||
|
|
||||||
|
this.contentContainer = contentContainer;
|
||||||
|
this.callback = callback;
|
||||||
|
|
||||||
|
//get reference node
|
||||||
|
let referenceNode = document.getElementById("player-container-id")
|
||||||
|
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||||
|
if (referenceNode == null) {
|
||||||
|
//for embeds
|
||||||
|
let player = document.getElementById("player");
|
||||||
|
referenceNode = player.firstChild as HTMLElement;
|
||||||
|
let index = 1;
|
||||||
|
|
||||||
|
//find the child that is the video player (sometimes it is not the first)
|
||||||
|
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
||||||
|
referenceNode = player.children[index] as HTMLElement;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.noticeElement = document.createElement("div");
|
||||||
|
this.noticeElement.id = "submissionNoticeContainer";
|
||||||
|
|
||||||
|
referenceNode.prepend(this.noticeElement);
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<SubmissionNoticeComponent
|
||||||
|
contentContainer={contentContainer}
|
||||||
|
callback={callback}
|
||||||
|
ref={this.noticeRef}
|
||||||
|
closeListener={() => this.close()} />,
|
||||||
|
this.noticeElement
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.noticeRef.current.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||||
|
|
||||||
|
this.noticeElement.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SubmissionNotice;
|
||||||
52
src/types.ts
52
src/types.ts
@@ -1,7 +1,55 @@
|
|||||||
interface videoDurationResponse {
|
import SubmissionNotice from "./render/SubmissionNotice";
|
||||||
|
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||||
|
|
||||||
|
interface ContentContainer {
|
||||||
|
(): {
|
||||||
|
vote: (type: any, UUID: any, skipNotice?: SkipNoticeComponent) => void,
|
||||||
|
dontShowNoticeAgain: () => void,
|
||||||
|
unskipSponsorTime: (UUID: any) => void,
|
||||||
|
sponsorTimes: SponsorTime[],
|
||||||
|
sponsorTimesSubmitting: SponsorTime[],
|
||||||
|
hiddenSponsorTimes: number[],
|
||||||
|
v: HTMLVideoElement,
|
||||||
|
sponsorVideoID,
|
||||||
|
reskipSponsorTime: (UUID: any) => void,
|
||||||
|
updatePreviewBar: () => void,
|
||||||
|
onMobileYouTube: boolean,
|
||||||
|
sponsorSubmissionNotice: SubmissionNotice,
|
||||||
|
resetSponsorSubmissionNotice: () => void,
|
||||||
|
changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise<boolean>,
|
||||||
|
previewTime: (time: number) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoDurationResponse {
|
||||||
duration: number;
|
duration: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CategorySkipOption {
|
||||||
|
ShowOverlay,
|
||||||
|
ManualSkip,
|
||||||
|
AutoSkip
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CategorySelection {
|
||||||
|
name: string;
|
||||||
|
option: CategorySkipOption
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SponsorTime {
|
||||||
|
segment: number[];
|
||||||
|
UUID: string;
|
||||||
|
|
||||||
|
category: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type VideoID = string;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
videoDurationResponse
|
VideoDurationResponse,
|
||||||
|
ContentContainer,
|
||||||
|
CategorySelection,
|
||||||
|
CategorySkipOption,
|
||||||
|
SponsorTime,
|
||||||
|
VideoID
|
||||||
};
|
};
|
||||||
107
src/utils.ts
107
src/utils.ts
@@ -1,4 +1,7 @@
|
|||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
|
import { CategorySelection, SponsorTime } from "./types";
|
||||||
|
|
||||||
|
import * as CompileConfig from "../config.json";
|
||||||
|
|
||||||
class Utils {
|
class Utils {
|
||||||
|
|
||||||
@@ -154,6 +157,42 @@ class Utils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets just the timestamps from a sponsorTimes array
|
||||||
|
*
|
||||||
|
* @param sponsorTimes
|
||||||
|
*/
|
||||||
|
getSegmentsFromSponsorTimes(sponsorTimes: SponsorTime[]): number[][] {
|
||||||
|
let segments: number[][] = [];
|
||||||
|
for (const sponsorTime of sponsorTimes) {
|
||||||
|
segments.push(sponsorTime.segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSponsorIndexFromUUID(sponsorTimes: SponsorTime[], UUID: string): number {
|
||||||
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
|
if (sponsorTimes[i].UUID === UUID) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSponsorTimeFromUUID(sponsorTimes: SponsorTime[], UUID: string): SponsorTime {
|
||||||
|
return sponsorTimes[this.getSponsorIndexFromUUID(sponsorTimes, UUID)];
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategorySelection(category: string): CategorySelection {
|
||||||
|
for (const selection of Config.config.categorySelections) {
|
||||||
|
if (selection.name === category) {
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
localizeHtmlPage() {
|
localizeHtmlPage() {
|
||||||
//Localize by replacing __MSG_***__ meta tags
|
//Localize by replacing __MSG_***__ meta tags
|
||||||
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||||
@@ -230,6 +269,39 @@ class Utils {
|
|||||||
return errorMessage;
|
return errorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the SponsorBlock server with address added as a query
|
||||||
|
*
|
||||||
|
* @param type The request type. "GET", "POST", etc.
|
||||||
|
* @param address The address to add to the SponsorBlock server address
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
async asyncRequestToServer(type: string, address: string, data = {}) {
|
||||||
|
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||||
|
|
||||||
|
// If GET, convert JSON to parameters
|
||||||
|
if (type.toLowerCase() === "get") {
|
||||||
|
for (const key in data) {
|
||||||
|
let seperator = address.includes("?") ? "&" : "?";
|
||||||
|
let value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]);
|
||||||
|
address += seperator + key + "=" + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(serverAddress + address, {
|
||||||
|
method: type,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
redirect: 'follow',
|
||||||
|
body: data ? JSON.stringify(data) : null
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a request to the SponsorBlock server with address added as a query
|
* Sends a request to the SponsorBlock server with address added as a query
|
||||||
*
|
*
|
||||||
@@ -240,7 +312,9 @@ class Utils {
|
|||||||
sendRequestToServer(type: string, address: string, callback?: (xmlhttp: XMLHttpRequest, err: boolean) => any) {
|
sendRequestToServer(type: string, address: string, callback?: (xmlhttp: XMLHttpRequest, err: boolean) => any) {
|
||||||
let xmlhttp = new XMLHttpRequest();
|
let xmlhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
xmlhttp.open(type, Config.config.serverAddress + address, true);
|
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||||
|
|
||||||
|
xmlhttp.open(type, serverAddress + address, true);
|
||||||
|
|
||||||
if (callback != undefined) {
|
if (callback != undefined) {
|
||||||
xmlhttp.onreadystatechange = function () {
|
xmlhttp.onreadystatechange = function () {
|
||||||
@@ -256,6 +330,37 @@ class Utils {
|
|||||||
xmlhttp.send();
|
xmlhttp.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFormattedMinutes(seconds: number) {
|
||||||
|
return Math.floor(seconds / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormattedSeconds(seconds: number) {
|
||||||
|
return seconds % 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormattedTime(seconds: number, precise?: boolean) {
|
||||||
|
let minutes = Math.floor(seconds / 60);
|
||||||
|
let secondsNum: number = seconds - minutes * 60;
|
||||||
|
if (!precise) {
|
||||||
|
secondsNum = Math.floor(secondsNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
let secondsDisplay: string = String(secondsNum.toFixed(3));
|
||||||
|
|
||||||
|
if (secondsNum < 10) {
|
||||||
|
//add a zero
|
||||||
|
secondsDisplay = "0" + secondsDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
let formatted = minutes + ":" + secondsDisplay;
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRawSeconds(minutes: number, seconds: number): number {
|
||||||
|
return minutes * 60 + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this Firefox (web-extensions)
|
* Is this Firefox (web-extensions)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"outDir": "dist/js",
|
"outDir": "dist/js",
|
||||||
"noEmitOnError": true,
|
"noEmitOnError": true,
|
||||||
"typeRoots": [ "node_modules/@types" ],
|
"typeRoots": [ "node_modules/@types" ],
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true,
|
||||||
|
"jsx": "react"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user