mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-14 15:37:12 +03:00
Compare commits
93 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 | ||
|
|
88350e3421 | ||
|
|
36d79313de | ||
|
|
a9993d5d80 | ||
|
|
4a6ddf6774 | ||
|
|
b6172c6d9b | ||
|
|
b21a59f4e5 | ||
|
|
78dd44c502 | ||
|
|
f100ee4738 | ||
|
|
37662138df | ||
|
|
037d1089a3 | ||
|
|
1df123de6d | ||
|
|
3063591a4c | ||
|
|
a182354254 | ||
|
|
a02aef591e | ||
|
|
1a92265e65 | ||
|
|
92a6065c98 | ||
|
|
d7ca56941a | ||
|
|
da6ccb561d | ||
|
|
c526a812e0 | ||
|
|
ccbc0456f9 | ||
|
|
0d9b624fd5 | ||
|
|
008c9380b1 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -67,10 +67,12 @@ jobs:
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtension.zip
|
||||
name: ChromeExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/FirefoxExtension.zip
|
||||
name: FirefoxExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
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.
|
||||
|
||||
# Important Links
|
||||
|
||||
See the [Wiki](https://github.com/ajayyy/SponsorBlock/wiki) for important links.
|
||||
|
||||
# Server
|
||||
|
||||
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).
|
||||
|
||||
@@ -66,7 +70,7 @@ Run `npm run dev` to run the extension using a clean browser profile with hot re
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"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:
|
||||
- source: /_locales/en/*
|
||||
translation: /_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"
|
||||
- source: /public/_locales/en/*
|
||||
translation: /public/_locales/%two_letters_code%/%original_file_name%
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "__MSG_Name__",
|
||||
"version": "1.2.23",
|
||||
"version": "1.2.26",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"content_scripts": [{
|
||||
@@ -32,6 +32,7 @@
|
||||
"icons/downvote.png",
|
||||
"icons/report.png",
|
||||
"icons/close.png",
|
||||
"icons/beep.ogg",
|
||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||
"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": "",
|
||||
"main": "background.js",
|
||||
"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": {
|
||||
"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": {
|
||||
"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."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Ungültige Anforderung"
|
||||
},
|
||||
@@ -33,7 +21,7 @@
|
||||
"Sponsors": {
|
||||
"message": "Sponsoren"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "gesponsorter Inhalt"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -133,37 +121,37 @@
|
||||
"message": "Bist du sicher, dass die Auswahl abgeschickt werden soll?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Kanal auf Whitelist setzen "
|
||||
"message": "Kanal auf Whitelist setzen "
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Kanal von Whitelist entfernen"
|
||||
"message": "Kanal von Whitelist entfernen"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Stimme für Zeiten ab"
|
||||
"message": "Stimme für Zeiten ab"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Lege das Zeitfenster eines gesponsorten Inhalts fest"
|
||||
"message": "Lege das Zeitfenster eines gesponsorten Inhalts fest"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Gemeldet wurden von dir bisher"
|
||||
"message": "Gemeldet wurden von dir bisher"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Du hast andere Benutzer bewahrt vor"
|
||||
"message": "Du hast andere Benutzer bewahrt vor"
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Siehe Rangliste"
|
||||
"message": "Siehe Rangliste"
|
||||
},
|
||||
"here": {
|
||||
"message": "hier"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klicke den Knopf unten, wenn der gesponsorte Inhalt beginnt und endet, um aufzunehmen und\n einzusenden"
|
||||
"message": "Klicke den Knopf unten, wenn der gesponsorte Inhalt beginnt und endet, um aufzunehmen und\n einzusenden"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Hinweis: In den Optionen lässt sich eine Taste für das Festlegen von Anfang/Ende des gesponsorten Inhalts, sowie für das Einsenden festlegen"
|
||||
"message": "Hinweis: In den Optionen lässt sich eine Taste für das Festlegen von Anfang/Ende des gesponsorten Inhalts, sowie für das Einsenden festlegen"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Letzte ausgewählte Zeitabschnitte"
|
||||
"message": "Letzte ausgewählte Zeitabschnitte"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Zeiten löschen"
|
||||
|
||||
1
public/_locales/el/messages.json
Normal file
1
public/_locales/el/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -291,6 +291,12 @@
|
||||
"autoSkipDescription": {
|
||||
"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": {
|
||||
"message": "You have skipped "
|
||||
},
|
||||
@@ -441,6 +447,24 @@
|
||||
"incorrectlyFormattedOptions": {
|
||||
"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": {
|
||||
"message": "Copy Debug Information To Clipboard"
|
||||
},
|
||||
@@ -461,5 +485,51 @@
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"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": {
|
||||
"message": "SponsorBlock pour YouTube - Supprime les messages commerciaux et publicités intégrées",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"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.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Soumission invalide"
|
||||
},
|
||||
@@ -25,7 +17,7 @@
|
||||
"message": "Déja soumis"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Cette chaîne est sur la liste blanche !"
|
||||
"message": "Chaîne mise sur liste blanche !"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "message commercial"
|
||||
@@ -43,16 +35,16 @@
|
||||
"message": "Message commercial passé"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Incorrect"
|
||||
"message": "Signaler"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Signaler que ce segment commercial est incorrect ou n'existe pas."
|
||||
"message": "Signaler que ce segment commercial est incorrect."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Fermer"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Chargement en cours..."
|
||||
"message": "Chargement..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
@@ -85,10 +77,10 @@
|
||||
"message": "Une erreur s'est produite lors de la soumission, veuillez ré-essayer plus tard."
|
||||
},
|
||||
"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": {
|
||||
"message": "Pas de messages commerciaux trouvés"
|
||||
"message": "Pas de sponsors trouvés"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Début du message commercial"
|
||||
@@ -138,9 +130,6 @@
|
||||
"removeFromWhitelist": {
|
||||
"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": {
|
||||
"message": "Voter sur un segment commercial"
|
||||
},
|
||||
@@ -187,7 +176,7 @@
|
||||
"message": "Cacher"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Options"
|
||||
"message": "Paramètres"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Montrer les boutons sur le lecteur YouTube"
|
||||
@@ -259,5 +248,147 @@
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"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": {
|
||||
"message": "SponsorBlock per YouTube - Salta gli sponsor",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"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."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Richiesta non valida"
|
||||
},
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "sponsorizzazioni"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "spezzone sponsorizzato"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -84,7 +76,6 @@
|
||||
"Unknown": {
|
||||
"message": "Si è verificato un errore durante l'invio dello spezzone sponsorizzato, per favore riprova più tardi."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "I contenuti sponsorizzati di questo video sono nel database!"
|
||||
},
|
||||
@@ -134,40 +125,37 @@
|
||||
"message": "Sei sicuro di volerlo inviare?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Aggiungi Canale alla Whitelist"
|
||||
"message": "Aggiungi Canale alla Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"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."
|
||||
"message": "Rimuovi Canale dalla Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vota uno Spezzone Sponsorizzato"
|
||||
"message": "Vota uno Spezzone Sponsorizzato"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registra uno Spezzone Sponsorizzato"
|
||||
"message": "Registra uno Spezzone Sponsorizzato"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Fino ad ora hai inviato"
|
||||
"message": "Fino ad ora hai inviato"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Hai salvato le persone da "
|
||||
"message": "Hai salvato le persone da "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Guarda la classifica"
|
||||
"message": "Guarda la classifica"
|
||||
},
|
||||
"here": {
|
||||
"message": "qui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Premi il pulsante qui sotto quando inizia e finisce la sponsorizzazione per registrarla e\ninviarla al database."
|
||||
"message": "Premi il pulsante qui sotto quando inizia e finisce la sponsorizzazione per registrarla e\ninviarla al database."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Suggerimento: Premi il tasto punto e virgola mentre il video è attivo per segnalare l'inizio/fine di una sponsorizzazione e virgolette per inviare."
|
||||
"message": "Suggerimento: Premi il tasto punto e virgola mentre il video è attivo per segnalare l'inizio/fine di una sponsorizzazione e virgolette per inviare."
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ultimi minutaggi sponsorizzati scelti"
|
||||
"message": "Ultimi minutaggi sponsorizzati scelti"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Cancella Minutaggi"
|
||||
@@ -197,7 +185,7 @@
|
||||
"message": "Nascondi i Pulsanti nel Lettore di YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Nasconde i pulsanti che appaiono nel lettore di YouTube per inviare spezzoni sponsorizzati. Capisco che può essere fastidioso per alcune\n persone. Invece di utilizzare quei pulsanti, è possibile utilizzare questo popup per inviare gli spezzoni sponsorizzati. Per nascondere l'avviso che appare, \nusa il bottone \"Non mostrare più\" nell'avviso. Potrai sempre abilitare nuovamente queste impostazioni in futuro."
|
||||
"message": "Nasconde i pulsanti che appaiono nel lettore di YouTube per inviare spezzoni sponsorizzati. Capisco che può essere fastidioso per alcune\n persone. Invece di utilizzare quei pulsanti, è possibile utilizzare questo popup per inviare gli spezzoni sponsorizzati. Per nascondere l'avviso che appare, \nusa il bottone \"Non mostrare più\" nell'avviso. Potrai sempre abilitare nuovamente queste impostazioni in futuro."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Mostra il Pulsante Informazioni nel Lettore di YouTube"
|
||||
|
||||
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,390 +1,373 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nazwa rozszerzenia."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
||||
"description": "Nazwa rozszerzenia."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
||||
"description": "Opis rozszerzenia."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||
},
|
||||
"429": {
|
||||
"message": "Zgłosiłeś bardzo dużo segmentów reklamowych dla tego jednego nagrania, jesteś pewien, że jest ich tak dużo?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Treść została już wcześniej zgłoszona"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanał dodany do wyjątków!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorzy"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmet sponsorowany"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty sponsorowane"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Segment przewinięty"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Zgłoś"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Zgłoś ten segment reklamowy jako nieprawidłowy."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Odrzuć"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Ładowanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nigdy nie pokazuj"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Kliknij cofnij aby przenieść się do miejsca przed przewinięciem."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Cofnij"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Zatrzymany"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Żeby zmienić lub usunąć wartości, kliknij na guzik informacji lub otwórz okienko rozszerzenia klikając w ikonę rozszerzenia znajdującą się w prawym górnym rogu."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Jesteś pewien, że chcesz to usunąć?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Wystąpił błąd podczas przesyłania twojego zgłoszenia, proszę spróbować ponownie później."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Segmenty reklamowe dla tego nagrania są już w bazie!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nie znaleziono segmentów reklamowych"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Reklama zaczyna się teraz"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Reklama kończy się teraz"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono nagrania wideo w tej karcie. Jeśli wiesz, że to karta YouTube'a, zamknij to okienko i otwórz je ponownie. Jeśli to nie zadziała spróbuj przeładować stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Zagłosowano!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Już na to głosowałeś."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Wygląda na to, że serwer nie działa. Skontaktuj się z dewloperem."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Chcesz zgłosić segment sponsorowany dla nagrania z id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że masz nie wysłane segmenty reklamowe. Cofnij się do tej strony i zgłoś je (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty reklamowe"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Otwórz okienko SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Zgłoś segmenty reklamowe"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Jesteś pewien, że chcesz to zgłosić?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanał do wyjątków"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Usuń kanał z listy wyjątków"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Głosuj na segment reklamowy"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Nagraj czasy segmentów reklamowych"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Jak na razie zgłosiłeś:"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij guzik poniżej kiedy segment reklamowy się zaczyna i kończy żeby go oznaczyć i wysłać do bazy danych."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Klikając średnik kiedy zaznaczone jest zgłaszanie wideo możesz oznaczyć początek reklamy, znakiem cytatu oznaczysz jej koniec. (Klawisze można zmienić w opcjach)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ostanie wybrane czasy reklam"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Usuń czasy"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Zgłoś czasy"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ustaw nazwę użytkownika"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Dołącz do oficjalnego serwera na discordzie i podziel się wrażeniami i sugestiami!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Ukryj to"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opcje"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Pokaż guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Ukryj guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ta opcja ukrywa guziki zgłaszania reklamy w odtwarzaczu. Wiem, że mogą one irytować niektórych. Zamiast zgłaszania bezpośrednio w odtwarzaczu możesz to zrobić w tym okienku. Zawsze możesz zmienić te opcje później."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Pokaż guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Ukryj guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Jest to guzik otwierający popup na stronie YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Ukryj guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Pokaż guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ten guzik pozwala ci wyczyścić wszystkie segmenty reklamowe w odtwarzaczu YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Wyłącz licznik przewinięć"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Włącz licznik przewinięć"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ta opcja śledzi które segmenty pominąłeś i informuje zgłaszających ile czasu Ci zaoszczędzili, też wraz systemem głosowania pomaga wykrywać spam w zgłoszeniach. Rozszerzenie wysyła zapytanie do serwera za każdym razem kiedy przewinąłeś segment reklamowy. Miejmy nadzieję, że większość ludzi tego nie wyłączy i licznik wyświetleń będzie rzetelny. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
"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.",
|
||||
"description": "Pełny opis rozszerzenia na stronie w sklepie."
|
||||
},
|
||||
"website": {
|
||||
"message": "Strona",
|
||||
"description": "Używane w sklepie Firefoxa"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Kod źródłowy",
|
||||
"description": "Używane w sklepie Firefoxa"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Informacje zostały zaktualizowane!",
|
||||
"description": "Pierwsza linia po aktualizacji informacji."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
||||
"description": "Druga linia po aktualizacji informacji."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Ustaw klawisz do wysyłania czasów"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Wybierz klawisz klikając go na klawiaturze"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Ustawiony klawisz to: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Połączenie przerwane z powodu braku odpowiedzi. Sprawdź swoje połączenie z internetem. Jeśli wszystko z nim w porządku oznacza to, że serwer jest prawdopodobnie przeciążony lub nie działa."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Wyłącz SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Włącz SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Twój wkład",
|
||||
"description": "Nagłowek sekcji ze statystykami użytkownika."
|
||||
},
|
||||
"502": {
|
||||
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Kod błędu: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Przewinąć reklamę?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Wyłącz auto przewijanie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Włącz auto przewijanie"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto przewijanie przewinie segment za ciebie, wyłączone wyświetli komunikat z pytaniem czy chcesz przewinąć reklamę."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Przewinąłeś "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Oszczędziłeś sobie "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuta"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minuty"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "godzina"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "godziny"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Oszczędziłeś ludziom"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " czasu."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Upewnij się, że zgłaszany fragment zawiera tylko reklamę i nic więcej.\n- Upewnij się, że nie zostanie przewinięta wartościowa treść\n- Jeśli całe nagranie to reklama, proszę nie zgłaszaj go. Blokowanie całych nagrań pojawi się wkrótce.\n- Nie ukrywaj treści które są istotne dla użytkownika (nie ukrywaj informacji, że recenzja produktu została opłacona przez producenta)"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Wejdź na status.sponsor.ajay.app żeby sprawdzić czy serwer działa."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Zaimportuj/Wyeksportuj swój UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ta informacja jest poufna i działa jak hasło, użytkownik który ma do niej dostęp może zgłaszać treści jako ty."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ustaw UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Ostrzeżenie: Zmiana UserID jest nieodwracalna. Jesteś pewien, że chcesz to zrobić? Skopiuj obecny UserID na wszelki wypadek."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto przewijanie"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Pokaż informację po przewiniętym fragmencie"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jest obecnie ustawione jako:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Wesprzyj Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) to nieoficjalny klient YouTube. Aby go wesprzeć musisz przyznać dodatkowe uprawnienia rozszerzeniowi. Ta opcja nie działa w incognito i innych wersjach Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Wesprzyj Invidious, wyłącz auto przewijanie, ukryj guziki i więcej."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Dodaj instancje Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Dodaj niestandardową instancje Invidious. W formie domeny. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Dodaj"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Ta domena jest nieprawidłowa. Wartość powinna zawierać TYLKO domenę. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Zresetuj listę instancji Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Zresetujesz listę instancji Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Obecne instancje:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto potwierdzanie"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"invidiousInfo1": {
|
||||
"message": "Invidious (nieoficjalny klient YouTube) została dodana do wspieranych!"
|
||||
},
|
||||
"invidiousInfo2": {
|
||||
"message": "Musisz odblokować to w opcjach aby móc to zrobić."
|
||||
}
|
||||
"fullName": {
|
||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||
},
|
||||
"429": {
|
||||
"message": "Zgłosiłeś bardzo dużo segmentów reklamowych dla tego jednego nagrania, jesteś pewien, że jest ich tak dużo?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Treść została już wcześniej zgłoszona"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanał dodany do wyjątków!"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorzy"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmet sponsorowany"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty sponsorowane"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Segment przewinięty"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Zgłoś"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Zgłoś ten segment reklamowy jako nieprawidłowy."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Odrzuć"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Ładowanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nigdy nie pokazuj"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Kliknij cofnij aby przenieść się do miejsca przed przewinięciem."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Cofnij"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Zatrzymany"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Żeby zmienić lub usunąć wartości, kliknij na guzik informacji lub otwórz okienko rozszerzenia klikając w ikonę rozszerzenia znajdującą się w prawym górnym rogu."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Jesteś pewien, że chcesz to usunąć?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Wystąpił błąd podczas przesyłania twojego zgłoszenia, proszę spróbować ponownie później."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Segmenty reklamowe dla tego nagrania są już w bazie!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nie znaleziono segmentów reklamowych"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Reklama zaczyna się teraz"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Reklama kończy się teraz"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono nagrania wideo w tej karcie. Jeśli wiesz, że to karta YouTube'a, zamknij to okienko i otwórz je ponownie. Jeśli to nie zadziała spróbuj przeładować stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Zagłosowano!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Już na to głosowałeś."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Wygląda na to, że serwer nie działa. Skontaktuj się z dewloperem."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Chcesz zgłosić segment sponsorowany dla nagrania z id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że masz nie wysłane segmenty reklamowe. Cofnij się do tej strony i zgłoś je (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty reklamowe"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Otwórz okienko SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Zgłoś segmenty reklamowe"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Jesteś pewien, że chcesz to zgłosić?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanał do wyjątków"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Usuń kanał z listy wyjątków"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Głosuj na segment reklamowy"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Nagraj czasy segmentów reklamowych"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Jak na razie zgłosiłeś:"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij guzik poniżej kiedy segment reklamowy się zaczyna i kończy żeby go oznaczyć i wysłać do bazy danych."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Klikając średnik kiedy zaznaczone jest zgłaszanie wideo możesz oznaczyć początek reklamy, znakiem cytatu oznaczysz jej koniec. (Klawisze można zmienić w opcjach)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ostanie wybrane czasy reklam"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Usuń czasy"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Zgłoś czasy"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ustaw nazwę użytkownika"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Dołącz do oficjalnego serwera na discordzie i podziel się wrażeniami i sugestiami!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Ukryj to"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opcje"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Pokaż guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Ukryj guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ta opcja ukrywa guziki zgłaszania reklamy w odtwarzaczu. Wiem, że mogą one irytować niektórych. Zamiast zgłaszania bezpośrednio w odtwarzaczu możesz to zrobić w tym okienku. Zawsze możesz zmienić te opcje później."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Pokaż guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Ukryj guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Jest to guzik otwierający popup na stronie YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Ukryj guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Pokaż guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ten guzik pozwala ci wyczyścić wszystkie segmenty reklamowe w odtwarzaczu YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Wyłącz licznik przewinięć"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Włącz licznik przewinięć"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ta opcja śledzi które segmenty pominąłeś i informuje zgłaszających ile czasu Ci zaoszczędzili, też wraz systemem głosowania pomaga wykrywać spam w zgłoszeniach. Rozszerzenie wysyła zapytanie do serwera za każdym razem kiedy przewinąłeś segment reklamowy. Miejmy nadzieję, że większość ludzi tego nie wyłączy i licznik wyświetleń będzie rzetelny. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
"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.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Strona",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Kod źródłowy",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Informacje zostały zaktualizowane!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Ustaw klawisz do wysyłania czasów"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Wybierz klawisz klikając go na klawiaturze"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Ustawiony klawisz to: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Połączenie przerwane z powodu braku odpowiedzi. Sprawdź swoje połączenie z internetem. Jeśli wszystko z nim w porządku oznacza to, że serwer jest prawdopodobnie przeciążony lub nie działa."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Wyłącz SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Włącz SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Twój wkład",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Kod błędu: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Przewinąć reklamę?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Wyłącz auto przewijanie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Włącz auto przewijanie"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto przewijanie przewinie segment za ciebie, wyłączone wyświetli komunikat z pytaniem czy chcesz przewinąć reklamę."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Przewinąłeś "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Oszczędziłeś sobie "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuta"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minuty"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "godzina"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "godziny"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Oszczędziłeś ludziom"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " czasu."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Upewnij się, że zgłaszany fragment zawiera tylko reklamę i nic więcej.\n- Upewnij się, że nie zostanie przewinięta wartościowa treść\n- Jeśli całe nagranie to reklama, proszę nie zgłaszaj go. Blokowanie całych nagrań pojawi się wkrótce.\n- Nie ukrywaj treści które są istotne dla użytkownika (nie ukrywaj informacji, że recenzja produktu została opłacona przez producenta)"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Wejdź na status.sponsor.ajay.app żeby sprawdzić czy serwer działa."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Zaimportuj/Wyeksportuj swój UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ta informacja jest poufna i działa jak hasło, użytkownik który ma do niej dostęp może zgłaszać treści jako ty."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ustaw UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Ostrzeżenie: Zmiana UserID jest nieodwracalna. Jesteś pewien, że chcesz to zrobić? Skopiuj obecny UserID na wszelki wypadek."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto przewijanie"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Pokaż informację po przewiniętym fragmencie"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jest obecnie ustawione jako:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Wesprzyj Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) to nieoficjalny klient YouTube. Aby go wesprzeć musisz przyznać dodatkowe uprawnienia rozszerzeniowi. Ta opcja nie działa w incognito i innych wersjach Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Wesprzyj Invidious, wyłącz auto przewijanie, ukryj guziki i więcej."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Dodaj instancje Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Dodaj niestandardową instancje Invidious. W formie domeny. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Dodaj"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Ta domena jest nieprawidłowa. Wartość powinna zawierać TYLKO domenę. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Zresetuj listę instancji Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Zresetujesz listę instancji Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Obecne instancje:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto potwierdzanie"
|
||||
},
|
||||
"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."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock para YouTube - Pule patrocínios",
|
||||
"description": "Nome da extensão."
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"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."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "O servidor disse que esse pedido foi inválido"
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "patrocinadores"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "segmento de patrocinador"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -84,7 +76,6 @@
|
||||
"Unknown": {
|
||||
"message": "Teve um erro ao enviar seus segmentos, tente novamente depois."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "Os patrocinadores desse vídeo estão no banco de dados!"
|
||||
},
|
||||
@@ -134,40 +125,37 @@
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"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."
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
@@ -231,14 +219,14 @@
|
||||
},
|
||||
"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.",
|
||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"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": {
|
||||
"message": "SponsorBlock para o YouTube - Salte patrocínios",
|
||||
"description": "Nome da extensão."
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"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."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "O servidor disse que este pedido foi inválido"
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "patrocinadores"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "segmento de patrocínio"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -133,40 +125,37 @@
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"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."
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
@@ -230,14 +219,14 @@
|
||||
},
|
||||
"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.",
|
||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"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": {
|
||||
"message": "SponsorBlock для YouTube - Пропускайте спонсорские вставки",
|
||||
"description": "Название расширения."
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Пропускайте спонсорские вставки в видео на YouTube. Сообщайте о спонсорских вставках в видео, которые Вы смотрите, чтобы сэкономить время других пользователей.",
|
||||
"description": "Описание раширения."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Сервер отклонил этот запрос."
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "спонсоров"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "спонсорская вставка"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -84,7 +76,6 @@
|
||||
"Unknown": {
|
||||
"message": "При отправке отчета о спонсорском сегменте произошла ошибка. Попытайтесь отправить его позже."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "Спонсоры этого видео уже находятся в базе данных!"
|
||||
},
|
||||
@@ -125,37 +116,37 @@
|
||||
"message": "Вы уверены, что хотите отправить эту информацию?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Добавить канал в белый список"
|
||||
"message": "Добавить канал в белый список"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Удалить канал из белого списка"
|
||||
"message": "Удалить канал из белого списка"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Проголосовать за время спонсорской вставки"
|
||||
"message": "Проголосовать за время спонсорской вставки"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Записать время спонсорской вставки"
|
||||
"message": "Записать время спонсорской вставки"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "На данный момент Вы отправили"
|
||||
"message": "На данный момент Вы отправили"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Вы помогли людям сэкономить "
|
||||
"message": "Вы помогли людям сэкономить "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Посмотреть доску почёта"
|
||||
"message": "Посмотреть доску почёта"
|
||||
},
|
||||
"here": {
|
||||
"message": "здесь"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Нажмите кнопку ниже, когда спонсорская вставка начинается и заканчивается, чтобы записать\nи отправить её в базу данных."
|
||||
"message": "Нажмите кнопку ниже, когда спонсорская вставка начинается и заканчивается, чтобы записать\nи отправить её в базу данных."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Подсказка: нажмите ;, чтобы сообщить начало/конец спонсорской вставки, и \", чтобы отправить. (Это можно изменить в настройках)"
|
||||
"message": "Подсказка: нажмите ;, чтобы сообщить начало/конец спонсорской вставки, и \", чтобы отправить. (Это можно изменить в настройках)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Последнее выбранное время спонсорской вставки"
|
||||
"message": "Последнее выбранное время спонсорской вставки"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Очистить время"
|
||||
@@ -219,15 +210,15 @@
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock — это расширение, которое пропускает спонсорские вставки в видео на YouTube. SponsorBlock — это краудсорсинговое расширение, которое позволяет каждому отправить время начала и конца спонсорских сегментов в видео на YouTube. После того, как кто-нибудь отправляет эту информацию, все остальные пользователи расширения будут автоматически пропускать спонсорские сегменты.",
|
||||
"description": "Полное описание расширения на страницах магазинов."
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Сайт",
|
||||
"description": "Используется на странице магазина Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Исходный код",
|
||||
"description": "Используется на странице магазина Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Уведомление было обновлено!",
|
||||
@@ -378,7 +369,7 @@
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Спонсорские сегменты короче этого значения не будут пропускаться и не будут показаны в плеере."
|
||||
},
|
||||
},
|
||||
"shortCheck": {
|
||||
"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;
|
||||
|
||||
animation: fadeIn 0.5s;
|
||||
|
||||
border-spacing: 5px 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.sponsorSkipNoticeFadeIn {
|
||||
animation: fadeIn 0.5s;
|
||||
}
|
||||
|
||||
.sponsorSkipNoticeFadeOut {
|
||||
animation: fadeOut 3s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||
}
|
||||
@@ -311,4 +313,66 @@
|
||||
.sponsorSkipDontShowButton:active {
|
||||
position:relative;
|
||||
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.
@@ -323,4 +323,27 @@ svg {
|
||||
|
||||
font-size: 14px;
|
||||
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="category-type" option-type="react-CategoryChooserComponent">
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div id="support-invidious" option-type="toggle" sync-option="supportInvidious">
|
||||
<label class="switch-container" label-name="__MSG_supportInvidious__">
|
||||
<label class="switch">
|
||||
@@ -76,24 +83,6 @@
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="disableAutoSkip">
|
||||
<label class="switch-container" label-name="__MSG_autoSkip__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_autoSkipDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<div option-type="keybind-change" sync-option="startSponsorKeybind">
|
||||
<div class="option-button trigger-button">
|
||||
@@ -228,6 +217,23 @@
|
||||
<div class="small-description">__MSG_whatUploadButton__</div>
|
||||
</div>
|
||||
|
||||
<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/>
|
||||
|
||||
@@ -346,7 +352,23 @@
|
||||
|
||||
<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">
|
||||
<label class="text-label-container">
|
||||
|
||||
@@ -39,29 +39,15 @@
|
||||
|
||||
<div id="submissionSection" class="popupElement" style="display: none">
|
||||
<h3 class="popupElement">__MSG_lastTimes__</h3>
|
||||
<b>
|
||||
<div id="sponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
</b>
|
||||
|
||||
<b>Sponsor Editing has been moved and will appear after you click submit</b>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="clearTimes" class="smallButton popupElement">__MSG_clearTimesButton__</button>
|
||||
|
||||
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -88,10 +88,6 @@ chrome.runtime.onInstalled.addListener(function (object) {
|
||||
const newUserID = utils.generateUserID();
|
||||
//save this UUID
|
||||
Config.config.userID = newUserID;
|
||||
|
||||
//TODO: Remove when mobile support is old
|
||||
// Don't show this to new users
|
||||
// Config.config.mobileUpdateShowCount = 1;
|
||||
}
|
||||
}, 1500);
|
||||
});
|
||||
@@ -188,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
|
||||
let sponsorTimes = Config.config.sponsorTimes.get(videoID);
|
||||
let userID = Config.config.userID;
|
||||
|
||||
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({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
@@ -222,21 +218,24 @@ async function submitTimes(videoID, callback) {
|
||||
+ "&userID=" + userID, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && !error) {
|
||||
callback({
|
||||
statusCode: xmlhttp.status
|
||||
statusCode: xmlhttp.status,
|
||||
responseText: xmlhttp.responseText
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (xmlhttp.status == 200) {
|
||||
//save the amount contributed
|
||||
if (!increasedContributionAmount) {
|
||||
increasedContributionAmount = true;
|
||||
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimes.length;
|
||||
}
|
||||
} else if (error) {
|
||||
callback({
|
||||
statusCode: -1
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (error) {
|
||||
callback({
|
||||
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 { CategorySelection, CategorySkipOption } from "./types";
|
||||
|
||||
interface SBConfig {
|
||||
userID: string,
|
||||
@@ -10,7 +11,6 @@ interface SBConfig {
|
||||
skipCount: number,
|
||||
sponsorTimesContributed: number,
|
||||
disableSkipping: boolean,
|
||||
disableAutoSkip: boolean,
|
||||
trackViewCount: boolean,
|
||||
dontShowNotice: boolean,
|
||||
hideVideoPlayerControls: boolean,
|
||||
@@ -24,8 +24,13 @@ interface SBConfig {
|
||||
supportInvidious: boolean,
|
||||
serverAddress: string,
|
||||
minDuration: number,
|
||||
audioNotificationOnSkip,
|
||||
checkForUnlistedVideos: boolean,
|
||||
mobileUpdateShowCount: number
|
||||
mobileUpdateShowCount: number,
|
||||
testingServer: boolean,
|
||||
|
||||
// What categories should be skipped
|
||||
categorySelections: CategorySelection[]
|
||||
}
|
||||
|
||||
interface SBObject {
|
||||
@@ -105,7 +110,6 @@ var Config: SBObject = {
|
||||
skipCount: 0,
|
||||
sponsorTimesContributed: 0,
|
||||
disableSkipping: false,
|
||||
disableAutoSkip: false,
|
||||
trackViewCount: true,
|
||||
dontShowNotice: false,
|
||||
hideVideoPlayerControls: false,
|
||||
@@ -119,8 +123,15 @@ var Config: SBObject = {
|
||||
supportInvidious: false,
|
||||
serverAddress: CompileConfig.serverAddress,
|
||||
minDuration: 0,
|
||||
audioNotificationOnSkip: false,
|
||||
checkForUnlistedVideos: false,
|
||||
mobileUpdateShowCount: 0
|
||||
mobileUpdateShowCount: 0,
|
||||
testingServer: false,
|
||||
|
||||
categorySelections: [{
|
||||
name: "sponsor",
|
||||
option: CategorySkipOption.AutoSkip
|
||||
}]
|
||||
},
|
||||
localConfig: null,
|
||||
config: null,
|
||||
@@ -225,11 +236,14 @@ function fetchConfig() {
|
||||
});
|
||||
}
|
||||
|
||||
function migrateOldFormats() { // Convert sponsorTimes format
|
||||
for (const key in Config.localConfig) {
|
||||
if (key.startsWith("sponsorTimes") && key !== "sponsorTimes" && key !== "sponsorTimesContributed") {
|
||||
Config.config.sponsorTimes.set(key.substr(12), Config.config[key]);
|
||||
delete Config.config[key];
|
||||
function migrateOldFormats() {
|
||||
if (Config.config["disableAutoSkip"]) {
|
||||
for (const selection of Config.config.categorySelections) {
|
||||
if (selection.name === "sponsor") {
|
||||
selection.option = CategorySkipOption.ManualSkip;
|
||||
|
||||
chrome.storage.sync.remove("disableAutoSkip");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
624
src/content.ts
624
src/content.ts
@@ -1,40 +1,47 @@
|
||||
import Config from "./config";
|
||||
|
||||
import { SponsorTime, CategorySkipOption, CategorySelection, VideoID } from "./types";
|
||||
|
||||
import { ContentContainer } from "./types";
|
||||
import Utils from "./utils";
|
||||
var utils = new Utils();
|
||||
|
||||
import runThePopup from "./popup";
|
||||
|
||||
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)
|
||||
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
||||
|
||||
//was sponsor data found when doing SponsorsLookup
|
||||
var sponsorDataFound = false;
|
||||
var previousVideoID = null;
|
||||
var previousVideoID: VideoID = null;
|
||||
//the actual sponsorTimes if loaded and UUIDs associated with them
|
||||
var sponsorTimes: number[][] = null;
|
||||
var UUIDs = [];
|
||||
var sponsorTimes: SponsorTime[] = null;
|
||||
//what video id are these sponsors for
|
||||
var sponsorVideoID = null;
|
||||
var sponsorVideoID: VideoID = null;
|
||||
|
||||
// Skips are scheduled to ensure precision.
|
||||
// Skips are rescheduled every seeked event.
|
||||
// Skips are rescheduled every seeking event.
|
||||
// Skips are canceled every seeking event
|
||||
var currentSkipSchedule: NodeJS.Timeout = null;
|
||||
var seekListenerSetUp = false
|
||||
|
||||
//these are sponsors that have been downvoted
|
||||
var hiddenSponsorTimes = [];
|
||||
var hiddenSponsorTimes: number[] = [];
|
||||
|
||||
/** @type {Array[boolean]} Has the sponsor been skipped */
|
||||
var sponsorSkipped = [];
|
||||
var sponsorSkipped: boolean[] = [];
|
||||
|
||||
//the video
|
||||
var video: HTMLVideoElement;
|
||||
|
||||
/** The last time this video was seeking to */
|
||||
var lastVideoTime: number = null;
|
||||
|
||||
var onInvidious;
|
||||
var onMobileYouTube;
|
||||
|
||||
@@ -80,32 +87,39 @@ var sponsorLookupRetries = 0;
|
||||
|
||||
//the last time in the video a sponsor was skipped
|
||||
//used for the go back button
|
||||
var lastSponsorTimeSkipped = null;
|
||||
var lastSponsorTimeSkipped: number = null;
|
||||
//used for ratings
|
||||
var lastSponsorTimeSkippedUUID = null;
|
||||
var lastSponsorTimeSkippedUUID: string = null;
|
||||
|
||||
//if showing the start sponsor button or the end sponsor button on the player
|
||||
var showingStartSponsor = true;
|
||||
|
||||
//the sponsor times being prepared to be submitted
|
||||
var sponsorTimesSubmitting = [];
|
||||
var sponsorTimesSubmitting: SponsorTime[] = [];
|
||||
|
||||
//becomes true when isInfoFound is called
|
||||
//this is used to close the popup on YouTube when the other popup opens
|
||||
var popupInitialised = false;
|
||||
|
||||
var submissionNotice: SubmissionNotice = null;
|
||||
|
||||
// Contains all of the functions and variables needed by the skip notice
|
||||
var skipNoticeContentContainer = () => ({
|
||||
var skipNoticeContentContainer: ContentContainer = () => ({
|
||||
vote,
|
||||
dontShowNoticeAgain,
|
||||
unskipSponsorTime,
|
||||
sponsorTimes,
|
||||
UUIDs,
|
||||
v: video,
|
||||
reskipSponsorTime,
|
||||
sponsorTimesSubmitting,
|
||||
hiddenSponsorTimes,
|
||||
v: video,
|
||||
sponsorVideoID,
|
||||
reskipSponsorTime,
|
||||
updatePreviewBar,
|
||||
onMobileYouTube
|
||||
onMobileYouTube,
|
||||
sponsorSubmissionNotice: submissionNotice,
|
||||
resetSponsorSubmissionNotice,
|
||||
changeStartSponsorButton,
|
||||
previewTime
|
||||
});
|
||||
|
||||
//get messages from the background script and the popup
|
||||
@@ -130,8 +144,7 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
||||
sendResponse({
|
||||
found: sponsorDataFound,
|
||||
sponsorTimes: sponsorTimes,
|
||||
hiddenSponsorTimes: hiddenSponsorTimes,
|
||||
UUIDs: UUIDs
|
||||
hiddenSponsorTimes: hiddenSponsorTimes
|
||||
});
|
||||
|
||||
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
|
||||
@@ -195,6 +208,10 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
||||
case "changeStartSponsorButton":
|
||||
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
|
||||
|
||||
break;
|
||||
case "submitTimes":
|
||||
submitSponsorTimes();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -248,7 +265,6 @@ function resetValues() {
|
||||
|
||||
//reset sponsor times
|
||||
sponsorTimes = null;
|
||||
UUIDs = [];
|
||||
sponsorLookupRetries = 0;
|
||||
|
||||
//empty the preview bar
|
||||
@@ -338,37 +354,22 @@ async function videoIDChange(id) {
|
||||
sponsorsLookup(id, channelIDPromise);
|
||||
|
||||
//make sure everything is properly added
|
||||
updateVisibilityOfPlayerControlsButton();
|
||||
updateVisibilityOfPlayerControlsButton().then(() => {
|
||||
//see if the onvideo control image needs to be changed
|
||||
let segments = Config.config.sponsorTimes.get(sponsorVideoID);
|
||||
if (segments != null && segments.length > 0 && segments[segments.length - 1].length >= 2) {
|
||||
changeStartSponsorButton(true, true);
|
||||
} else if (segments != null && segments.length > 0 && segments[segments.length - 1].length < 2) {
|
||||
changeStartSponsorButton(false, true);
|
||||
} else {
|
||||
changeStartSponsorButton(true, false);
|
||||
}
|
||||
});
|
||||
|
||||
//reset sponsor times submitting
|
||||
sponsorTimesSubmitting = [];
|
||||
updateSponsorTimesSubmitting();
|
||||
|
||||
//see if the onvideo control image needs to be changed
|
||||
utils.wait(getControls).then(result => {
|
||||
chrome.runtime.sendMessage({
|
||||
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);
|
||||
} else if (sponsorTimes != null && sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
|
||||
changeStartSponsorButton(false, true);
|
||||
} else {
|
||||
changeStartSponsorButton(true, false);
|
||||
}
|
||||
|
||||
//see if this data should be saved in the sponsorTimesSubmitting variable
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||
sponsorTimesSubmitting = sponsorTimes;
|
||||
|
||||
updatePreviewBar();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//see if video controls buttons should be added
|
||||
if (!onInvidious) {
|
||||
updateVisibilityOfPlayerControlsButton();
|
||||
@@ -380,9 +381,9 @@ function handleMobileControlsMutations(): void {
|
||||
|
||||
updateVisibilityOfPlayerControlsButton().then((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);
|
||||
} 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);
|
||||
} else {
|
||||
changeStartSponsorButton(true, false);
|
||||
@@ -455,7 +456,7 @@ function cancelSponsorSchedule(): void {
|
||||
*
|
||||
* @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();
|
||||
if (video.paused) return;
|
||||
|
||||
@@ -465,27 +466,46 @@ function startSponsorSchedule(currentTime?: number): void {
|
||||
|
||||
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
||||
|
||||
let skipInfo = getNextSkipIndex(currentTime);
|
||||
let skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments);
|
||||
|
||||
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;
|
||||
|
||||
// Don't skip if this category should not be skipped
|
||||
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ShowOverlay) return;
|
||||
|
||||
let skippingFunction = () => {
|
||||
let forcedSkipTime: number = null;
|
||||
let forcedIncludeIntersectingSegments = false;
|
||||
|
||||
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
|
||||
skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice);
|
||||
// Double check that the videoID is correct
|
||||
// TODO: Remove this bug catching if statement when the bug is found
|
||||
let currentVideoID = getYouTubeVideoID(document.URL);
|
||||
if (currentVideoID == sponsorVideoID) {
|
||||
skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice);
|
||||
|
||||
if (Config.config.disableAutoSkip) {
|
||||
forcedSkipTime = skipTime[0] + 0.001;
|
||||
// TODO: Know the autoSkip settings for ALL items being skipped
|
||||
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) {
|
||||
forcedSkipTime = skipTime[0] + 0.001;
|
||||
} else {
|
||||
forcedSkipTime = skipTime[1];
|
||||
forcedIncludeIntersectingSegments = true;
|
||||
}
|
||||
} else {
|
||||
forcedSkipTime = skipTime[1];
|
||||
// Something has really gone wrong
|
||||
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be.");
|
||||
console.error("[SponsorBlock] VideoID recorded: " + sponsorVideoID + ". Actual VideoID: " + currentVideoID);
|
||||
|
||||
// Video ID change occured
|
||||
videoIDChange(currentVideoID);
|
||||
}
|
||||
}
|
||||
|
||||
startSponsorSchedule(forcedSkipTime);
|
||||
startSponsorSchedule(forcedIncludeIntersectingSegments, forcedSkipTime);
|
||||
};
|
||||
|
||||
if (timeUntilSponsor <= 0) {
|
||||
@@ -533,12 +553,27 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
||||
startSponsorSchedule();
|
||||
}
|
||||
});
|
||||
video.addEventListener('seeked', () => {
|
||||
if (!video.paused) startSponsorSchedule();
|
||||
video.addEventListener('seeking', () => {
|
||||
// Reset lastCheckVideoTime
|
||||
lastCheckVideoTime = -1
|
||||
lastCheckTime = 0;
|
||||
|
||||
lastVideoTime = video.currentTime;
|
||||
|
||||
if (!video.paused){
|
||||
startSponsorSchedule();
|
||||
}
|
||||
});
|
||||
video.addEventListener('ratechange', () => startSponsorSchedule());
|
||||
video.addEventListener('seeking', cancelSponsorSchedule);
|
||||
video.addEventListener('pause', cancelSponsorSchedule);
|
||||
video.addEventListener('pause', () => {
|
||||
// Reset lastCheckVideoTime
|
||||
lastCheckVideoTime = -1;
|
||||
lastCheckTime = 0;
|
||||
|
||||
lastVideoTime = video.currentTime;
|
||||
|
||||
cancelSponsorSchedule();
|
||||
});
|
||||
|
||||
startSponsorSchedule();
|
||||
}
|
||||
@@ -558,61 +593,70 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
||||
//check database for sponsor times
|
||||
//made true once a setTimeout has been created to try again after a server error
|
||||
let recheckStarted = false;
|
||||
utils.sendRequestToServer('GET', "/api/getVideoSponsorTimes?videoID=" + id, function(xmlhttp) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
// Create categories list
|
||||
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;
|
||||
|
||||
let recievedSponsorTimes = JSON.parse(xmlhttp.responseText).sponsorTimes;
|
||||
let recievedUUIDs = JSON.parse(xmlhttp.responseText).UUIDs;
|
||||
|
||||
// Check if any old submissions should be kept
|
||||
for (let i = 0; i < UUIDs.length; i++) {
|
||||
if (UUIDs[i] === null) {
|
||||
// This is a user submission, keep it
|
||||
recievedSponsorTimes.push(sponsorTimes[i]);
|
||||
recievedUUIDs.push(UUIDs[i]);
|
||||
if (sponsorTimes !== null) {
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i].UUID === null) {
|
||||
// This is a user submission, keep it
|
||||
recievedSegments.push(sponsorTimes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sponsorTimes = recievedSponsorTimes;
|
||||
UUIDs = recievedUUIDs;
|
||||
sponsorTimes = recievedSegments;
|
||||
|
||||
// Remove all submissions smaller than the minimum duration
|
||||
if (Config.config.minDuration !== 0) {
|
||||
let smallSponsors = [];
|
||||
let smallUUIDs = [];
|
||||
let smallSegments: SponsorTime[] = [];
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i][1] - sponsorTimes[i][0] >= Config.config.minDuration) {
|
||||
smallSponsors.push(sponsorTimes[i]);
|
||||
smallUUIDs.push(UUIDs[i]);
|
||||
if (sponsorTimes[i].segment[1] - sponsorTimes[i].segment[0] >= Config.config.minDuration) {
|
||||
smallSegments.push(sponsorTimes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
sponsorTimes = smallSponsors;
|
||||
UUIDs = smallUUIDs;
|
||||
sponsorTimes = smallSegments;
|
||||
}
|
||||
|
||||
if (!switchingVideos) {
|
||||
// See if there are any starting sponsors
|
||||
let startingSponsor: number = -1;
|
||||
for (const time of sponsorTimes) {
|
||||
if (time[0] <= video.currentTime && time[0] > startingSponsor && time[1] > video.currentTime) {
|
||||
startingSponsor = time[0];
|
||||
if (time[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
|
||||
startingSponsor = time.segment[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!startingSponsor) {
|
||||
for (const time of sponsorTimesSubmitting) {
|
||||
if (time[0] <= video.currentTime && time[0] > startingSponsor && time[1] > video.currentTime) {
|
||||
startingSponsor = time[0];
|
||||
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
|
||||
startingSponsor = time.segment[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startingSponsor !== -1) {
|
||||
startSponsorSchedule(startingSponsor);
|
||||
startSponsorSchedule(false, startingSponsor);
|
||||
} else {
|
||||
startSponsorSchedule();
|
||||
}
|
||||
@@ -630,7 +674,7 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
||||
}
|
||||
|
||||
sponsorLookupRetries = 0;
|
||||
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 404) {
|
||||
} else if (response.status === 404) {
|
||||
sponsorDataFound = false;
|
||||
|
||||
//check if this video was uploaded recently
|
||||
@@ -655,7 +699,7 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
||||
});
|
||||
|
||||
sponsorLookupRetries = 0;
|
||||
} else if (xmlhttp.readyState == 4 && sponsorLookupRetries < 90 && !recheckStarted) {
|
||||
} else if (sponsorLookupRetries < 90 && !recheckStarted) {
|
||||
recheckStarted = true;
|
||||
|
||||
//TODO lower when server becomes better (back to 1 second)
|
||||
@@ -768,6 +812,8 @@ function updatePreviewBarPositionMobile(parent: Element) {
|
||||
}
|
||||
|
||||
function updatePreviewBar() {
|
||||
if (previewBar === null || video === null) return;
|
||||
|
||||
let localSponsorTimes = sponsorTimes;
|
||||
if (localSponsorTimes == null) localSponsorTimes = [];
|
||||
|
||||
@@ -777,17 +823,17 @@ function updatePreviewBar() {
|
||||
let types = [];
|
||||
for (let i = 0; i < localSponsorTimes.length; i++) {
|
||||
if (!hiddenSponsorTimes.includes(i)) {
|
||||
types.push("sponsor");
|
||||
types.push(localSponsorTimes[i].category);
|
||||
} else {
|
||||
// Don't show this sponsor
|
||||
types.push(null);
|
||||
}
|
||||
}
|
||||
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
|
||||
lastPreviewBarUpdate = sponsorVideoID;
|
||||
@@ -806,33 +852,80 @@ function whitelistCheck() {
|
||||
/**
|
||||
* Returns info about the next upcoming sponsor skip
|
||||
*/
|
||||
function getNextSkipIndex(currentTime: number): {array: number[][], index: number, openNotice: boolean} {
|
||||
let sponsorStartTimes = getStartTimes(sponsorTimes);
|
||||
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, currentTime, true);
|
||||
function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean):
|
||||
{array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} {
|
||||
|
||||
let sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments);
|
||||
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, currentTime, true);
|
||||
|
||||
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
||||
let endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex);
|
||||
|
||||
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting);
|
||||
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, currentTime, false);
|
||||
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments);
|
||||
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, currentTime, false);
|
||||
|
||||
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
|
||||
let previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex);
|
||||
|
||||
if ((minPreviewSponsorTimeIndex === -1 && minSponsorTimeIndex !== -1) ||
|
||||
sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) {
|
||||
return {
|
||||
array: sponsorTimes,
|
||||
index: minSponsorTimeIndex,
|
||||
endIndex: endTimeIndex,
|
||||
openNotice: true
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
array: sponsorTimesSubmitting,
|
||||
index: minPreviewSponsorTimeIndex,
|
||||
endIndex: previewEndTimeIndex,
|
||||
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.
|
||||
* Optionally specify a minimum
|
||||
@@ -840,57 +933,76 @@ function getNextSkipIndex(currentTime: number): {array: number[][], index: numbe
|
||||
* @param sponsorTimes
|
||||
* @param minimum
|
||||
* @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 [];
|
||||
|
||||
let startTimes: number[] = [];
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if ((minimum === undefined || sponsorTimes[i][0] >= minimum) && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) {
|
||||
startTimes.push(sponsorTimes[i][0]);
|
||||
if ((minimum === undefined || (sponsorTimes[i].segment[0] >= minimum || (includeIntersectingSegments && sponsorTimes[i].segment[1] > minimum)))
|
||||
&& (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) {
|
||||
startTimes.push(sponsorTimes[i].segment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return startTimes;
|
||||
}
|
||||
|
||||
//skip from the start time to the end time for a certain index sponsor time
|
||||
function skipToTime(v, index, sponsorTimes, openNotice) {
|
||||
if (!Config.config.disableAutoSkip || previewResetter !== null) {
|
||||
v.currentTime = sponsorTimes[index][1];
|
||||
/**
|
||||
* Skip to exact time in a video and autoskips
|
||||
*
|
||||
* @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;
|
||||
|
||||
if (openNotice) {
|
||||
//send out the message saying that a sponsor message was skipped
|
||||
if (!Config.config.dontShowNotice) {
|
||||
|
||||
let skipNotice = new SkipNotice(this, currentUUID, Config.config.disableAutoSkip, skipNoticeContentContainer);
|
||||
|
||||
//TODO: Remove this when Mobile support is old
|
||||
if (Config.config.mobileUpdateShowCount < 1) {
|
||||
skipNotice.addNoticeInfoMessage(chrome.i18n.getMessage("mobileUpdateInfo"));
|
||||
|
||||
Config.config.mobileUpdateShowCount += 1;
|
||||
}
|
||||
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||
let skipNotice = new SkipNotice(currentUUID, autoSkip, skipNoticeContentContainer);
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
// 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;
|
||||
|
||||
sponsorSkipped[index] = true;
|
||||
@@ -901,17 +1013,31 @@ function skipToTime(v, index, sponsorTimes, openNotice) {
|
||||
function unskipSponsorTime(UUID) {
|
||||
if (sponsorTimes != null) {
|
||||
//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) {
|
||||
if (sponsorTimes != null) {
|
||||
//add a tiny bit of time to make sure it is not skipped again
|
||||
video.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][1];
|
||||
video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[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 {
|
||||
if (document.getElementById(baseID + "Button") != null) return false;
|
||||
|
||||
@@ -1023,36 +1149,57 @@ function startSponsorClicked() {
|
||||
|
||||
toggleStartSponsorButton();
|
||||
|
||||
//send back current time with message
|
||||
chrome.runtime.sendMessage({
|
||||
message: "addSponsorTime",
|
||||
time: video.currentTime,
|
||||
videoID: sponsorVideoID
|
||||
}, function(response) {
|
||||
//see if the sponsorTimesSubmitting needs to be updated
|
||||
updateSponsorTimesSubmitting();
|
||||
});
|
||||
//add to sponsorTimes
|
||||
if (sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length < 2) {
|
||||
//it is an end time
|
||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment[1] = video.currentTime;
|
||||
} else {
|
||||
//it is a start time
|
||||
sponsorTimesSubmitting.push({
|
||||
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() {
|
||||
chrome.runtime.sendMessage({
|
||||
message: "getSponsorTimes",
|
||||
videoID: sponsorVideoID
|
||||
}, function(response) {
|
||||
if (response != undefined) {
|
||||
let sponsorTimes = response.sponsorTimes;
|
||||
function updateSponsorTimesSubmitting(getFromConfig: boolean = true) {
|
||||
let segments = Config.config.sponsorTimes.get(sponsorVideoID);
|
||||
|
||||
//see if this data should be saved in the sponsorTimesSubmitting variable
|
||||
if (sponsorTimes != undefined) {
|
||||
sponsorTimesSubmitting = sponsorTimes;
|
||||
//see if this data should be saved in the sponsorTimesSubmitting variable
|
||||
if (getFromConfig && segments != undefined) {
|
||||
sponsorTimesSubmitting = [];
|
||||
|
||||
updatePreviewBar();
|
||||
|
||||
// Restart skipping schedule
|
||||
startSponsorSchedule();
|
||||
}
|
||||
for (const segment of segments) {
|
||||
sponsorTimesSubmitting.push({
|
||||
segment: segment,
|
||||
UUID: null,
|
||||
// Default to sponsor
|
||||
category: "sponsor"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updatePreviewBar();
|
||||
|
||||
// Restart skipping schedule
|
||||
if (video !== null) startSponsorSchedule();
|
||||
|
||||
if (submissionNotice !== null) {
|
||||
submissionNotice.update();
|
||||
}
|
||||
}
|
||||
|
||||
async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
|
||||
@@ -1167,7 +1314,7 @@ function clearSponsorTimes() {
|
||||
let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID);
|
||||
|
||||
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")
|
||||
if(!confirm(confirmMessage)) return;
|
||||
|
||||
@@ -1185,14 +1332,17 @@ function clearSponsorTimes() {
|
||||
}
|
||||
|
||||
//if skipNotice is null, it will not affect the UI
|
||||
function vote(type, UUID, skipNotice) {
|
||||
if (skipNotice != null) {
|
||||
function vote(type, UUID, skipNotice?: SkipNoticeComponent) {
|
||||
if (skipNotice !== null && skipNotice !== undefined) {
|
||||
//add loading info
|
||||
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
|
||||
if (type == 0 && sponsorSkipped[sponsorIndex] || type == 1 && !sponsorSkipped[sponsorIndex]) {
|
||||
@@ -1204,7 +1354,7 @@ function vote(type, UUID, skipNotice) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -1224,10 +1374,10 @@ function vote(type, UUID, skipNotice) {
|
||||
}
|
||||
} else if (response.successType == 0) {
|
||||
//failure: duplicate vote
|
||||
skipNotice.addNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail"))
|
||||
skipNotice.setNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail"))
|
||||
skipNotice.resetVoteButtonInfo.bind(skipNotice)();
|
||||
} 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)();
|
||||
}
|
||||
}
|
||||
@@ -1260,116 +1410,106 @@ function sponsorMessageStarted(callback) {
|
||||
toggleStartSponsorButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for the submission notice to clear itself when it closes
|
||||
*/
|
||||
function resetSponsorSubmissionNotice() {
|
||||
submissionNotice = null;
|
||||
}
|
||||
|
||||
function submitSponsorTimes() {
|
||||
if (document.getElementById("submitButton").style.display == "none") {
|
||||
//don't submit, not ready
|
||||
return;
|
||||
}
|
||||
if (submissionNotice !== null) return;
|
||||
|
||||
//it can't update to this info yet
|
||||
closeInfoMenu();
|
||||
|
||||
let currentVideoID = sponsorVideoID;
|
||||
|
||||
let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID);
|
||||
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||
//check if a sponsor exceeds the duration of the video
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i][1] > 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();
|
||||
if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) {
|
||||
submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//send the message to the background js
|
||||
//called after all the checks have been made that it's okay to do so
|
||||
function sendSubmitMessage(){
|
||||
async function sendSubmitMessage(){
|
||||
//add loading animation
|
||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png");
|
||||
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({
|
||||
message: "submitTimes",
|
||||
videoID: currentVideoID
|
||||
}, function(response) {
|
||||
if (response != undefined) {
|
||||
if (response.statusCode == 200) {
|
||||
//hide loading message
|
||||
let submitButton = document.getElementById("submitButton");
|
||||
//finish this animation
|
||||
submitButton.style.animation = "rotate 1s";
|
||||
//when the animation is over, hide the button
|
||||
let animationEndListener = function() {
|
||||
changeStartSponsorButton(true, false);
|
||||
//update sponsorTimes
|
||||
Config.config.sponsorTimes.set(sponsorVideoID, utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting));
|
||||
|
||||
submitButton.style.animation = "none";
|
||||
|
||||
submitButton.removeEventListener("animationend", animationEndListener);
|
||||
};
|
||||
|
||||
submitButton.addEventListener("animationend", animationEndListener);
|
||||
|
||||
//clear the sponsor times
|
||||
Config.config.sponsorTimes.delete(currentVideoID);
|
||||
|
||||
//add submissions to current sponsors list
|
||||
if (sponsorTimes === null) 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 < 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));
|
||||
|
||||
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);
|
||||
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
||||
// Add placeholder IDs
|
||||
UUIDs.push(null);
|
||||
}
|
||||
|
||||
// Empty the submitting times
|
||||
sponsorTimesSubmitting = [];
|
||||
|
||||
updatePreviewBar();
|
||||
} else {
|
||||
//show that the upload failed
|
||||
document.getElementById("submitButton").style.animation = "unset";
|
||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png");
|
||||
|
||||
alert(utils.getErrorMessage(response.statusCode));
|
||||
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
|
||||
let submitButton = document.getElementById("submitButton");
|
||||
submitButton.style.animation = "rotate 1s";
|
||||
//finish this animation
|
||||
//when the animation is over, hide the button
|
||||
let animationEndListener = function() {
|
||||
changeStartSponsorButton(true, false);
|
||||
|
||||
submitButton.style.animation = "none";
|
||||
|
||||
submitButton.removeEventListener("animationend", animationEndListener);
|
||||
};
|
||||
|
||||
submitButton.addEventListener("animationend", animationEndListener);
|
||||
|
||||
//clear the sponsor times
|
||||
Config.config.sponsorTimes.delete(sponsorVideoID);
|
||||
|
||||
//add submissions to current sponsors list
|
||||
if (sponsorTimes === null) sponsorTimes = [];
|
||||
|
||||
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);
|
||||
|
||||
// Empty the submitting times
|
||||
sponsorTimesSubmitting = [];
|
||||
|
||||
updatePreviewBar();
|
||||
} else {
|
||||
//show that the upload failed
|
||||
document.getElementById("submitButton").style.animation = "unset";
|
||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png");
|
||||
|
||||
alert(utils.getErrorMessage(response.status) + "\n\n" + (await response.text()));
|
||||
}
|
||||
}
|
||||
|
||||
//get the message that visually displays the video times
|
||||
function getSponsorTimesMessage(sponsorTimes) {
|
||||
function getSegmentsMessage(segments: number[][]): string {
|
||||
let sponsorTimesMessage = "";
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
for (let s = 0; s < sponsorTimes[i].length; s++) {
|
||||
let timeMessage = getFormattedTime(sponsorTimes[i][s]);
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
for (let s = 0; s < segments[i].length; s++) {
|
||||
let timeMessage = utils.getFormattedTime(segments[i][s]);
|
||||
//if this is an end time
|
||||
if (s == 1) {
|
||||
timeMessage = " to " + timeMessage;
|
||||
@@ -1432,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) {
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
|
||||
|
||||
@@ -8,15 +8,55 @@
|
||||
let barTypes = {
|
||||
"undefined": {
|
||||
color: "#00d400",
|
||||
opacity: "0.5"
|
||||
opacity: "0.7"
|
||||
},
|
||||
"sponsor": {
|
||||
color: "#00d400",
|
||||
opacity: "0.5"
|
||||
opacity: "0.7"
|
||||
},
|
||||
"previewSponsor": {
|
||||
color: "#0000d4",
|
||||
opacity: "0.5"
|
||||
"preview-sponsor": {
|
||||
color: "#007800",
|
||||
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;
|
||||
|
||||
import Utils from "./utils";
|
||||
import CategoryChooser from "./render/CategoryChooser";
|
||||
var utils = new Utils();
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
@@ -31,6 +32,8 @@ async function init() {
|
||||
let checkbox = optionsElements[i].querySelector("input");
|
||||
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
||||
|
||||
let confirmMessage = optionsElements[i].getAttribute("confirm-message");
|
||||
|
||||
if (optionResult != undefined) {
|
||||
checkbox.checked = optionResult;
|
||||
|
||||
@@ -48,6 +51,12 @@ async function init() {
|
||||
|
||||
// Add click listener
|
||||
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;
|
||||
|
||||
// See if anything extra must be run
|
||||
@@ -164,6 +173,9 @@ async function init() {
|
||||
});
|
||||
|
||||
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 Utils from "./utils";
|
||||
import { SponsorTime } from "./types";
|
||||
var utils = new Utils();
|
||||
|
||||
interface MessageListener {
|
||||
@@ -56,7 +57,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
"showNoticeAgain",
|
||||
"optionsButton",
|
||||
// More controls
|
||||
"clearTimes",
|
||||
"submitTimes",
|
||||
"reportAnIssue",
|
||||
// sponsorTimesContributions
|
||||
@@ -82,9 +82,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
// discordButtons
|
||||
"discordButtonContainer",
|
||||
"hideDiscordButton",
|
||||
// submitTimesInfoMessage
|
||||
"submitTimesInfoMessageContainer",
|
||||
"submitTimesInfoMessage",
|
||||
// Username
|
||||
"setUsernameContainer",
|
||||
"setUsernameButton",
|
||||
@@ -108,7 +105,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel);
|
||||
PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true));
|
||||
PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false));
|
||||
PageElements.clearTimes.addEventListener("click", clearTimes);
|
||||
PageElements.submitTimes.addEventListener("click", submitTimes);
|
||||
PageElements.showNoticeAgain.addEventListener("click", showNoticeAgain);
|
||||
PageElements.setUsernameButton.addEventListener("click", setUsernameButton);
|
||||
@@ -263,8 +259,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
|
||||
sponsorTimes = sponsorTimesStorage;
|
||||
|
||||
displaySponsorTimes();
|
||||
|
||||
//show submission section
|
||||
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) {
|
||||
//This page doesn't have the injected content script, or at least not yet
|
||||
displayNoVideo();
|
||||
@@ -363,28 +357,14 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
|
||||
updateStartTimeChosen();
|
||||
|
||||
//display video times on screen
|
||||
displaySponsorTimes();
|
||||
|
||||
//show submission section
|
||||
PageElements.submissionSection.style.display = "unset";
|
||||
|
||||
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
|
||||
function displayDownloadedSponsorTimes(request) {
|
||||
function displayDownloadedSponsorTimes(request: {found: boolean, sponsorTimes: SponsorTime[], hiddenSponsorTimes: number[]}) {
|
||||
if (request.sponsorTimes != undefined) {
|
||||
//set it to the message
|
||||
if (PageElements.downloadedSponsorMessageTimes.innerText != chrome.i18n.getMessage("channelWhitelisted")) {
|
||||
@@ -403,11 +383,11 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
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 UUID = request.UUIDs[i];
|
||||
let UUID = request.sponsorTimes[i].UUID;
|
||||
|
||||
//thumbs up and down buttons
|
||||
let voteButtonsContainer = document.createElement("div");
|
||||
@@ -451,12 +431,12 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
}
|
||||
|
||||
//get the message that visually displays the video times
|
||||
function getSponsorTimesMessage(sponsorTimes) {
|
||||
function getSponsorTimesMessage(sponsorTimes: SponsorTime[]) {
|
||||
let sponsorTimesMessage = "";
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
for (let s = 0; s < sponsorTimes[i].length; s++) {
|
||||
let timeMessage = getFormattedTime(sponsorTimes[i][s]);
|
||||
for (let s = 0; s < sponsorTimes[i].segment.length; s++) {
|
||||
let timeMessage = getFormattedTime(sponsorTimes[i].segment[s]);
|
||||
//if this is an end time
|
||||
if (s == 1) {
|
||||
timeMessage = " to " + timeMessage;
|
||||
@@ -692,8 +672,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
});
|
||||
|
||||
if (closeEditMode) {
|
||||
displaySponsorTimes();
|
||||
|
||||
showSubmitTimesIfNecessary();
|
||||
}
|
||||
}
|
||||
@@ -721,9 +699,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
//save this
|
||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
||||
|
||||
//update display
|
||||
displaySponsorTimes();
|
||||
|
||||
//if they are all removed
|
||||
if (sponsorTimes.length == 0) {
|
||||
//update chrome tab
|
||||
@@ -753,67 +728,17 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
});
|
||||
}
|
||||
|
||||
function clearTimes() {
|
||||
//send new sponsor time state to tab
|
||||
function submitTimes() {
|
||||
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({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
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;
|
||||
}
|
||||
|
||||
enum CategorySkipOption {
|
||||
ShowOverlay,
|
||||
ManualSkip,
|
||||
AutoSkip
|
||||
}
|
||||
|
||||
interface CategorySelection {
|
||||
name: string;
|
||||
option: CategorySkipOption
|
||||
}
|
||||
|
||||
interface SponsorTime {
|
||||
segment: number[];
|
||||
UUID: string;
|
||||
|
||||
category: string;
|
||||
}
|
||||
|
||||
type VideoID = string;
|
||||
|
||||
export {
|
||||
videoDurationResponse
|
||||
VideoDurationResponse,
|
||||
ContentContainer,
|
||||
CategorySelection,
|
||||
CategorySkipOption,
|
||||
SponsorTime,
|
||||
VideoID
|
||||
};
|
||||
109
src/utils.ts
109
src/utils.ts
@@ -1,4 +1,7 @@
|
||||
import Config from "./config";
|
||||
import { CategorySelection, SponsorTime } from "./types";
|
||||
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
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() {
|
||||
//Localize by replacing __MSG_***__ meta tags
|
||||
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
@@ -230,6 +269,39 @@ class Utils {
|
||||
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
|
||||
*
|
||||
@@ -239,8 +311,10 @@ class Utils {
|
||||
*/
|
||||
sendRequestToServer(type: string, address: string, callback?: (xmlhttp: XMLHttpRequest, err: boolean) => any) {
|
||||
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) {
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
@@ -256,6 +330,37 @@ class Utils {
|
||||
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)
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"outDir": "dist/js",
|
||||
"noEmitOnError": true,
|
||||
"typeRoots": [ "node_modules/@types" ],
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user