mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-06 11:37:02 +03:00
Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33ec82882d | ||
|
|
647a3839d0 | ||
|
|
2808b76655 | ||
|
|
ece66522e5 | ||
|
|
bddbedbdd0 | ||
|
|
1d83a4616d | ||
|
|
06f09f5fd9 | ||
|
|
e95029c229 | ||
|
|
6d1c51e7ec | ||
|
|
83a9526e52 | ||
|
|
0f68c503b3 | ||
|
|
3828c00d27 | ||
|
|
0baf01c1af | ||
|
|
edbbb9022b | ||
|
|
73b81424b1 | ||
|
|
bd12ccb6f4 | ||
|
|
d81229a157 | ||
|
|
0e32042634 | ||
|
|
54c36e65ef | ||
|
|
979e7e7629 | ||
|
|
cba0fc0a87 | ||
|
|
24df146c53 | ||
|
|
bc10690304 | ||
|
|
8dd9a79aa5 | ||
|
|
1bab5063aa | ||
|
|
1d7dab6ea0 | ||
|
|
c30038fd26 | ||
|
|
81926367b1 | ||
|
|
5ac5b557b0 | ||
|
|
e5ec478e6a | ||
|
|
90d53a34b5 | ||
|
|
fbe64c115b | ||
|
|
9bd5c971c6 | ||
|
|
41e5cb25aa | ||
|
|
fd9116c81c | ||
|
|
1b4bee1b90 | ||
|
|
608aa73ae4 | ||
|
|
3b07bc638a | ||
|
|
2afe510912 | ||
|
|
b6b109b226 | ||
|
|
e31aaba24c | ||
|
|
c0d910decd | ||
|
|
17eead2bb6 | ||
|
|
cd4f5fc667 | ||
|
|
09c527417d | ||
|
|
094ef84f15 | ||
|
|
dc36e8097d | ||
|
|
b7ea5689c7 | ||
|
|
7756a89960 | ||
|
|
865422eaaa | ||
|
|
9b572609f8 | ||
|
|
ba01293067 | ||
|
|
59fbc84017 | ||
|
|
4b0c6b80f6 | ||
|
|
881f46c65c | ||
|
|
a8714409a6 | ||
|
|
ae6130259b | ||
|
|
bd51f5b621 | ||
|
|
3b22733c1a | ||
|
|
dbee744bd7 | ||
|
|
5d0559aebd | ||
|
|
120642667d | ||
|
|
70667a43d7 | ||
|
|
b47a71c000 | ||
|
|
7078e1f033 | ||
|
|
59826aae6d | ||
|
|
fd4452a078 | ||
|
|
c3f32aae26 | ||
|
|
55856c5566 | ||
|
|
57e6268fc7 | ||
|
|
fd8a3a05fe | ||
|
|
06d600c6d0 | ||
|
|
0253016871 | ||
|
|
03e34281f6 | ||
|
|
125a83ac3f | ||
|
|
1afabb934f | ||
|
|
df84f328a7 | ||
|
|
7cc8cd75d4 | ||
|
|
b6fd1f0804 | ||
|
|
3f19506137 | ||
|
|
b23e6fa3d2 | ||
|
|
7bf0090195 | ||
|
|
bdcfec38c2 | ||
|
|
042f2eb4e8 | ||
|
|
7b27de279b | ||
|
|
dde6b44005 | ||
|
|
d80dad7963 | ||
|
|
a150a97991 | ||
|
|
141d8456d8 | ||
|
|
e353591a7b | ||
|
|
e2ef7412a4 | ||
|
|
36558f5460 | ||
|
|
105c148ccc | ||
|
|
0854b74080 | ||
|
|
3c0f24a0f3 | ||
|
|
f0152db605 | ||
|
|
c310e05ae0 | ||
|
|
1d35ac913e | ||
|
|
637dcbee00 | ||
|
|
b6e5fe461f | ||
|
|
ad406d72e4 | ||
|
|
31d4c621d1 | ||
|
|
afa4cfa2c6 | ||
|
|
7c82a74e78 | ||
|
|
5e4aed7afd | ||
|
|
21f4d2928f | ||
|
|
a67c972e03 | ||
|
|
7a6f65803e | ||
|
|
0ad1abb108 | ||
|
|
718666cdf0 | ||
|
|
8cd3d92639 | ||
|
|
e3fb851713 | ||
|
|
9bd4f12d2b | ||
|
|
980e401628 | ||
|
|
03cba1940c | ||
|
|
7fecf2a8d4 | ||
|
|
8f7ed9ce13 | ||
|
|
508553b2e1 | ||
|
|
82815ca6ba | ||
|
|
0126f44617 | ||
|
|
0c9573ae4c | ||
|
|
c191132a01 | ||
|
|
4dec4df8e8 | ||
|
|
76db584daf | ||
|
|
e64410df91 | ||
|
|
f2317caad2 | ||
|
|
25c4819bef | ||
|
|
24c5253ab8 | ||
|
|
abc6f70329 | ||
|
|
34ea13ecba | ||
|
|
a4d9d83989 | ||
|
|
447445fcb0 |
31
.eslintrc.js
Normal file
31
.eslintrc.js
Normal file
@@ -0,0 +1,31 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 12,
|
||||
sourceType: "module",
|
||||
},
|
||||
plugins: ["react", "@typescript-eslint"],
|
||||
rules: {
|
||||
// TODO: Remove warn rules when not needed anymore
|
||||
"no-self-assign": "off",
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -97,6 +97,7 @@ The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) was
|
||||
|
||||
Originally forked from [YTSponsorSkip](https://github.com/NDevTK/YTSponsorSkip), but zero code remains.
|
||||
|
||||
Some icons made by <a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||
|
||||
Some icons made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||
Icons made by:
|
||||
* <a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||
* <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||
* <a href="https://iconmonstr.com/about/#creator">Alexander Kahlkopf</a> from <a href="https://iconmonstr.com/">iconmonstr.com</a> and are licensed by <a href="https://iconmonstr.com/license/">iconmonstr License</a>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "SponsorBlock",
|
||||
"version": "2.0.9",
|
||||
"version": "2.0.11.2",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"content_scripts": [{
|
||||
@@ -28,6 +28,9 @@
|
||||
"icons/PlayerStopIconSponsorBlocker256px.png",
|
||||
"icons/PlayerUploadIconSponsorBlocker256px.png",
|
||||
"icons/PlayerUploadFailedIconSponsorBlocker256px.png",
|
||||
"icons/settings.svg",
|
||||
"icons/pencil.svg",
|
||||
"icons/check.svg",
|
||||
"icons/upvote.png",
|
||||
"icons/downvote.png",
|
||||
"icons/thumbs_down.svg",
|
||||
|
||||
File diff suppressed because one or more lines are too long
2274
package-lock.json
generated
2274
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -19,13 +19,17 @@
|
||||
"@types/firefox-webext-browser": "70.0.1",
|
||||
"@types/jest": "^24.0.23",
|
||||
"@types/jquery": "^3.3.31",
|
||||
"@typescript-eslint/eslint-plugin": "^4.9.1",
|
||||
"@typescript-eslint/parser": "^4.9.1",
|
||||
"copy-webpack-plugin": "^6.0.3",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-plugin-react": "^7.21.5",
|
||||
"jest": "^26.4.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"ts-jest": "^26.2.0",
|
||||
"ts-loader": "^6.2.1",
|
||||
"typescript": "~3.7.3",
|
||||
"web-ext": "^5.0.0",
|
||||
"web-ext": "^5.4.1",
|
||||
"webpack": "~4.41.2",
|
||||
"webpack-cli": "~3.3.10",
|
||||
"webpack-merge": "~4.2.2"
|
||||
@@ -47,7 +51,9 @@
|
||||
"dev": "npm run build:dev && concurrently \"npm run web-run\" \"npm run build:watch\"",
|
||||
"dev:firefox": "npm run build:dev:firefox && concurrently \"npm run web-run:firefox\" \"npm run build:watch:firefox\"",
|
||||
"clean": "rimraf dist",
|
||||
"test": "npx jest"
|
||||
"test": "npx jest",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
"Loading": {
|
||||
"message": "Зареждане..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Минути"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Секунди"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Никога не показвай"
|
||||
},
|
||||
@@ -70,9 +64,6 @@
|
||||
"sponsorEnd": {
|
||||
"message": "Сегментът Свършва Сега"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Не е намерено YouTube видео в този раздел. Ако сте сигурни, че това е YouTube раздел, затворете този изскачащ прозорец и го отворете отново. Ако това не проработи, опитайте се да презаредите раздела."
|
||||
},
|
||||
"success": {
|
||||
"message": "Успешно!"
|
||||
},
|
||||
@@ -91,21 +82,6 @@
|
||||
"submitCheck": {
|
||||
"message": "Сигурни ли сте, че искате да подадете това?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Добавяне на канала към Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Премахване на канала от Whitelist"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Вие сте помогнали на хора да пропуснат "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Вижте leaderboard-а"
|
||||
},
|
||||
"here": {
|
||||
"message": "тук"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Елате в официалния Discord сървър за да давате предложения!"
|
||||
},
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Carregant..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuts"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Segons"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "No mostris mai"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock pro YouTube - Přeskoč Sponzorství",
|
||||
"message": "SponsorBlock pro YouTube - Přeskoč sponzorství",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
@@ -23,7 +23,7 @@
|
||||
"message": "segment"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty"
|
||||
"message": "segmentů"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Hlasovat pro tento příspěvek"
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Načítání..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nikdy nezobrazovat"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segment nyní končí"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Na této záložce nebylo nalezeno žádné YouTube video. Pokud jste si jistí, že tato záložka je YouTube, zavřete toto vyskakovací okno a znovu jej otevřete. Pokud to nepomůže, zkuste záložku znovu načíst."
|
||||
"message": "Nebylo nalezeno žádné YouTube video.\nPokud je to nesprávně, obnovte záložku."
|
||||
},
|
||||
"success": {
|
||||
"message": "Úspěch!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Hlasovat pro segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Zatím jste přidali"
|
||||
"Submissions": {
|
||||
"message": "Příspěvky"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Lidem jste ušetřili "
|
||||
"message": "Ušetřili jste lidem "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobrazit žebříček"
|
||||
},
|
||||
"here": {
|
||||
"message": "zde"
|
||||
"message": "Žebříček"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Stiskněte tlačítko níže, když segment začne a skončí, k nahrání a uložení do databáze."
|
||||
"message": "Odeslat"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Úpravy sekcí se objeví po odeslání",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Tip: Pokud je video aktivní, stiskněte středník pro nahlášení začátku/konce segmentu, a apostrof pro odeslání. (Klávesy lze změnit v nastavení)"
|
||||
"message": "Tip: V možnostech můžete nastavit klávesové zkratky pro odeslání"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Vymazat časy"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Toto se používá ve veřejném žebříčku k ukázání jak moc jste přispěli. Podívejte se na něj"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Uživatelské jméno"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Nastavit uživatelské jméno"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Vypršel časový limit připojení. Zkontrolujte vaše připojení k internetu. Pokud váš internet funguje, server je nejspíš přetížený nebo spadnul."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Zakázat SponsorBlock"
|
||||
"message": "Přeskakování je povoleno"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Povolit SponsorBlock"
|
||||
"message": "Přeskakování je zakázáno"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Vaše práce",
|
||||
@@ -275,7 +273,7 @@
|
||||
"message": "Přeskočit {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Přeskočeno"
|
||||
"message": "- přeskočeno"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Zakázat automatické přeskočení"
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "Ušetřili jste lidem"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " jejich života."
|
||||
"message": " jejich života"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Podívejte se na status.sponsor.ajay.app pro stav serverů."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Vyberte kategorii"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Pro odeslání segmentů v kategorii \"{0}\" to nejprve musíte povolit v nastavení. Nyní budete přesměrováni do nastavení.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Musíte vybrat kategorii pro všechny odeslané segmenty!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Odeslat upozornění, když opustíte video s nenahranými segmenty"
|
||||
},
|
||||
"help": {
|
||||
"message": "Nápověda"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Indlæser..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutter"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekunder"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Vis aldrig"
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Überspringe gesponserte Videosegmente, Betteln um Abonnenten und mehr in YouTube Videos. Melde gesponserte Videosegmente in Videos, die du guckst, um anderen Zeit zu sparen.",
|
||||
"message": "Überspringe Sponsoren, betteln um Abonnenten und mehr in YouTube Videos. Melde Sponsoren in Videos, die du guckst, um anderen Zeit zu sparen.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Laden..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuten"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekunden"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Verstecken"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segment endet jetzt"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Keine YouTube-Videos in diesem Tab gefunden. Wenn dies ein Youtube-Tab ist, schließe dieses Pop-up und öffne es erneut. Wenn das nicht hilft, versuche den Tab neu zu laden."
|
||||
"message": "Kein YouTube-Video gefunden.\nWenn dies falsch ist, aktualisiere den Tab."
|
||||
},
|
||||
"success": {
|
||||
"message": "Geschafft!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Über ein Segment abstimmen"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Von dir bisher gemeldet:"
|
||||
"Submissions": {
|
||||
"message": "Beiträge"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "\nDamit hast du anderen Nutzer folgendes erspart:"
|
||||
"message": "Andere Nutzer bewahrt vor: "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Wirf einen Blick auf die Rangliste:"
|
||||
},
|
||||
"here": {
|
||||
"message": "hier"
|
||||
"message": "Rangliste"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klicke beim Start und am Ende des Segments auf den Knopf unten, um es in die Datenbank zu übermitteln."
|
||||
"message": "Senden"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Die Bearbeitung von Beiträgen wird angezeigt, nachdem du auf Senden klickst",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Hinweis: Du kannst auch alternativ eine Taste in den Optionen festlegen, welche du drücken kannst, während du das Video guckst, um die Start- und Endpunkte des Segments zu markieren."
|
||||
"message": "Tipp: Du kannst Tastenkombinationen für das Senden in den Optionen festlegen"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Zeiten löschen"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "So wirst du in der öffentlichen Rangliste angezeigt. Siehe"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Benutzername"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Alias festlegen"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Zeitüberschreibung. Überprüfe deine Internetverbindung. Bist du mit dem Internet verbunden, ist der Server wahrscheinlich offline."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock deaktivieren"
|
||||
"message": "Überspringen ist aktiviert"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock aktivieren"
|
||||
"message": "Überspringen ist deaktiviert"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Deine Statistik",
|
||||
@@ -296,7 +294,7 @@
|
||||
"message": "Diese Zeit wird in Klammern neben der kompletten Videodauer im YouTube-Videoplayer angezeigt. Dies betrifft auch Segmente, die als \"In Suchleiste anzeigen\" markiert sind."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Du übersprangst bisher "
|
||||
"message": "Du übersprangst "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": " und erspartest dir damit "
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "Stunden"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "\nAndere haben dank dir"
|
||||
"message": "Du erspartest anderen"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " ihrer wertvollen Zeit gespart."
|
||||
"message": " ihres Lebens"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Du kannst den Serverstatus auf https://status.sponsor.ajay.app überprüfen."
|
||||
@@ -350,10 +348,10 @@
|
||||
"message": "Invidious-Kompatibilität"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (https://invidio.us) ist ein Drittanbieter-YouTube-Client. Um SponsorBlock mit Invidious verwenden zu können, musst du die zusätzlichen Berechtigungen akzeptieren. Dies funktioniert NICHT in Chrome's Inkognitomodus oder anderen Chromium-Varianten."
|
||||
"message": "Invidious (invidio.us) ist ein Drittanbieter-YouTube-Client. Um Support zu aktivieren, müssen Sie die zusätzlichen Berechtigungen akzeptieren. Dies funktioniert NICHT im Incongnito-modus auf Chrome und anderen Chromium-Varianten."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Zu überspringende Videosegmente auswählen, automatisches Überspringen, Knöpfe ein- & ausblenden und noch viel mehr."
|
||||
"message": "Zu überspringende Kategorien auswählen, automatisches Überspringen, Tasten ein- & ausblenden und noch viel mehr."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Invidious-Instanzen hinzufügen"
|
||||
@@ -560,10 +558,10 @@
|
||||
"message": "Betatest-Server aktivieren"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Deine Einreichungen und Bewertungen/Meldungen werden NICHT an den Hauptserver übertragen. Benutze diese Option also nur für Tests."
|
||||
"message": "Deine Beiträge und Bewertungen/Meldungen werden NICHT an den Hauptserver übertragen. Benutze diese Option also nur für Tests."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Alle Einreichungen und Bewertungen/Meldungen werden NICHT an den Hauptserver übertragen. Deaktiviere die Betatest-Server Option um Einreichungen an den Hauptserver zu senden."
|
||||
"message": "Alle Beiträge und Bewertungen/Meldungen werden NICHT an den Hauptserver übertragen. Deaktiviere die Betatest-Server Option um Einreichungen an den Hauptserver zu senden."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(jetzt)"
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Wähle eine Kategorie"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Um Segmente aus der Kategorie \"{0}\" zu senden, musst du diese in den Optionen aktivieren. Du wirst jetzt zu den Optionen weitergeleitet.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Du musst eine Kategorie für jedes zu übermittelnde Segment auswählen!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Zeigt eine Benachrichtigung an, wenn du ein Video mit nicht übertragenden Segmenten verlässt."
|
||||
},
|
||||
"help": {
|
||||
"message": "Hilfe"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Segment": {
|
||||
"message": "τμήμα"
|
||||
},
|
||||
@@ -20,12 +24,6 @@
|
||||
"Loading": {
|
||||
"message": "Φόρτωση..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Λεπτά"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Δευτερόλεπτα"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Να μην εμφανίζεται ποτέ"
|
||||
},
|
||||
@@ -47,9 +45,6 @@
|
||||
"clearTimes": {
|
||||
"message": "Καθαρισμός τμημάτων"
|
||||
},
|
||||
"here": {
|
||||
"message": "εδώ"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Επιλογές"
|
||||
},
|
||||
@@ -67,9 +62,6 @@
|
||||
"skip": {
|
||||
"message": "Παράκαμψη"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "Παράκαμψη {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Παραλείφθηκε"
|
||||
},
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Loading..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Seconds"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Never Show"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segment Ends Now"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "No YouTube video found at this tab. If you know this is a YouTube tab, close this popup and open it again. If that does not work, try reloading the tab."
|
||||
"message": "No YouTube video found.\nIf this is incorrect, refresh the tab."
|
||||
},
|
||||
"success": {
|
||||
"message": "Success!"
|
||||
@@ -122,31 +116,32 @@
|
||||
"message": "Are you sure you want to submit this?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Whitelist Channel"
|
||||
"message": "Whitelist channel"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remove Channel From Whitelist"
|
||||
"message": "Remove channel from whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote On A Segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "So far, you've submitted"
|
||||
"Submissions": {
|
||||
"message": "Submissions"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "You have saved people from "
|
||||
"message": "You've saved people from "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "View the leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "here"
|
||||
"message": "Leaderboard"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Click the button below when the segment starts and ends to record and submit it to the database."
|
||||
"message": "Submit"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Section editing will appear after you click submit",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Hint: Press the semicolon key while focused on a video to report the start/end of a segment and quote to submit. (This can be changed in the options)"
|
||||
"message": "Hint: You can setup keybinds for submitting in the options"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Clear Times"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "This is used on the public stats page to show off how much you've contributed. See it"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Username"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Set Username"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Connection Timeout. Check your internet connection. If your internet is working, the server is probably overloaded or down."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Disable SponsorBlock"
|
||||
"message": "Skipping is enabled"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Enable SponsorBlock"
|
||||
"message": "Skipping is disabled"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Your Work",
|
||||
@@ -296,7 +294,7 @@
|
||||
"message": "This time appears in brackets next to the current time on below the seekbar. This shows the total video duration minus any segments. This includes segments marked as only \"Show In Seekbar\"."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "You have skipped "
|
||||
"message": "You've skipped "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "You have saved yourself "
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "hours"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "You have saved people"
|
||||
"message": "You've saved people"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " of their lives."
|
||||
"message": " of their lives"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Check status.sponsor.ajay.app for server status."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Choose a Category"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "To submit segments with the category of \"{0}\", you must enable it in the options. You will be redirected to the options now.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "You must select a category for all segments you are submitting!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Send a notification when you leave a video with segments that are not uploaded"
|
||||
},
|
||||
"help": {
|
||||
"message": "Help"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Cargando..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutos"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Segundos"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nunca Mostrar"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "El segmento termina ahora"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Ningún video de YouTube se encontró en esta pestaña. Si sabes que esto es una pestaña de YouTube, cierra esta ventana y ábrela otra vez. Si eso no funciona, intenta recargar la pestaña."
|
||||
"message": "No se encontró vídeo de YouTube.\nSi esto es incorrecto, actualice la pestaña."
|
||||
},
|
||||
"success": {
|
||||
"message": "¡Completado!"
|
||||
@@ -121,32 +115,27 @@
|
||||
"submitCheck": {
|
||||
"message": "¿Estás seguro de que quieres enviar esto?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Permitir Canal"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Parar De Permitir Canal"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote En Un Segmento"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Hasta ahora, has enviado"
|
||||
"Submissions": {
|
||||
"message": "Solicitudes"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Has salvado personas de "
|
||||
"message": "Tú salvado personas de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver la tabla de clasificación"
|
||||
},
|
||||
"here": {
|
||||
"message": "aquí"
|
||||
"message": "Tablas de clasificación"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Haga clic en el botón de abajo cuando el segmento comience y termine para grabarlo y enviarlo a la base de datos."
|
||||
"message": "Enviar"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "La edición de la sección aparecerá después de hacer clic en enviar",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Pista: Presione la tecla de punto y coma mientras está enfocado en un video para indicar el comienzo/final de un segmento y citación para enviarlo. (Esto puede cambiarse en opciones)"
|
||||
"message": "Sugerencia: puede configurar los teclas para enviar en las opciones"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Eliminar Tiempos"
|
||||
@@ -157,6 +146,9 @@
|
||||
"publicStats": {
|
||||
"message": "Esto se utiliza en la página de estadísticas públicas para mostrar cuánto has contribuido. Véala"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Usuario"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Escoger Nombre De Usuario"
|
||||
},
|
||||
@@ -209,7 +201,7 @@
|
||||
"message": "En el lugar de solicitar segmentos del servidor usando el videoID, se envían los primeros 4 caracteres del hash del videoID. Este servidor devolverá los datos de todos los vídeos con hashes similares."
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Actualizar segmentos en nuevos vídeos"
|
||||
"message": "Actualizar Segmentos En Nuevos Vídeos"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Si el video es nuevo, y no hay segmentos encontrados, seguirá recuperándose cada pocos minutos mientras veas."
|
||||
@@ -253,10 +245,10 @@
|
||||
"message": "Tiempo de espera agotado. Compruebe su conexión a Internet. Si su internet está funcionando, el servidor probablemente esta sobrecargado o desconectado."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Desactivar SponsorBlock"
|
||||
"message": "Saltar está activado"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Activar SponsorBlock"
|
||||
"message": "Saltar está desactivado"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Tu trabajo",
|
||||
@@ -272,7 +264,7 @@
|
||||
"message": "Omitir"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "¿Saltarse {0}?"
|
||||
"message": "¿Saltar {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Omitido"
|
||||
@@ -296,7 +288,7 @@
|
||||
"message": "Esta duración aparece entre paréntesis junto al tiempo actual del video, debajo de la barra de navegación. Esta muestra la duración total del vídeo menos cualquier segmento eliminado. Esto incluye los segmentos marcados como solo \"Mostrar en la barra de navegación\"."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Has omitido "
|
||||
"message": "Los has saltado "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Te has ahorrado "
|
||||
@@ -314,10 +306,10 @@
|
||||
"message": "horas"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Has ahorrado a otras personas"
|
||||
"message": "Has salvado personas"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " de sus vidas."
|
||||
"message": " de sus vidas"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Comprueba status.sponsor.ajay.app para ver el estado del servidor."
|
||||
@@ -634,5 +626,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Envía una notificación cuando dejas un vídeo con segmentos que no se suben"
|
||||
},
|
||||
"help": {
|
||||
"message": "Ayuda"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,613 @@
|
||||
{}
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock YouTube'ile - jäta sponsorid vahele",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Jäta sponsorid, tellimise palumine ja muud YouTube'i videote tüütused vahele. Teata vaadatavate videote sponsoritest, et säästa teiste aega.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Server ütles, et see taotlus oli sobimatu"
|
||||
},
|
||||
"429": {
|
||||
"message": "Sa oled sellele ühele videole liiga palju sponsoriaegu saatnud, kas oled kindel, et neid on tõesti nii palju?"
|
||||
},
|
||||
"409": {
|
||||
"message": "See on juba varasemalt saadetud"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanal lubamisnimekirjas!"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmendi"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenti"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Anna segmendile poolthääl"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Teavita"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Teavita sellest segmendist kui sobimatust."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Sulge"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Laadimine..."
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Ära näita kunagi"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Vajuta \"tühista vahelejätmine\", et jõuda sinna, kust tulid."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Tühista vahelejätmine"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Jäta uuesti vahele"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Pausil"
|
||||
},
|
||||
"manualPaused": {
|
||||
"message": "Taimer peatatud"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Üksikute väärtuste muutmiseks või kustutamiseks vajuta infonuppu või ava laienduse hüpik, vajutades selle ikoonile üleval paremal nurgas."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Kas soovid tõesti selle tühjendada?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Sinu sponsoriaegade saatmisel esines tõrge, palun proovi hiljem uuesti."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Sellel videol on andmebaasis segmente!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Segmente ei leitud"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Segment algab nüüd"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Segment lõpeb nüüd"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "YouTube'i videot ei leitud.\nKui see ei vasta tõele, laadi kaart uuesti."
|
||||
},
|
||||
"success": {
|
||||
"message": "Õnnestus!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Hääletatud!"
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Tundub, et server on maas. Anna sellest koheselt arendajale teada."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Ühendusega esines tõrge. Veakood: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Kas soovid segmendid saata video IDle"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Sul tunduvad olevat mõned segmendid esitamata. Nende esitamiseks mine sellele lehele tagasi (need ei ole kustutatud)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Tühjenda segmendid"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Ava SponsorBlocki hüpik"
|
||||
},
|
||||
"closePopup": {
|
||||
"message": "Sulge hüpik"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Esita segmendid"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Kas soovid kindlasti selle saata?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Lisa kanal lubamisnimekirja"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Eemalda kanal lubamisnimekirjast"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Hääleta segmendi sobivust"
|
||||
},
|
||||
"Submissions": {
|
||||
"message": "Saadetud segmendid"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Oled inimeste aega säästnud "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Edetabel"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Saada"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Segmendi töötlemine avaneb pärast saatmist",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Vihje: sa võid saatmiseks määrata valikutes klaviatuuriotseteid"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Tühjenda ajad"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Saada ajad"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Seda kasutatakse avaliku statistika lehel, et näidata välja, kui palju oled panustanud. Vaata seda"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Kasutajanimi"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Määra kasutajanimi"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Tule liitu ametliku Discordi serveriga, et anda soovitusi ja tagasisidet!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Peida see"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Valikud"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Kuva YouTube'i mängijal nupud"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Peida YouTube'i mängijal nupud"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "See peidab nupud, mis kuvatakse YouTube'i mängijal vahelejätmiste segmentide saatmiseks."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Kuva YouTube'i mängijal infonupp"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Peida YouTube'i mängijal infonupp"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "See on see nupp, mis avab YouTube'i lehel hüpiku."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Peida YouTube'i mängijal kustutusnupp"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Kuva YouTube'i mängijal kustutusnupp"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "YouTube'i mängija nupp, mis tühjendab kõik sinu praeguse video saatmata segmendid."
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Luba vahelejätmiste arvu jälgimine"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "See funktsioon jälgib, milliseid segmente sa oled vahele jätnud, et kasutajad teaksid, kui palju nende sisestus on teisi aidanud ning et koos poolthäältega veenduda rämpsu mittesattumises andmebaasi. Laiendus saadab iga segmendi vahelejätmisel serverisse sõnumi. Loodetavasti enamus inimesi ei muuda seda seadistust, et vaatamisarvud oleksid täpsed. :)"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Küsi räsi eesliite järgi"
|
||||
},
|
||||
"whatQueryByHashPrefix": {
|
||||
"message": "VideoID järgi segmentide küsimise asemel saadetakse videoID räsi 4 esimest märki ning server saadab tagasi kõigi sarnaste räsidega videote andmed."
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Too segmendid uutel videotel uuesti"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Kui video on uus ning segmente ei leitud, proovitakse vaatamise ajal iga paari minuti tagant uuesti segmente tuua."
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Kuva märkus uuesti"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock lubab sul vahele jätta sponsorid, vaheajad, kanali tellimise meeldetuletused ja muud YouTube'i videote tüütud kohad. SponsorBlock on rahva ühistööna toimiv brauserilaiendus, mis lubab igaühel saata sponsoreeritud segmendi algus- ja lõpuaegu ning teiste video segmentide aegu. Kui üks inimene saadab sponsoreeritud segmendi, jätavad teised laienduse kasutajad kohe selle vahele. Laiendus võimaldab ka muusikavideotel mitte-muusika jaotised vahele jätta.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Veebileht",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Lähtekood",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Teavitus on uuendatud!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Kui sulle see ikka ei meeldi, vajuta \"ära näita kunagi\" nuppu.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Seadista segmendi alustamise klahv"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Seadista segmendi saatmise klahv"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Vali klahv, seda vajutades"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Otsetee on seatud: "
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Vahelejätmine on lubatud"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Vahelejätmine on keelatud"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Sinu töö",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Server paistab olevat ülekoormatud. Proovi uuesti mõne sekundi pärast."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Veakood: "
|
||||
},
|
||||
"skip": {
|
||||
"message": "Jäta vahele"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "Jätad {0} vahele?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Vahelejäetud"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Keela automaatne vahelejätmine"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Luba automaatne vahelejätmine"
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Heliteavitus vahelejätmisel"
|
||||
},
|
||||
"showTimeWithSkips": {
|
||||
"message": "Kuva vahelejäetud segmentidega aeg"
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Oled vahele jätnud "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Oled enda aega säästnud "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minut"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minutit"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "tund"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "tundi"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Oled inimestel säästnud"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " nende ajast"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Serveri oleku saamiseks vaata status.sponsor.ajay.app"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Impordi/ekspordi oma UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Seda tuleks privaatsena hoida. See on nagu parool ning seda ei tohiks kellegagi jagada. Kui kellelgi see on, saavad nad sinuna esineda."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Seadista UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Hoiatus: UserID muutmine on püsiv. Kas soovid kindlasti seda teha? Igaks juhuks soovitame eelmise UserID varundada."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Autor"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Autom. vahelejätmine"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Kuva segmendi vahelejätmisel teatis"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Hetkel on selleks määratud:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Invidiouse tugi"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) on kolmanda osapoole YouTube'i klient. Selle toe lubamiseks pead nõustuma lisalubadega. See EI tööta inkognito-režiimis nii Chromes kui ka teistes Chromiumi brauserites."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Luba Invidiouse tugi, keela automaatne vahelejätmine, peida nupud ja muud valikud."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Lisa Invidiouse eksemplar"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Lisa kohandatud Invidiouse eksemplar. See tuleb vormistada AINULT domeeniga. Näide:\ninvidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Lisa"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "See on sobimatu domeen. Siia tuleks kirjutada AINULT domeeniosa, nt invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Lähtesta Invidiouse eksemplaride nimekiri"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Lähtestad Invidiouse eksemplaride nimekirja"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Praegused eksemplarid:"
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimaalne kestus (sekundit):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Segmendid, mis on lühemad kui määratud väärtus ei jäeta vahele või ei kuvata mängijal."
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Kuva üleslaadimisnupp"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "See nupp kuvatakse YouTube'i mängijal, kui oled ajatempli ära valinud ning saatmiseks valmis."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlocki serveri aadress"
|
||||
},
|
||||
"save": {
|
||||
"message": "Salvesta"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Lähtesta"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Aadress ei ole õiges vormingus. Veendu, et sul on alguses http:// või https:// ning lõpus ei ole kaldkriipsu."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Kas soovid kindlasti selle lähtestada?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "See video on registrivälisena tuvastatud. Klõpsa \"tühista\", kui ei soovi otsida vahelejätmise segmente."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignoreeri registriväliseid/privaatsed videoid"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "See valik aeglustab veidi SponsorBlocki. Vahelejätmise segmentide hankimiseks saadetakse video ID serverisse. Kui oled mures registriväliste videote IDde internetti saatmise üle, luba see valik."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com on nüüd toetatud"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Impordi/ekspordi kõik valikud"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "See on sinu kogu seadistus JSON-formaadis. Selle hulgas on ka UserID, seega jaga seda targalt."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Määra valikud"
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "See JSON ei ole korralikult vormistatud. Sinu valikuid ei muudetud."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Saada segment"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Saada"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Katkesta"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Kustuta"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Eelvaade"
|
||||
},
|
||||
"inspect": {
|
||||
"message": "Inspekteeri"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Muuda"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Kopeeri silumisteave lõikelauale"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Lõikelauale kirjutamine ebaõnnestus"
|
||||
},
|
||||
"theKey": {
|
||||
"message": "Klahv"
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "on juba teisele tegevusele määratud. Palun vali teine klahv."
|
||||
},
|
||||
"to": {
|
||||
"message": "kuni",
|
||||
"description": "Used between segments. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"category_sponsor_description": {
|
||||
"message": "Tasulised promod, tasulised viited ja otsesed reklaamid. Pole mõeldud enesepromo või tasuta petitsioonide/autorite/veebilehtede/toodete mainimiste puhul."
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Vaheaeg/sissejuhatav animatsioon"
|
||||
},
|
||||
"category_intro_description": {
|
||||
"message": "Tegeliku sisuta intervall. Võib olla paus, seisev pilt, korduv animatsioon. Seda ei peaks kasutama üleminekutel, milles on teabega sisu."
|
||||
},
|
||||
"category_intro_short": {
|
||||
"message": "Vaheaeg"
|
||||
},
|
||||
"category_outro": {
|
||||
"message": "Lõpukaardid/-tiitrid"
|
||||
},
|
||||
"category_outro_description": {
|
||||
"message": "Tiitrid või YouTube'i lõpukaardid. Pole mõeldud informatsiooniga järelduste jaoks."
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Tegutsemise meeldetuletus (kanali tellimine)"
|
||||
},
|
||||
"category_interaction_description": {
|
||||
"message": "Lühike sisukeskne meeldetuletus anda videole meeldib, tellida kanalit või jälgida autorit. Kui see on pikk või millegi kindlaga seotud, peaks see olema enesepromo all."
|
||||
},
|
||||
"category_interaction_short": {
|
||||
"message": "Tegutsemise meeldetuletus"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Tasumata/enesepromo"
|
||||
},
|
||||
"category_selfpromo_description": {
|
||||
"message": "Sarnaneb \"sponsorile\", ent on mõeldud tasumata või enesepromo jaoks. Selle alla kuuluvad jaotised oma müüdava kauba, annetuste ja koostööpartnerite kohta."
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Muusika: mitte-muusika jaotis"
|
||||
},
|
||||
"category_music_offtopic_description": {
|
||||
"message": "Ainult muusikavideotes kasutamiseks. Sisaldab muusikavideote sissejuhatusi ja väljajuhatusi."
|
||||
},
|
||||
"category_music_offtopic_short": {
|
||||
"message": "Mitte-muusika"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Otseülekanne: annetuste ja sõnumite lugemine"
|
||||
},
|
||||
"category_livestream_messages_short": {
|
||||
"message": "Sõnumite lugemine"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Keela"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Käsitsi vahelejätmine"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Kuva mängija ajaribal"
|
||||
},
|
||||
"colorFormatIncorrect": {
|
||||
"message": "Sinu värv on sobimatult vormistatud. See peaks olema 3- või 6-numbriline 16-kümmendsüsteemis kood, arvu ees trellid."
|
||||
},
|
||||
"previewColor": {
|
||||
"message": "Värvi eelvaade",
|
||||
"description": "Referring to submissions that have not been sent to the server yet."
|
||||
},
|
||||
"seekBarColor": {
|
||||
"message": "Ajariba värv"
|
||||
},
|
||||
"category": {
|
||||
"message": "Kategooria"
|
||||
},
|
||||
"skipOption": {
|
||||
"message": "Vahelejätmise valik",
|
||||
"description": "Used on the options page to describe the ways to skip the segment (auto skip, manual, etc.)"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Luba beetatestimise server"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Sinu saadetud segmendid ja hääled EI LÄHE põhiserveri alla. Kasuta seda vaid katsetamiseks."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(nüüd)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Rohkem kategooriaid"
|
||||
},
|
||||
"chooseACategory": {
|
||||
"message": "Vali kategooria"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Kategooriaga \"{0}\" segmentide saatmiseks pead selle enne valikutes lubama. Sind suunatakse nüüd valikutesse.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Sa pead enne saatmist igale segmendile kategooria valima!"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(lõpp)"
|
||||
},
|
||||
"hiddenDueToDownvote": {
|
||||
"message": "peidetud: vastuhääl"
|
||||
},
|
||||
"hiddenDueToDuration": {
|
||||
"message": "peidetud: liiga lühike"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "Kanali ID pole veel laaditud."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "Tundub, et miski segab SponsorBlocki video andmete hankimise võimalust. See on ilmselt sinu reklaamiblokeerija. Palun vaata https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "Kui see jätkub, võib see olla põhjustatud sinu reklaamiblokeerijast. Palun vaata https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "Sunnitud kanalikontroll enne vahelejätmist"
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Kaalu valiku \"Sunnitud kanalikontroll enne vahelejätmist\" lubamist"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Sobimatu/vale ajastus"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "Vale kategooria"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "See video on muusikana kategoriseeritud. Kas oled kindel, et sellel on sponsor? Kui see on tegelikult \"mitte-muusika segment\", ava laienduse valikud ning luba see kategooria. Seejärel saad selle segmendi saata \"mitte-muusika\" kategoorias. Segaduse korral palun loe üle juhised."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "Mitu segmenti"
|
||||
},
|
||||
"guidelines": {
|
||||
"message": "Juhised"
|
||||
},
|
||||
"readTheGuidelines": {
|
||||
"message": "Loe juhiseid!!",
|
||||
"description": "Show the first time they submit or if they are \"high risk\""
|
||||
},
|
||||
"categoryUpdate1": {
|
||||
"message": "Kategooriad on siin!"
|
||||
},
|
||||
"categoryUpdate2": {
|
||||
"message": "Ava valikud, et jätta vahele vaheaegu, müüdavat kaupa jms."
|
||||
},
|
||||
"unsubmittedWarning": {
|
||||
"message": "Saatmata segmentide teatis"
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Saada teavitus, kui lahkud videost segmentidega, mis ei ole üleslaaditud"
|
||||
},
|
||||
"help": {
|
||||
"message": "Abi"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,6 @@
|
||||
"Loading": {
|
||||
"message": "درحال بارگذاری..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "دقیقه"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "ثانیه"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "هرگز نمایش نده"
|
||||
},
|
||||
@@ -99,27 +93,9 @@
|
||||
"submitCheck": {
|
||||
"message": "مطمئن هستید که میخواهید این را ثبت کنید؟"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "قرار دادن کانال در لیست سفید"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "حذف کانال از لیست سفید"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "رأی دهی به یک بخش"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "شما تا اینجا، ثبت کرده اید"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "شما دیگران را نجات دادید از "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "نمایش لیست امتیاز ها"
|
||||
},
|
||||
"here": {
|
||||
"message": "اینجا"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "حذف دفعات"
|
||||
},
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Ladataan..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuuttia"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekuntia"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Älä näytä koskaan"
|
||||
},
|
||||
@@ -85,9 +79,6 @@
|
||||
"sponsorEnd": {
|
||||
"message": "Segmentti Päättyy Nyt"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Välilehdeltä ei löytynyt YouTube-videota. Jos olet varma, että tämä on YouTube-välilehti, sulje tämä ponnahdusikkuna ja avaa se uudelleen. Jos sekään ei toimi, yritä ladata välilehti uudelleen."
|
||||
},
|
||||
"success": {
|
||||
"message": "Onnistui!"
|
||||
},
|
||||
@@ -121,33 +112,9 @@
|
||||
"submitCheck": {
|
||||
"message": "Haluatko varmasti lähettää tämän?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Lisää kanava valkoiselle listalle"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Poista kanava valkoiselta listalta"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Äänestä Segmenttiä"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Tähän mennessä, olet lähettänyt"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Olet säästänyt ihmisiltä "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Näytä tulostaulukko"
|
||||
},
|
||||
"here": {
|
||||
"message": "tässä"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Napsauta alla olevaa painiketta, kun segmentti alkaa ja päättyy tallentaaksesi ja lähettääksesi sen tietokantaan."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Vihje: Paina puolipisteen näppäintä kun video on kohdennettu ilmoittaaksesi segmentin alku/loppu ja viesti lähetettäväksi. (Tämän voi muuttaa asetuksissa)"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Tyhjennä ajat"
|
||||
},
|
||||
@@ -233,12 +200,6 @@
|
||||
"0": {
|
||||
"message": "Yhteyden aikakatkaisu. Tarkista internet-yhteytesi. Jos internetyhteytesi toimii, palvelin on todennäköisesti ylikuormittunut tai alhaalla."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Poista Sponsorblock käytöstä"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Ota SponsorBlock käyttöön"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Sinun työsi",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
@@ -252,9 +213,6 @@
|
||||
"skip": {
|
||||
"message": "Ohita"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "Ohita {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Ohitettu"
|
||||
},
|
||||
@@ -268,10 +226,7 @@
|
||||
"message": "Äänellinen Ilmoitus Ohitettaessa"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Ääni-ilmoitus ohituksessa toistaa äänen, kun segmentti ohitetaan. Jos pois päältä (tai automaattinen ohitus on pois käytöstä), ääntä ei soiteta."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Olet ohittanut "
|
||||
"message": "Ääni-ilmoitus ohittaessa toistaa äänen kun segmentti ohitetaan. Jos asetus on pois päältä (tai automaattinen ohitus on pois käytöstä), ääntä ei soiteta."
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Olet säästänyt itseltäsi "
|
||||
@@ -288,14 +243,8 @@
|
||||
"hoursLower": {
|
||||
"message": "tuntia"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Olet säästänyt ihmisiltä"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " heidän elämästään."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Tarkista status.sponsor.ajay.app palvelimen tila."
|
||||
"message": "Tarkista palvelimen tila osoitteessa status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Tuo/vie sinun UserID:si"
|
||||
@@ -346,7 +295,7 @@
|
||||
"message": "Vähimmäiskesto (sekuntia):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Segmentit, jotka ovat asetettua arvoa lyhyempiä, ei tulla ohittamaan tai näytetä soittimessa."
|
||||
"message": "Segmenttejä jotka ovat asetettua arvoa lyhyempiä ei ohiteta tai näytetä soittimessa."
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Näytä lähetä-painike"
|
||||
@@ -358,7 +307,7 @@
|
||||
"message": "SponsorBlock Palvelimen Osoite"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Osoite jota SponsorBlock käyttää lähettääkseen kutsuja palvelimelle.\nEllei sinulla ole omaa palvelin instanssia, tätä ei pitäisi muuttaa."
|
||||
"message": "Osoite jota SponsorBlock käyttää lähettääkseen kutsuja palvelimelle.\nEllei sinulla ole omaa palvelininstanssia, tätä ei pitäisi muuttaa."
|
||||
},
|
||||
"save": {
|
||||
"message": "Tallenna"
|
||||
@@ -373,7 +322,7 @@
|
||||
"message": "Oletko varma, että haluat nollata tämän?"
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ohita Listaamattomat/Yksityiset Videot"
|
||||
"message": "Ohita listaamattomat/yksityiset videot"
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com-osoitetta tuetaan nyt"
|
||||
@@ -428,7 +377,7 @@
|
||||
"message": "Sponsori"
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Väli/Intro Animaatio"
|
||||
"message": "Väli- tai introanimaatio"
|
||||
},
|
||||
"category_intro_description": {
|
||||
"message": "Aikaväli ilman varsinaista sisältöä. Voi olla tauko, staattinen kehys, toistuva animaatio. Tätä ei pitäisi käyttää siirtymisiin, jotka sisältävät tietoa."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock pour YouTube - Supprime les messages commerciaux et publicités intégrées",
|
||||
"message": "SponsorBlock pour YouTube - Supprime les publicités intégrées",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Chargement..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Secondes"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Ne plus montrer"
|
||||
},
|
||||
@@ -80,13 +74,13 @@
|
||||
"message": "Aucun segment trouvé"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Début du segement"
|
||||
"message": "Début du segment"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Fin du segment"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Ceci n'est pas un onglet YouTube, ou vous avez cliqué trop tôt. \n Si vous êtes sûr(e) que c'est un onglet YouTube, fermez cette fenêtre et réessayez."
|
||||
"message": "Aucune vidéo Youtube trouvée.\nActualisez l'onglet si il est censé y en avoir une."
|
||||
},
|
||||
"success": {
|
||||
"message": "Succès !"
|
||||
@@ -100,6 +94,9 @@
|
||||
"connectionError": {
|
||||
"message": "Erreur de connexion. Code d'erreur : "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Voulez-vous soumettre vos segments pour la vidéo"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Vous semblez avoir laissé certains segments non soumis. Retournez à cette page pour les soumettre (ils ne sont pas supprimés)."
|
||||
},
|
||||
@@ -119,31 +116,32 @@
|
||||
"message": "Êtes-vous sûr de vouloir soumettre ces segments?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Ajouter la chaîne à la liste blanche"
|
||||
"message": "Whitelister la chaîne"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Supprimer la chaîne de la liste blanche"
|
||||
"message": "Enlever la chaîne de la liste blanche"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Voter pour un segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Vous avez soumis jusqu'à présent"
|
||||
"Submissions": {
|
||||
"message": "Contributions"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Vous avez permis aux autres de passer "
|
||||
"message": "Vous avez sauvé les utilisateurs de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Consulter le classement"
|
||||
},
|
||||
"here": {
|
||||
"message": "ici"
|
||||
"message": "Classement"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Cliquez sur le bouton ci-dessous quand le segment commence puis quand il finit pour l'enregistrer et le soumettre à la base de données."
|
||||
"message": "Envoyer"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Le menu d'édition du segment apparaîtra après que vous ayez cliqué sur envoyer",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Astuce : utilisez la touche point-virgule lorsque la vidéo est sélectionnée pour enregistrer le début et la fin d'un segment commercial; utilisez la touche guillemet pour le soumettre. (Les touches peuvent être modifiées dans les options)"
|
||||
"message": "Astuce : Vous pouvez configurer des raccourcis clavier dans les options"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Supprimer les temps"
|
||||
@@ -154,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Votre pseudo est inscrit dans le classement public pour afficher vos contributions. Le consulter"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Pseudonyme"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Choisir un pseudonyme"
|
||||
},
|
||||
@@ -193,9 +194,31 @@
|
||||
"whatDeleteButton": {
|
||||
"message": "Il s'agit du bouton qui permet de supprimer tous les segments commerciaux depuis le lecteur YouTube."
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Activer le suivi du nombre de sauts de segments"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Cette fonctionnalité permet de suivre les segments que vous avez sautés pour faire savoir aux utilisateurs à quel point leur soumission a aidé les autres et est utilisée comme donnée avec les votes positifs pour s'assurer que des spams n'entre pas dans la base de données. L'extension envoie un message au serveur chaque fois que vous sautez un segment. Il est à espérer que la plupart des gens ne modifient pas ce paramètre pour que les données sur le nombre d'affichage soient exacts :)"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Requête par préfixe du hash"
|
||||
},
|
||||
"whatQueryByHashPrefix": {
|
||||
"message": "Au lieu de demander des segments au serveur à l'aide de l'identifiant de la vidéo, les 4 premiers caractères du hash de l'identifiant de la vidéo sont envoyés. Ce serveur renverra les données pour toutes les vidéos ayant des hash similaires."
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Récupérer les segments sur les nouvelles vidéos"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Si la vidéo est nouvelle et qu'aucun segment n'a été trouvé, ils seront réactualisés toutes les quelques minutes pendant le visionnage."
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Afficher la notification"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock vous permet de passer les sponsors, les intros, les outros, les rappels d'abonnement et autres parties ennuyeuses des vidéos YouTube. SponsorBlock est une extension de navigateur qui permet à n'importe qui de soumettre les temps de début et de fin des segments sponsorisés et d'autres segments de vidéos YouTube. Une fois qu'une personne a soumis ces informations, toutes les autres personnes possédant cette extension passeront directement les segments sponsorisés. Vous pouvez également sauter les sections non musicales des vidéos musicales.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site web",
|
||||
"description": "Used on Firefox Store Page"
|
||||
@@ -228,10 +251,10 @@
|
||||
"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"
|
||||
"message": "Le saut de segment est activé"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Activer SponsorBlock"
|
||||
"message": "Le saut de segment est désactivé"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Votre travail",
|
||||
@@ -289,10 +312,7 @@
|
||||
"message": "heures"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Vous avez économisé"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " aux autres."
|
||||
"message": "Les utilisateurs ont gagné"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Vérifiez status.sponsor.ajay.app pour le status du serveur."
|
||||
@@ -354,6 +374,9 @@
|
||||
"minDuration": {
|
||||
"message": "Durée minimale (en secondes):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Les segments plus courts que la valeur fixée ne seront pas sautés ou 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 ?"
|
||||
},
|
||||
@@ -381,9 +404,15 @@
|
||||
"areYouSureReset": {
|
||||
"message": "Voulez-vous vraiment remettre à zéro ?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "La vidéo a été détectée comme étant non répertoriée. Cliquez sur annuler si vous ne voulez pas vérifier les segments sautés."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignorer les vidéos non listées"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Ce réglage ralentira légèrement SponsorBlock. Pour sauter des segments, il faut envoyer l'ID de la vidéo au serveur. Si vous craignez que des identifiants de vidéo non répertoriés soient envoyés sur Internet, activez cette option."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com est maintenant pris en charge"
|
||||
},
|
||||
@@ -455,7 +484,7 @@
|
||||
"message": "Entracte/Animation d'intro"
|
||||
},
|
||||
"category_intro_description": {
|
||||
"message": "Un intervalle sans réel contenu, comme une pause, une image statique ou une animation répétitive. Ne doit pas être utilisé pour les transitions avec des informations ou pour les vidéos musicales."
|
||||
"message": "Un intervalle sans réel contenu, comme une pause, une image statique ou une animation répétitive. Ne doit pas être utilisé pour les transitions avec des informations."
|
||||
},
|
||||
"category_intro_short": {
|
||||
"message": "Entracte"
|
||||
@@ -464,7 +493,7 @@
|
||||
"message": "Générique de fin"
|
||||
},
|
||||
"category_outro_description": {
|
||||
"message": "Crédits ou quand les écrans de fin Youtube apparaissent. Pas pour les conclusions qui contiennent des informations."
|
||||
"message": "Crédits ou quand les annotations Youtube de fin apparaissent. Pas pour les conclusions qui contiennent des informations."
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Rappel d'interaction (abonnement)"
|
||||
@@ -565,7 +594,7 @@
|
||||
"message": "Forcer la vérification du canal avant de passer"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "Par défaut, passer les segments avant même de savoir à quelle chaîne appartient la vidéo. Par défaut, certains segments au début des vidéos des chaînes qui sont sur la liste blanche peuvent être passés. Activer cette option empêchera ça mais passer les segments aura un délai car obtenir l'id des chaînes peut prendre du temps. Ce délai peut ne pas être remarqué si votre connexion est rapide."
|
||||
"message": "Par défaut, passer les segments avant même de savoir à quelle chaîne appartient la vidéo. Par défaut, les segments en début des vidéos des chaînes sur liste blanche peuvent être passés. Activer cette option empêchera cela mais passer les segments aura un délai, car obtenir l'id des chaînes peut prendre du temps. Ce délai sera imperceptible si votre connexion est rapide."
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Envisagez d'activer \"Forcez la vérification de la chaîne avant de passer\""
|
||||
@@ -577,7 +606,7 @@
|
||||
"message": "Mauvaise catégorie"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "Cette vidéo est catégorisée comme de la musique. Êtes-vous sûr qu'elle est sponsorisée ? S'il s'agit en fait d'un \"segment non-musical\", allez dans les options de l'extension et activez cette catégorie. Ensuite, vous pourrez soumettre ce segment en tant que \"segment non-musical\" au lieu de sponsor. Lisez les \"Guidelines\" en cas de confusion."
|
||||
"message": "Cette vidéo est catégorisée comme de la musique. Êtes-vous sûr qu'elle est sponsorisée ? S'il s'agit en fait d'un \"segment non-musical\", allez dans les options de l'extension et activez cette catégorie. Ensuite, vous pourrez soumettre ce segment en tant que \"segment non-musical\" au lieu de sponsor. Lisez les instructions en cas de confusion."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "Plusieurs segments"
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Učitavanje..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minute"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekunde"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nikad ne prikazuj"
|
||||
},
|
||||
@@ -85,9 +79,6 @@
|
||||
"sponsorEnd": {
|
||||
"message": "Isječak završava sada"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "YouTube video nije pronađen na ovoj kartici. Ako si siguran da je ovo YouTube kartica, zatvori ovaj okvir i ponovno ga otvori. Ako to ne radi, probaj ponovno učitati karticu."
|
||||
},
|
||||
"success": {
|
||||
"message": "Uspjeh!"
|
||||
},
|
||||
@@ -118,33 +109,9 @@
|
||||
"submitCheck": {
|
||||
"message": "Jesi li siguran da želiš unijeti ovo?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanal na popis dopuštenih"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Makni kanal s popisa dopuštenih"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Glasaj za isječak"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Do sada si podnio"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Sačuvao si ljude od "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Pregledaj tablicu bodova"
|
||||
},
|
||||
"here": {
|
||||
"message": "ovdje"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klikni gumb ispod kada isječak započinje i završava kako bi ga zabilježio i unio u bazu podataka."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Savjet: Pritisni tipku točka-zarez dok si fokusiran na video kako bi zabilježio početak i kraj isječka te podnio isječak. (Ovo se može promijeniti u postavkama)"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Očisti vremena"
|
||||
},
|
||||
|
||||
@@ -1,31 +1,56 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponorBlock YouTube-ra - Szponzorok kihagyása",
|
||||
"message": "SponorBlock YouTube-ra - Szponzorok átugrására",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Szponzorok, feliratkozás-kérelmek és több átugrása a YouTube videókon. Jelöljön meg szponzorokat videókon amiket néz, hogy mások idejét is megtakarítsa.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Szerver: Ez a kérés érvénytelen"
|
||||
},
|
||||
"429": {
|
||||
"message": "Túl sok szponzoridőt jelölt be ezen a videón. Biztos benne, hogy van ennyi?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Ez már korábban be lett küldve"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "A csatorna az engedélyezőlistára került!"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "szegmens"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "részletek"
|
||||
"message": "szegmensek"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Részlet felszavazása"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Bejelentés"
|
||||
"message": "Jelentés"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Szegmens jelentése helytelenként."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Elvetés"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Betöltés..."
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Sose mutassa"
|
||||
"message": "Ne mutassa többé"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Kattintson a visszaugrásra, hogy visszakerüljön oda, ahonnan ugrott."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Kihagyás visszavonása"
|
||||
"message": "Visszaugrás"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Újra-kihagyás"
|
||||
"message": "Újra-átugrás"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Szüneteltetve"
|
||||
@@ -33,29 +58,80 @@
|
||||
"manualPaused": {
|
||||
"message": "Időzítő megállítva"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Ahhoz, hogy értékeket szerkesszen, vagy töröljön kattintson az info gombra, vagy nyissa meg a bővítmény felugró ablakát a bővítmény ikonjával a jobb felső sarokban."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Biztosan törölni akarja?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Hiba történt a szponzoridők bejelentésekor. Kérjük, próbálja újra."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Ennek a videónak már vannak szegmensei az adatbázisban!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nem találhatóak szegmensek"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Részlet kezdődik most"
|
||||
"message": "Szegmens eleje"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Részlet végződik most"
|
||||
"message": "Szegmens vége"
|
||||
},
|
||||
"success": {
|
||||
"message": "Siker!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Szavaztál!"
|
||||
"message": "Szavazott!"
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Úgy tűnik a szerver nem működik. Kérjük, mihamarabb értesítse a fejlesztőket."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Kapcsolódási probléma merült fel. Error kód: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Szeretné beküldeni a szegmenst ehhez a videóhoz:"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Úgy tűnik pár megjelölt szegmenst beküldetlenül hagyott. Lépjen vissza az oldalra, hogy beküldhesse őket (nem kerültek törlésre)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Szegmensek törlése"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "SponsorBlock felugró ablak megnyitása"
|
||||
},
|
||||
"closePopup": {
|
||||
"message": "Doboz bezárása"
|
||||
"message": "Felugró ablak bezárása"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Szegmens beküldése"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Biztosan be akarja küldeni?"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Szavazz egy részleten"
|
||||
"message": "Szavazzon a szegmensről"
|
||||
},
|
||||
"here": {
|
||||
"message": "itt"
|
||||
"clearTimesButton": {
|
||||
"message": "Időpontok törlése"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Időpontok megadása"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Ezt használja a nyilvános ranglistán, hogy megmutassa mennyit járult hozzá. Nézze meg"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Felhasználónév megadása"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Csatlakozzon a hivatalos discord szerverhez, hogy javaslatokat és visszajelzést adhasson!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Rejtsd el ezt"
|
||||
"message": "Elrejtés"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Beállítások"
|
||||
@@ -67,7 +143,7 @@
|
||||
"message": "Gombok elrejtése a YouTube lejátszón"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ez elrejti a kihagyásos részletek létrehozásához szükséges gombokat a YouTube lejátszón."
|
||||
"message": "Ez elrejti az átugrandó szegmensek megjelöléséhez használt gombokat a YouTube lejátszón."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Info gomb mutatása a YouTube lejátszón"
|
||||
@@ -76,7 +152,7 @@
|
||||
"message": "Info gomb elrejtése a YouTube lejátszón"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Ez a gomb az, ami feldob egy dobozt a YouTube oldalon."
|
||||
"message": "Ez a gomb felhoz egy felugró dobozt a YouTube oldalon."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Törlés gomb elrejtése a YouTube lejátszón"
|
||||
@@ -84,6 +160,34 @@
|
||||
"showDeleteButton": {
|
||||
"message": "Törlés gomb mutatása a YouTube lejátszón"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ez egy gomb a lejátszón, ami törli az összes beküldetlen szegmensét a jelenlegi videón."
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Átugrás-számláló követés bekapcsolása"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ez a funkció követi, mely szegmenseket ugrotta át, hogy más felhasználók megtudhassák mennyit segítettek a bejelentéseik és a szavazatokkal együtt egy mértékegységként van használva, hogy ne kerülhessen spam az adatbázisba. A bővítmény küld egy üzenetet a szervernek, minden alkalommal, mikor átugrik egy szegmenst. Remélhetőleg nem sokan állítják át ezt a beállítást, hogy a számok pontosak maradhassanak. :)"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Lekérdezés Hash előtaggal"
|
||||
},
|
||||
"whatQueryByHashPrefix": {
|
||||
"message": "A szerverről videoID helyett, a videoID hash első négy karaktere lesz elküldve szegmenslekéréskor. A szerver visszaküldi az összes hasonló hashel rendelkező videó adatait."
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Szegmensek újrakeresése új videókon"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Ha a videó új, és még nem találhatóak szegmensek, a bővítmény pár percenkét újra keresi őket, miközben nézi."
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Értesítés megjelenítése ismét"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "A SponsorBlock-al átugorhatja a szponzorokat, introkat, outrokat, feliratkozás emlékeztetőket és a YouTube videók többi idegesítő részeit. A SponsorBlock egy közösség által vezérelt böngészőbővítmény, ami lehetővé tesz bárkit arra, hogy megjelölhesse egy szponzor vagy más szegmens kezdő és végpontjait. Ha megosztja ezt az információt, mindenki más ennek a bővítménynek a birtokában egyenesen átugorja majd ezt a szponzorszegmenst. Emellett például a zene videók nem-zene részei is átugorhatóak.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Weboldal",
|
||||
"description": "Used on Firefox Store Page"
|
||||
@@ -92,45 +196,68 @@
|
||||
"message": "Forráskód",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock kikapcsolása"
|
||||
"noticeUpdate": {
|
||||
"message": "Az értesítést frissítettük!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock bekapcsolása"
|
||||
"noticeUpdate2": {
|
||||
"message": "Ha még mindig nem tetszik, kattintson a ne mutassa többé gombra.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Billentyű beállítása a szegmenskezdés gombhoz"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Billentyű beállítása a beküldés gombhoz"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Válasszon billentyűt azzal, hogy lenyomja"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "A funkció erre a billentyűre lett állítva: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Kapcsolati időtúllépés. Ellenőrizze az internetkapcsolatot. Ha az internet működik, a kiszolgáló valószínűleg túlterhelt vagy leállt."
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Te munkád",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Úgy tűnik, hogy a szerver túlterhelt. Néhány másodperc múlva próbálkozzon újra."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Hibakód: "
|
||||
},
|
||||
"skip": {
|
||||
"message": "Kihagy"
|
||||
"message": "Átugrás"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "Kihagyod {0}-t?"
|
||||
"message": "Átugorja ezt: {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Kihagyva"
|
||||
"message": "Átugorva"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Auto kihagyás kikapcsolása"
|
||||
"message": "Auto átugrás kikapcsolása"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Auto kihagyás bekapcsolása"
|
||||
"message": "Auto átugrás bekapcsolása"
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Hangjelzés kihagyáskor"
|
||||
"message": "Hangjelzés átugráskor"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Hangjelzés kihagyáskor egy hangot fog játszani amikor kihagyunk egy részletet. Ha ez ki van kapcsolva (vagy az auto kihagyás), nem lesz semmilyen hang lejátszva."
|
||||
"message": "A hangjelzés átugráskor lejátszik egy hangot minden alkalommal amikor átugrik egy szegmenst. Ha kikapcsolja (vagy az auto átugrás ki van kapcsolva) nem lesz hangjelzés lejátszva."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Te kihagytál "
|
||||
"showTimeWithSkips": {
|
||||
"message": "Idő megtekintése az átugrandók nélkül"
|
||||
},
|
||||
"showTimeWithSkipsDescription": {
|
||||
"message": "Ez az idő zárójelben jelenik meg az aktuális idő mellett a keresősáv alatt. Megmutatja a videó teljes időtartamát, levonva a szegmenseket. Beletartoznak a csak \"Megjelenítés a keresősávban\" jelöléssel ellátott szegmensek is."
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Te mentettél magadnak "
|
||||
"message": "Megtakarított magának "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "perc"
|
||||
@@ -144,50 +271,128 @@
|
||||
"hoursLower": {
|
||||
"message": "óra"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Megmentettél embereknek"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " az életüknek."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Nézd meg status.sponsor.ajay.app-t a szerver állapotához."
|
||||
"message": "A szerver állapotához tekintse meg a status.sponsor.ajay.app oldalt."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "UserID importálása / exportálása"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ezt titokban kell tartani. Olyan, mint egy jelszó, nem szabad senkivel megosztania. Ha valakinek megvan, megszemélyesítheti Önt."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "UserID beállítása"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Figyelem: A UserID megváltoztatása végleges. Biztosan szeretné megtenni? Minden esetben készítsen biztonsági másolatot a régiről."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Készítette"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto kihagyás"
|
||||
"message": "Auto átugrás"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Jelezzen ha egy részlet ki van hagyva"
|
||||
"message": "Jelezzen, ha egy szegmens át lett ugorva"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jelenleg állítva van:"
|
||||
"message": ". Jelenleg erre van állítva:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Invidious támogatása"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Az Invidious (invidio.us) egy harmadik fél által készített YouTube kliens. A támogatás engedélyezéséhez el kell fogadnia további engedélyeket. NEM működik inkognitómódban a Chrome-on vagy más Chromium-változatokon."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Invidious támogatás engedélyezése, autoátugrás kikapcsolása, gombok eltűntetése és több."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Invidious példány hozzáadása"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Egyedi Invidious példány hozzáadása. CSAK a domain-nel kell formázni. Például: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Hozzáadás"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Érvénytelen domain. CSAK a domain részt tartalmazhatja. Például: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Invidious példányok listájának visszaállítása"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Épp visszaállítja az Invidious példányok listát"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Jelenlegi példányok:"
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimális időtartam (másodpercekben):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "A beállított értéknél rövidebb szegmenseket nem ugorja át és nem jeleníti meg a lejátszó."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "A következő szegmens rövidebb, mint az Ön által beállított minimális időtartam. Ez azt jelentheti, hogy már beküldhették, csak emiatt az opció miatt Önnek figyelmen kívül marad. Biztosan beküldi?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Feltöltés gomb megjelenítése"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Ez a gomb a YouTube lejátszón jelenik meg, miután kiválasztott egy időtartamot és készen áll a beküldésre."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlock szerver címe"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "A SponsorBlock által használt cím a szerverre történő hívások kezdeményezésére szolgál.\nHacsak nincs saját szerverpéldánya, ezt nem szabad megváltoztatni."
|
||||
},
|
||||
"save": {
|
||||
"message": "Mentés"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Visszaállítás"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "A cím helytelenül van formázva. Győződjön meg róla, hogy http:// vagy https:// van az elején, és nem fordított perjeleket használ."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Biztosan vissza szeretné állítani?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Videó észlelve nem listázottként. Kattintson a Mégse gombra, ha nem akar ellenőrizni átugorható szegmensek után."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Nem listázott/Privát videók ignorálása"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Ez a beállítás kissé lelassíthatja a SponsorBlockot. A szegmensek átugrásához szükséges, hogy a videoID el legyen küldve a szerverre. Ha aggódik az interneten küldött nem listázott videóazonosítók küldése miatt, kapcsolja be ezt a funkciót."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "az m.youtube.com már támogatott"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Összes beállítás importálása / exportálása"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Ez az össze beállítása JSON-ban. Ebbe bele tartozik a userID-ja, szóval csak ésszel ossza meg."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Beállítások"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Figyelem: Az beállítások megváltoztatása végleges, és tönkreteheti a bővítményét. Biztosan meg szeretné tenni? Készítsen egy biztonsági mentést a régi beállításairól, biztos, ami biztos."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "Ez a JSON helytelenül van formázva. A beállításai nem lettek megváltoztatva."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Szegmens beküldése"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Elküld"
|
||||
"message": "Beküld"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Mégse"
|
||||
@@ -204,14 +409,69 @@
|
||||
"edit": {
|
||||
"message": "Szerkesztés"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Hibakeresési információ másolása a vágólapra"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Hiba a vágólapra másoláskor"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Információt másol a vágólapra, amit megadhat egy fejlesztőnek, ha bejelent egy hibát, vagy egy fejlesztő kéri öntől. Az érzékeny információkat, például a felhasználói azonosítót, az engedélyezőlistán szereplő csatornákat és az egyéni szerver címét eltávolítottuk. Azonban tartalmaz olyan információkat, mint a böngésző, az operációs rendszer és a bővítmény verziószáma. "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "A hibakeresési információ másolva lett a vágólapjára. Nyugodtan távolítson el belőle olyan információkat, amiket nem szívesen osztana meg. Mentse el szöveges fájlként, vagy másolja a hibajelentésbe."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "A kulcs"
|
||||
"message": "A billentyű"
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "már máshoz van állítva. Kérem, válasszon egy másik billentyűt."
|
||||
},
|
||||
"to": {
|
||||
"message": "-tól eddig:",
|
||||
"description": "Used between segments. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Szponzor"
|
||||
},
|
||||
"category_sponsor_description": {
|
||||
"message": "Fizetett promóció, vagy közvetlen reklám. Nem ön-promóció vagy ingyenes ajánlat (/shoutout) emberekről/termékekről/weboldalakról amik tetszenek nekik."
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Megszakítás/Intro animáció"
|
||||
},
|
||||
"category_intro_description": {
|
||||
"message": "Egy részlet tartalom nélkül. Lehet szünet, álló képkocka, vagy ismétlődő animáció. Nem használandó információt tartalmazó átmeneteknél."
|
||||
},
|
||||
"category_intro_short": {
|
||||
"message": "Megszakítás"
|
||||
},
|
||||
"category_outro": {
|
||||
"message": "Záróképernyő/ Stáblista"
|
||||
},
|
||||
"category_outro_description": {
|
||||
"message": "Stáblista, vagy amikor megjelennek a YouTube zárókártyák. Nem használandó információt tartalmazó következtetésekkor."
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Emlékeztető (Feliratkozás)"
|
||||
},
|
||||
"category_interaction_description": {
|
||||
"message": "Egy rövid emlékeztető arról, hogy likeoljunk, iratkozzunk fel, vagy kövessük a tartalom közben. Ha hosszabb szakasz, vagy egy adott témáról van, inkább a az ön-promóció alá tartozik."
|
||||
},
|
||||
"category_interaction_short": {
|
||||
"message": "Szünet"
|
||||
"message": "Emlékeztető"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Nem fizetett/ön-promóció"
|
||||
},
|
||||
"category_selfpromo_description": {
|
||||
"message": "Hasonló a szponzorhoz, de nem fizetett vagy ön-promóció. Beletartozik a saját ruhaáru, adományok, vagy infó arról hogy kivel működtek együtt."
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Zene: nem-zene szegmens"
|
||||
},
|
||||
"category_music_offtopic_description": {
|
||||
"message": "Csak zenei videókon. Beletartoznak a zenei videók intro és outro részei is."
|
||||
},
|
||||
"category_music_offtopic_short": {
|
||||
"message": "Nem-Zene"
|
||||
@@ -220,24 +480,39 @@
|
||||
"message": "Élő adás: Adomány / üzenet olvasások"
|
||||
},
|
||||
"category_livestream_messages_short": {
|
||||
"message": "Üzenet olvasás"
|
||||
"message": "Üzenet beolvasása"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Kikapcsol"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Manuális kihagyás"
|
||||
"message": "Átugrás manuálisan"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Keresősáv megjelenítése"
|
||||
"message": "Megjelenítés a keresősávban"
|
||||
},
|
||||
"colorFormatIncorrect": {
|
||||
"message": "A szín helytelenül van formázva. Egy 3 vagy 6 számjegyből álló hex kódnak kell lennie egy kettőskereszttel az elején."
|
||||
},
|
||||
"previewColor": {
|
||||
"message": "Előnézeti szín",
|
||||
"description": "Referring to submissions that have not been sent to the server yet."
|
||||
},
|
||||
"seekBarColor": {
|
||||
"message": "Keresősáv színe"
|
||||
},
|
||||
"category": {
|
||||
"message": "Kategória"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Bétateszt szerver bekapcsolása"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "A hozzájárulásai/szavazatai NEM FOGNAK SZÁMÍTANI a fő szerveren. Csak tesztelésre használja."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Az összes hozzájárulás/szavazat NEM FOG SZÁMÍTANI a fő szerverhez, amíg a tesztszerverhez kapcsolódik. Győződjön meg róla, hogy ki van kapcsolva, ha valódi hozzájárulásokat szeretne megosztani."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Most)"
|
||||
},
|
||||
@@ -245,7 +520,10 @@
|
||||
"message": "További kategóriák"
|
||||
},
|
||||
"chooseACategory": {
|
||||
"message": "Válassz egy kategóriát"
|
||||
"message": "Válasszon kategóriát"
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Minden szegmenshez kategóriát kell választania beküldés előtt!"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Vége)"
|
||||
@@ -257,7 +535,22 @@
|
||||
"message": "elrejtve: túl rövid"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "Csatorna azonosító nem töltődött be."
|
||||
"message": "A csatorna azonosító még nem töltődött be."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "Valami meggátolja a SponsorBlockot a videó adatainak megszerzésében. Valószínűleg az ad-blockere. Kérem ellenőrizze: https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "Ha ez folyamatosan előfordul, lehet hogy az ad-blockere okozza. Kérem nézzen utána: https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "Csatorna ellenőrzése átugrás előtt"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "Alapértelmezett állapotban, a bővítmény átugorhat szegmenseket, mielőtt tudná melyik csatornán van. Alapból ezért, néhány szegmens, ami a videók legelején van, engedélyezett csatornákon is átugródhat. Ennek a bekapcsolásával ez elkerülhető, de minden átugrás előtt lesz egy kis késleltetés, hiszen a channelID megszerzéséhez elkell egy kis idő. Ez a késleltetés akár észrevehetetlen is lehet, ha elég gyors a kapcsolata."
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Gondolja át a \"Csatorna ellenőrzése átugrás előtt\" bekapcsolását"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Helytelen/rossz időzítés"
|
||||
@@ -266,19 +559,28 @@
|
||||
"message": "Hibás kategória"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "Ez a videó zeneként van kategorizálva. Biztos vagy benne, hogy ennek van szponzorja? Ha ez valójában egy \"nem-zene részlet\", nyisd meg a bővítmény beállításait és kapcsold be ezt a kategóriát. Ezt követően elküldheted ezt a részletet \"Nem-Zene\"-ként szponzor helyett. Olvasd el az irányelveket, ha nem érted."
|
||||
"message": "Ez a videó zeneként van kategorizálva. Biztos benne, hogy ennek van szponzora? Ha ez valójában egy \"nem-zene szegmens\", nyissa meg a bővítmény beállításait és kapcsolja be azt a kategóriát. Ezt követően elküldheti ezt a szegmenst \"nem-zene\"-ként szponzor helyett. Amennyiben nem érti, kérjük olvassa el az irányelveket."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "Több részlet"
|
||||
"message": "Több szegmens"
|
||||
},
|
||||
"guidelines": {
|
||||
"message": "Irányelvek"
|
||||
},
|
||||
"readTheGuidelines": {
|
||||
"message": "Olvasd el az irányelveket!!",
|
||||
"message": "Olvassa el az irányelveket!!",
|
||||
"description": "Show the first time they submit or if they are \"high risk\""
|
||||
},
|
||||
"categoryUpdate1": {
|
||||
"message": "Itt vannak a kategóriák!"
|
||||
},
|
||||
"categoryUpdate2": {
|
||||
"message": "Nyissa meg a beállításokat, hogy átugorhasson introkat, outrokat stb."
|
||||
},
|
||||
"unsubmittedWarning": {
|
||||
"message": "Beküldetlen szegmens értesítő"
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Küldjön egy értesítést, ha elhagy egy videót amelyen beküldetlen szegmensek vannak"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Memuat..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Menit"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Detik"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Jangan tampilkan"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segmen Berakhir Sekarang"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Tidak ada video YouTube yang ditemukan di tab ini. Jika anda tahu ini merupakan tab YouTube, tutup popup ini dan buka lagi. Jika masih tidak berfungsi, coba muat ulang tab."
|
||||
"message": "Video YouTube tidak ditemukan.\nJika ini salah, segarkan tab."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukses!"
|
||||
@@ -122,31 +116,32 @@
|
||||
"message": "Apakah anda yakin ingin mengirim ini?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Daftar-putihkan Channel"
|
||||
"message": "Saluran daftar putih"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Hapus Channel Dari Daftar Putih"
|
||||
"message": "Hapus saluran dari daftar putih"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Beri Segmen Vote"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Sejauh ini, anda sudah mengirim"
|
||||
"Submissions": {
|
||||
"message": "Kiriman"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Anda sudah menghemat waktu orang dari "
|
||||
"message": "Anda telah menyelamatkan orang dari "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Lihat papan peringkat"
|
||||
},
|
||||
"here": {
|
||||
"message": "disini"
|
||||
"message": "Papan peringkat"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klik tombol dibawah saat segmen dimulai dan berakhir untuk direkam lalu dikirim ke basis data."
|
||||
"message": "Kirim"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Pengeditan bagian akan muncul setelah anda mengklik kirim",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Petunjuk: Tekan tombol titik koma saat terfokus pada video untuk melaporkan awal/akhir dari segmen untuk dikirim. (Bisa diganti di pengaturan)"
|
||||
"message": "Petunjuk: Anda dapat mengatur keybinds untuk dikirim dalam opsi"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Hapus Waktu"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Ini digunakan di halaman statistik publik untuk menampilkan berapa banyak anda berkontribusi. Lihat disini"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Nama pengguna"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Atur Nama Pengguna"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Koneksi Timeout. Cek koneksi internet anda. Jika internet anda berfungsi, server mungkin kewalahan atau down."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Nonaktifkan SponsorBlock"
|
||||
"message": "Melewati diaktifkan"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Aktifkan SponsorBlock"
|
||||
"message": "Melewati dinonaktifkan"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Hasil Kerja Anda",
|
||||
@@ -296,7 +294,7 @@
|
||||
"message": "Waktu ini muncul di dalam kurung disamping waktu asli di bilah waktu. Ini menunjukkan durasi total video yang tidak termasuk segmen apapun. Ini termasuk segmen yang ditandai hanya \"Tampilkan Di Bilah Waktu\"."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Anda sudah melewati "
|
||||
"message": "Anda telah melewatkan "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Anda sudah menghemat waktu "
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "jam"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Anda sudah menghemat waktu orang lain"
|
||||
"message": "Anda telah menyelamatkan orang"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " dari hidup mereka."
|
||||
"message": " dalam hidup mereka"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Cek status.sponsor.ajay.app untuk status server."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Pilih Kategori"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Untuk mengirimkan segmen dengan kategori \"{0}\", Anda harus mengaktifkannya di opsi. Anda akan diarahkan ke opsi sekarang.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Anda harus memilih kategori untuk semua segmen yang anda kirimkan!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Tampilkan notifikasi saat kamu meninggalkan video dengan segmen yang belum diunggah"
|
||||
},
|
||||
"help": {
|
||||
"message": "Bantuan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Caricamento..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuti"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Secondi"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Non mostrare più"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Il Segmento Termina Ora"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Probabilmente questa non è una scheda di YouTube, oppure hai cliccato troppo presto. \nSe sei sicuro di essere in una scheda di YouTube,\n riapri questo popup."
|
||||
"message": "Nessun video YouTube trovato.\nSe questo non è corretto, ricarica la scheda."
|
||||
},
|
||||
"success": {
|
||||
"message": "Successo!"
|
||||
@@ -121,32 +115,27 @@
|
||||
"submitCheck": {
|
||||
"message": "Sei sicuro di volerlo inviare?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Aggiungi Canale alla Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Rimuovi Canale dalla Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vota un Segmento"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Fino ad ora hai inviato"
|
||||
"Submissions": {
|
||||
"message": "Iscrizioni"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Hai salvato le persone da "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Guarda la classifica"
|
||||
},
|
||||
"here": {
|
||||
"message": "qui"
|
||||
"message": "Classifica"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Premi il pulsante in basso quando il segmento inizia e finisce per registrarlo ed inviarlo al database."
|
||||
"message": "Invia"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "La modifica della sezione comparirà dopo aver cliccato Iscriviti",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Suggerimento: Premi il pulsante 'punto e virgola' mentre sei concentrato su un video, per segnalare l'inizio e la fine di un segmento e la relativa citazione da inviare. (Questo può essere modificato nelle opzioni)"
|
||||
"message": "Suggerimento: Puoi configurare combinazioni di tasti per l'inserimento nelle opzioni"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Cancella Minutaggi"
|
||||
@@ -157,6 +146,9 @@
|
||||
"publicStats": {
|
||||
"message": "Viene utilizzato nelle pagine delle statistiche pubbliche che mostrano quanto hai contribuito. Vedi"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Nome Utente"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Imposta Username"
|
||||
},
|
||||
@@ -203,16 +195,16 @@
|
||||
"message": "Questa funzionalità tiene traccia dei segmenti che hai saltato, per far sapere agli utenti quanto il loro contributo abbia aiutato gli altri e sia stato utilizzato come metrica insieme ai voti positivi, per garantire che lo spam non entri nel database. L'estensione invierà un messaggio al server ogni volta che salterai un segmento. Si spera che la maggior parte delle persone non modifichino questa impostazione, in modo da non intaccare l'accuratezza dei numeri di visualizzazione. :)"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Query Del Prefisso di Hash"
|
||||
"message": "Ricerca tramite prefisso hash"
|
||||
},
|
||||
"whatQueryByHashPrefix": {
|
||||
"message": "Invece di richiedere i segmenti dal server usando il videoID, i primi 4 caratteri dell'hash del videoID sono inviati. Questo server reinvierà i dati per tutti i video con hash simili."
|
||||
"message": "Invece di richiedere segmenti dal server utilizzando l'Id video, vengono inviati i primi 4 caratteri dell'hash dell'ID video. Questo server invierà i dati per tutti i video con hash simili."
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Riprendi Segmenti Sui Nuovi Video"
|
||||
"message": "Ricarica I Segmenti Su Nuovi Video"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Se il video è nuovo e non ci sono segmenti al suo interno, continuerà a recuperare ogni qualche minuto mentre lo guardi."
|
||||
"message": "Se il video è nuovo, e non risultano esserci segmenti, questi continueranno ad essere ricaricati dopo pochi minuti mentre guardi il video."
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Mostra di Nuovo l'Avviso"
|
||||
@@ -253,10 +245,10 @@
|
||||
"message": "Timeout della connessione. Controlla la tua connessione a Internet. Se internet sta funzionando, il server è probabilmente sovraccarico oppure giù."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Disabilita SponsorBlock"
|
||||
"message": "Salta abilitato"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Abilita SponsorBlock"
|
||||
"message": "Salta disabilitato"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Il Tuo Lavoro",
|
||||
@@ -314,10 +306,10 @@
|
||||
"message": "ore"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Hai salvato alle persone"
|
||||
"message": "Hai salvato le persone"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " delle loro vite."
|
||||
"message": " delle loro vite"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Controlla status.sponsor.ajay.app per lo stato del server."
|
||||
@@ -634,5 +626,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Invia una notifica quando lasci un video con segmenti non caricati"
|
||||
},
|
||||
"help": {
|
||||
"message": "Aiuto"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,6 @@
|
||||
"Loading": {
|
||||
"message": "読み込み中..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "分"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "秒"
|
||||
},
|
||||
"unskip": {
|
||||
"message": "スキップしない"
|
||||
},
|
||||
@@ -39,15 +33,6 @@
|
||||
"closePopup": {
|
||||
"message": "ポップアップを閉じる"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "ホワイトリストからチャンネルを削除"
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "リーダーボードを表示"
|
||||
},
|
||||
"here": {
|
||||
"message": "こちら"
|
||||
},
|
||||
"Options": {
|
||||
"message": "オプション"
|
||||
},
|
||||
@@ -71,12 +56,6 @@
|
||||
"message": "ソースコード",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock を無効にする"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock を有効にする"
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "エラーコード: "
|
||||
},
|
||||
@@ -98,9 +77,6 @@
|
||||
"audioNotification": {
|
||||
"message": "オーディオ通知をスキップ"
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "スキップしました "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "分"
|
||||
},
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "로딩 중..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "분"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "초"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "보지 않기"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "광고 구간 끝"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "현재 페이지에서 YouTube 영상을 찾지 못하였습니다. 이 페이지에 YouTube 영상이 있는 경우, 이 팝업을 닫고 다시 열어주세요. 그래도 이 팝업이 바뀌지 않는 경우, 페이지를 새로고침하세요."
|
||||
"message": "찾은 유튜브 비디오가 없습니다.\n이 것이 틀리다면, 텝을 새로고침 하세요."
|
||||
},
|
||||
"success": {
|
||||
"message": "성공!"
|
||||
@@ -122,32 +116,14 @@
|
||||
"message": "정말로 제출하시겠습니까?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "채널을 화이트리스트에 추가하기"
|
||||
"message": "화이트리스트 체널"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "채널을 화이트리스트에서 삭제하기"
|
||||
"message": "항목을 화이트리스트에서 삭제하기"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "구간 투표"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "지금까지 제출한 구간:"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "사람을 다음에서 구했습니다 "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "리더보드 보기"
|
||||
},
|
||||
"here": {
|
||||
"message": "링크"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "구간이 시작 및 종료될 때 아래의 버튼을 눌러 구간을 기록하고 데이터베이스에 제출하세요."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "참고: 영상 내에서 쉼표 키를 눌러서 초점을 맞추어서 시작/끝을 제보하고 따옴표로 제출하세요. (설정에서 변경 가능)"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "시간 초기화"
|
||||
},
|
||||
@@ -252,12 +228,6 @@
|
||||
"0": {
|
||||
"message": "연결 타임아웃 오류입니다. 인터넷이 연결되어 있는지 확인해주세요. 인터넷이 연결되어 있는 경우, 서버가 과부하되어 있거나 다운되어 있어서 오류가 발생하는 것일 수도 있습니다."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock 비활성화"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock 활성화"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "지금까지 한 일",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
@@ -295,9 +265,6 @@
|
||||
"showTimeWithSkipsDescription": {
|
||||
"message": "이 시간은 탐색 막대 아래의 현재 시간 옆에 있는 괄호 안에 표시되며 부분을 제외한 총 동영상 길이를 보여줍니다. 여기에는 \"슬라이드바에 표시\"로만 표시된 부분도 포함됩니다."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "지금까지 스킵한 구간: "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "지금까지 절약한 시간: "
|
||||
},
|
||||
@@ -313,12 +280,6 @@
|
||||
"hoursLower": {
|
||||
"message": "시간"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "사람들"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": "의 시간을 아꼈습니다."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Status.sponsor.ajay.app 사이트를 확인하여 서버 상태를 확인하세요."
|
||||
},
|
||||
@@ -634,5 +595,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "업로드되지 않은 구간이 있는 영상이 있을 때 알림을 보냅니다"
|
||||
},
|
||||
"help": {
|
||||
"message": "도움"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "ലോഡിംഗ്..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "മിനിറ്റ്"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "സെക്കൻഡ്"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "ഒരിക്കലും കാണിക്കരുത്"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "സെഗ്മെന്റ് ഇപ്പോൾ അവസാനിക്കുന്നു"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "ഈ ടാബിൽ YouTube വീഡിയോകളൊന്നും കണ്ടെത്തിയില്ല. ഇതൊരു YouTube ടാബാണെന്ന് നിങ്ങൾക്കറിയാമെങ്കിൽ, ഈ പോപ്പ്അപ്പ് അടച്ച് വീണ്ടും തുറക്കുക. അത് പ്രവർത്തിക്കുന്നില്ലെങ്കിൽ, ടാബ് വീണ്ടും ലോഡുചെയ്യാൻ ശ്രമിക്കുക."
|
||||
"message": "YouTube വീഡിയോകളൊന്നും കണ്ടെത്തിയില്ല.\nഇത് തെറ്റാണെങ്കിൽ, ടാബ് പുതുക്കുക."
|
||||
},
|
||||
"success": {
|
||||
"message": "വിജയം!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "ഒരു സെഗ്മെന്റിൽ വോട്ടുചെയ്യുക"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "ഇതുവരെ, നിങ്ങൾ സമർപ്പിച്ചു"
|
||||
"Submissions": {
|
||||
"message": "സമർപ്പിക്കലുകൾ"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "നിങ്ങൾ ആളുകളെ രക്ഷിച്ചു "
|
||||
"message": "നിങ്ങൾ ആളുകളെ സംരക്ഷിച്ചു "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "ലീഡർബോർഡ് കാണുക"
|
||||
},
|
||||
"here": {
|
||||
"message": "ഇവിടെ"
|
||||
"message": "ലീഡർബോർഡ്"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "സെഗ്മെന്റ് ആരംഭിച്ച് അവസാനിക്കുമ്പോൾ ചുവടെയുള്ള ബട്ടൺ ക്ലിക്കുചെയ്ത് റെക്കോർഡുചെയ്ത് ഡാറ്റാബേസിൽ സമർപ്പിക്കുക."
|
||||
"message": "സമർപ്പിക്കുക"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "സമർപ്പിക്കുക ക്ലിക്കുചെയ്തതിനുശേഷം വിഭാഗം എഡിറ്റിംഗ് ദൃശ്യമാകും",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "സൂചന: ഒരു സെഗ്മെന്റിന്റെ ആരംഭം / അവസാനം റിപ്പോർട്ടുചെയ്യുന്നതിന് ഒരു വീഡിയോയിൽ ഫോക്കസ് ചെയ്യുമ്പോൾ അർദ്ധവിരാമ കീ അമർത്തുക, സമർപ്പിക്കാനുള്ള ഉദ്ധരണി. (ഓപ്ഷനുകളിൽ ഇത് മാറ്റാം)"
|
||||
"message": "സൂചന: ഓപ്ഷനുകളിൽ സമർപ്പിക്കുന്നതിന് നിങ്ങൾക്ക് കീബൈൻഡുകൾ സജ്ജമാക്കാൻ കഴിയും"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "ടൈംസ് മായ്ക്കുക"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "നിങ്ങൾ എത്രമാത്രം സംഭാവന നൽകി എന്ന് കാണിക്കുന്നതിന് ഇത് പൊതു സ്ഥിതിവിവരക്കണക്ക് പേജിൽ ഉപയോഗിക്കുന്നു. അത് കാണുക"
|
||||
},
|
||||
"Username": {
|
||||
"message": "ഉപയോക്തൃനാമം"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "ഉപയോക്തൃനാമം സജ്ജമാക്കുക"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "കണക്ഷൻ കാലഹരണപ്പെട്ടു. നിങ്ങളുടെ ഇന്റർനെറ്റ് കണക്ഷൻ പരിശോധിക്കുക. നിങ്ങളുടെ ഇൻറർനെറ്റ് പ്രവർത്തിക്കുന്നുണ്ടെങ്കിൽ, സെർവർ ഓവർലോഡ് അല്ലെങ്കിൽ ഡ. ൺ ആയിരിക്കാം."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "സ്പോൺസർബ്ലോക്ക് അപ്രാപ്തമാക്കുക"
|
||||
"message": "ഒഴിവാക്കൽ പ്രാപ്തമാക്കി"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "സ്പോൺസർബ്ലോക്ക് പ്രാപ്തമാക്കുക"
|
||||
"message": "ഒഴിവാക്കുന്നത് പ്രവർത്തനരഹിതമാക്കി"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "നിങ്ങളുടെ ജോലി",
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "മണിക്കൂറുകൾ"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "നിങ്ങൾ ആളുകളെ രക്ഷിച്ചു"
|
||||
"message": "നിങ്ങൾ ആളുകളെ സംരക്ഷിച്ചു"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " അവരുടെ ജീവിതത്തിന്റെ."
|
||||
"message": " അവരുടെ ജീവിതത്തിന്റെ"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "സെർവർ നിലയ്ക്കായി status.sponsor.ajay.app പരിശോധിക്കുക."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "ഒരു വിഭാഗം തിരഞ്ഞെടുക്കുക"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "\"{0}\" വിഭാഗത്തിൽ സെഗ്മെന്റുകൾ സമർപ്പിക്കുന്നതിന്, നിങ്ങൾ ഇത് ഓപ്ഷനുകളിൽ പ്രവർത്തനക്ഷമമാക്കണം. നിങ്ങളെ ഇപ്പോൾ ഓപ്ഷനുകളിലേക്ക് റീഡയറക്ട് ചെയ്യും.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "നിങ്ങൾ സമർപ്പിക്കുന്ന എല്ലാ സെഗ്മെന്റുകൾക്കും നിങ്ങൾ ഒരു വിഭാഗം തിരഞ്ഞെടുക്കണം!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "അപ്ലോഡ് ചെയ്യാത്ത സെഗ്മെന്റുകളുള്ള ഒരു വീഡിയോ നിങ്ങൾ ഉപേക്ഷിക്കുമ്പോൾ ഒരു അറിയിപ്പ് അയയ്ക്കുക"
|
||||
},
|
||||
"help": {
|
||||
"message": "സഹായം"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Memuat..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minit"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Detik"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Jangan Tunjukkan"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segmen Berakhir Sekarang"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Tidak terdapat video YouTube di tab ini. Sekiranya anda tahu ini adalah tab YouTube, tutup pop timbul ini dan buka lagi. Sekiranya tidak berjaya, cuba muat semula tab."
|
||||
"message": "Tiada video YouTube dijumpai.\nSekiranya ini tidak betul, muat semula tab."
|
||||
},
|
||||
"success": {
|
||||
"message": "Berjaya!"
|
||||
@@ -122,31 +116,32 @@
|
||||
"message": "Adakah anda pasti mahu menghantarnya?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Saluran Senarai Putih"
|
||||
"message": "Saluran senarai putih"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Alih keluar Saluran Dari Senarai Putih"
|
||||
"message": "Alih keluar saluran dari senarai putih"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Undi Segmen"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Setakat ini, anda telah menghantar"
|
||||
"Submissions": {
|
||||
"message": "Penyerahan"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Anda telah menyelamatkan orang dari "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Lihat papan pendahulu"
|
||||
},
|
||||
"here": {
|
||||
"message": "di sini"
|
||||
"message": "Papan pendahulu"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klik butang di bawah apabila segmen bermula dan berakhir untuk merekod dan menyerahkannya ke pangkalan data."
|
||||
"message": "Hantar"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Penyuntingan bahagian akan muncul setelah anda mengklik hantar",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Petunjuk: Tekan kekunci titik koma sambil fokus pada video untuk melaporkan permulaan / akhir segmen dan petikan untuk dihantar. (Ini boleh diubah dalam pilihan)"
|
||||
"message": "Petunjuk: Anda boleh menetapkan kunci untuk dihantar dalam pilihan"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Jelas Masa"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Ini digunakan di halaman statistik awam untuk menunjukkan berapa banyak yang anda sumbangkan. Lihatlah"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Nama pengguna"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Tetapkan Nama Pengguna"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Masa sambungan telah tamat. Periksa sambungan internet anda. Sekiranya internet anda berfungsi, pelayan mungkin berlebihan atau tidak berfungsi."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Lumpuhkan SponsorBlock"
|
||||
"message": "Melangkau diaktifkan"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Dayakan SponsorBlock"
|
||||
"message": "Melangkau dilumpuhkan"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Kerja awak",
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "Anda telah menyelamatkan orang"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " kehidupan mereka."
|
||||
"message": " kehidupan mereka"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Periksa status.sponsor.ajay.app untuk status pelayan."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Pilih Kategori"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Untuk menghantar segmen dengan kategori \"{0}\", anda mesti mengaktifkannya dalam pilihan. Anda akan diarahkan ke pilihan sekarang.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Anda mesti memilih kategori untuk semua segmen yang anda kirimkan!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Kirim pemberitahuan ketika anda meninggalkan video dengan segmen yang tidak diunggah"
|
||||
},
|
||||
"help": {
|
||||
"message": "Bantuan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Overslaan van sponsoring, abonneer-herinneringen en meer in YouTube-video's. Rapporteer sponsors in video's die u bekijkt om anderen tijd te besparen.",
|
||||
"message": "Overslaan van sponsors, vragen om te abonneren en meer in YouTube-video's. Rapporteer sponsors in video's die u bekijkt om anderen tijd te besparen.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
@@ -14,7 +14,7 @@
|
||||
"message": "U heeft te veel sponsortijdstippen ingediend voor deze video. Weet u zeker dat er zoveel zijn?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Dit is al een keer ingediend"
|
||||
"message": "Dit is al eerder ingediend"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanaal gewhitelist!"
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Laden..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuten"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Seconden"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nooit weergeven"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segment eindigt nu"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Er is geen YouTube-video gevonden op dit tabblad. Als u weet dat dit een YouTube-tabblad is, sluit dan deze pop-up en open hem opnieuw. Als dat niet werkt, probeer dan het tabblad opnieuw te laden."
|
||||
"message": "Geen YouTube-video gevonden.\nVernieuw het tabblad als dit onjuist is."
|
||||
},
|
||||
"success": {
|
||||
"message": "Gelukt!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Stemmen op een segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Tot nu toe heeft u ingediend:"
|
||||
"Submissions": {
|
||||
"message": "Inzendingen"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "U heeft mensen geholpen met het vermijden van "
|
||||
"message": "U heeft mensen gered van "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Bekijk de ranglijst"
|
||||
},
|
||||
"here": {
|
||||
"message": "hier"
|
||||
"message": "Ranglijst"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klik op de knop hieronder wanneer het segment begint en eindigt om het te registreren en te verzenden naar de database."
|
||||
"message": "Indienen"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Sectiebewerking verschijnt nadat u op verzenden hebt geklikt",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Tip: druk op de puntkomma-toets terwijl een video in focus is om het begin/einde van een segment te registreren en op de aanhalingsteken-toets om het in te dienen (dit kan worden gewijzigd in de opties)."
|
||||
"message": "Tip: u kunt sneltoetsen voor het indienen instellen in de opties"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Tijdstippen wissen"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Dit wordt gebruikt op de publieke statistiekenpagina om te laten zien hoeveel u heeft bijgedragen. Bekijk het"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Gebruikersnaam"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Gebruikersnaam instellen"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Time-out van de verbinding. Controleer uw internetverbinding. Als uw internet werkt, is de server waarschijnlijk overbelast of offline."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock uitschakelen"
|
||||
"message": "Overslaan is ingeschakeld"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock inschakelen"
|
||||
"message": "Overslaan is uitgeschakeld"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Uw werk",
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "uren"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "U heeft andere mensen bespaard:"
|
||||
"message": "U heeft mensen bespaard:"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " van hun leven."
|
||||
"message": " van hun leven"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Controleer status.sponsor.ajay.app voor de serverstatus."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Een categorie kiezen"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Om segmenten met de categorie \"{0}\" in te dienen, moet u deze in de opties inschakelen. U wordt nu doorgestuurd naar de opties.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "U moet een categorie selecteren voor alle segmenten die u indient!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Een melding sturen wanneer u een video verlaat met segmenten die niet zijn geüpload"
|
||||
},
|
||||
"help": {
|
||||
"message": "Help"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Ładowanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nie pokazuj więcej"
|
||||
},
|
||||
@@ -65,10 +59,10 @@
|
||||
"message": "Timer 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."
|
||||
"message": "Aby edytować lub usuwać poszczególne wartości, kliknij na przycisk informacyjny lub otwórz okienko rozszerzenia, klikając na ikonę rozszerzenia w prawym górnym rogu."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Jesteś pewien, że chcesz to usunąć?\n\n"
|
||||
"message": "Czy na pewno chcesz to usunąć?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Wystąpił błąd podczas przesyłania twojego segmentu. Proszę spróbować ponownie później."
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Koniec segmentu"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono filmu na 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 odświeżyć stronę."
|
||||
"message": "Nie znaleziono filmu YouTube.\nJeśli jest to nieprawidłowe, odśwież stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
@@ -101,10 +95,10 @@
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Czy chcesz zamieścić dla filmu o ID"
|
||||
"message": "Czy chcesz coś zamieścić dla filmu o ID"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że zostawiłeś pewne niewysłane segmenty. Cofnij się do tamtej strony, by je zamieścić (nie zostały usunięte)."
|
||||
"message": "Wygląda na to, że pozostawiono pewne niewysłane segmenty. Cofnij się do tamtej strony, aby je zamieścić (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Oceń segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Do tej pory zgłosiłeś"
|
||||
"Submissions": {
|
||||
"message": "Zgłoszenia"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
"message": "Oszczędziłeś innym "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
"message": "Ranking"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij przycisk poniżej, gdy segment zaczyna się i kończy, by oznaczyć go i przesłać do bazy danych."
|
||||
"message": "Wyślij"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Edycja sekcji pojawi się po kliknięciu",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Wciśnij średnik, koncentrując się na filmie, aby oznaczyć początek/koniec segmentu, i cudzysłów, by go wysłać. (Klawisze można zmienić w opcjach)"
|
||||
"message": "Wskazówka: Możesz skonfigurować skróty klawiszowe do zatwierdzania w opcjach"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Usuń czasy"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Nazwa użytkownika"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ustaw nazwę użytkownika"
|
||||
},
|
||||
@@ -203,13 +201,13 @@
|
||||
"message": "Ta opcja monitoruje pomijane przez Ciebie segmenty, by dać znać użytkownikom, jak bardzo ich wkład pomógł innym, oraz w połączeniu z systemem głosowania zapobiegać dostawaniu się spamu do bazy danych. Rozszerzenie wysyła wiadomość do serwera za każdym razem, kiedy pomijasz segment. Miejmy nadzieję, że większość ludzi tego nie wyłączy i liczniki wyświetleń będą wiarygodne. :)"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Zapytanie Według Hash Prefix"
|
||||
"message": "Zapytanie z użyciem funkcji skrótu"
|
||||
},
|
||||
"whatQueryByHashPrefix": {
|
||||
"message": "Zamiast żądać segmentów z serwera używając videoID, pierwsze 4 znaki haszu videoID'u są wysyłane. Ten serwer zwróci wszystkie dane dla wszystkich filmików z podobnymi hashami."
|
||||
"message": "Zamiast wysyłać do serwera zapytanie o segmenty zawierające ID filmu, wysyłane są 4 pierwsze znaki hashu tego ID. Serwer zwróci dane dla wszystkich filmów z podobnymi hashami."
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Pobierz na nowo segmenty z nowych filmów"
|
||||
"message": "Ponawiaj pobieranie segmentów na nowych filmach"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Jeśli film jest nowy i nie znaleziono żadnych segmentów, dane będą pobierane na nowo, co kilka minut, w czasie kiedy oglądasz."
|
||||
@@ -253,10 +251,10 @@
|
||||
"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"
|
||||
"message": "Pomijanie jest włączone"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Włącz SponsorBlock"
|
||||
"message": "Pomijanie jest wyłączone"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Twój wkład",
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "Oszczędziłeś ludziom"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " czasu."
|
||||
"message": " ich życia"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Sprawdź status serwera na status.sponsor.ajay.app"
|
||||
@@ -359,7 +357,7 @@
|
||||
"message": "Dodaj instancje Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Dodaj niestandardową instancje Invidious. W formie domeny. Na przykład: invidious.ajay.app"
|
||||
"message": "Dodaj niestandardową instancję Invidious. Musi to być w formie samej domeny. Przykładowo: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Dodaj"
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Wybierz kategorię"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Aby przesyłać segmenty o kategorii \"{0}\", musisz ją włączyć w opcjach. Zostaniesz przekierowany do ustawień.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Musisz wybrać kategorię dla każdego segmentu, który zamieszczasz!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Wyślij powiadomienie po opuszczeniu filmu z segmentami, które nie zostały przesłane"
|
||||
},
|
||||
"help": {
|
||||
"message": "Pomoc"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,623 +0,0 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorowane",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Pomijaj sponsorów, prośby o subskrypcje i inne fragmenty filmów na YouTube. Zgłaszaj segmenty sponsorów na filmach, które oglądasz, by oszczędzić czas innym.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||
},
|
||||
"429": {
|
||||
"message": "Zgłosiłeś za dużo segmentów sponsora dla tego jednego filmu. Jesteś pewien, że jest ich tak dużo?"
|
||||
},
|
||||
"409": {
|
||||
"message": "To już zostało wcześniej zgłoszone"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanał dodany do wyjątków!"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segment"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Oceń pozytywnie ten segment"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Zgłoś"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Zgłoś ten segment 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"
|
||||
},
|
||||
"manualPaused": {
|
||||
"message": "Timer 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 segmentu. Proszę spróbować ponownie później."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Ten film ma segmenty w bazie danych!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nie znaleziono segmentów"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Segment zaczyna się teraz"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Segment kończy się teraz"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono filmu na 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 odświeżyć stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Zagłosowano!"
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Wygląda na to, że serwer nie działa. Skontaktuj się niezwłocznie z deweloperem."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Czy chcesz zamieścić dla filmu o ID"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że zostawiłeś pewne niewysłane segmenty. Cofnij się do tamtej strony, by je zamieścić (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Otwórz okienko SponsorBlock"
|
||||
},
|
||||
"closePopup": {
|
||||
"message": "Zamknij okienko"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Prześlij segmenty"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Czy na pewno chcesz to zamieścić?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanał do wyjątków"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Usuń kanał z listy wyjątków"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Oceń segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Do tej pory zgłosiłeś"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij przycisk poniżej, gdy segment zaczyna się i kończy, by oznaczyć go i przesłać do bazy danych."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Wciśnij średnik, koncentrując się na filmie, aby oznaczyć początek/koniec segmentu, i cudzysłów, by go wysłać. (Klawisze można zmienić w opcjach)"
|
||||
},
|
||||
"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ż przyciski na odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Ukryj przyciski na odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ta opcja ukrywa przyciski do zamieszczania segmentów pojawiające się na odtwarzaczu YouTube."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Pokaż przycisk informacyjny na odtwarzaczu YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Ukryj przycisk informacyjny na odtwarzaczu YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Jest to przycisk otwierający okienko pop-up na stronie YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Ukryj przycisk usuwania na odtwarzaczu YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Pokaż przycisk usuwania na odtwarzaczu YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ten przycisk na odtwarzaczu YouTube wyczyści wszystkie twoje niewysłane segmenty dla bieżącego filmu."
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Włącz monitorowanie liczby pominięć"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ta opcja monitoruje pomijane przez Ciebie segmenty, by dać znać użytkownikom, jak bardzo ich wkład pomógł innym, oraz w połączeniu z systemem głosowania zapobiegać dostawaniu się spamu do bazy danych. Rozszerzenie wysyła wiadomość do serwera za każdym razem, kiedy pomijasz segment. Miejmy nadzieję, że większość ludzi tego nie wyłączy i liczniki wyświetleń będą wiarygodne. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock pozwala pomijać sponsorów, intra, outra, przypomnienia o subskrypcjach i inne irytujące fragmenty filmów na YouTube. SponsorBlock jest opartym na crowdsourcingu rozszerzeniem do przeglądarki, które pozwala każdemu zgłosić początek i koniec segmentów sponsorowanych oraz innych segmentów w filmach na YouTube. Kiedy ktoś już zamieści te informacje, wszyscy pozostali z tym rozszerzeniem będą pomijać segment sponsorowany. Możesz również pomijać fragmenty teledysków bez muzyki.",
|
||||
"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 segmentu"
|
||||
},
|
||||
"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: "
|
||||
},
|
||||
"skip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "Przewiń {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Pominięto"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Wyłącz autopomijanie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Włącz autopomijanie"
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Powiadomienie dźwiękowe przy pominięciu"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Powiadomienie dźwiękowe przy pominięciu będzie odtwarzane za każdym razem, gdy pomijany jest segment. Jeśli wyłączone (lub automatyczne pomijanie jest wyłączone), dźwięk nie zostanie odtworzony."
|
||||
},
|
||||
"showTimeWithSkips": {
|
||||
"message": "Pokaż czas po usunięciu segmentów"
|
||||
},
|
||||
"showTimeWithSkipsDescription": {
|
||||
"message": "Czas ten pojawia się w nawiasie obok czasu bieżącego, pod paskiem postępu. Pokazuje on długość całego filmu po odjęciu wszystkich segmentów. Wliczają się w to segmenty ustawione jako \"pokaż na pasku\"."
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Sprawdź status serwera na status.sponsor.ajay.app"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importuj/Eksportuj swój identyfikator użytkownika"
|
||||
},
|
||||
"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 identyfikator użytkownika"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Uwaga: Zmiana identyfikatora użytkownika jest trwała. Czy na pewno chcesz to zrobić? Na wszelki wypadek skopiuj swój poprzedni."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Autopomijanie"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Pokaż informację po pominięciu segmentu"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jest obecnie ustawione jako:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Wsparcie dla Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) to nieoficjalny klient YouTube'a. Aby włączyć dla niego wsparcie musisz przyznać dodatkowe uprawnienia. W Chrome'ie i innych przeglądarkach bazujących na Chromium, ta opcja nie działa w trybie incognito."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Włącz wsparcie dla Invidious, wyłącz autopomijanie, ukryj przyciski 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:"
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimalny czas trwania (sekundy):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Segmenty krótsze niż ustawiona wartość nie będą pomijane ani pokazywane w odtwarzaczu."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Ten segment jest krótszy od ustawionego przez Ciebie minimalnego czasu trwania. Może to oznaczać, że ktoś już to zamieścił, ale nie widzisz tego przez to ustawienie. Czy na pewno chcesz to zamieścić?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Pokaż przycisk wysyłania"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Ten przycisk pojawia się na odtwarzaczu YouTube po wybraniu przedziału czasowego, gdy segment jest gotowy do wysłania."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "Adres serwera SponsorBlock"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Adres SponsorBlock używa do wykonywania połączeń do serwera.\nDo póki nie posiadasz własnego serwera, to nie powinno być zmieniane."
|
||||
},
|
||||
"save": {
|
||||
"message": "Zapisz"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Reset"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Ten adres nie jest w prawidłowej formie. Upewnij się, że http:// lub https:// znajduje się na początku i nie ma końcowych ukośników."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Czy na pewno chcesz to zresetować?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Ten film został wykryty jako niepubliczny. Kliknij Anuluj, jeśli nie chcesz sprawdzać, czy są dla niego segmenty."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignoruj niepubliczne/prywatne filmy"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Ta opcja spowolni nieco SponsorBlock. Wyszukiwanie istniejących segmentów wymaga wysłania ID filmu do serwera. Jeśli niepokoi Cię fakt wysyłania przez internet ID niepublicznych filmów, włącz tę opcję."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com jest teraz wspierany"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Importuj/Eksportuj wszystkie ustawienia"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Jest to cała twoja konfiguracja w formacie JSON. Zawarty jest w niej twój identyfikator użytkownika, więc uważaj, komu ją udostępniasz."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Zapisz ustawienia"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Uwaga: Zmiana ustawień jest trwała i może popsuć twoją instalację. Czy na pewno chcesz to zrobić? Na wszelki wypadek utwórz kopię poprzednich."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "Ten JSON nie został poprawnie sformatowany. Twoje opcje nie zostały zmienione."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Zgłoś segment"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Wyślij"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Anuluj"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Usuń"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Podgląd"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Edytuj"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Skopiuj informacje debugowania do schowka"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Nie udało się skopiować do schowka"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Kopiuje do schowka informacje do dostarczenia deweloperowi podczas zgłaszania błędu / gdy deweloper ich sobie zażyczy. Poufne informacje, takie jak ID użytkownika, kanały dodane do wyjątków i adres niestandardowego serwera zostały usunięte. Wciąż zawiera to jednak informacje takie jak twój user agent, przeglądarka, system operacyjny i wersja rozszerzenia. "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "Informacje do debugowania zostały skopiowane do schowka. Możesz usunąć dane, których nie chcesz udostępniać. Zapisz je w pliku tekstowym albo wklej do raportu podczas zgłaszania błędu."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "Klucz"
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "jest przypisane do innej akcji. Wybierz proszę inny klawisz."
|
||||
},
|
||||
"to": {
|
||||
"message": "do",
|
||||
"description": "Used between segments. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"category_sponsor_description": {
|
||||
"message": "Płatna promocja, płatne rekomendacje oraz bezpośrednie reklamy. Nie do autopromocji ani darmowych wyrazów uznania dla kwestii/twórców/stron/produktów, które im się podobają."
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Przerwa/Animowane intro"
|
||||
},
|
||||
"category_intro_description": {
|
||||
"message": "Fragment bez faktycznej treści. Może to być pauza, statyczna klatka, powtarzająca się animacja. Nie powinno to być używane do przejść zawierających informacje."
|
||||
},
|
||||
"category_intro_short": {
|
||||
"message": "Przerwa"
|
||||
},
|
||||
"category_outro": {
|
||||
"message": "Ekran końcowy/Napisy"
|
||||
},
|
||||
"category_outro_description": {
|
||||
"message": "Napisy końcowe lub gdy pojawia się ekran końcowy. Nie do konkluzji zawierających informacje."
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Przypomnienie o interakcji (Subskrybuj)"
|
||||
},
|
||||
"category_interaction_description": {
|
||||
"message": "Gdy ma miejsce krótkie przypomnienie, by lajkować, subskrybować lub śledzić ich w trakcie kontentu. Jeśli trwa to długo lub dotyczy czegoś konkretnego, powinno być zamiast tego jako promocja własna."
|
||||
},
|
||||
"category_interaction_short": {
|
||||
"message": "Przypomnienie o interakcji"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Nieopłacona/Własna promocja"
|
||||
},
|
||||
"category_selfpromo_description": {
|
||||
"message": "Podobnie jak \"sponsor\", ale nieodpłatnie bądź w ramach promocji własnej. Obejmuje to sekcje o własnych produktach, donacjach czy informacje o tym, z kim współpracowali."
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Muzyka: Sekcja niemuzyczna"
|
||||
},
|
||||
"category_music_offtopic_description": {
|
||||
"message": "Do użytku tylko w filmach muzycznych. Wliczają się w to wprowadzenia i outro w teledyskach."
|
||||
},
|
||||
"category_music_offtopic_short": {
|
||||
"message": "Bez muzyki"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Transmisja live: Dotacja/Czytanie wiadomości"
|
||||
},
|
||||
"category_livestream_messages_short": {
|
||||
"message": "Czytanie wiadomości"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Wyłączone"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Ręczne pomijanie"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Pokaż na pasku"
|
||||
},
|
||||
"colorFormatIncorrect": {
|
||||
"message": "Nieprawidłowy format koloru. Powinien to być zapis szesnastkowy (heksadecymalny) składający się z 3 lub 6 znaków poprzedzonych kratką (#)."
|
||||
},
|
||||
"previewColor": {
|
||||
"message": "Kolor podglądu",
|
||||
"description": "Referring to submissions that have not been sent to the server yet."
|
||||
},
|
||||
"seekBarColor": {
|
||||
"message": "Kolor paska postępu"
|
||||
},
|
||||
"category": {
|
||||
"message": "Kategoria"
|
||||
},
|
||||
"skipOption": {
|
||||
"message": "Tryb pomijania",
|
||||
"description": "Used on the options page to describe the ways to skip the segment (auto skip, manual, etc.)"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Aktywuj serwer beta-testów"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Twoje segmenty i głosy NIE BĘDĄ uwzględniane na głównym serwerze. Używaj tego tylko do testowania."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Żadne segmenty ani głosy NIE BĘDĄ uwzględniane na głównym serwerze podczas połączenia z serwerem testowym. Pamiętaj, żeby to wyłączyć, gdy zechcesz dodać realny wkład."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Teraz)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Więcej kategorii"
|
||||
},
|
||||
"chooseACategory": {
|
||||
"message": "Wybierz kategorię"
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Musisz wybrać kategorię dla każdego segmentu, który zamieszczasz!"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Koniec)"
|
||||
},
|
||||
"hiddenDueToDownvote": {
|
||||
"message": "ukryty: zminusowany"
|
||||
},
|
||||
"hiddenDueToDuration": {
|
||||
"message": "ukryty: zbyt krótki"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "ID kanału nie zostało póki co załadowane."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "Wygląda na to, że coś blokuje możliwość pobierania danych o filmach przez SponsorBlock. To prawdopodobnie Twój ad blocker. Sprawdź proszę https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "Jeśli ten problem się powtarza, możliwą przyczyną jest Twój ad blocker. Sprawdź proszę https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "Wymuś sprawdzenie kanału przed pominięciem"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "Domyślnie, rozszerzenie pominie segmenty od razu, jeszcze zanim dowie się jaki to kanał. Domyślnie, pewne segmenty na początku filmu mogą zostać pominięte na kanałach dodanych do wyjątków. Włączenie tej opcji temu zapobiegnie, ale wszystkie pominięcia będą nieco opóźnione, gdyż uzyskanie ID kanału może chwilę potrwać. Opóźnienie to może być nieodczuwalne, jeśli masz szybki internet."
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Rozważ włączenie \"Wymuś sprawdzenie kanału przed pominięciem\""
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Niepoprawne/Zły czas"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "Zła kategoria"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "Ten film jest skategoryzowany jako muzyka. Czy jesteś pewien, że to jest sponsor? Jeśli jest to rzeczywiście \"segment niemuzyczny\", otwórz opcje rozszerzenia i włącz tę kategorię. Następnie możesz przesłać ten segment jako \"Niemuzyczny\" zamiast sponsora. Proszę przeczytać wytyczne, jeśli jesteś zdezorientowany."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "Wiele segmentów"
|
||||
},
|
||||
"guidelines": {
|
||||
"message": "Wytyczne"
|
||||
},
|
||||
"readTheGuidelines": {
|
||||
"message": "Przeczytaj wytyczne!!",
|
||||
"description": "Show the first time they submit or if they are \"high risk\""
|
||||
},
|
||||
"categoryUpdate1": {
|
||||
"message": "Kategorie są tutaj!"
|
||||
},
|
||||
"categoryUpdate2": {
|
||||
"message": "Otwórz opcje, aby pominąć intra, outra, merch, itp."
|
||||
},
|
||||
"unsubmittedWarning": {
|
||||
"message": "Powiadomienie o niewysłanych segmentach"
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Wyślij powiadomienie po opuszczeniu filmu z segmentami, które nie zostały przesłane"
|
||||
}
|
||||
}
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Carregando..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutos"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Segundos"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nunca mostrar"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "O segmento termina agora"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nenhum vídeo do YouTube foi encontrado nesta aba. Se você sabe que esta é uma aba do YouTube, feche este pop-up e abra-o novamente. Se isso não funcionar, tente recarregar a aba."
|
||||
"message": "Nenhum vídeo do YouTube encontrado.\nSe isto estiver incorreto, atualize a aba."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sucesso!"
|
||||
@@ -122,7 +116,7 @@
|
||||
"message": "Você tem certeza que deseja enviar isto?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Colocar canal na lista branca"
|
||||
"message": "Canal na lista branca"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remover canal da lista branca"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Votar Em Um Segmento"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora, você já enviou"
|
||||
"Submissions": {
|
||||
"message": "Envios"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
"message": "Você salvou pessoas de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
"message": "Classificação"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Clique no botão abaixo quando o segmento começa e termina para gravar e enviá-lo para o banco de dados."
|
||||
"message": "Enviar"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "A edição da seção aparecerá depois que você clicar em enviar",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Aperte a tecla ponto e vírgula com a janela focada em um vídeo para reportar o começo/fim de um segmento e aspas para enviar. (Esta configuração pode ser mudada nas opções)"
|
||||
"message": "Dica: Você pode configurar os atalhos de tecla para enviar nas opções"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Isso é usado na página pública de estatísticas que mostra o quanto você já contríbuíu. Veja-a"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Usuário"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Definir nome de usuário"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Tempo limite de conexão excedida. Cheque a sua conexão de internet. Se a sua internet estiver funcionando, o servidor está sobrecarregado ou fora do ar."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Desativar SponsorBlock"
|
||||
"message": "Pular está habilitado"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Ativar SponsorBlock"
|
||||
"message": "Pular está desabilitado"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Suas submissões",
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "horas"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Você poupou outros"
|
||||
"message": "Você poupou das pessoas"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " de suas vidas."
|
||||
"message": " de suas vidas"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Verifique status.sponsor.ajay.app para o status do servidor."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Selecione uma Categoria"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Para enviar os segmentos com a categoria de \"{0}\", você deve ativá-lo nas opções. Você será redirecionado para as opções agora.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Você deve selecionar uma categoria para todos os segmentos que você está enviando!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Enviar uma notificação quando você sair de um vídeo com segmentos que não foram enviados"
|
||||
},
|
||||
"help": {
|
||||
"message": "Ajuda"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,6 @@
|
||||
"Loading": {
|
||||
"message": "A carregar..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutos"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Segundos"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nunca mostrar"
|
||||
},
|
||||
@@ -54,9 +48,6 @@
|
||||
"Unknown": {
|
||||
"message": "Erro ao enviar os seus segmentos, tente novamente mais tarde."
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Isto provavelmente não é uma tab do YouTube, ou pode ter clicado muito cedo. \n Se sabe que é uma tab do YouTube,\n feche este popup e abra de novo."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sucesso!"
|
||||
},
|
||||
@@ -72,24 +63,6 @@
|
||||
"submitCheck": {
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
},
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Se încarcă..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minute"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Secunde"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nu mai afișa niciodată"
|
||||
},
|
||||
@@ -85,9 +79,6 @@
|
||||
"sponsorEnd": {
|
||||
"message": "Segmentul se termină acum"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nu există niciun videoclip YouTube în aceast tab. Dacă știți că acesta este un tab YouTube, închideți acest popup și deschideți-l din nou. Daca nici asta nu merge, încercați să reîncărcați pagina."
|
||||
},
|
||||
"success": {
|
||||
"message": "Succes!"
|
||||
},
|
||||
@@ -121,33 +112,9 @@
|
||||
"submitCheck": {
|
||||
"message": "Sunteți sigur că doriți să trimiteți asta?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Adaugă Canalul La Excepții"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Șterge Canalul De La Excepții"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Votează pe un Segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Până acum, ai trimis"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ai salvat alte persoane de la "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Vezi clasamentul"
|
||||
},
|
||||
"here": {
|
||||
"message": "aici"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Faceţi clic pe butonul de mai jos atunci când segmentul începe şi se termină pentru a înregistra şi trimite-l în baza de date."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Indiciu: Apasă pe tasta punct și virgulă în timp ce ești centrat pe videoclip pentru a raporta începutul/finalul unei sponsorizări și apasă pe ghilimele pentru a o trimite. (Acest lucru poate fi schimbat din opțiuni)"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Șterge Timpii"
|
||||
},
|
||||
@@ -227,12 +194,6 @@
|
||||
"0": {
|
||||
"message": "Eroare de Conexiune. Verifică-ți conexiunea la internet. Daca internetul functionează, serverul este probabil supraîncărcat sau a căzut."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Dezactivează SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Activează SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Munca Ta",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
@@ -246,9 +207,6 @@
|
||||
"skip": {
|
||||
"message": "Sari"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "Sari {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Sărit"
|
||||
},
|
||||
@@ -267,9 +225,6 @@
|
||||
"showTimeWithSkipsDescription": {
|
||||
"message": "Acest timp apare în paranteze lângă ora curentă sub bara de progres. Aceasta arată durata totală a videoclipului minus orice segment. Aceasta include segmente marcate doar ca \"Afișare în Seekbar\"."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Ai sărit peste "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "V-ați salvat "
|
||||
},
|
||||
@@ -285,12 +240,6 @@
|
||||
"hoursLower": {
|
||||
"message": "ore"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Ai salvat alte persoane"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " din viața lor."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Verificați status.sponsor.ajay.app pentru starea serverului."
|
||||
},
|
||||
|
||||
@@ -40,14 +40,8 @@
|
||||
"Loading": {
|
||||
"message": "Загрузка..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "мин"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "сек"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Никогда не показывать"
|
||||
"message": "Больше не показывать"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Нажмите «Назад», чтобы вернуться обратно."
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Сегмент заканчивается здесь"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Видео YouTube не найдено на этой вкладке. Если вы уверены, что это вкладка YouTube, закройте это всплывающее окно и откройте его снова. Если это не поможет, перезагрузите вкладку."
|
||||
"message": "Видео YouTube не найдено.\nЕсли это не так, обновите вкладку."
|
||||
},
|
||||
"success": {
|
||||
"message": "Успех!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Проголосовать за сегмент"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "На данный момент Вы отправили"
|
||||
"Submissions": {
|
||||
"message": "Отправлено сегментов"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Вы помогли людям пропустить "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Посмотреть доску почёта"
|
||||
},
|
||||
"here": {
|
||||
"message": "здесь"
|
||||
"message": "Доска почёта"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Нажмите кнопку ниже, когда сегмент начинается и заканчивается, чтобы записать и отправить его в базу."
|
||||
"message": "Отправить"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Редактирование сегментов появится после нажатия на кнопку \"Отправить\"",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Подсказка: нажмите на кнопку \"Ж\" во время воспроизведения, чтобы сообщить о начале/конце сегмента, и \"Э\", чтобы отправить его. (Это можно изменить в настройках)"
|
||||
"message": "Подсказка: Вы можете настроить сочетания клавиш для отправки в опциях"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Очистить время"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Оно используется на публичной странице статистики, чтобы показать Ваш вклад. Её можно посмотреть "
|
||||
},
|
||||
"Username": {
|
||||
"message": "Имя пользователя"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Установить имя пользователя"
|
||||
},
|
||||
@@ -203,7 +201,7 @@
|
||||
"message": "Эта возможность отслеживает, какие сегменты Вы пропустили, чтобы помочь пользователям узнать, насколько их вклад помог другим, и, наряду с голосами, используется как метрика, чтобы убедиться, что спам не попадает в базу данных. Расширение отправляет сообщение на сервер каждый раз, когда Вы пропускаете сегмент. Надеемся, большая часть пользователей не поменяет эту настройку, так что у нас будет точная статистика просмотров. :)"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Поиск по части хэша"
|
||||
"message": "Запрос по префиксу хэша"
|
||||
},
|
||||
"whatQueryByHashPrefix": {
|
||||
"message": "Вместо отправки на сервер ID видео, для получения сегментов будут использоваться первые 4 символа хэша ID. Сервер вернёт данные для всех видео с похожими хэшами."
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Таймаут подключения. Проверьте ваше соединение с интернетом. Если ваш интернет работает, сервер, скорее всего, перегружен или лежит."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Отключить SponsorBlock"
|
||||
"message": "Пропуск включен"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Включить SponsorBlock"
|
||||
"message": "Пропуск выключен"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Ваша работа",
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "Вы сэкономили людям"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " их жизней."
|
||||
"message": " их жизней"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Смотрите состояние сервера на status.sponsor.ajay.app."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Выберите категорию"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Чтобы отправить сегменты категории \"{0}\", вы должны включить её в настройках. Сейчас вы будете туда перенаправлены.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Вы должны выбрать категорию для всех сегментов, которые вы отправляете!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Отправлять уведомление, когда вы уходите со страницы видео, сегменты к которому Вы не отправили"
|
||||
},
|
||||
"help": {
|
||||
"message": "Помощь"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanál bol pridaný do whitelistu!"
|
||||
},
|
||||
@@ -20,12 +24,6 @@
|
||||
"Loading": {
|
||||
"message": "Načítavanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minúty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nikdy nezobrazovať"
|
||||
},
|
||||
@@ -68,9 +66,6 @@
|
||||
"closePopup": {
|
||||
"message": "Zavrieť okno"
|
||||
},
|
||||
"here": {
|
||||
"message": "tu"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Skryť"
|
||||
},
|
||||
@@ -97,12 +92,6 @@
|
||||
"0": {
|
||||
"message": "Spojenie vypršalo. Skontrolujte svoje internetové pripojenie. Ak váš internet funguje, server je pravdepodobne preťažený alebo nefunkčný."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Vypnúť SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Zapnúť SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Vaša Práca",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Laddar..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuter"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekunder"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Visa Aldrig"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Segmentet slutar nu"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Kunde inte hitta någon YouTube-video i denna tab. Om du är säker på att detta är en Youtube-flik, stäng den här rutan och öppna den igen. Ladda om fliken om inte det funkar."
|
||||
"message": "Hittade ingen YouTube-video.\nUppdatera fliken om detta är felaktigt."
|
||||
},
|
||||
"success": {
|
||||
"message": "Lyckades!"
|
||||
@@ -122,7 +116,7 @@
|
||||
"message": "Är du säker på att du vill rapportera detta?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Vitlista Kanal"
|
||||
"message": "Vitlistkanal"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Ta bort kanal från vitlistan"
|
||||
@@ -130,23 +124,17 @@
|
||||
"voteOnTime": {
|
||||
"message": "Rösta på ett segment"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Hitills har du rapporterat"
|
||||
"Submissions": {
|
||||
"message": "Inskickade"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Du har sparat andra "
|
||||
"message": "Du har sparat andra från "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Se leaderboarden"
|
||||
},
|
||||
"here": {
|
||||
"message": "här"
|
||||
"message": "Topplista"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klicka på knappen nedan när segmentet startar och slutar för att spela in och skicka in det till databasen."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Tips: Tryck på tangenten semikolon medan du fokuserar på en video för att rapportera början/slutet av ett segment för att skicka in. (Detta kan ändras i alternativen)"
|
||||
"message": "Skicka"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Rensa Tider"
|
||||
@@ -157,6 +145,9 @@
|
||||
"publicStats": {
|
||||
"message": "Detta kommer att användas på den publika statistiksidan för att visa hur mycket du har bidragit. Spana in den"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Användarnamn"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ange Användarnamn"
|
||||
},
|
||||
@@ -205,6 +196,12 @@
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Fråga efter hash-prefix"
|
||||
},
|
||||
"enableRefetchWhenNotFound": {
|
||||
"message": "Uppdatera segment på nya videor"
|
||||
},
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Om videon är ny och inga segment hittades då kommer den att uppdatera med några minuter mellanrum medan du tittar på videon."
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Visa Notisen Igen"
|
||||
},
|
||||
@@ -244,10 +241,10 @@
|
||||
"message": "Anslutningsfel. Se över din internetanslutning. Om du kan komma åt internet så är servern förmodligen överbelastad eller nere."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Avaktivera SponsorBlock"
|
||||
"message": "Hoppa över är aktiverat"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Aktivera SponsorBlock"
|
||||
"message": "Hoppa över är inaktiverat"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Ditt Bidrag",
|
||||
@@ -308,7 +305,7 @@
|
||||
"message": "Du har sparat andra"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " av deras liv."
|
||||
"message": " av deras liv"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Gå till status.sponsor.ajay.app för serverstatus."
|
||||
@@ -485,6 +482,9 @@
|
||||
"category_interaction": {
|
||||
"message": "Interaktionspåminnelse (Prenumerera)"
|
||||
},
|
||||
"category_interaction_short": {
|
||||
"message": "Interaktionspåminnelse"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Obetald/självbefodran"
|
||||
},
|
||||
@@ -497,6 +497,9 @@
|
||||
"category_music_offtopic_short": {
|
||||
"message": "Icke-musik"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Liveström: Donations-/meddelandeavläsningar"
|
||||
},
|
||||
"category_livestream_messages_short": {
|
||||
"message": "Läser meddelande"
|
||||
},
|
||||
@@ -509,6 +512,9 @@
|
||||
"showOverlay": {
|
||||
"message": "Visa Lager Ovanpå Spelare"
|
||||
},
|
||||
"colorFormatIncorrect": {
|
||||
"message": "Din färg är felaktigt formaterad. Det ska vara en 3- eller 6-siffrig hex-kod med en siffra i början."
|
||||
},
|
||||
"previewColor": {
|
||||
"message": "Förhandsgranskningsfärg",
|
||||
"description": "Referring to submissions that have not been sent to the server yet."
|
||||
@@ -541,6 +547,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Välj en kategori"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "För att skicka segment med kategorin \"{0}\" måste du först aktivera det i alternativen. Du kommer nu att bli omdirigerad till alternativen.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Du måste välja en kategori för alla segment du skickar in!"
|
||||
},
|
||||
@@ -574,6 +584,9 @@
|
||||
"incorrectCategory": {
|
||||
"message": "Fel kategori"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "Den här videon kategoriseras som musik. Är du säker på att denna har en sponsor? Om detta faktiskt är ett \"icke-musiksegment\", öppna tilläggsalternativen och aktivera denna kategori. Då kan du skicka in detta segment som \"icke-musik\" i stället för sponsor. Läs riktlinjerna om något är oklart."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "Flera segment"
|
||||
},
|
||||
@@ -592,5 +605,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Visa en avisering när du lämnar en video med segment som inte har laddats upp"
|
||||
},
|
||||
"help": {
|
||||
"message": "Hjälp"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "YouTube க்கான ஸ்பான்சர் பிளாக் - ஸ்பான்சர்ஷிப்களைத் தவிர்",
|
||||
"message": "YouTube க்கான SponsorBlock - ஸ்பான்சர்ஷிப்களைத் தவிர்",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "ஏற்றுகிறது..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "நிமிடம்"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "நொடிகள்"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "ஒருபோதும் அனுமதிக்காதே"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "பிரிவு இப்போது முடிகிறது"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "இந்த தாவலில் YouTube வீடியோ எதுவும் இல்லை. இது ஒரு YouTube தாவல் என்று உங்களுக்குத் தெரிந்தால், இந்த பாப்அப்பை மூடிவிட்டு மீண்டும் திறக்கவும். அது வேலை செய்யவில்லை என்றால், தாவலை மீண்டும் ஏற்ற முயற்சிக்கவும்."
|
||||
"message": "YouTube வீடியோ எதுவும் கிடைக்கவில்லை.\nஇது தவறாக இருந்தால், தாவலைப் புதுப்பிக்கவும்."
|
||||
},
|
||||
"success": {
|
||||
"message": "வெற்றி!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "ஒரு பிரிவில் வாக்களியுங்கள்"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "இதுவரை, நீங்கள் சமர்ப்பித்தீர்கள்"
|
||||
"Submissions": {
|
||||
"message": "சமர்ப்பிப்புகள்"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "நீங்கள் மக்களை காப்பாற்றியுள்ளீர்கள் "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "லீடர்போர்டைக் காண்க"
|
||||
},
|
||||
"here": {
|
||||
"message": "இங்கே"
|
||||
"message": "லீடர்போர்டு"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "பிரிவு துவங்கி முடிவடையும் போது கீழே உள்ள பொத்தானைக் கிளிக் செய்து பதிவுசெய்து தரவுத்தளத்தில் சமர்ப்பிக்கவும்."
|
||||
"message": "சமர்ப்பிக்கவும்"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "நீங்கள் சமர்ப்பி என்பதைக் கிளிக் செய்த பிறகு பிரிவு எடிட்டிங் தோன்றும்",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "குறிப்பு: ஒரு பிரிவின் தொடக்க / முடிவைப் புகாரளிக்க ஒரு வீடியோவில் கவனம் செலுத்துகையில் அரைக்காற்பகுதி விசையை அழுத்தி சமர்ப்பிக்க மேற்கோள். (இதை விருப்பங்களில் மாற்றலாம்)"
|
||||
"message": "குறிப்பு: விருப்பங்களில் சமர்ப்பிக்க விசைப்பலகைகளை அமைக்கலாம்"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "நேரங்களை அழி"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "நீங்கள் எவ்வளவு பங்களித்தீர்கள் என்பதைக் காட்ட இது பொது புள்ளிவிவரங்கள் பக்கத்தில் பயன்படுத்தப்படுகிறது. அதை பார்"
|
||||
},
|
||||
"Username": {
|
||||
"message": "பயனர்பெயர்"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "பயனர்பெயரை அமைக்கவும்"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "இணைப்பு நேரம் முடிந்தது. உங்கள் இணைய இணைப்பைச் சரிபார்க்கவும். உங்கள் இணையம் இயங்கினால், சேவையகம் அதிக சுமை அல்லது கீழே இருக்கும்."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "ஸ்பான்சர் பிளாக் முடக்கு"
|
||||
"message": "ஸ்கிப்பிங் இயக்கப்பட்டது"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "ஸ்பான்சர் பிளாக் இயக்கவும்"
|
||||
"message": "ஸ்கிப்பிங் முடக்கப்பட்டுள்ளது"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "உங்கள் வேலை",
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "நீங்கள் மக்களைக் காப்பாற்றியுள்ளீர்கள்"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " அவர்களின் வாழ்க்கையில்."
|
||||
"message": " அவர்களின் வாழ்க்கையில்"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "சேவையக நிலைக்கு status.sponsor.ajay.app ஐச் சரிபார்க்கவும்."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "ஒரு வகையைத் தேர்வுசெய்க"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "\"{0}\" வகையுடன் பிரிவுகளைச் சமர்ப்பிக்க, நீங்கள் அதை விருப்பங்களில் இயக்க வேண்டும். நீங்கள் இப்போது விருப்பங்களுக்கு திருப்பி விடப்படுவீர்கள்.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "நீங்கள் சமர்ப்பிக்கும் அனைத்து பிரிவுகளுக்கும் ஒரு வகையைத் தேர்ந்தெடுக்க வேண்டும்!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "பதிவேற்றப்படாத பிரிவுகளுடன் வீடியோவை விட்டு வெளியேறும்போது அறிவிப்பை அனுப்பவும்"
|
||||
},
|
||||
"help": {
|
||||
"message": "உதவி"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "YouTube కోసం స్పాన్సర్బ్లాక్ - స్పాన్సర్షిప్లను దాటవేయి",
|
||||
"message": "YouTube కోసం SponsorBlock - స్పాన్సర్షిప్లను దాటవేయి",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "లోడ్ అవుతుంది..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "నిమిషాలు"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "సెకన్లు"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "నెవర్ షో"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "సెగ్మెంట్ ఇప్పుడు ముగుస్తుంది"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "ఈ ట్యాబ్లో YouTube వీడియో ఏదీ కనుగొనబడలేదు. ఇది యూట్యూబ్ ట్యాబ్ అని మీకు తెలిస్తే, ఈ పాపప్ను మూసివేసి మళ్ళీ తెరవండి. అది పని చేయకపోతే, టాబ్ను మళ్లీ లోడ్ చేయడానికి ప్రయత్నించండి."
|
||||
"message": "YouTube వీడియో కనుగొనబడలేదు.\nఇది తప్పు అయితే, టాబ్ను రిఫ్రెష్ చేయండి."
|
||||
},
|
||||
"success": {
|
||||
"message": "విజయం!"
|
||||
@@ -122,31 +116,32 @@
|
||||
"message": "మీరు దీన్ని ఖచ్చితంగా సమర్పించాలనుకుంటున్నారా?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "వైట్లిస్ట్ ఛానల్"
|
||||
"message": "వైట్లిస్ట్ ఛానెల్"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "వైట్లిస్ట్ నుండి ఛానెల్ తొలగించండి"
|
||||
"message": "వైట్లిస్ట్ నుండి ఛానెల్ని తొలగించండి"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "ఒక విభాగంలో ఓటు వేయండి"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "ఇప్పటివరకు, మీరు సమర్పించారు"
|
||||
"Submissions": {
|
||||
"message": "సమర్పణలు"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "మీరు ప్రజలను రక్షించారు "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "లీడర్బోర్డ్ను చూడండి"
|
||||
},
|
||||
"here": {
|
||||
"message": "ఇక్కడ"
|
||||
"message": "లీడర్బోర్డ్"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "సెగ్మెంట్ ప్రారంభమైనప్పుడు మరియు రికార్డ్ చేయడానికి ముగిసినప్పుడు క్రింది బటన్ను క్లిక్ చేసి డేటాబేస్కు సమర్పించండి."
|
||||
"message": "సమర్పించండి"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "మీరు సమర్పించు క్లిక్ చేసిన తర్వాత విభాగం సవరణ కనిపిస్తుంది",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "సూచన: ఒక సెగ్మెంట్ యొక్క ప్రారంభ / ముగింపును నివేదించడానికి వీడియోపై దృష్టి కేంద్రీకరించినప్పుడు సెమికోలన్ కీని నొక్కండి మరియు సమర్పించడానికి కోట్ చేయండి. (దీన్ని ఎంపికలలో మార్చవచ్చు)"
|
||||
"message": "సూచన: మీరు ఎంపికలలో సమర్పించడానికి కీబైండ్లను సెటప్ చేయవచ్చు"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "టైమ్స్ క్లియర్"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "మీరు ఎంత సహకరించారో చూపించడానికి ఇది పబ్లిక్ గణాంకాల పేజీలో ఉపయోగించబడుతుంది. ఇది చూడు"
|
||||
},
|
||||
"Username": {
|
||||
"message": "వినియోగదారు పేరు"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "వినియోగదారు పేరును సెట్ చేయండి"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "అనుసంధాన సమయం సమాప్తం. మీ ఇంటర్నెట్ కనెక్షన్ను తనిఖీ చేయండి. మీ ఇంటర్నెట్ పనిచేస్తుంటే, సర్వర్ ఓవర్లోడ్ లేదా డౌన్ అయి ఉండవచ్చు."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "స్పాన్సర్బ్లాక్ను ఆపివేయి"
|
||||
"message": "దాటవేయడం ప్రారంభించబడింది"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "స్పాన్సర్బ్లాక్ని ప్రారంభించండి"
|
||||
"message": "దాటవేయడం నిలిపివేయబడింది"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "నీ పని",
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "మీరు ప్రజలను రక్షించారు"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " వారి జీవితాల."
|
||||
"message": " వారి జీవితాల"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "సర్వర్ స్థితి కోసం status.sponsor.ajay.app ని తనిఖీ చేయండి."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "వర్గాన్ని ఎంచుకోండి"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "\"{0}\" వర్గంతో విభాగాలను సమర్పించడానికి, మీరు దీన్ని ఎంపికలలో ప్రారంభించాలి. మీరు ఇప్పుడు ఎంపికలకు మళ్ళించబడతారు.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "మీరు సమర్పించే అన్ని విభాగాల కోసం మీరు తప్పనిసరిగా ఒక వర్గాన్ని ఎంచుకోవాలి!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "మీరు అప్లోడ్ చేయని విభాగాలతో వీడియోను వదిలివేసినప్పుడు నోటిఫికేషన్ పంపండి"
|
||||
},
|
||||
"help": {
|
||||
"message": "సహాయం"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "กำลังโหลด..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "นาที"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "วินาที"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "ไม่แสดงเสมอ"
|
||||
},
|
||||
@@ -70,9 +64,6 @@
|
||||
"sponsor404": {
|
||||
"message": "ไม่พบส่วนในวีดีโอนี้"
|
||||
},
|
||||
"here": {
|
||||
"message": "ที่นี่"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "ล้างเวลา"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"message": "kısım"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "kısımlar"
|
||||
"message": "kısım"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Bu öneriye oy ver"
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Yükleniyor..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Dakika"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Saniye"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Asla Gösterme"
|
||||
},
|
||||
@@ -74,7 +68,7 @@
|
||||
"message": "Sponsor sürelerini yollarken bir sorun oluştur, lütfen tekrar deneyin."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Bu videonun veri tabanımızda kısımları mevcut!"
|
||||
"message": "Bu video için veritabanımızda kısımlar mevcut!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Kısımlar bulunamadı"
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Kısım Şimdi Bitiyor"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Bu sekmede YouTube videosu bulunamadı. Bu sekmenin bir YouTube sekmesi olduğundan eminseniz, bu pencereyi kapatıp, tekrar açın. Eğer o da işe yaramazsa, sekmeyi yenilemeyi deneyin."
|
||||
"message": "YouTube videosu bulunamadı.\nHatalı olduğunu düşünüyorsanız sayfayı yenileyin."
|
||||
},
|
||||
"success": {
|
||||
"message": "Başarılı!"
|
||||
@@ -122,31 +116,32 @@
|
||||
"message": "Bunu göndermek istediğinize emin misiniz?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Kanalı Beyazlisteye Ekle"
|
||||
"message": "Kanalı beyaz listeye ekle"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Kanalı Beyazlisteden Kaldır"
|
||||
"message": "Kanalı beyaz listeden çıkar"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Bir Kısmı Oyla"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Şu an kadar yolladığınız"
|
||||
"Submissions": {
|
||||
"message": "Gönderimleriniz"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "İnsanların şu kadar vaktini kurtardınız "
|
||||
"message": "İnsanları şu kadar kısımdan kurtardınız "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Liderlik tablosunu görüntüle"
|
||||
},
|
||||
"here": {
|
||||
"message": "burada"
|
||||
"message": "Lider Tablosu"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kısmın başladığı ve bittiği yeri kaydetmek ve veri tabanına göndermek için aşağıdaki butona tıklayın."
|
||||
"message": "Gönder"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Kısım düzenlemesi Gönder'e tıkladığınızda görünecek",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "İpucu: Bir kısmın başlangıcını / sonunu seçmek ve göndermek için bir videoyu izlerken noktalı virgül tuşuna basın. (Bu, ayarlardan değiştirilebilir)"
|
||||
"message": "İpucu: Gönderim için ayarlardan kısayol tuşu atayabilirsiniz"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Süreleri Temizle"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Bu, ne kadar katkı sağladığınızı göstermek için herkese açık istatistik sayfasında kullanılacaktır. Görün"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Kullanıcı adı"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Kullanıcı Adı Belirle"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Bağlantı zaman aşımına uğradı. İnternet bağlantınızı kontrol ediniz. Eğer internetiniz çalışıyor ise, büyük ihtimalle sunucuya erişilemiyor veya sunucuya aşırı yüklenilmiş olabilir."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock'u Devredışı Bırak"
|
||||
"message": "Atlama etkin"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock'u Devreye Sok"
|
||||
"message": "Atlama devre dışı"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Çalışmalarınız",
|
||||
@@ -296,7 +294,7 @@
|
||||
"message": "Bu süre, video ilerleme çubuğunun altındaki geçerli zamanın yanında parantez içinde görüntülenir. Bu, videodaki kısımların silinmiş toplam video süresini gösterir. Bu, yalnızca \"Video İlerleme Çubuğunda Göster\" olarak işaretlenen kısımları içerir."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Bunu atladınız "
|
||||
"message": "Şu kadar kısım atladınız "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Şu kadar süre kazandınız "
|
||||
@@ -314,10 +312,10 @@
|
||||
"message": "saat"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "İnsanların"
|
||||
"message": "İnsanların şu kadar vaktini kurtardınız:"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " kadar vaktini kurtardınız."
|
||||
"message": " ömürden"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Sunucu durumu için status.sponsor.ajay.app kontrol edin."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Bir Kategori Seç"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "\"{0}\" kategorisinde bir kısım göndermek için onu ayarlardan açmalısınız. Ayarlara yönlendiriliyorsunuz.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Göndereceğin tüm kısımlar için bir kategori seçmelisin!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Bir videodan kısımları göndermeden ayrılırsan bir bildirim gönderir"
|
||||
},
|
||||
"help": {
|
||||
"message": "Yardım"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Завантаження..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "хв"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "сек"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Не відображати"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "Сегмент закінчується тут"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Можливо, це не вкладка YouTube, або Ви натиснули занадто рано.\n Якщо це вкладка YouTube,\n закрийте це спливаюче вікно і відкрийте його знову."
|
||||
"message": "Відео YouTube, не знайдено.\nЯкщо це не так, поновіть вкладку."
|
||||
},
|
||||
"success": {
|
||||
"message": "Успіх!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "Проголосувати за сегмент"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "На даний момент Ви надіслали"
|
||||
"Submissions": {
|
||||
"message": "Надіслано сегментів"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ви допомогли людям заощадити "
|
||||
"message": "Ви допомогли людям пропустити "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Подивитися дошку пошани"
|
||||
},
|
||||
"here": {
|
||||
"message": "тут"
|
||||
"message": "Дошка пошани"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Натисніть кнопку нижче, коли сегмент починається і закінчується, щоб записати і Надіслати його в базу."
|
||||
"message": "Надіслати"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "Редагування сегментів з'явиться після натискання на кнопку \"Надіслати\"",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Підказка: натисніть на кнопку \"Ж\" під час відтворення, щоб повідомити про початок / кінці сегмента, і \"Е\", щоб надіслати його. (Це можна змінити в налаштуваннях)"
|
||||
"message": "Підказка: Ви можете налаштувати комбінації клавіш для надсилання в опціях"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Очистити час"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "Воно використовується на публічній сторінці статистики, щоб показати Ваш внесок. Її можна подивитися"
|
||||
},
|
||||
"Username": {
|
||||
"message": "Ім'я користувача"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Встановити ім'я користувача"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "Таймаут підключення. Перевірте ваше з'єднання з інтернетом. Якщо ваш інтернет працює, сервер, швидше за все, перевантажений або лежить."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Відключити SponsorBlock"
|
||||
"message": "Пропуск увімкнено"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Увімкнути SponsorBlock"
|
||||
"message": "Пропуск вимкнено"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Ваша робота",
|
||||
@@ -317,7 +315,7 @@
|
||||
"message": "Ви заощадили людям"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " їх життя."
|
||||
"message": " їх життів"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Дивіться стан сервера на status.sponsor.ajay.app."
|
||||
@@ -574,6 +572,10 @@
|
||||
"chooseACategory": {
|
||||
"message": "Оберіть категорію"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "Щоб надіслати сегменти категорії \"{0}\", ви повинні включити її в налаштуваннях. Зараз ви будете туди перенаправлені.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"youMustSelectACategory": {
|
||||
"message": "Ви повинні обрати категорію для всіх сегментів, які ви відправляєте!"
|
||||
},
|
||||
@@ -634,5 +636,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "Надсилати повідомлення, коли ви йдете зі сторінки відео, сегменти до якого Ви не надіслали"
|
||||
},
|
||||
"help": {
|
||||
"message": "Допомога"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "Đang tải..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Phút"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Giây"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Không hiển thị nữa"
|
||||
},
|
||||
@@ -85,9 +79,6 @@
|
||||
"sponsorEnd": {
|
||||
"message": "Đoạn quảng cáo kết thúc vào lúc này"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Không tìm thấy video Youtube trong tab này. Nếu bạn chắc chắn đây là tab Youtube, hãy đóng bảng popup này rồi mở lại. Nếu vẫn không được, hãy thử tải lại tab."
|
||||
},
|
||||
"success": {
|
||||
"message": "Thành công!"
|
||||
},
|
||||
@@ -121,33 +112,9 @@
|
||||
"submitCheck": {
|
||||
"message": "Bạn có chắc là muốn đăng không?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Không chặn kênh này"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Bỏ kênh này khỏi danh sách không chặn"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Bầu chọn một đoạn quảng cáo"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Cho tới giờ, bạn đã đăng"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Bạn đã giúp mọi người bỏ qua "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Xem bảng xếp hạng"
|
||||
},
|
||||
"here": {
|
||||
"message": "ở đây"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Nhấn nút phía dưới khi đoạn quảng cáo bắt đầu và kết thúc để ghi lại và đăng lên kho dữ liệu."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Gợi ý: Nhấn phím dấu chấm phẩy khi đang xem video để báo cáo lúc quảng cáo bắt đầu/kết thúc, và nhấn phím ngoặc kép để đăng. (Có thể thay đổi phím trong phần tùy chọn)"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Xóa thời gian"
|
||||
},
|
||||
@@ -243,12 +210,6 @@
|
||||
"0": {
|
||||
"message": "Kết nối quá hạn thời gian. Hãy kiểm tra đường truyền mạng của bạn. Nếu mạng của bạn vẫn hoạt động, có thể máy chủ đang bị quá tải hoặc không hoạt động."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Tắt SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Bật SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Thành quả của bạn",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
@@ -286,9 +247,6 @@
|
||||
"showTimeWithSkipsDescription": {
|
||||
"message": "Độ dài này được hiển thị trong ngoặc đơn, bên cạnh độ dài hiện tại, phía dưới thanh tiến trình video. Con số này là độ dài video trừ đi các đoạn quảng cáo, bao gồm cả những đoạn được đánh dấu là chỉ \"Hiển thị trong thanh tiến trình video\"."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Bạn đã bỏ qua "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Bạn đã tiết kiệm cho mình "
|
||||
},
|
||||
@@ -304,12 +262,6 @@
|
||||
"hoursLower": {
|
||||
"message": "giờ"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Bạn đã giúp người khác tiết kiệm"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " của đời họ."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Truy cập trang status.sponsor.ajay.app để biết tình trạng máy chủ."
|
||||
},
|
||||
@@ -497,6 +449,9 @@
|
||||
"category_selfpromo": {
|
||||
"message": "Quảng cáo không trả công/Tự quảng cáo"
|
||||
},
|
||||
"category_selfpromo_description": {
|
||||
"message": "Tương tự như 'nhà tài trợ' ngoại trừ việc quảng cáo không được trả tiền hay tự quảng cáo. Điều này bao gồm các phần hàng hóa, đóng góp, hoặc thông tin về người mà họ hợp tác với."
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Nhạc: Phần không nhạc"
|
||||
},
|
||||
|
||||
@@ -30,12 +30,6 @@
|
||||
"Loading": {
|
||||
"message": "加载中..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "分钟"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "秒"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "不再显示"
|
||||
},
|
||||
@@ -63,9 +57,6 @@
|
||||
"Unknown": {
|
||||
"message": "提交您的赞助商广告时间时出错。请稍后再试。"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "在此标签页未找到 Youtube 视频。如果您确定这是一个 Youtube 页面,请关闭此弹窗并重新打开。如果那没用,请尝试重新加载页面。"
|
||||
},
|
||||
"success": {
|
||||
"message": "成功 !"
|
||||
},
|
||||
@@ -84,24 +75,6 @@
|
||||
"submitCheck": {
|
||||
"message": "您确定要提交它吗?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "白名单频道"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "将频道移出白名单"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "您目前已提交"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "您已为人们节省了 "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "查看排行榜"
|
||||
},
|
||||
"here": {
|
||||
"message": "这里"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "清除时间"
|
||||
},
|
||||
@@ -181,12 +154,6 @@
|
||||
"0": {
|
||||
"message": "连接超时。请检查您的网络连接。如果您的网络运行正常,则可能是服务器过载或宕机。"
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "禁用 SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "启用 SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "您的成果",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
@@ -200,9 +167,6 @@
|
||||
"skip": {
|
||||
"message": "跳过"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "跳过 {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "跳过"
|
||||
},
|
||||
@@ -215,9 +179,6 @@
|
||||
"audioNotification": {
|
||||
"message": "跳过时音频通知"
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "您已跳过 "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "您为自己节省了 "
|
||||
},
|
||||
@@ -233,12 +194,6 @@
|
||||
"hoursLower": {
|
||||
"message": "小时"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "您为人们节省了"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " 的生命。"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "在 status.sponsor.ajay.app 检查服务器状态。"
|
||||
},
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
"Loading": {
|
||||
"message": "載入中…"
|
||||
},
|
||||
"Mins": {
|
||||
"message": "分"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "秒"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "永不顯示"
|
||||
},
|
||||
@@ -86,7 +80,7 @@
|
||||
"message": "片段現在結束"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "未在這個分頁找到任何YouTube影片。 如果您知道這是個YouTube分頁的話,關閉這個彈出視窗並重新開啟它。如果還是不管用,嘗試重新載入分頁"
|
||||
"message": "找不到 YouTube 影片。\n如果這是不正確的,重新整理此分頁"
|
||||
},
|
||||
"success": {
|
||||
"message": "成功!"
|
||||
@@ -130,23 +124,24 @@
|
||||
"voteOnTime": {
|
||||
"message": "為分段投票"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "您目前已提交"
|
||||
"Submissions": {
|
||||
"message": "提交數"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "您已為大家節省 "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "查看排行榜"
|
||||
},
|
||||
"here": {
|
||||
"message": "這裡"
|
||||
"message": "排行榜"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "點擊下方的按鈕來錄製分段的始與末"
|
||||
"message": "提交"
|
||||
},
|
||||
"submissionEditHint": {
|
||||
"message": "段落編輯會在您提交之後出現",
|
||||
"description": "Appears in the popup to inform them that editing has been moved to the video player."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "小提醒:在聚焦於影片時按下分號鍵來記錄分段的始與末然後按下冒號鍵來提交(您可以透過選項來更改這項設定)"
|
||||
"message": "小提醒:你可以為提交在設定裡綁定一個按鍵"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "清除時間"
|
||||
@@ -157,6 +152,9 @@
|
||||
"publicStats": {
|
||||
"message": "這會被公開的統計頁面來展示您的貢獻。查看它"
|
||||
},
|
||||
"Username": {
|
||||
"message": "使用者名稱"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "設定使用者名稱"
|
||||
},
|
||||
@@ -253,10 +251,10 @@
|
||||
"message": "連線超時。請檢查您的網路連線。若您的網路運作正常,則可能是伺服器超載或離線"
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "停用 SponsorBlock"
|
||||
"message": "跳過已啟用"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "啟用 SponsorBlock"
|
||||
"message": "跳過已停用"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "您的成果",
|
||||
@@ -272,7 +270,7 @@
|
||||
"message": "略過"
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "略過 {0}?"
|
||||
"message": "跳過 {0}?"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "已跳過"
|
||||
@@ -634,5 +632,8 @@
|
||||
},
|
||||
"unsubmittedWarningDescription": {
|
||||
"message": "在您離開含有未提交的片段的影片時寄送通知"
|
||||
},
|
||||
"help": {
|
||||
"message": "幫助"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.sbHidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
.previewbar {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
@@ -23,12 +18,29 @@
|
||||
|
||||
/* Preview Bar page hacks */
|
||||
|
||||
.sbTooltipTwoTitleThumbnailOffset {
|
||||
bottom: -5px !important;
|
||||
.ytp-tooltip:not(.sponsorCategoryTooltipVisible) .sponsorCategoryTooltip {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.sbTooltipOneTitleThumbnailOffset {
|
||||
bottom: 10px !important;
|
||||
.ytp-tooltip.sponsorCategoryTooltipVisible {
|
||||
transform: translateY(-1em) !important;
|
||||
}
|
||||
|
||||
.ytp-big-mode .ytp-tooltip.sponsorCategoryTooltipVisible {
|
||||
transform: translateY(-2em) !important;
|
||||
}
|
||||
|
||||
#movie_player:not(.ytp-big-mode) .ytp-tooltip.sponsorCategoryTooltipVisible > .ytp-tooltip-text-wrapper {
|
||||
transform: translateY(1em) !important;
|
||||
}
|
||||
|
||||
.ytp-big-mode .ytp-tooltip.sponsorCategoryTooltipVisible > .ytp-tooltip-text-wrapper {
|
||||
transform: translateY(0.5em) !important;
|
||||
}
|
||||
|
||||
.ytp-big-mode .ytp-tooltip.sponsorCategoryTooltipVisible > .ytp-tooltip-text-wrapper > .ytp-tooltip-text {
|
||||
display: block !important;
|
||||
transform: translateY(1em) !important;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
1
public/icons/check.svg
Normal file
1
public/icons/check.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="#fff" d="M20.3 2L9 13.6l-5.3-5L0 12.3 9 21 24 5.7z"/></svg>
|
||||
|
After Width: | Height: | Size: 134 B |
1
public/icons/pencil.svg
Normal file
1
public/icons/pencil.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="#fff" d="M14.1 7.1l2.9 2.9L6.1 20.7l-3.6.7.7-3.6L14.1 7.1zm0-2.8L1.4 16.9 0 24l7.1-1.4L19.8 9.9l-5.7-5.7zm7.1 4.3L24 5.7 18.3 0l-2.8 2.8 5.7 5.7z"/></svg>
|
||||
|
After Width: | Height: | Size: 229 B |
1
public/icons/settings.svg
Normal file
1
public/icons/settings.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="#fff" d="M24 13.6v-3.2c-1.7-.6-2.7-.8-3.2-2h0c-.5-1.3.1-2.1.8-3.7l-2.3-2.3c-1.6.7-2.4 1.4-3.7.8h0c-1.3-.5-1.4-1.6-2-3.2h-3.2c-.6 1.6-.7 2.7-2 3.2h0c-1.3.5-2.1-.1-3.7-.8L2.4 4.7c.7 1.6 1.4 2.4.8 3.7s-1.6 1.4-3.2 2v3.2c1.6.6 2.7.7 3.2 2 .5 1.3-.1 2.2-.8 3.7l2.3 2.3c1.6-.7 2.4-1.4 3.7-.8h0c1.3.5 1.4 1.6 2 3.2h3.2c.6-1.6.8-2.7 2-3.2h0c1.3-.5 2.1.1 3.7.9l2.3-2.3c-.7-1.6-1.4-2.4-.8-3.7s1.6-1.4 3.2-2zM12 16a4 4 0 1 1 0-8 4 4 0 1 1 0 8z"/></svg>
|
||||
|
After Width: | Height: | Size: 516 B |
1
public/icons/thumb.svg
Normal file
1
public/icons/thumb.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="#fff" d="M21.4 9.6c-1.2 0-2.9-.3-4-.8.8-3.3 1.3-8.8-2.2-8.8-1.8 0-2.3 1.7-2.8 3.3-1.6 5.4-4 6.9-6.4 7.5V10H0v12h6v-.9a19.2 19.2 0 016.2 1.8c1.2.5 3 1.1 5.3 1.1 2.5 0 4.3-1 5-3.7.5-1.9 1.5-7.2 1.5-8.2 0-1.7-1.2-2.5-2.6-2.5zM4 20H2v-8h2v8zm15.9-5.6h1c1.2 0 1.1 1.5 0 1.6h-1.7c-.7.2-.7 1.3.1 1.2h1.2c1 0 1 1.4 0 1.5l-1.7.1c-.8.1-.7 1.3 0 1.2h.8c.9-.1 1 .8-.3 1.6-1.5.9-4.6.1-6.4-.6-2.2-1-4.4-2-7-2v-6c3.3-.8 6.4-2.3 8.4-9.1.9-3.1 1.7-2 1.7.6 0 2-.5 3.8-1 5.5 1.1.5 3.4 1.4 6.2 1.6 1 0 1 1.4 0 1.5l-1.5.2s-.6 1.1.2 1.1z"/></svg>
|
||||
|
After Width: | Height: | Size: 599 B |
@@ -3,7 +3,7 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2) format('woff2');
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@@ -11,7 +11,7 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2) format('woff2');
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@@ -19,7 +19,7 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2) format('woff2');
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@@ -27,7 +27,7 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2) format('woff2');
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@@ -35,15 +35,15 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2) format('woff2');
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@@ -51,6 +51,62 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v12/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2) format('woff2');
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@@ -529,81 +529,81 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@types/prop-types
|
||||
15.7.3 <https://github.com/DefinitelyTyped/DefinitelyTyped>
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
@types/react
|
||||
16.9.22 <https://github.com/DefinitelyTyped/DefinitelyTyped>
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
@types/react-dom
|
||||
16.9.5 <https://github.com/DefinitelyTyped/DefinitelyTyped>
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
|
||||
******************************
|
||||
@@ -637,26 +637,26 @@ SOFTWARE.
|
||||
|
||||
@webassemblyjs/floating-point-hex-parser
|
||||
1.8.5 <https://github.com/xtuc/webassemblyjs>
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Mauro Bringolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Mauro Bringolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
******************************
|
||||
@@ -1855,7 +1855,7 @@ THE SOFTWARE.
|
||||
async-each
|
||||
1.0.3 <https://github.com/paulmillr/async-each>
|
||||
license: MIT
|
||||
authors: Paul Miller <https://paulmillr.com/>
|
||||
authors: Paul Miller (https://paulmillr.com/)
|
||||
|
||||
******************************
|
||||
|
||||
@@ -2640,6 +2640,34 @@ The above copyright notice and this permission notice shall be included in all c
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
bindings
|
||||
1.5.0 <https://github.com/TooTallNate/node-bindings>
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
bluebird
|
||||
@@ -3760,13 +3788,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
color-name
|
||||
1.1.3 <https://github.com/dfcreative/color-name>
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2015 Dmitry Ivanov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2015 Dmitry Ivanov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************
|
||||
@@ -3830,30 +3858,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
component-emitter
|
||||
1.3.0 <https://github.com/component/emitter>
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Component contributors <dev@component.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Component contributors <dev@component.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
@@ -4918,6 +4946,32 @@ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
|
||||
USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
file-uri-to-path
|
||||
1.0.0 <https://github.com/TooTallNate/file-uri-to-path>
|
||||
Copyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
fill-range
|
||||
@@ -5153,6 +5207,34 @@ the licensed code:
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
fsevents
|
||||
2.1.3 <https://github.com/fsevents/fsevents>
|
||||
MIT License
|
||||
-----------
|
||||
|
||||
Copyright (C) 2010-2020 by Philipp Dunkel, Ben Noordhuis, Elan Shankar, Paul Miller
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
gensync
|
||||
@@ -6709,6 +6791,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
nan
|
||||
2.14.1 <https://github.com/nodejs/nan>
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright (c) 2018 NAN contributors
|
||||
-----------------------------------
|
||||
|
||||
*NAN contributors listed at <https://github.com/nodejs/nan#contributors>*
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
nanomatch
|
||||
@@ -8034,26 +8135,26 @@ authors: Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
regjsgen
|
||||
0.2.0 <https://github.com/d10/regjsgen>
|
||||
Copyright 2014 Benjamin Tan <demoneaux@gmail.com> (https://d10.github.io/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Copyright 2014 Benjamin Tan <demoneaux@gmail.com> (https://d10.github.io/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
@@ -8350,7 +8451,7 @@ SOFTWARE.
|
||||
run-queue
|
||||
1.0.3 <https://github.com/iarna/run-queue>
|
||||
license: ISC
|
||||
authors: Rebecca Turner <me@re-becca.org>
|
||||
authors: Rebecca Turner <me@re-becca.org> (http://re-becca.org/)
|
||||
|
||||
******************************
|
||||
|
||||
@@ -9336,7 +9437,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
spdx-license-ids
|
||||
3.0.5 <https://github.com/shinnn/spdx-license-ids>
|
||||
license: CC0-1.0
|
||||
authors: Shinnosuke Watanabe <https://github.com/shinnn>
|
||||
authors: Shinnosuke Watanabe (https://github.com/shinnn)
|
||||
|
||||
******************************
|
||||
|
||||
@@ -9961,61 +10062,61 @@ THE SOFTWARE.
|
||||
|
||||
tslib
|
||||
1.10.0 <https://github.com/Microsoft/tslib>
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
517
public/popup.css
517
public/popup.css
@@ -1,242 +1,373 @@
|
||||
/* reset some properties to default (youtube messes with them */
|
||||
p.popupElement {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
:root {
|
||||
--sb-main-bg-color: #222626;
|
||||
--sb-main-fg-color: white;
|
||||
--sb-gray-fg-color: #444848;
|
||||
--sb-on-white-bg: black;
|
||||
--sb-green-bg: #077B27;
|
||||
}
|
||||
|
||||
h1.popupElement {
|
||||
margin-block-start: 0.67em;
|
||||
margin-block-end: 0.67em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
font-weight: bold;
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
h2.popupElement {
|
||||
margin-block-start: 0.83em;
|
||||
margin-block-end: 0.83em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
font-weight: bold;
|
||||
@media only screen and (max-width: 600px) {
|
||||
#sponsorBlockPopupBody {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
h3.popupElement {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
font-weight: bold;
|
||||
#sponsorBlockPopupBody {
|
||||
margin: auto;
|
||||
width: 374px;
|
||||
background: var(--sb-main-bg-color);
|
||||
}
|
||||
|
||||
sub.popupElement {
|
||||
font-size: smaller;
|
||||
#sponsorblockPopup {
|
||||
color: var(--sb-main-fg-color);
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
width: 330px;
|
||||
padding: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
/* end reset */
|
||||
|
||||
#sponsorBlockPopupLogo {
|
||||
vertical-align: text-bottom;
|
||||
#issueReporterTimeButtons > .votingButtons > .segmentTimeButton {
|
||||
font-weight: bold;
|
||||
color: var(--sb-main-fg-color);
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 7px;
|
||||
outline: none;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.sponsorTimesThanksForVotingText {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.voteButton {
|
||||
height: 20px;
|
||||
padding: 0 5px;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#videoInfo>p, #videoInfo>div>p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.logoText {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
color: var(--sb-main-fg-color);
|
||||
}
|
||||
|
||||
div.logoText>p, .sbHeader {
|
||||
font-size: 32px;
|
||||
margin: -4px 0 -2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sbHeader.sbSubHeader {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.largeButton{
|
||||
background: white;
|
||||
/*font-weight: bold;*/
|
||||
padding: 6px 24px;
|
||||
font-size: 20px;
|
||||
border-radius: 25px;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
min-height: 26px;
|
||||
min-width: 152px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
}
|
||||
|
||||
.sponsorBlockPageBody .mediumButton {
|
||||
background-color:#cc1717;
|
||||
-moz-border-radius:28px;
|
||||
-webkit-border-radius:28px;
|
||||
border-radius:28px;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:16px;
|
||||
padding:8px 37px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 0px 0px #662727;
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
|
||||
transition: 0.01s background-color;
|
||||
}
|
||||
.sponsorBlockPageBody .mediumButton:hover {
|
||||
background-color:#ec1c1c;
|
||||
}
|
||||
.sponsorBlockPageBody .mediumButton:focus {
|
||||
outline: none;
|
||||
background-color:#ec1c1c;
|
||||
}
|
||||
.sponsorBlockPageBody .mediumButton:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
/* disable extension */
|
||||
|
||||
#disableExtension {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* switch button */
|
||||
|
||||
.toggleSwitchContainer {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switchBg {
|
||||
display: block;
|
||||
height: 37px;
|
||||
width: 78px;
|
||||
border-radius: 18.5px;
|
||||
}
|
||||
|
||||
.switchBg.shadow {
|
||||
background: none;
|
||||
box-shadow: 0.75px 0.75px 10px 0px rgba(50, 50, 50, 0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.switchBg.white {
|
||||
position: absolute;
|
||||
background: white;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.switchBg.green {
|
||||
position: absolute;
|
||||
background: #00a205;
|
||||
opacity: 0;
|
||||
transition: opacity .2s ease-out;
|
||||
}
|
||||
|
||||
.switchDot {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: 6px;
|
||||
background: white;
|
||||
position: absolute;
|
||||
border-radius: 12.5px;
|
||||
box-shadow: .75px .75px 3.8px 0px rgba(50, 50, 50, 0.45);
|
||||
transition: transform .2s ease-out;
|
||||
}
|
||||
|
||||
.preload * {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
#toggleSwitch:checked~.switchDot {
|
||||
transform: translateX(40px);
|
||||
}
|
||||
|
||||
#toggleSwitch:checked~.switchBg.green {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
#toggleSwitch:checked~.switchBg.white {
|
||||
opacity: 0 !important;
|
||||
transition: opacity .2s step-end;
|
||||
}
|
||||
|
||||
.sidebyside {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
width: 88%;
|
||||
margin: 0 6% 0 6%;
|
||||
}
|
||||
|
||||
.sidebyside>div {
|
||||
width: 50%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#whitelistButton, #sponsorTimesSkipsDoneContainer, .toggleSwitchContainer {
|
||||
margin-bottom: 2px !important;
|
||||
}
|
||||
|
||||
#whitelistForceCheck {
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
font-size: large;
|
||||
cursor: pointer;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.sbHeader {
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.logoText {
|
||||
color: white;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
h1.popupElement {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 10px;
|
||||
#videoInfo, #mainControls, .sidebyside, #sponsorTimesSkipsDoneContainer, .largeButton {
|
||||
margin-bottom: 12px !important;
|
||||
}
|
||||
#mainControls{
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
#submitTimesContainer{
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
/* additional buttons */
|
||||
|
||||
#additionalButtons {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.popupBody {
|
||||
font-size: 14px;
|
||||
background-color: #333;
|
||||
padding: 0px 5px;
|
||||
#additionalButtons>button, button#setUsernameButton, #submitUsername {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
width: fit-content;
|
||||
padding-left: 0;
|
||||
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
|
||||
color: #dddddd;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.outerPopupBody {
|
||||
background-color: #222626;
|
||||
overflow-y: scroll;
|
||||
#submitUsername {
|
||||
padding-left: 5pt;
|
||||
}
|
||||
|
||||
.discreteLink.popupElement {
|
||||
color: #dddddd;
|
||||
#additionalButtons, #additionalButtons>button {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.recordingSubtitle.popupElement {
|
||||
margin-bottom: 10px;
|
||||
#usernameValue, #usernameInput, #sponsorTimesContributionsDisplay{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.voteButton.popupElement {
|
||||
height: 32px;
|
||||
margin-right: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.voteButton:hover.popupElement {
|
||||
filter: brightness(80%);
|
||||
.SBWhitelistIcon {
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#discordButtonContainer.popupElement {
|
||||
font-size: 12px;
|
||||
.SBWhitelistIcon>path {
|
||||
fill: var(--sb-main-fg-color);
|
||||
}
|
||||
|
||||
.sponsorTime.popupElement {
|
||||
font-size: 20px;
|
||||
label>p, #disableExtension>p, #usernameValue, #usernameElement > div > p,#sponsorTimesContributionsContainer > div > p, #usernameElement > div > #setUsername > #setUsernameStatusContainer > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.smallLink.popupElement {
|
||||
font-size: 10px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
#usernameElement > div > p, #sponsorTimesContributionsContainer {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.mediumLink.popupElement {
|
||||
font-size: 15px;
|
||||
margin-left: 25px;
|
||||
margin-right: 25px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
.grayedOut>.SBWhitelistIcon>path {
|
||||
fill: var(--sb-gray-fg-color);
|
||||
}
|
||||
|
||||
.tinyLink.popupElement {
|
||||
font-size: 10px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
.grayedOut>label {
|
||||
color: var(--sb-gray-fg-color);
|
||||
}
|
||||
|
||||
.whitelistButton.popupElement {
|
||||
background-color:#27a52d;
|
||||
-moz-border-radius:28px;
|
||||
-webkit-border-radius:28px;
|
||||
border-radius:28px;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:16px;
|
||||
padding:8px 37px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 0px 0px #27663c;
|
||||
|
||||
transition: 0.01s background-color;
|
||||
}
|
||||
.whitelistButton:hover.popupElement {
|
||||
background-color:#3acc3a;
|
||||
}
|
||||
.whitelistButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#3acc3a;
|
||||
}
|
||||
.whitelistButton:active.popupElement {
|
||||
position:relative;
|
||||
top:1px;
|
||||
.SBWhitelistIcon.rotated {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.greenButton.popupElement {
|
||||
background-color:#cc1717;
|
||||
-moz-border-radius:28px;
|
||||
-webkit-border-radius:28px;
|
||||
border-radius:28px;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:16px;
|
||||
padding:8px 37px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 0px 0px #662727;
|
||||
|
||||
transition: 0.01s background-color;
|
||||
}
|
||||
.greenButton:hover.popupElement {
|
||||
background-color:#ec1c1c;
|
||||
}
|
||||
.greenButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#ec1c1c;
|
||||
}
|
||||
.greenButton:active.popupElement {
|
||||
position:relative;
|
||||
top:1px;
|
||||
.SBWhitelistIconContainer, button#optionsButton>img, .logoText>img, #usernameValue {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.dangerButton.popupElement {
|
||||
background-color:#bc3315;
|
||||
-moz-border-radius:3px;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:13px;
|
||||
padding:6px 24px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 1px 0px #854629;
|
||||
}
|
||||
.dangerButton:hover.popupElement {
|
||||
background-color:#d0451b;
|
||||
}
|
||||
.dangerButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#d0451b;
|
||||
}
|
||||
.dangerButton:active.popupElement {
|
||||
position:relative;
|
||||
top:1px;
|
||||
#whitelistButton>label, #additionalButtons>button, div#setUsernameContainer {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.warningButton.popupElement {
|
||||
background-color:#bc8215;
|
||||
-moz-border-radius:3px;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:13px;
|
||||
padding:6px 24px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 1px 0px #856829;
|
||||
}
|
||||
.warningButton:hover.popupElement {
|
||||
background-color:#d0821b;
|
||||
}
|
||||
.warningButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#d0821b;
|
||||
}
|
||||
.warningButton:active.popupElement {
|
||||
position:relative;
|
||||
top:1px;
|
||||
#whitelistButton>label, #additionalButtons>button, div#setUsernameContainer>button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.smallButton.popupElement {
|
||||
background-color:#f9902d;
|
||||
-moz-border-radius:3px;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
border:1px solid #f9a72d;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:14px;
|
||||
padding:6px 10px;
|
||||
text-decoration:none;
|
||||
#usernameElement > div, #sponsorTimesContributionsContainer > div {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.smallButton:hover.popupElement {
|
||||
background-color:#fa9806;
|
||||
|
||||
.sidebyside > #usernameElement, .sidebyside > #sponsorTimesContributionsContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.smallButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#fa9806;
|
||||
|
||||
#usernameValue{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 130px;
|
||||
}
|
||||
|
||||
#setUsername {
|
||||
display:flex;
|
||||
}
|
||||
|
||||
#usernameInput {
|
||||
background: none;
|
||||
padding: 0;
|
||||
border: white 1px solid;
|
||||
color: var(--sb-main-fg-color);
|
||||
width: calc(100% - 24px);
|
||||
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#setUsername.SBExpanded {
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
/* footer */
|
||||
|
||||
#sbFooter > a {
|
||||
color: var(--sb-main-fg-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#showNoticeAgain {
|
||||
margin-top: 30px;
|
||||
|
||||
color: var(--sb-main-fg-color);
|
||||
background: none;
|
||||
border: 1px solid white;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
|
||||
border-radius: 5px;
|
||||
}
|
||||
.smallButton:active.popupElement {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
@@ -1,203 +1,148 @@
|
||||
<html>
|
||||
<head>
|
||||
<link id="sponsorBlockPopupFont" rel="stylesheet" type="text/css" href="/libs/Source+Sans+Pro.css"/>
|
||||
<link id="sponsorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/>
|
||||
</head>
|
||||
<head>
|
||||
<title>__MSG_openPopup__</title>
|
||||
<link id="sponsorBlockPopupFont" rel="stylesheet" type="text/css" href="/libs/Source+Sans+Pro.css">
|
||||
<link id="sponsorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css">
|
||||
|
||||
<body class="outerPopupBody">
|
||||
<center>
|
||||
<div id="app" class="popupBody sponsorBlockPageBody">
|
||||
<h1 class="popupElement logoText">
|
||||
<img src="icons/IconSponsorBlocker256px.png" height="32px" id="sponsorBlockPopupLogo"/>
|
||||
SponsorBlock
|
||||
</h1>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
|
||||
<!-- Loading text -->
|
||||
<p id="loadingIndicator" class="popupElement">__MSG_noVideoID__</p>
|
||||
|
||||
<!-- Hidden until loading complete -->
|
||||
<div id="mainControls" class="main popupElement" style="display: none">
|
||||
<!-- If the video was found in the database -->
|
||||
<div id="videoFound">
|
||||
|
||||
<body id="sponsorBlockPopupBody">
|
||||
<div id="sponsorblockPopup" class="sponsorBlockPageBody preload">
|
||||
<div class="logoText bottomSpace">
|
||||
<img src="icons/IconSponsorBlocker256px.png" height="40px" id="sponsorBlockPopupLogo">
|
||||
<p>SponsorBlock</p>
|
||||
</div>
|
||||
<div id="videoInfo" class="bottomSpace">
|
||||
<div class="bottomSpace">
|
||||
<!-- Loading text -->
|
||||
<p id="loadingIndicator">__MSG_noVideoID__</p>
|
||||
<!-- If the video was found in the database -->
|
||||
<p id="videoFound"></p>
|
||||
</div>
|
||||
<div id="issueReporterContainer">
|
||||
<div id="issueReporterTimeButtons"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebyside">
|
||||
<div id="disableExtension">
|
||||
<!--github: mbledkowski/toggle-switch-->
|
||||
<label for="toggleSwitch" class="toggleSwitchContainer">
|
||||
<input type="checkbox" style="display:none;" id="toggleSwitch" checked>
|
||||
<span class="switchBg shadow"></span>
|
||||
<span class="switchBg white"></span>
|
||||
<span class="switchBg green"></span>
|
||||
<span class="switchDot"></span>
|
||||
</label>
|
||||
<p id="disableSkipping">__MSG_disableSkipping__</p>
|
||||
<p id="enableSkipping" style="display: none">__MSG_enableSkipping__</p>
|
||||
</div>
|
||||
<div id="additionalButtons">
|
||||
<!-- grayedOut until loading complete -->
|
||||
<div id="whitelistButton" class="hidden bottomSpace" title="__MSG_forceChannelCheckPopup__">
|
||||
<input type="checkbox" style="display:none;" id="whitelistToggle">
|
||||
<label for="whitelistToggle" class="whitelistToggleText">
|
||||
<div class="SBWhitelistIconContainer">
|
||||
<svg viewBox="0 0 24 24" width="16" height="16" class="SBWhitelistIcon">
|
||||
<path d="M24 10H14V0h-4v10H0v4h10v10h4V14h10z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div id="downloadedSponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
|
||||
<p class="popupElement">
|
||||
__MSG_recordTimesDescription__
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<button id="sponsorStart" class="greenButton popupElement">__MSG_sponsorStart__</button>
|
||||
</div>
|
||||
|
||||
<sub class="popupElement">__MSG_popupHint__</sub>
|
||||
|
||||
<div id="submissionSection" class="popupElement" style="display: none">
|
||||
<br/>
|
||||
|
||||
<b>Sponsor Editing has been moved and will appear after you click submit</b>
|
||||
|
||||
<br/>
|
||||
|
||||
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
||||
|
||||
<button id="submitTimes" class="smallButton popupElement">__MSG_submitTimesButton__</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="discordButtonContainer" class="popupElement" style="display: none">
|
||||
<br/>
|
||||
|
||||
<a href="https://discord.gg/QnmVMpU" class="popupElement" target="_blank"><img src="https://www.logolynx.com/images/logolynx/1b/1bcc0f0aefe71b2c8ce66ffe8645d365.png" height="32px"/></a>
|
||||
|
||||
<br/>
|
||||
|
||||
__MSG_discordAdvert__
|
||||
|
||||
<br/>
|
||||
|
||||
<span id="hideDiscordButton" class="smallLink popupElement">__MSG_hideThis__</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<br/>
|
||||
|
||||
<button id="whitelistChannel" class="whitelistButton popupElement">__MSG_whitelistChannel__</button>
|
||||
<button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">__MSG_removeFromWhitelist__</button>
|
||||
|
||||
<div id="whitelistForceCheck" style="text-decoration: underline; cursor: pointer;display: none">
|
||||
__MSG_forceChannelCheckPopup__
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="reportAnIssue" class="dangerButton popupElement">__MSG_voteOnTime__</button>
|
||||
|
||||
<div id="issueReporterContainer" class="popupElement" style="display: none">
|
||||
|
||||
<h3 style="margin-top: 0px" class="popupElement">__MSG_voteOnTime__</h3>
|
||||
|
||||
<div id="issueReporterTimeButtons" class="popupElement">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button id="disableSkipping" class="greenButton popupElement">__MSG_disableSkipping__</button>
|
||||
<button id="enableSkipping" class="whitelistButton popupElement" style="display: none">__MSG_enableSkipping__</button>
|
||||
</div>
|
||||
|
||||
<h2 class="recordingSubtitle popupElement">__MSG_yourWork__</h2>
|
||||
|
||||
<p class="popupElement">
|
||||
<span id="sponsorTimesContributionsContainer" class="popupElement" style="display: none">
|
||||
__MSG_soFarUHSubmited__
|
||||
<span id="sponsorTimesContributionsDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesContributionsDisplayEndWord" class="popupElement">__MSG_Sponsors__</span>.
|
||||
</span>
|
||||
|
||||
<span id="sponsorTimesViewsContainer" class="popupElement" style="display: none">
|
||||
__MSG_savedPeopleFrom__
|
||||
<span id="sponsorTimesViewsDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesViewsDisplayEndWord" class="popupElement">__MSG_Segments__</span>.
|
||||
</span>
|
||||
|
||||
<span id="sponsorTimesOthersTimeSavedContainer" class="popupElement" style="display: none">
|
||||
__MSG_youHaveSavedTime__
|
||||
<span id="sponsorTimesOthersTimeSavedDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesOthersTimeSavedEndWord" class="popupElement">__MSG_minsLower__</span>
|
||||
|
||||
<span class="popupElement">__MSG_youHaveSavedTimeEnd__</span>
|
||||
</span>
|
||||
|
||||
<div id="sponsorTimesSkipsDoneContainer" class="popupElement" style="display: none">
|
||||
__MSG_youHaveSkipped__
|
||||
<span id="sponsorTimesSkipsDoneDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesSkipsDoneEndWord" class="popupElement">__MSG_Segments__</span>
|
||||
</div>
|
||||
|
||||
<div id="sponsorTimeSavedContainer" class="popupElement" style="display: none">
|
||||
__MSG_youHaveSaved__
|
||||
<span id="sponsorTimeSavedDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimeSavedEndWord" class="popupElement">__MSG_minsLower__</span>.
|
||||
|
||||
</br/>
|
||||
</br/>
|
||||
</div>
|
||||
|
||||
<div class="popupElement">
|
||||
__MSG_viewLeaderboard__ <a class="popupElement discreteLink" href="https://sponsor.ajay.app/stats" target="_blank">__MSG_here__</a>.
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div id="setUsernameContainer" class="popupElement">
|
||||
|
||||
<button id="setUsernameButton" class="warningButton popupElement">__MSG_setUsername__</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
__MSG_publicStats__ <a class="popupElement discreteLink" href="https://sponsor.ajay.app/stats" target="_blank">__MSG_here__</a>.
|
||||
</sub>
|
||||
</div>
|
||||
|
||||
<div id="setUsername" class="popupElement" style="display: none">
|
||||
<h3>__MSG_setUsername__</h3>
|
||||
|
||||
<div id="setUsernameStatusContainer" style="display: none">
|
||||
<h2 id="setUsernameStatus"></h2>
|
||||
</div>
|
||||
|
||||
<input id="usernameInput" hint="Username"></input>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="submitUsername" class="warningButton popupElement">__MSG_setUsername__</button>
|
||||
</div>
|
||||
|
||||
<div id="optionsButtonContainer" class="popupElement">
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="optionsButton" class="dangerButton popupElement">__MSG_Options__</button>
|
||||
|
||||
<br/>
|
||||
|
||||
<sub class="popupElement">
|
||||
__MSG_optionsInfo__
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
<button id="showNoticeAgain" style="display: none" class="dangerButton popupElement">__MSG_showNotice__</button>
|
||||
<p id="whitelistChannel">__MSG_whitelistChannel__</p>
|
||||
<p id="unwhitelistChannel" style="display: none">__MSG_removeFromWhitelist__</p>
|
||||
</label>
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
<button id="optionsButton" title="__MSG_optionsInfo__">
|
||||
<img src="/icons/settings.svg" alt="Settings icon" width="16" height="16" id="sbPopupIconSettings">
|
||||
__MSG_Options__
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="whitelistForceCheck" class="hidden">
|
||||
__MSG_forceChannelCheckPopup__
|
||||
</div>
|
||||
|
||||
<div id="mainControls" style="display: none">
|
||||
<p class="sbHeader sbSubHeader">
|
||||
__MSG_recordTimesDescription__
|
||||
</p>
|
||||
<sub style="margin-bottom: 12px;">__MSG_popupHint__</sub>
|
||||
<div>
|
||||
<button id="sponsorStart" class="mediumButton">__MSG_sponsorStart__</button>
|
||||
</div>
|
||||
<div id="submissionSection" style="display: none">
|
||||
<b style="display: block; margin-top: 12px;">__MSG_submissionEditHint__</b>
|
||||
<div id="submitTimesContainer" style="display: none; margin-top: 12px;">
|
||||
<button id="submitTimes" class="mediumButton">__MSG_submitTimesButton__</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="recordingSubtitle sbHeader sbSubHeader">__MSG_yourWork__</h1>
|
||||
<div class="sidebyside">
|
||||
<div id="usernameElement">
|
||||
<div>
|
||||
<p>__MSG_Username__:</p>
|
||||
<div id="setUsernameContainer">
|
||||
<p id="usernameValue"></p>
|
||||
<button id="setUsernameButton" title="__MSG_setUsername__">
|
||||
<img src="/icons/pencil.svg" alt="__MSG_setUsername__" width="16" height="16" id="sbPopupIconEdit">
|
||||
</button>
|
||||
</div>
|
||||
<div id="setUsername" style="display: none">
|
||||
<div id="setUsernameStatusContainer" style="display: none">
|
||||
<p id="setUsernameStatus"></p>
|
||||
</div>
|
||||
<input id="usernameInput" hint="Username"></input>
|
||||
<button id="submitUsername">
|
||||
<img src="/icons/check.svg" alt="__MSG_setUsername__" width="16" height="16" id="sbPopupIconCheck">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sponsorTimesContributionsContainer" class="hidden">
|
||||
<div>
|
||||
<p>__MSG_Submissions__:</p>
|
||||
<span id="sponsorTimesContributionsDisplay">
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span id="sponsorTimesViewsContainer" style="display: none">
|
||||
__MSG_savedPeopleFrom__
|
||||
<b><span id="sponsorTimesViewsDisplay">
|
||||
0
|
||||
</span></b>
|
||||
<span id="sponsorTimesViewsDisplayEndWord">__MSG_Segments__</span>
|
||||
<br>
|
||||
(<b><span id="sponsorTimesOthersTimeSavedDisplay">0</span>
|
||||
<span id="sponsorTimesOthersTimeSavedEndWord">__MSG_minsLower__</span></b>
|
||||
<span>__MSG_youHaveSavedTimeEnd__</span>).
|
||||
</span>
|
||||
<div id="sponsorTimesSkipsDoneContainer" style="display: none">
|
||||
__MSG_youHaveSkipped__
|
||||
<b><span id="sponsorTimesSkipsDoneDisplay">
|
||||
0
|
||||
</span></b>
|
||||
<span id="sponsorTimesSkipsDoneEndWord">__MSG_Segments__</span>
|
||||
(<b><span id="sponsorTimeSavedDisplay">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimeSavedEndWord">__MSG_minsLower__</span></b>).
|
||||
</div>
|
||||
<footer id="sbFooter">
|
||||
<a href="https://sponsor.ajay.app" target="_blank" rel="noopener">__MSG_website__</a> |
|
||||
<a href="https://sponsor.ajay.app/stats" target="_blank" rel="noopener">__MSG_viewLeaderboard__</a> |
|
||||
<a href="https://github.com/ajayyy/SponsorBlock" target="_blank" rel="noopener">GitHub</a>
|
||||
<br/>
|
||||
<a href="https://discord.gg/QnmVMpU" target="_blank" rel="noopener">Discord</a> |
|
||||
<a href="https://matrix.to/#/+sponsorblock:ajay.app" target="_blank" rel="noopener">Matrix</a> |
|
||||
<a id="helpButton" style="cursor: pointer;">__MSG_help__</a>
|
||||
</footer>
|
||||
|
||||
<button id="showNoticeAgain" style="display: none" class="dangerButton popupElement">__MSG_showNotice__</button>
|
||||
</div>
|
||||
<!-- Scripts that need to load after the html -->
|
||||
<script src="./js/vendor.js"></script>
|
||||
<script src="./js/popup.js"></script>
|
||||
</html>
|
||||
<script src="./js/vendor.js" async></script>
|
||||
<script src="./js/popup.js" async></script>
|
||||
</body>
|
||||
@@ -1,17 +1,20 @@
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
import Config from "./config";
|
||||
import { Registration } from "./types";
|
||||
|
||||
// Make the config public for debugging purposes
|
||||
(<any> window).SB = Config;
|
||||
|
||||
window.SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
var utils = new Utils({
|
||||
const utils = new Utils({
|
||||
registerFirefoxContentScript,
|
||||
unregisterFirefoxContentScript
|
||||
});
|
||||
|
||||
// Used only on Firefox, which does not support non persistent background pages.
|
||||
var contentScriptRegistrations = {};
|
||||
const contentScriptRegistrations = {};
|
||||
|
||||
// Register content script if needed
|
||||
if (utils.isFirefox()) {
|
||||
@@ -31,6 +34,9 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
case "openConfig":
|
||||
chrome.runtime.openOptionsPage();
|
||||
return;
|
||||
case "openHelp":
|
||||
chrome.tabs.create({url: chrome.runtime.getURL('help/index_en.html')});
|
||||
return;
|
||||
case "sendRequest":
|
||||
sendRequestToCustomServer(request.type, request.url, request.data).then(async (response) => {
|
||||
callback({
|
||||
@@ -55,6 +61,7 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
iconUrl: "./icons/LogoSponsorBlocker256px.png"
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "registerContentScript":
|
||||
registerFirefoxContentScript(request);
|
||||
return false;
|
||||
@@ -65,7 +72,7 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
});
|
||||
|
||||
//add help page on install
|
||||
chrome.runtime.onInstalled.addListener(function (object) {
|
||||
chrome.runtime.onInstalled.addListener(function () {
|
||||
// This let's the config sync to run fully before checking.
|
||||
// This is required on Firefox
|
||||
setTimeout(function() {
|
||||
@@ -90,8 +97,8 @@ chrome.runtime.onInstalled.addListener(function (object) {
|
||||
*
|
||||
* @param {JSON} options
|
||||
*/
|
||||
function registerFirefoxContentScript(options) {
|
||||
let oldRegistration = contentScriptRegistrations[options.id];
|
||||
function registerFirefoxContentScript(options: Registration) {
|
||||
const oldRegistration = contentScriptRegistrations[options.id];
|
||||
if (oldRegistration) oldRegistration.unregister();
|
||||
|
||||
browser.contentScripts.register({
|
||||
@@ -121,10 +128,10 @@ async function submitVote(type: number, UUID: string, category: string) {
|
||||
Config.config.userID = userID;
|
||||
}
|
||||
|
||||
let typeSection = (type !== undefined) ? "&type=" + type : "&category=" + category;
|
||||
const typeSection = (type !== undefined) ? "&type=" + type : "&category=" + category;
|
||||
|
||||
//publish this vote
|
||||
let response = await asyncRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + typeSection);
|
||||
const response = await asyncRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + typeSection);
|
||||
|
||||
if (response.ok) {
|
||||
return {
|
||||
@@ -146,7 +153,7 @@ async function submitVote(type: number, UUID: string, category: string) {
|
||||
}
|
||||
|
||||
async function asyncRequestToServer(type: string, address: string, data = {}) {
|
||||
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
const serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
|
||||
return await (sendRequestToCustomServer(type, serverAddress + address, data));
|
||||
}
|
||||
@@ -162,8 +169,8 @@ async function sendRequestToCustomServer(type: string, url: string, data = {}) {
|
||||
// If GET, convert JSON to parameters
|
||||
if (type.toLowerCase() === "get") {
|
||||
for (const key in data) {
|
||||
let seperator = url.includes("?") ? "&" : "?";
|
||||
let value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]);
|
||||
const seperator = url.includes("?") ? "&" : "?";
|
||||
const value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]);
|
||||
url += seperator + key + "=" + value;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from "react";
|
||||
|
||||
import Config from "../config"
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import CategorySkipOptionsComponent from "./CategorySkipOptionsComponent";
|
||||
|
||||
@@ -23,7 +22,7 @@ class CategoryChooserComponent extends React.Component<CategoryChooserProps, Cat
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render(): React.ReactElement {
|
||||
return (
|
||||
<table id="categoryChooserTable"
|
||||
className="categoryChooserTable">
|
||||
@@ -55,7 +54,7 @@ class CategoryChooserComponent extends React.Component<CategoryChooserProps, Cat
|
||||
}
|
||||
|
||||
getCategorySkipOptions(): JSX.Element[] {
|
||||
let elements: JSX.Element[] = [];
|
||||
const elements: JSX.Element[] = [];
|
||||
|
||||
for (const category of CompileConfig.categoryList) {
|
||||
elements.push(
|
||||
|
||||
@@ -2,9 +2,6 @@ import * as React from "react";
|
||||
|
||||
import Config from "../config"
|
||||
import { CategorySkipOption } from "../types";
|
||||
import Utils from "../utils";
|
||||
|
||||
const utils = new Utils();
|
||||
|
||||
export interface CategorySkipOptionsProps {
|
||||
category: string;
|
||||
@@ -29,7 +26,7 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render(): React.ReactElement {
|
||||
let defaultOption = "disable";
|
||||
// Set the default opton properly
|
||||
for (const categorySelection of Config.config.categorySelections) {
|
||||
@@ -145,9 +142,9 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
|
||||
}
|
||||
|
||||
getCategorySkipOptions(): JSX.Element[] {
|
||||
let elements: JSX.Element[] = [];
|
||||
const elements: JSX.Element[] = [];
|
||||
|
||||
let optionNames = ["disable", "showOverlay", "manualSkip", "autoSkip"];
|
||||
const optionNames = ["disable", "showOverlay", "manualSkip", "autoSkip"];
|
||||
|
||||
for (const optionName of optionNames) {
|
||||
elements.push(
|
||||
@@ -160,7 +157,7 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
|
||||
return elements;
|
||||
}
|
||||
|
||||
setColorState(event: React.FormEvent<HTMLInputElement>, preview: boolean) {
|
||||
setColorState(event: React.FormEvent<HTMLInputElement>, preview: boolean): void {
|
||||
if (preview) {
|
||||
this.setState({
|
||||
previewColor: event.currentTarget.value
|
||||
|
||||
@@ -28,14 +28,14 @@ export interface NoticeState {
|
||||
|
||||
class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
countdownInterval: NodeJS.Timeout;
|
||||
idSuffix: any;
|
||||
idSuffix: string;
|
||||
|
||||
amountOfPreviousNotices: number;
|
||||
|
||||
constructor(props: NoticeProps) {
|
||||
super(props);
|
||||
|
||||
let maxCountdownTime = () => {
|
||||
const maxCountdownTime = () => {
|
||||
if (this.props.maxCountdownTime) return this.props.maxCountdownTime();
|
||||
else return 4;
|
||||
};
|
||||
@@ -60,12 +60,12 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
componentDidMount(): void {
|
||||
this.startCountdown();
|
||||
}
|
||||
|
||||
render() {
|
||||
let noticeStyle: React.CSSProperties = {
|
||||
render(): React.ReactElement {
|
||||
const noticeStyle: React.CSSProperties = {
|
||||
zIndex: this.props.zIndex || (50 + this.amountOfPreviousNotices)
|
||||
}
|
||||
|
||||
@@ -124,19 +124,19 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
);
|
||||
}
|
||||
|
||||
timerMouseEnter() {
|
||||
timerMouseEnter(): void {
|
||||
if (this.state.countdownManuallyPaused) return;
|
||||
|
||||
this.pauseCountdown();
|
||||
}
|
||||
|
||||
timerMouseLeave() {
|
||||
timerMouseLeave(): void {
|
||||
if (this.state.countdownManuallyPaused) return;
|
||||
|
||||
this.startCountdown();
|
||||
}
|
||||
|
||||
toggleManualPause() {
|
||||
toggleManualPause(): void {
|
||||
this.setState({
|
||||
countdownManuallyPaused: !this.state.countdownManuallyPaused
|
||||
}, () => {
|
||||
@@ -149,10 +149,10 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
}
|
||||
|
||||
//called every second to lower the countdown before hiding the notice
|
||||
countdown() {
|
||||
countdown(): void {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
let countdownTime = this.state.countdownTime - 1;
|
||||
const countdownTime = this.state.countdownTime - 1;
|
||||
|
||||
if (countdownTime <= 0) {
|
||||
//remove this from setInterval
|
||||
@@ -166,7 +166,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
|
||||
if (countdownTime == 3) {
|
||||
//start fade out animation
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
const notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.style.removeProperty("animation");
|
||||
notice.classList.add("sponsorSkipNoticeFadeOut");
|
||||
}
|
||||
@@ -176,7 +176,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
})
|
||||
}
|
||||
|
||||
pauseCountdown() {
|
||||
pauseCountdown(): void {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
//remove setInterval
|
||||
@@ -190,12 +190,12 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
});
|
||||
|
||||
//remove the fade out class if it exists
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
const notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
||||
notice.style.animation = "none";
|
||||
}
|
||||
|
||||
startCountdown() {
|
||||
startCountdown(): void {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
//if it has already started, don't start it again
|
||||
@@ -209,7 +209,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
||||
}
|
||||
|
||||
resetCountdown() {
|
||||
resetCountdown(): void {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
this.setState({
|
||||
@@ -221,36 +221,36 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
/**
|
||||
* @param silent If true, the close listener will not be called
|
||||
*/
|
||||
close(silent?: boolean) {
|
||||
close(silent?: boolean): void {
|
||||
//remove setInterval
|
||||
if (this.countdownInterval !== null) clearInterval(this.countdownInterval);
|
||||
|
||||
if (!silent) this.props.closeListener();
|
||||
}
|
||||
|
||||
changeNoticeTitle(title) {
|
||||
changeNoticeTitle(title: string): void {
|
||||
this.setState({
|
||||
noticeTitle: title
|
||||
});
|
||||
}
|
||||
|
||||
addNoticeInfoMessage(message: string, message2: string = "") {
|
||||
addNoticeInfoMessage(message: string, message2 = ""): void {
|
||||
//TODO: Replace
|
||||
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
||||
const 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");
|
||||
const 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");
|
||||
const thanksForVotingText = document.createElement("p");
|
||||
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
@@ -259,7 +259,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
|
||||
if (message2 !== undefined) {
|
||||
let thanksForVotingText2 = document.createElement("p");
|
||||
const thanksForVotingText2 = document.createElement("p");
|
||||
thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2";
|
||||
thanksForVotingText2.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText2.innerText = message2;
|
||||
@@ -270,4 +270,4 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
}
|
||||
}
|
||||
|
||||
export default NoticeComponent;
|
||||
export default NoticeComponent;
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as React from "react";
|
||||
export interface NoticeTextSelectionProps {
|
||||
text: string,
|
||||
idSuffix: string,
|
||||
onClick?: (event: React.MouseEvent) => any
|
||||
onClick?: (event: React.MouseEvent) => unknown
|
||||
}
|
||||
|
||||
export interface NoticeTextSelectionState {
|
||||
@@ -16,8 +16,8 @@ class NoticeTextSelectionComponent extends React.Component<NoticeTextSelectionPr
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let style: React.CSSProperties = {};
|
||||
render(): React.ReactElement {
|
||||
const style: React.CSSProperties = {};
|
||||
if (this.props.onClick) {
|
||||
style.cursor = "pointer";
|
||||
style.textDecoration = "underline"
|
||||
|
||||
@@ -2,10 +2,6 @@ import * as React from "react";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import Config from "../config"
|
||||
import { ContentContainer, SponsorHideType, SponsorTime } from "../types";
|
||||
|
||||
import Utils from "../utils";
|
||||
var utils = new Utils();
|
||||
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
|
||||
@@ -31,7 +27,7 @@ export interface SkipNoticeState {
|
||||
noticeTitle: string;
|
||||
|
||||
messages: string[];
|
||||
messageOnClick: (event: React.MouseEvent) => any;
|
||||
messageOnClick: (event: React.MouseEvent) => unknown;
|
||||
|
||||
countdownTime: number;
|
||||
maxCountdownTime: () => number;
|
||||
@@ -42,7 +38,7 @@ export interface SkipNoticeState {
|
||||
|
||||
downvoting: boolean;
|
||||
choosingCategory: boolean;
|
||||
thanksForVotingText: boolean; //null until the voting buttons should be hidden
|
||||
thanksForVotingText: string; //null until the voting buttons should be hidden
|
||||
|
||||
actionState: SkipNoticeAction;
|
||||
}
|
||||
@@ -56,7 +52,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
amountOfPreviousNotices: number;
|
||||
audio: HTMLAudioElement;
|
||||
|
||||
idSuffix: any;
|
||||
idSuffix: string;
|
||||
|
||||
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||
categoryOptionRef: React.RefObject<HTMLSelectElement>;
|
||||
@@ -74,7 +70,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
this.contentContainer = props.contentContainer;
|
||||
this.audio = null;
|
||||
|
||||
let categoryName = chrome.i18n.getMessage(this.segments.length > 1 ? "multipleSegments"
|
||||
const categoryName = chrome.i18n.getMessage(this.segments.length > 1 ? "multipleSegments"
|
||||
: "category_" + this.segments[0].category + "_short") || chrome.i18n.getMessage("category_" + this.segments[0].category);
|
||||
let noticeTitle = categoryName + " " + chrome.i18n.getMessage("skipped");
|
||||
if (!this.autoSkip) {
|
||||
@@ -98,7 +94,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
if (this.amountOfPreviousNotices > 0) {
|
||||
//another notice exists
|
||||
|
||||
let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
||||
const previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
||||
previousNotice.classList.add("secondSkipNotice")
|
||||
}
|
||||
|
||||
@@ -129,15 +125,15 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
componentDidMount(): void {
|
||||
if (Config.config.audioNotificationOnSkip && this.audio) {
|
||||
this.audio.volume = this.contentContainer().v.volume * 0.1;
|
||||
if (this.autoSkip) this.audio.play();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let noticeStyle: React.CSSProperties = {
|
||||
render(): React.ReactElement {
|
||||
const noticeStyle: React.CSSProperties = {
|
||||
zIndex: 50 + this.amountOfPreviousNotices
|
||||
}
|
||||
if (this.contentContainer().onMobileYouTube) {
|
||||
@@ -286,7 +282,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
|
||||
getSubmissionChooser(): JSX.Element[] {
|
||||
let elements: JSX.Element[] = [];
|
||||
const elements: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < this.segments.length; i++) {
|
||||
elements.push(
|
||||
@@ -301,7 +297,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
return elements;
|
||||
}
|
||||
|
||||
prepAction(action: SkipNoticeAction) {
|
||||
prepAction(action: SkipNoticeAction): void {
|
||||
if (this.segments.length === 1) {
|
||||
this.performAction(0, action);
|
||||
} else {
|
||||
@@ -321,7 +317,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
);
|
||||
}
|
||||
|
||||
let elements: JSX.Element[] = [];
|
||||
const elements: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < this.state.messages.length; i++) {
|
||||
elements.push(
|
||||
@@ -341,7 +337,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
performAction(index: number, action?: SkipNoticeAction) {
|
||||
performAction(index: number, action?: SkipNoticeAction): void {
|
||||
switch (action ?? this.state.actionState) {
|
||||
case SkipNoticeAction.None:
|
||||
break;
|
||||
@@ -364,7 +360,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
});
|
||||
}
|
||||
|
||||
adjustDownvotingState(value: boolean) {
|
||||
adjustDownvotingState(value: boolean): void {
|
||||
if (!value) this.clearConfigListener();
|
||||
|
||||
this.setState({
|
||||
@@ -373,14 +369,14 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
});
|
||||
}
|
||||
|
||||
clearConfigListener() {
|
||||
clearConfigListener(): void {
|
||||
if (this.configListener) {
|
||||
Config.configListeners.splice(Config.configListeners.indexOf(this.configListener), 1);
|
||||
this.configListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
openCategoryChooser() {
|
||||
openCategoryChooser(): void {
|
||||
// Add as a config listener
|
||||
this.configListener = () => this.forceUpdate();
|
||||
Config.configListeners.push(this.configListener);
|
||||
@@ -396,8 +392,8 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
});
|
||||
}
|
||||
|
||||
getCategoryOptions() {
|
||||
let elements = [];
|
||||
getCategoryOptions(): React.ReactElement[] {
|
||||
const elements = [];
|
||||
|
||||
for (const category of Config.config.categorySelections) {
|
||||
elements.push(
|
||||
@@ -421,7 +417,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
return elements;
|
||||
}
|
||||
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
// See if show more categories was pressed
|
||||
if (event.target.value === "moreCategories") {
|
||||
// Open options page
|
||||
@@ -433,42 +429,38 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
}
|
||||
|
||||
unskip(index: number) {
|
||||
unskip(index: number): void {
|
||||
this.contentContainer().unskipSponsorTime(this.segments[index]);
|
||||
|
||||
this.unskippedMode(index, chrome.i18n.getMessage("reskip"));
|
||||
}
|
||||
|
||||
/** Sets up notice to be not skipped yet */
|
||||
unskippedMode(index: number, buttonText: string) {
|
||||
unskippedMode(index: number, buttonText: string): void {
|
||||
//setup new callback and reset countdown
|
||||
this.setState(this.getUnskippedModeInfo(index, buttonText), () => {
|
||||
this.noticeRef.current.resetCountdown();
|
||||
});
|
||||
}
|
||||
|
||||
getUnskippedModeInfo(index: number, buttonText: string) {
|
||||
let self = this;
|
||||
let maxCountdownTime = function() {
|
||||
let sponsorTime = self.segments[index];
|
||||
let duration = Math.round((sponsorTime.segment[1] - self.contentContainer().v.currentTime) * (1 / self.contentContainer().v.playbackRate));
|
||||
getUnskippedModeInfo(index: number, buttonText: string): SkipNoticeState {
|
||||
const maxCountdownTime = () => {
|
||||
const sponsorTime = this.segments[index];
|
||||
const duration = Math.round((sponsorTime.segment[1] - this.contentContainer().v.currentTime) * (1 / this.contentContainer().v.playbackRate));
|
||||
|
||||
return Math.max(duration, 4);
|
||||
};
|
||||
|
||||
return {
|
||||
unskipText: buttonText,
|
||||
|
||||
unskipCallback: (index) => this.reskip(index),
|
||||
|
||||
//change max duration to however much of the sponsor is left
|
||||
// change max duration to however much of the sponsor is left
|
||||
maxCountdownTime: maxCountdownTime,
|
||||
|
||||
countdownTime: maxCountdownTime()
|
||||
}
|
||||
} as SkipNoticeState;
|
||||
}
|
||||
|
||||
reskip(index: number) {
|
||||
reskip(index: number): void {
|
||||
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
||||
|
||||
//reset countdown
|
||||
@@ -488,7 +480,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
}
|
||||
|
||||
afterVote(segment: SponsorTime, type: number, category: string) {
|
||||
afterVote(segment: SponsorTime, type: number, category: string): void {
|
||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||
|
||||
if (type === 0) {
|
||||
@@ -508,32 +500,32 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
}
|
||||
|
||||
setNoticeInfoMessageWithOnClick(onClick: (event: React.MouseEvent) => any, ...messages: string[]) {
|
||||
setNoticeInfoMessageWithOnClick(onClick: (event: React.MouseEvent) => unknown, ...messages: string[]): void {
|
||||
this.setState({
|
||||
messages,
|
||||
messageOnClick: (event) => onClick(event)
|
||||
});
|
||||
}
|
||||
|
||||
setNoticeInfoMessage(...messages: string[]) {
|
||||
setNoticeInfoMessage(...messages: string[]): void {
|
||||
this.setState({
|
||||
messages
|
||||
});
|
||||
}
|
||||
|
||||
addVoteButtonInfo(message) {
|
||||
addVoteButtonInfo(message: string): void {
|
||||
this.setState({
|
||||
thanksForVotingText: message
|
||||
});
|
||||
}
|
||||
|
||||
resetVoteButtonInfo() {
|
||||
resetVoteButtonInfo(): void {
|
||||
this.setState({
|
||||
thanksForVotingText: null
|
||||
});
|
||||
}
|
||||
|
||||
closeListener() {
|
||||
closeListener(): void {
|
||||
this.clearConfigListener();
|
||||
|
||||
this.props.closeListener();
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as CompileConfig from "../../config.json";
|
||||
import Utils from "../utils";
|
||||
import { ContentContainer, SponsorTime } from "../types";
|
||||
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||
var utils = new Utils();
|
||||
const utils = new Utils();
|
||||
|
||||
export interface SponsorTimeEditProps {
|
||||
index: number,
|
||||
@@ -23,6 +23,8 @@ export interface SponsorTimeEditState {
|
||||
sponsorTimeEdits: [string, string];
|
||||
}
|
||||
|
||||
const DEFAULT_CATEGORY = "chooseACategory";
|
||||
|
||||
class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, SponsorTimeEditState> {
|
||||
|
||||
idSuffix: string;
|
||||
@@ -44,7 +46,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
componentDidMount(): void {
|
||||
// Prevent inputs from triggering key events
|
||||
document.getElementById("sponsorTimesContainer" + this.idSuffix).addEventListener('keydown', function (event) {
|
||||
event.stopPropagation();
|
||||
@@ -57,14 +59,14 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
componentWillUnmount(): void {
|
||||
if (this.configUpdateListener) {
|
||||
Config.configListeners.splice(Config.configListeners.indexOf(this.configUpdate.bind(this)), 1);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let style: React.CSSProperties = {
|
||||
render(): React.ReactElement {
|
||||
const style: React.CSSProperties = {
|
||||
textAlign: "center"
|
||||
};
|
||||
|
||||
@@ -74,7 +76,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
// This method is required to get !important
|
||||
// https://stackoverflow.com/a/45669262/1985387
|
||||
let oldYouTubeDarkStyles = (node) => {
|
||||
const oldYouTubeDarkStyles = (node) => {
|
||||
if (node) {
|
||||
node.style.setProperty("color", "black", "important");
|
||||
node.style.setProperty("text-shadow", "none", "important");
|
||||
@@ -83,8 +85,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
// Create time display
|
||||
let timeDisplay: JSX.Element;
|
||||
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
let segment = sponsorTime.segment;
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
const segment = sponsorTime.segment;
|
||||
if (this.state.editing) {
|
||||
timeDisplay = (
|
||||
<div id={"sponsorTimesContainer" + this.idSuffix}
|
||||
@@ -102,7 +104,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
type="text"
|
||||
value={this.state.sponsorTimeEdits[0]}
|
||||
onChange={(e) => {
|
||||
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
const sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[0] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
@@ -121,7 +123,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
type="text"
|
||||
value={this.state.sponsorTimeEdits[1]}
|
||||
onChange={(e) => {
|
||||
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
const sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[1] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
@@ -215,29 +217,19 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
);
|
||||
}
|
||||
|
||||
getCategoryOptions() {
|
||||
let elements = [(
|
||||
<option value={"chooseACategory"}
|
||||
key={"chooseACategory"}>
|
||||
{chrome.i18n.getMessage("chooseACategory")}
|
||||
getCategoryOptions(): React.ReactElement[] {
|
||||
const elements = [(
|
||||
<option value={DEFAULT_CATEGORY}
|
||||
key={DEFAULT_CATEGORY}>
|
||||
{chrome.i18n.getMessage(DEFAULT_CATEGORY)}
|
||||
</option>
|
||||
)];
|
||||
|
||||
for (const category of Config.config.categorySelections) {
|
||||
for (const category of CompileConfig.categoryList) {
|
||||
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 value={category}
|
||||
key={category}>
|
||||
{chrome.i18n.getMessage("category_" + category)}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
@@ -245,30 +237,35 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
return elements;
|
||||
}
|
||||
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
// 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;
|
||||
if (!Config.config.categorySelections.some((category) => category.name === event.target.value)) {
|
||||
const chosenCategory = event.target.value;
|
||||
event.target.value = DEFAULT_CATEGORY;
|
||||
|
||||
// Alert that they have to enable this category first
|
||||
if (confirm(chrome.i18n.getMessage("enableThisCategoryFirst")
|
||||
.replace("{0}", chrome.i18n.getMessage("category_" + chosenCategory)))) {
|
||||
// Open options page
|
||||
chrome.runtime.sendMessage({"message": "openConfig"});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.saveEditTimes();
|
||||
}
|
||||
|
||||
setTimeToNow(index: number) {
|
||||
setTimeToNow(index: number): void {
|
||||
this.setTimeTo(index, this.props.contentContainer().getRealCurrentTime());
|
||||
}
|
||||
|
||||
setTimeToEnd() {
|
||||
setTimeToEnd(): void {
|
||||
this.setTimeTo(1, this.props.contentContainer().v.duration);
|
||||
}
|
||||
|
||||
setTimeTo(index: number, time: number) {
|
||||
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
setTimeTo(index: number, time: number): void {
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
|
||||
sponsorTime.segment[index] =
|
||||
time;
|
||||
@@ -287,7 +284,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
this.saveEditTimes();
|
||||
} else {
|
||||
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
|
||||
this.setState({
|
||||
editing: true,
|
||||
@@ -302,8 +299,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
utils.getFormattedTime(sponsorTime.segment[1], true)];
|
||||
}
|
||||
|
||||
saveEditTimes() {
|
||||
let sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
saveEditTimes(): void {
|
||||
const sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
|
||||
if (this.state.editing) {
|
||||
const startTime = utils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]);
|
||||
@@ -323,26 +320,26 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
|
||||
previewTime(): void {
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
let index = this.props.index;
|
||||
const sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const index = this.props.index;
|
||||
|
||||
let skipTime = sponsorTimes[index].segment[0];
|
||||
const skipTime = sponsorTimes[index].segment[0];
|
||||
|
||||
this.props.contentContainer().previewTime(skipTime - 2);
|
||||
}
|
||||
|
||||
inspectTime(): void {
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
let index = this.props.index;
|
||||
const sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const index = this.props.index;
|
||||
|
||||
let skipTime = sponsorTimes[index].segment[0];
|
||||
const skipTime = sponsorTimes[index].segment[0];
|
||||
|
||||
this.props.contentContainer().previewTime(skipTime + 0.000001, false);
|
||||
}
|
||||
|
||||
deleteTime(): void {
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
let index = this.props.index;
|
||||
const sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const index = this.props.index;
|
||||
|
||||
//if it is not a complete sponsor time
|
||||
if (sponsorTimes[index].segment.length < 2) {
|
||||
@@ -369,7 +366,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
}
|
||||
|
||||
configUpdate() {
|
||||
configUpdate(): void {
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface SubmissionNoticeProps {
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
callback: () => any;
|
||||
callback: () => unknown;
|
||||
|
||||
closeListener: () => void
|
||||
}
|
||||
@@ -25,13 +25,15 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
callback: () => any;
|
||||
callback: () => unknown;
|
||||
|
||||
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||
timeEditRefs: React.RefObject<SponsorTimeEditComponent>[];
|
||||
|
||||
videoObserver: MutationObserver;
|
||||
|
||||
showingYouCapNotice: boolean;
|
||||
|
||||
constructor(props: SubmissionNoticeProps) {
|
||||
super(props);
|
||||
this.noticeRef = React.createRef();
|
||||
@@ -39,17 +41,17 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
this.contentContainer = props.contentContainer;
|
||||
this.callback = props.callback;
|
||||
|
||||
let noticeTitle = chrome.i18n.getMessage("confirmNoticeTitle");
|
||||
const noticeTitle = chrome.i18n.getMessage("confirmNoticeTitle");
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
noticeTitle,
|
||||
messages: [],
|
||||
idSuffix: "SubmissionNotice"
|
||||
idSuffix: "SubmissionNotice",
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
componentDidMount(): void {
|
||||
// Catch and rerender when the video size changes
|
||||
//TODO: Use ResizeObserver when it is supported in TypeScript
|
||||
this.videoObserver = new MutationObserver(() => {
|
||||
@@ -61,13 +63,13 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
componentWillUnmount(): void {
|
||||
if (this.videoObserver) {
|
||||
this.videoObserver.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render(): React.ReactElement {
|
||||
return (
|
||||
<NoticeComponent noticeTitle={this.state.noticeTitle}
|
||||
idSuffix={this.state.idSuffix}
|
||||
@@ -87,6 +89,8 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{this.getYouCapMessage()}
|
||||
|
||||
{/* Last Row */}
|
||||
<tr id={"sponsorSkipNoticeSecondRow" + this.state.idSuffix}>
|
||||
|
||||
@@ -113,14 +117,43 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
);
|
||||
}
|
||||
|
||||
/** TODO: Remove */
|
||||
getYouCapMessage(): JSX.Element {
|
||||
if (Config.config.sponsorTimesContributed < 20
|
||||
|| (Config.config.hasShownYouCapNotice && !this.showingYouCapNotice)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Config.config.hasShownYouCapNotice = true;
|
||||
if (!this.showingYouCapNotice) {
|
||||
this.showingYouCapNotice = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<tr style={{textAlign: "center"}}>
|
||||
<p style={{width: "300px", textAlign: "center", display: "inline-block", fontSize: "11px"}}>
|
||||
Like contributing to crowdsourced projects?
|
||||
Consider checking out <a href="https://gist.github.com/ajayyy/6f2cf90dd66e51067a7ab5e63544cd4e" style={{textDecoration: "underline"}} target="_blank" rel="noreferrer">YouCap or NekoCap</a>,
|
||||
new open-source replacements for YouTube{"'"}s now defunct community captions.
|
||||
</p>
|
||||
|
||||
<img src={chrome.extension.getURL("icons/close.png")}
|
||||
style={{padding: "0", margin: "auto"}}
|
||||
className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton"
|
||||
onClick={() => { this.showingYouCapNotice = false; this.forceUpdate(); }}>
|
||||
</img>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
getSponsorTimeMessages(): JSX.Element[] | JSX.Element {
|
||||
let elements: JSX.Element[] = [];
|
||||
const elements: JSX.Element[] = [];
|
||||
this.timeEditRefs = [];
|
||||
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
let timeRef = React.createRef<SponsorTimeEditComponent>();
|
||||
const timeRef = React.createRef<SponsorTimeEditComponent>();
|
||||
|
||||
elements.push(
|
||||
<SponsorTimeEditComponent key={i}
|
||||
@@ -139,7 +172,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
}
|
||||
|
||||
getMessageBoxes(): JSX.Element[] | JSX.Element {
|
||||
let elements: JSX.Element[] = [];
|
||||
const elements: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < this.state.messages.length; i++) {
|
||||
elements.push(
|
||||
@@ -153,7 +186,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
return elements;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
cancel(): void {
|
||||
this.noticeRef.current.close(true);
|
||||
|
||||
this.contentContainer().resetSponsorSubmissionNotice();
|
||||
@@ -161,13 +194,13 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
this.props.closeListener();
|
||||
}
|
||||
|
||||
submit() {
|
||||
submit(): void {
|
||||
// save all items
|
||||
for (const ref of this.timeEditRefs) {
|
||||
ref.current.saveEditTimes();
|
||||
}
|
||||
|
||||
let sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
for (const sponsorTime of sponsorTimesSubmitting) {
|
||||
if (sponsorTime.category === "chooseACategory") {
|
||||
alert(chrome.i18n.getMessage("youMustSelectACategory"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as CompileConfig from "../config.json";
|
||||
import { CategorySelection, CategorySkipOption, PreviewBarOption, SponsorTime } from "./types";
|
||||
import { CategorySelection, CategorySkipOption, PreviewBarOption, SponsorTime, StorageChangesObject } from "./types";
|
||||
|
||||
import Utils from "./utils";
|
||||
const utils = new Utils();
|
||||
@@ -55,11 +55,13 @@ interface SBConfig {
|
||||
"preview-selfpromo": PreviewBarOption,
|
||||
"music_offtopic": PreviewBarOption,
|
||||
"preview-music_offtopic": PreviewBarOption,
|
||||
}
|
||||
},
|
||||
|
||||
hasShownYouCapNotice: boolean
|
||||
}
|
||||
|
||||
interface SBObject {
|
||||
configListeners: Array<Function>;
|
||||
export interface SBObject {
|
||||
configListeners: Array<(changes: StorageChangesObject) => unknown>;
|
||||
defaults: SBConfig;
|
||||
localConfig: SBConfig;
|
||||
config: SBConfig;
|
||||
@@ -132,7 +134,7 @@ class SBMap<T, U> extends Map {
|
||||
}
|
||||
}
|
||||
|
||||
var Config: SBObject = {
|
||||
const Config: SBObject = {
|
||||
/**
|
||||
* Callback function when an option is updated
|
||||
*/
|
||||
@@ -149,7 +151,7 @@ var Config: SBObject = {
|
||||
skipCount: 0,
|
||||
sponsorTimesContributed: 0,
|
||||
submissionCountSinceCategories: 0,
|
||||
showTimeWithSkips: true,
|
||||
showTimeWithSkips: true,
|
||||
unsubmittedWarning: true,
|
||||
disableSkipping: false,
|
||||
trackViewCount: true,
|
||||
@@ -229,7 +231,9 @@ var Config: SBObject = {
|
||||
color: "#a6634a",
|
||||
opacity: "0.7"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hasShownYouCapNotice: false
|
||||
},
|
||||
localConfig: null,
|
||||
config: null,
|
||||
@@ -275,8 +279,8 @@ function decodeStoredItem<T>(id: string, data: T): T | SBMap<string, SponsorTime
|
||||
return data;
|
||||
}
|
||||
|
||||
function configProxy(): any {
|
||||
chrome.storage.onChanged.addListener((changes, namespace) => {
|
||||
function configProxy(): SBConfig {
|
||||
chrome.storage.onChanged.addListener((changes: {[key: string]: chrome.storage.StorageChange}) => {
|
||||
for (const key in changes) {
|
||||
Config.localConfig[key] = decodeStoredItem(key, changes[key].newValue);
|
||||
}
|
||||
@@ -286,8 +290,8 @@ function configProxy(): any {
|
||||
}
|
||||
});
|
||||
|
||||
var handler: ProxyHandler<any> = {
|
||||
set(obj, prop, value) {
|
||||
const handler: ProxyHandler<SBConfig> = {
|
||||
set<K extends keyof SBConfig>(obj: SBConfig, prop: K, value: SBConfig[K]) {
|
||||
Config.localConfig[prop] = value;
|
||||
|
||||
chrome.storage.sync.set({
|
||||
@@ -297,13 +301,13 @@ function configProxy(): any {
|
||||
return true;
|
||||
},
|
||||
|
||||
get(obj, prop): any {
|
||||
let data = Config.localConfig[prop];
|
||||
get<K extends keyof SBConfig>(obj: SBConfig, prop: K): SBConfig[K] {
|
||||
const data = Config.localConfig[prop];
|
||||
|
||||
return obj[prop] || data;
|
||||
},
|
||||
|
||||
deleteProperty(obj, prop) {
|
||||
deleteProperty(obj: SBConfig, prop: keyof SBConfig) {
|
||||
chrome.storage.sync.remove(<string> prop);
|
||||
|
||||
return true;
|
||||
@@ -311,11 +315,11 @@ function configProxy(): any {
|
||||
|
||||
};
|
||||
|
||||
return new Proxy({handler}, handler);
|
||||
return new Proxy<SBConfig>({handler} as unknown as SBConfig, handler);
|
||||
}
|
||||
|
||||
function fetchConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
function fetchConfig(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.sync.get(null, function(items) {
|
||||
Config.localConfig = <SBConfig> <unknown> items; // Data is ready
|
||||
resolve();
|
||||
@@ -351,7 +355,7 @@ function migrateOldFormats(config: SBConfig) {
|
||||
if (config.whitelistedChannels.length > 0 &&
|
||||
(config.whitelistedChannels[0] == null || config.whitelistedChannels[0].includes("/"))) {
|
||||
const channelURLFixer = async() => {
|
||||
let newChannelList: string[] = [];
|
||||
const newChannelList: string[] = [];
|
||||
for (const item of config.whitelistedChannels) {
|
||||
if (item != null) {
|
||||
if (item.includes("/channel/")) {
|
||||
@@ -360,7 +364,7 @@ function migrateOldFormats(config: SBConfig) {
|
||||
|
||||
|
||||
// Replace channel URL with channelID
|
||||
let response = await utils.asyncRequestToCustomServer("GET", "https://sponsor.ajay.app/invidious/api/v1/channels/" + item.split("/")[2] + "?fields=authorId");
|
||||
const response = await utils.asyncRequestToCustomServer("GET", "https://sponsor.ajay.app/invidious/api/v1/channels/" + item.split("/")[2] + "?fields=authorId");
|
||||
|
||||
if (response.ok) {
|
||||
newChannelList.push((JSON.parse(response.responseText)).authorId);
|
||||
@@ -408,9 +412,9 @@ function migrateOldFormats(config: SBConfig) {
|
||||
|
||||
// Otherwise junk data
|
||||
if (Array.isArray(jsonData)) {
|
||||
let oldMap = new Map(jsonData);
|
||||
const oldMap = new Map(jsonData);
|
||||
oldMap.forEach((sponsorTimes: number[][], key) => {
|
||||
let segmentTimes: SponsorTime[] = [];
|
||||
const segmentTimes: SponsorTime[] = [];
|
||||
for (const segment of sponsorTimes) {
|
||||
segmentTimes.push({
|
||||
segment: segment,
|
||||
@@ -439,11 +443,6 @@ async function setupConfig() {
|
||||
Config.config = config;
|
||||
}
|
||||
|
||||
// Reset config
|
||||
function resetConfig() {
|
||||
Config.config = Config.defaults;
|
||||
};
|
||||
|
||||
function convertJSON(): void {
|
||||
Object.keys(Config.localConfig).forEach(key => {
|
||||
Config.localConfig[key] = decodeStoredItem(key, Config.localConfig[key]);
|
||||
@@ -453,17 +452,17 @@ function convertJSON(): void {
|
||||
// Add defaults
|
||||
function addDefaults() {
|
||||
for (const key in Config.defaults) {
|
||||
if(!Config.localConfig.hasOwnProperty(key)) {
|
||||
Config.localConfig[key] = Config.defaults[key];
|
||||
if(!Object.prototype.hasOwnProperty.call(Config.localConfig, key)) {
|
||||
Config.localConfig[key] = Config.defaults[key];
|
||||
} else if (key === "barTypes") {
|
||||
for (const key2 in Config.defaults[key]) {
|
||||
if(!Config.localConfig[key].hasOwnProperty(key2)) {
|
||||
if(!Object.prototype.hasOwnProperty.call(Config.localConfig[key], key2)) {
|
||||
Config.localConfig[key][key2] = Config.defaults[key][key2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Sync config
|
||||
setupConfig();
|
||||
|
||||
442
src/content.ts
442
src/content.ts
@@ -1,96 +1,100 @@
|
||||
import Config from "./config";
|
||||
|
||||
import { SponsorTime, CategorySkipOption, CategorySelection, VideoID, SponsorHideType, FetchResponse } from "./types";
|
||||
import { SponsorTime, CategorySkipOption, VideoID, SponsorHideType, FetchResponse, VideoInfo, StorageChangesObject } from "./types";
|
||||
|
||||
import { ContentContainer } from "./types";
|
||||
import Utils from "./utils";
|
||||
var utils = new Utils();
|
||||
const utils = new Utils();
|
||||
|
||||
import runThePopup from "./popup";
|
||||
|
||||
import PreviewBar from "./js-components/previewBar";
|
||||
import PreviewBar, {PreviewBarSegment} from "./js-components/previewBar";
|
||||
import SkipNotice from "./render/SkipNotice";
|
||||
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
import SubmissionNotice from "./render/SubmissionNotice";
|
||||
import { Message, MessageResponse } from "./messageTypes";
|
||||
|
||||
// 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: VideoID = null;
|
||||
let sponsorDataFound = false;
|
||||
let previousVideoID: VideoID = null;
|
||||
//the actual sponsorTimes if loaded and UUIDs associated with them
|
||||
var sponsorTimes: SponsorTime[] = null;
|
||||
let sponsorTimes: SponsorTime[] = null;
|
||||
//what video id are these sponsors for
|
||||
var sponsorVideoID: VideoID = null;
|
||||
let sponsorVideoID: VideoID = null;
|
||||
|
||||
// JSON video info
|
||||
var videoInfo: any = null;
|
||||
let videoInfo: VideoInfo = null;
|
||||
//the channel this video is about
|
||||
var channelID;
|
||||
let channelID: string;
|
||||
|
||||
// Skips are scheduled to ensure precision.
|
||||
// Skips are rescheduled every seeking event.
|
||||
// Skips are canceled every seeking event
|
||||
var currentSkipSchedule: NodeJS.Timeout = null;
|
||||
var seekListenerSetUp = false
|
||||
let currentSkipSchedule: NodeJS.Timeout = null;
|
||||
let seekListenerSetUp = false
|
||||
|
||||
/** @type {Array[boolean]} Has the sponsor been skipped */
|
||||
var sponsorSkipped: boolean[] = [];
|
||||
let sponsorSkipped: boolean[] = [];
|
||||
|
||||
//the video
|
||||
var video: HTMLVideoElement;
|
||||
let video: HTMLVideoElement;
|
||||
|
||||
var onInvidious;
|
||||
var onMobileYouTube;
|
||||
let onInvidious;
|
||||
let onMobileYouTube;
|
||||
|
||||
//the video id of the last preview bar update
|
||||
var lastPreviewBarUpdate;
|
||||
let lastPreviewBarUpdate;
|
||||
|
||||
//whether the duration listener listening for the duration changes of the video has been setup yet
|
||||
var durationListenerSetUp = false;
|
||||
let durationListenerSetUp = false;
|
||||
|
||||
// Is the video currently being switched
|
||||
var switchingVideos = null;
|
||||
let switchingVideos = null;
|
||||
|
||||
// Made true every videoID change
|
||||
let firstEvent = false;
|
||||
|
||||
// Used by the play and playing listeners to make sure two aren't
|
||||
// called at the same time
|
||||
var lastCheckTime = 0;
|
||||
var lastCheckVideoTime = -1;
|
||||
let lastCheckTime = 0;
|
||||
let lastCheckVideoTime = -1;
|
||||
|
||||
//is this channel whitelised from getting sponsors skipped
|
||||
var channelWhitelisted = false;
|
||||
let channelWhitelisted = false;
|
||||
|
||||
// create preview bar
|
||||
var previewBar: PreviewBar = null;
|
||||
let previewBar: PreviewBar = null;
|
||||
|
||||
//the player controls on the YouTube player
|
||||
var controls = null;
|
||||
let controls = null;
|
||||
|
||||
// Direct Links after the config is loaded
|
||||
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document.URL)));
|
||||
|
||||
//the amount of times the sponsor lookup has retried
|
||||
//this only happens if there is an error
|
||||
var sponsorLookupRetries = 0;
|
||||
let sponsorLookupRetries = 0;
|
||||
|
||||
//if showing the start sponsor button or the end sponsor button on the player
|
||||
var showingStartSponsor = true;
|
||||
let showingStartSponsor = true;
|
||||
|
||||
//the sponsor times being prepared to be submitted
|
||||
var sponsorTimesSubmitting: SponsorTime[] = [];
|
||||
let 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;
|
||||
let popupInitialised = false;
|
||||
|
||||
var submissionNotice: SubmissionNotice = null;
|
||||
let submissionNotice: SubmissionNotice = null;
|
||||
|
||||
// If there is an advert playing (or about to be played), this is true
|
||||
var isAdPlaying = false;
|
||||
let isAdPlaying = false;
|
||||
|
||||
// Contains all of the functions and variables needed by the skip notice
|
||||
var skipNoticeContentContainer: ContentContainer = () => ({
|
||||
const skipNoticeContentContainer: ContentContainer = () => ({
|
||||
vote,
|
||||
dontShowNoticeAgain,
|
||||
unskipSponsorTime,
|
||||
@@ -112,7 +116,7 @@ var skipNoticeContentContainer: ContentContainer = () => ({
|
||||
//get messages from the background script and the popup
|
||||
chrome.runtime.onMessage.addListener(messageListener);
|
||||
|
||||
function messageListener(request: any, sender: any, sendResponse: (response: any) => void): void {
|
||||
function messageListener(request: Message, sender: unknown, sendResponse: (response: MessageResponse) => void): void {
|
||||
//messages from popup script
|
||||
switch(request.message){
|
||||
case "update":
|
||||
@@ -145,27 +149,6 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
||||
videoID: sponsorVideoID
|
||||
});
|
||||
|
||||
break;
|
||||
case "getVideoDuration":
|
||||
sendResponse({
|
||||
duration: video.duration
|
||||
});
|
||||
|
||||
break;
|
||||
case "skipToTime":
|
||||
video.currentTime = request.time;
|
||||
|
||||
// Unpause the video if needed
|
||||
if (video.paused){
|
||||
video.play();
|
||||
}
|
||||
|
||||
return;
|
||||
case "getCurrentTime":
|
||||
sendResponse({
|
||||
currentTime: getRealCurrentTime()
|
||||
});
|
||||
|
||||
break;
|
||||
case "getChannelID":
|
||||
sendResponse({
|
||||
@@ -190,7 +173,6 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
||||
break;
|
||||
case "submitTimes":
|
||||
submitSponsorTimes();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -200,7 +182,7 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
||||
*
|
||||
* @param {String} changes
|
||||
*/
|
||||
function contentConfigUpdateListener(changes) {
|
||||
function contentConfigUpdateListener(changes: StorageChangesObject) {
|
||||
for (const key in changes) {
|
||||
switch(key) {
|
||||
case "hideVideoPlayerControls":
|
||||
@@ -218,13 +200,13 @@ if (!Config.configListeners.includes(contentConfigUpdateListener)) {
|
||||
|
||||
//check for hotkey pressed
|
||||
document.onkeydown = function(e: KeyboardEvent){
|
||||
var key = e.key;
|
||||
const key = e.key;
|
||||
|
||||
let video = document.getElementById("movie_player");
|
||||
const video = document.getElementById("movie_player");
|
||||
|
||||
let startSponsorKey = Config.config.startSponsorKeybind;
|
||||
const startSponsorKey = Config.config.startSponsorKeybind;
|
||||
|
||||
let submitKey = Config.config.submitKeybind;
|
||||
const submitKey = Config.config.submitKeybind;
|
||||
|
||||
//is the video in focus, otherwise they could be typing a comment
|
||||
if (document.activeElement === video) {
|
||||
@@ -252,7 +234,7 @@ function resetValues() {
|
||||
|
||||
//empty the preview bar
|
||||
if (previewBar !== null) {
|
||||
previewBar.set([], [], 0);
|
||||
previewBar.clear();
|
||||
}
|
||||
|
||||
//reset sponsor data found check
|
||||
@@ -265,6 +247,8 @@ function resetValues() {
|
||||
switchingVideos = true;
|
||||
}
|
||||
|
||||
firstEvent = true;
|
||||
|
||||
// Reset advert playing flag
|
||||
isAdPlaying = false;
|
||||
}
|
||||
@@ -296,7 +280,7 @@ async function videoIDChange(id) {
|
||||
}
|
||||
|
||||
if (isUnlisted()) {
|
||||
let shouldContinue = confirm(chrome.i18n.getMessage("confirmPrivacy"));
|
||||
const shouldContinue = confirm(chrome.i18n.getMessage("confirmPrivacy"));
|
||||
if(!shouldContinue) return;
|
||||
}
|
||||
}
|
||||
@@ -309,12 +293,18 @@ async function videoIDChange(id) {
|
||||
if (onMobileYouTube) {
|
||||
// Mobile YouTube workaround
|
||||
const observer = new MutationObserver(handleMobileControlsMutations);
|
||||
let controlsContainer = null;
|
||||
|
||||
observer.observe(document.getElementById("player-control-container"), {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
utils.wait(() => {
|
||||
controlsContainer = document.getElementById("player-control-container")
|
||||
return controlsContainer !== null
|
||||
}).then(() => {
|
||||
observer.observe(document.getElementById("player-control-container"), {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}).catch();
|
||||
} else {
|
||||
utils.wait(getControls).then(createPreviewBar);
|
||||
}
|
||||
@@ -323,7 +313,7 @@ async function videoIDChange(id) {
|
||||
//warn them if they had unsubmitted times
|
||||
if (previousVideoID != null) {
|
||||
//get the sponsor times from storage
|
||||
let sponsorTimes = Config.config.segmentTimes.get(previousVideoID);
|
||||
const sponsorTimes = Config.config.segmentTimes.get(previousVideoID);
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0 && new URL(document.URL).host !== "music.youtube.com") {
|
||||
//warn them that they have unsubmitted sponsor times
|
||||
chrome.runtime.sendMessage({
|
||||
@@ -347,7 +337,7 @@ async function videoIDChange(id) {
|
||||
//make sure everything is properly added
|
||||
updateVisibilityOfPlayerControlsButton().then(() => {
|
||||
//see if the onvideo control image needs to be changed
|
||||
let segments = Config.config.segmentTimes.get(sponsorVideoID);
|
||||
const segments = Config.config.segmentTimes.get(sponsorVideoID);
|
||||
if (segments != null && segments.length > 0 && segments[segments.length - 1].segment.length >= 2) {
|
||||
changeStartSponsorButton(true, true);
|
||||
} else if (segments != null && segments.length > 0 && segments[segments.length - 1].segment.length < 2) {
|
||||
@@ -368,23 +358,13 @@ async function videoIDChange(id) {
|
||||
}
|
||||
|
||||
function handleMobileControlsMutations(): void {
|
||||
let mobileYouTubeSelector = ".progress-bar-background";
|
||||
|
||||
updateVisibilityOfPlayerControlsButton().then((createdButtons) => {
|
||||
if (createdButtons) {
|
||||
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].segment.length < 2) {
|
||||
changeStartSponsorButton(false, true);
|
||||
} else {
|
||||
changeStartSponsorButton(true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (previewBar !== null) {
|
||||
if (document.body.contains(previewBar.container)) {
|
||||
updatePreviewBarPositionMobile(document.getElementsByClassName(mobileYouTubeSelector)[0]);
|
||||
const progressBarBackground = document.querySelector<HTMLElement>(".progress-bar-background");
|
||||
|
||||
if (progressBarBackground !== null) {
|
||||
updatePreviewBarPositionMobile(progressBarBackground);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
@@ -415,11 +395,11 @@ function createPreviewBar(): void {
|
||||
];
|
||||
|
||||
for (const selector of progressElementSelectors) {
|
||||
const el = document.querySelectorAll(selector);
|
||||
const el = document.querySelector<HTMLElement>(selector);
|
||||
|
||||
if (el) {
|
||||
previewBar = new PreviewBar(el, onMobileYouTube, onInvidious);
|
||||
|
||||
if (el && el.length && el[0]) {
|
||||
previewBar = new PreviewBar(el[0], onMobileYouTube, onInvidious);
|
||||
|
||||
updatePreviewBar();
|
||||
|
||||
break;
|
||||
@@ -431,7 +411,7 @@ function createPreviewBar(): void {
|
||||
* Triggered every time the video duration changes.
|
||||
* This happens when the resolution changes or at random time to clear memory.
|
||||
*/
|
||||
function durationChangeListener() {
|
||||
function durationChangeListener(): void {
|
||||
updateAdFlag();
|
||||
updatePreviewBar();
|
||||
}
|
||||
@@ -470,14 +450,14 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||
|
||||
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
||||
|
||||
let skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
const skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
|
||||
if (skipInfo.index === -1) return;
|
||||
|
||||
let currentSkip = skipInfo.array[skipInfo.index];
|
||||
let skipTime: number[] = [currentSkip.segment[0], skipInfo.array[skipInfo.endIndex].segment[1]];
|
||||
let timeUntilSponsor = skipTime[0] - currentTime;
|
||||
let videoID = sponsorVideoID;
|
||||
const currentSkip = skipInfo.array[skipInfo.index];
|
||||
const skipTime: number[] = [currentSkip.segment[0], skipInfo.array[skipInfo.endIndex].segment[1]];
|
||||
const timeUntilSponsor = skipTime[0] - currentTime;
|
||||
const videoID = sponsorVideoID;
|
||||
|
||||
// Find all indexes in between the start and end
|
||||
let skippingSegments = [skipInfo.array[skipInfo.index]];
|
||||
@@ -496,7 +476,7 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||
if (utils.getCategorySelection(currentSkip.category)?.option === CategorySkipOption.ShowOverlay
|
||||
&& skipInfo.array !== sponsorTimesSubmitting) return;
|
||||
|
||||
let skippingFunction = () => {
|
||||
const skippingFunction = () => {
|
||||
let forcedSkipTime: number = null;
|
||||
let forcedIncludeIntersectingSegments = false;
|
||||
let forcedIncludeNonIntersectingSegments = true;
|
||||
@@ -529,7 +509,7 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||
* This makes sure the videoID is still correct and if the sponsorTime is included
|
||||
*/
|
||||
function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean {
|
||||
let currentVideoID = getYouTubeVideoID(document.URL);
|
||||
const currentVideoID = getYouTubeVideoID(document.URL);
|
||||
if (currentVideoID !== (videoID || sponsorVideoID) || (sponsorTime && (!sponsorTimes || !sponsorTimes.includes(sponsorTime)) && !sponsorTimesSubmitting.includes(sponsorTime))) {
|
||||
// Something has really gone wrong
|
||||
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be.");
|
||||
@@ -566,6 +546,12 @@ async function sponsorsLookup(id: string) {
|
||||
video.addEventListener('play', () => {
|
||||
switchingVideos = false;
|
||||
|
||||
// If it is not the first event, then the only way to get to 0 is if there is a seek event
|
||||
// This check makes sure that changing the video resolution doesn't cause the extension to think it
|
||||
// gone back to the begining
|
||||
if (!firstEvent && video.currentTime === 0) return;
|
||||
firstEvent = false;
|
||||
|
||||
// Check if an ad is playing
|
||||
updateAdFlag();
|
||||
|
||||
@@ -599,6 +585,8 @@ async function sponsorsLookup(id: string) {
|
||||
}
|
||||
});
|
||||
video.addEventListener('ratechange', () => startSponsorSchedule());
|
||||
// Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740)
|
||||
video.addEventListener('videoSpeed_ratechange', () => startSponsorSchedule());
|
||||
video.addEventListener('pause', () => {
|
||||
// Reset lastCheckVideoTime
|
||||
lastCheckVideoTime = -1;
|
||||
@@ -614,7 +602,7 @@ async function sponsorsLookup(id: string) {
|
||||
//made true once a setTimeout has been created to try again after a server error
|
||||
let recheckStarted = false;
|
||||
// Create categories list
|
||||
let categories: string[] = [];
|
||||
const categories: string[] = [];
|
||||
for (const categorySelection of Config.config.categorySelections) {
|
||||
categories.push(categorySelection.name);
|
||||
}
|
||||
@@ -649,7 +637,7 @@ async function sponsorsLookup(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
let recievedSegments: SponsorTime[] = result;
|
||||
const recievedSegments: SponsorTime[] = result;
|
||||
if (!recievedSegments.length) {
|
||||
console.error("[SponsorBlock] Server returned malformed response: " + JSON.stringify(recievedSegments));
|
||||
return;
|
||||
@@ -713,7 +701,7 @@ function retryFetch(id: string): void {
|
||||
|
||||
//check if this video was uploaded recently
|
||||
utils.wait(() => !!videoInfo).then(() => {
|
||||
let dateUploaded = videoInfo?.microformat?.playerMicroformatRenderer?.uploadDate;
|
||||
const dateUploaded = videoInfo?.microformat?.playerMicroformatRenderer?.uploadDate;
|
||||
|
||||
//if less than 3 days old
|
||||
if (Date.now() - new Date(dateUploaded).getTime() < 259200000) {
|
||||
@@ -733,7 +721,7 @@ function retryFetch(id: string): void {
|
||||
function startSkipScheduleCheckingForStartSponsors() {
|
||||
if (!switchingVideos) {
|
||||
// See if there are any starting sponsors
|
||||
let startingSponsor: number = -1;
|
||||
let startingSponsor = -1;
|
||||
for (const time of sponsorTimes) {
|
||||
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
|
||||
startingSponsor = time.segment[0];
|
||||
@@ -760,18 +748,18 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
/**
|
||||
* Get the video info for the current tab from YouTube
|
||||
*/
|
||||
function getVideoInfo() {
|
||||
sendRequestToCustomServer('GET', "https://www.youtube.com/get_video_info?video_id=" + sponsorVideoID, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
let decodedData = decodeURIComponent(xmlhttp.responseText).match(/player_response=([^&]*)/)[1];
|
||||
if (!decodedData) {
|
||||
console.error("[SB] Failed at getting video info from YouTube.");
|
||||
return;
|
||||
}
|
||||
async function getVideoInfo(): Promise<void> {
|
||||
const result = await utils.asyncRequestToCustomServer("GET", "https://www.youtube.com/get_video_info?video_id=" + sponsorVideoID);
|
||||
|
||||
videoInfo = JSON.parse(decodedData);
|
||||
if (result.ok) {
|
||||
const decodedData = decodeURIComponent(result.responseText).match(/player_response=([^&]*)/)[1];
|
||||
if (!decodedData) {
|
||||
console.error("[SB] Failed at getting video info from YouTube.");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
videoInfo = JSON.parse(decodedData);
|
||||
}
|
||||
}
|
||||
|
||||
function getYouTubeVideoID(url: string) {
|
||||
@@ -803,7 +791,7 @@ function getYouTubeVideoID(url: string) {
|
||||
|
||||
//Get ID from searchParam
|
||||
if (urlObject.searchParams.has("v") && ["/watch", "/watch/"].includes(urlObject.pathname) || urlObject.pathname.startsWith("/tv/watch")) {
|
||||
let id = urlObject.searchParams.get("v");
|
||||
const id = urlObject.searchParams.get("v");
|
||||
return id.length == 11 ? id : false;
|
||||
} else if (urlObject.pathname.startsWith("/embed/")) {
|
||||
try {
|
||||
@@ -819,46 +807,53 @@ function getYouTubeVideoID(url: string) {
|
||||
/**
|
||||
* This function is required on mobile YouTube and will keep getting called whenever the preview bar disapears
|
||||
*/
|
||||
function updatePreviewBarPositionMobile(parent: Element) {
|
||||
function updatePreviewBarPositionMobile(parent: HTMLElement) {
|
||||
if (document.getElementById("previewbar") === null) {
|
||||
previewBar.updatePosition(parent);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePreviewBar() {
|
||||
if(isAdPlaying) {
|
||||
previewBar.set([], [], 0);
|
||||
function updatePreviewBar(): void {
|
||||
if (previewBar === null) return;
|
||||
|
||||
if (isAdPlaying) {
|
||||
previewBar.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (previewBar === null || video === null) return;
|
||||
if (video === null) return;
|
||||
|
||||
let localSponsorTimes = sponsorTimes;
|
||||
if (localSponsorTimes == null) localSponsorTimes = [];
|
||||
const previewBarSegments: PreviewBarSegment[] = [];
|
||||
|
||||
let allSponsorTimes = localSponsorTimes.concat(sponsorTimesSubmitting);
|
||||
|
||||
//create an array of the sponsor types
|
||||
let types = [];
|
||||
for (let i = 0; i < localSponsorTimes.length; i++) {
|
||||
if (localSponsorTimes[i].hidden === SponsorHideType.Visible) {
|
||||
types.push(localSponsorTimes[i].category);
|
||||
} else {
|
||||
// Don't show this sponsor
|
||||
types.push(null);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
||||
types.push("preview-" + sponsorTimesSubmitting[i].category);
|
||||
if (sponsorTimes) {
|
||||
sponsorTimes.forEach((segment) => {
|
||||
if (segment.hidden !== SponsorHideType.Visible) return;
|
||||
|
||||
previewBarSegments.push({
|
||||
segment: segment.segment as [number, number],
|
||||
category: segment.category,
|
||||
preview: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration)
|
||||
sponsorTimesSubmitting.forEach((segment) => {
|
||||
previewBarSegments.push({
|
||||
segment: segment.segment as [number, number],
|
||||
category: segment.category,
|
||||
preview: true,
|
||||
});
|
||||
});
|
||||
|
||||
previewBar.set(previewBarSegments, video.duration)
|
||||
|
||||
if (Config.config.showTimeWithSkips) {
|
||||
showTimeWithoutSkips(allSponsorTimes);
|
||||
const skippedDuration = utils.getTimestampsDuration(previewBarSegments.map(({segment}) => segment));
|
||||
|
||||
showTimeWithoutSkips(skippedDuration);
|
||||
}
|
||||
|
||||
//update last video id
|
||||
// Update last video id
|
||||
lastPreviewBarUpdate = sponsorVideoID;
|
||||
}
|
||||
|
||||
@@ -872,7 +867,7 @@ function whitelistCheck() {
|
||||
}
|
||||
|
||||
//see if this is a whitelisted channel
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
const whitelistedChannels = Config.config.whitelistedChannels;
|
||||
|
||||
if (whitelistedChannels != undefined && whitelistedChannels.includes(channelID)) {
|
||||
channelWhitelisted = true;
|
||||
@@ -888,17 +883,17 @@ function whitelistCheck() {
|
||||
function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean):
|
||||
{array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} {
|
||||
|
||||
let sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, true, true);
|
||||
const sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
const sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, true, true);
|
||||
|
||||
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
||||
let endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex);
|
||||
const minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
||||
const endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex);
|
||||
|
||||
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, false, false);
|
||||
const previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
const previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, false, false);
|
||||
|
||||
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
|
||||
let previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex);
|
||||
const minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
|
||||
const previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex);
|
||||
|
||||
if ((minPreviewSponsorTimeIndex === -1 && minSponsorTimeIndex !== -1) ||
|
||||
sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) {
|
||||
@@ -931,7 +926,7 @@ function getNextSkipIndex(currentTime: number, includeIntersectingSegments: bool
|
||||
* @param index Index of the given sponsor
|
||||
* @param hideHiddenSponsors
|
||||
*/
|
||||
function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideHiddenSponsors: boolean = true): number {
|
||||
function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideHiddenSponsors = true): number {
|
||||
// Only combine segments for AutoSkip
|
||||
if (index == -1 ||
|
||||
utils.getCategorySelection(sponsorTimes[index].category)?.option !== CategorySkipOption.AutoSkip) return index;
|
||||
@@ -940,8 +935,8 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
|
||||
let latestEndTimeIndex = index;
|
||||
|
||||
for (let i = 0; i < sponsorTimes?.length; i++) {
|
||||
let currentSegment = sponsorTimes[i].segment;
|
||||
let latestEndTime = sponsorTimes[latestEndTimeIndex].segment[1];
|
||||
const currentSegment = sponsorTimes[i].segment;
|
||||
const latestEndTime = sponsorTimes[latestEndTimeIndex].segment[1];
|
||||
|
||||
if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime
|
||||
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
|
||||
@@ -970,10 +965,10 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
|
||||
* the current time, but end after
|
||||
*/
|
||||
function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean,
|
||||
minimum?: number, onlySkippableSponsors: boolean = false, hideHiddenSponsors: boolean = false): number[] {
|
||||
minimum?: number, onlySkippableSponsors = false, hideHiddenSponsors = false): number[] {
|
||||
if (sponsorTimes === null) return [];
|
||||
|
||||
let startTimes: number[] = [];
|
||||
const startTimes: number[] = [];
|
||||
|
||||
for (let i = 0; i < sponsorTimes?.length; i++) {
|
||||
if ((minimum === undefined
|
||||
@@ -1006,7 +1001,7 @@ function previewTime(time: number, unpause = true) {
|
||||
//skip from the start time to the end time for a certain index sponsor time
|
||||
function skipToTime(v: HTMLVideoElement, skipTime: number[], skippingSegments: SponsorTime[], openNotice: boolean) {
|
||||
// There will only be one submission if it is manual skip
|
||||
let autoSkip: boolean = utils.getCategorySelection(skippingSegments[0].category)?.option === CategorySkipOption.AutoSkip;
|
||||
const autoSkip: boolean = utils.getCategorySelection(skippingSegments[0].category)?.option === CategorySkipOption.AutoSkip;
|
||||
|
||||
if ((autoSkip || sponsorTimesSubmitting.includes(skippingSegments[0])) && v.currentTime !== skipTime[1]) {
|
||||
// Fix for looped videos not working when skipping to the end #426
|
||||
@@ -1031,7 +1026,7 @@ function skipToTime(v: HTMLVideoElement, skipTime: number[], skippingSegments: S
|
||||
let isPreviewSegment = false;
|
||||
|
||||
for (const segment of skippingSegments) {
|
||||
let index = sponsorTimes.indexOf(segment);
|
||||
const index = sponsorTimes.indexOf(segment);
|
||||
if (index !== -1 && !sponsorSkipped[index]) {
|
||||
utils.asyncRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + segment.UUID);
|
||||
|
||||
@@ -1060,24 +1055,26 @@ function unskipSponsorTime(segment: SponsorTime) {
|
||||
|
||||
function reskipSponsorTime(segment: SponsorTime) {
|
||||
video.currentTime = segment.segment[1];
|
||||
|
||||
startSponsorSchedule(true, segment.segment[1], false);
|
||||
}
|
||||
|
||||
function createButton(baseID, title, callback, imageName, isDraggable=false): boolean {
|
||||
if (document.getElementById(baseID + "Button") != null) return false;
|
||||
|
||||
// Button HTML
|
||||
let newButton = document.createElement("button");
|
||||
const newButton = document.createElement("button");
|
||||
newButton.draggable = isDraggable;
|
||||
newButton.id = baseID + "Button";
|
||||
newButton.classList.add("playerButton");
|
||||
newButton.classList.add("ytp-button");
|
||||
newButton.setAttribute("title", chrome.i18n.getMessage(title));
|
||||
newButton.addEventListener("click", (event: Event) => {
|
||||
newButton.addEventListener("click", () => {
|
||||
callback();
|
||||
});
|
||||
|
||||
// Image HTML
|
||||
let newButtonImage = document.createElement("img");
|
||||
const newButtonImage = document.createElement("img");
|
||||
newButton.draggable = isDraggable;
|
||||
newButtonImage.id = baseID + "Image";
|
||||
newButtonImage.className = "playerButtonImage";
|
||||
@@ -1092,8 +1089,8 @@ function createButton(baseID, title, callback, imageName, isDraggable=false): bo
|
||||
return true;
|
||||
}
|
||||
|
||||
function getControls(): HTMLElement | boolean {
|
||||
let controlsSelectors = [
|
||||
function getControls(): HTMLElement | false {
|
||||
const controlsSelectors = [
|
||||
// YouTube
|
||||
".ytp-right-controls",
|
||||
// Mobile YouTube
|
||||
@@ -1103,7 +1100,7 @@ function getControls(): HTMLElement | boolean {
|
||||
]
|
||||
|
||||
for (const controlsSelector of controlsSelectors) {
|
||||
let controls = document.querySelectorAll(controlsSelector);
|
||||
const controls = document.querySelectorAll(controlsSelector);
|
||||
|
||||
if (controls && controls.length > 0) {
|
||||
return <HTMLElement> controls[controls.length - 1];
|
||||
@@ -1111,13 +1108,13 @@ function getControls(): HTMLElement | boolean {
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
//adds all the player controls buttons
|
||||
async function createButtons(): Promise<boolean> {
|
||||
if (onMobileYouTube) return;
|
||||
|
||||
let result = await utils.wait(getControls).catch();
|
||||
const result = await utils.wait(getControls).catch();
|
||||
|
||||
//set global controls variable
|
||||
controls = result;
|
||||
@@ -1125,7 +1122,7 @@ async function createButtons(): Promise<boolean> {
|
||||
let createdButton = false;
|
||||
|
||||
// Add button if does not already exist in html
|
||||
createdButton = createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png") || createdButton;
|
||||
createdButton = createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png") || createdButton;
|
||||
createdButton = createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png") || createdButton;
|
||||
createdButton = createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png") || createdButton;
|
||||
createdButton = createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png") || createdButton;
|
||||
@@ -1138,7 +1135,8 @@ async function updateVisibilityOfPlayerControlsButton(): Promise<boolean> {
|
||||
//not on a proper video yet
|
||||
if (!sponsorVideoID) return false;
|
||||
|
||||
let createdButtons = await createButtons();
|
||||
const createdButtons = await createButtons();
|
||||
if (!createdButtons) return;
|
||||
|
||||
if (Config.config.hideVideoPlayerControls || onInvidious) {
|
||||
document.getElementById("startSponsorButton").style.display = "none";
|
||||
@@ -1168,8 +1166,8 @@ async function updateVisibilityOfPlayerControlsButton(): Promise<boolean> {
|
||||
*/
|
||||
function getRealCurrentTime(): number {
|
||||
// Used to check if replay button
|
||||
let playButtonSVGData = document.querySelector(".ytp-play-button")?.querySelector(".ytp-svg-fill")?.getAttribute("d");
|
||||
let replaceSVGData = "M 18,11 V 7 l -5,5 5,5 v -4 c 3.3,0 6,2.7 6,6 0,3.3 -2.7,6 -6,6 -3.3,0 -6,-2.7 -6,-6 h -2 c 0,4.4 3.6,8 8,8 4.4,0 8,-3.6 8,-8 0,-4.4 -3.6,-8 -8,-8 z";
|
||||
const playButtonSVGData = document.querySelector(".ytp-play-button")?.querySelector(".ytp-svg-fill")?.getAttribute("d");
|
||||
const replaceSVGData = "M 18,11 V 7 l -5,5 5,5 v -4 c 3.3,0 6,2.7 6,6 0,3.3 -2.7,6 -6,6 -3.3,0 -6,-2.7 -6,-6 h -2 c 0,4.4 3.6,8 8,8 4.4,0 8,-3.6 8,-8 0,-4.4 -3.6,-8 -8,-8 z";
|
||||
|
||||
if (playButtonSVGData === replaceSVGData) {
|
||||
// At the end of the video
|
||||
@@ -1189,6 +1187,7 @@ function startSponsorClicked() {
|
||||
if (sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length < 2) {
|
||||
//it is an end time
|
||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment[1] = getRealCurrentTime();
|
||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.sort((a, b) => a > b ? 1 : (a < b ? -1 : 0));
|
||||
} else {
|
||||
//it is a start time
|
||||
sponsorTimesSubmitting.push({
|
||||
@@ -1204,8 +1203,8 @@ function startSponsorClicked() {
|
||||
updateSponsorTimesSubmitting(false)
|
||||
}
|
||||
|
||||
function updateSponsorTimesSubmitting(getFromConfig: boolean = true) {
|
||||
let segmentTimes = Config.config.segmentTimes.get(sponsorVideoID);
|
||||
function updateSponsorTimesSubmitting(getFromConfig = true) {
|
||||
const segmentTimes = Config.config.segmentTimes.get(sponsorVideoID);
|
||||
|
||||
//see if this data should be saved in the sponsorTimesSubmitting variable
|
||||
if (getFromConfig && segmentTimes != undefined) {
|
||||
@@ -1230,11 +1229,11 @@ function updateSponsorTimesSubmitting(getFromConfig: boolean = true) {
|
||||
}
|
||||
}
|
||||
|
||||
async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
|
||||
if(!sponsorVideoID) return false;
|
||||
async function changeStartSponsorButton(showStartSponsor: boolean, uploadButtonVisible: boolean): Promise<boolean> {
|
||||
if(!sponsorVideoID || onMobileYouTube) return false;
|
||||
|
||||
//if it isn't visible, there is no data
|
||||
let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
|
||||
const shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
|
||||
document.getElementById("deleteButton").style.display = shouldHide;
|
||||
|
||||
if (showStartSponsor) {
|
||||
@@ -1275,12 +1274,20 @@ function openInfoMenu() {
|
||||
|
||||
sendRequestToCustomServer('GET', chrome.extension.getURL("popup.html"), function(xmlhttp) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
var popup = document.createElement("div");
|
||||
const popup = document.createElement("div");
|
||||
popup.id = "sponsorBlockPopupContainer";
|
||||
popup.innerHTML = xmlhttp.responseText
|
||||
|
||||
let htmlData = xmlhttp.responseText;
|
||||
// Hack to replace head data (title, favicon)
|
||||
htmlData = htmlData.replace(/<head>[\S\s]*<\/head>/gi, "");
|
||||
// Hack to replace body tag with div
|
||||
htmlData = htmlData.replace(/<body/gi, "<div");
|
||||
htmlData = htmlData.replace(/<\/body/gi, "</div");
|
||||
|
||||
popup.innerHTML = htmlData;
|
||||
|
||||
//close button
|
||||
let closeButton = document.createElement("div");
|
||||
const closeButton = document.createElement("div");
|
||||
closeButton.innerText = chrome.i18n.getMessage("closePopup");
|
||||
closeButton.classList.add("smallLink");
|
||||
closeButton.setAttribute("align", "center");
|
||||
@@ -1291,7 +1298,7 @@ function openInfoMenu() {
|
||||
//add the close button
|
||||
popup.prepend(closeButton);
|
||||
|
||||
let parentNodes = document.querySelectorAll("#secondary");
|
||||
const parentNodes = document.querySelectorAll("#secondary");
|
||||
let parentNode = null;
|
||||
for (let i = 0; i < parentNodes.length; i++) {
|
||||
if (parentNodes[i].firstElementChild !== null) {
|
||||
@@ -1302,16 +1309,18 @@ function openInfoMenu() {
|
||||
//old youtube theme
|
||||
parentNode = document.getElementById("watch7-sidebar-contents");
|
||||
}
|
||||
|
||||
|
||||
//make the logo source not 404
|
||||
//query selector must be used since getElementByID doesn't work on a node and this isn't added to the document yet
|
||||
let logo = <HTMLImageElement> popup.querySelector("#sponsorBlockPopupLogo");
|
||||
const logo = <HTMLImageElement> popup.querySelector("#sponsorBlockPopupLogo");
|
||||
const settings = <HTMLImageElement> popup.querySelector("#sbPopupIconSettings");
|
||||
const edit = <HTMLImageElement> popup.querySelector("#sbPopupIconEdit");
|
||||
const check = <HTMLImageElement> popup.querySelector("#sbPopupIconCheck");
|
||||
logo.src = chrome.extension.getURL("icons/LogoSponsorBlocker256px.png");
|
||||
|
||||
//remove the style sheet and font that are not necessary
|
||||
popup.querySelector("#sponsorBlockPopupFont").remove();
|
||||
popup.querySelector("#sponsorBlockStyleSheet").remove();
|
||||
settings.src = chrome.extension.getURL("icons/settings.svg");
|
||||
edit.src = chrome.extension.getURL("icons/pencil.svg");
|
||||
check.src = chrome.extension.getURL("icons/check.svg");
|
||||
check.src = chrome.extension.getURL("icons/thumb.svg");
|
||||
|
||||
parentNode.insertBefore(popup, parentNode.firstChild);
|
||||
|
||||
@@ -1322,7 +1331,7 @@ function openInfoMenu() {
|
||||
}
|
||||
|
||||
function closeInfoMenu() {
|
||||
let popup = document.getElementById("sponsorBlockPopupContainer");
|
||||
const popup = document.getElementById("sponsorBlockPopupContainer");
|
||||
if (popup != null) {
|
||||
popup.remove();
|
||||
|
||||
@@ -1337,12 +1346,12 @@ function clearSponsorTimes() {
|
||||
//it can't update to this info yet
|
||||
closeInfoMenu();
|
||||
|
||||
let currentVideoID = sponsorVideoID;
|
||||
const currentVideoID = sponsorVideoID;
|
||||
|
||||
let sponsorTimes = Config.config.segmentTimes.get(currentVideoID);
|
||||
const sponsorTimes = Config.config.segmentTimes.get(currentVideoID);
|
||||
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||
let confirmMessage = chrome.i18n.getMessage("clearThis") + getSegmentsMessage(sponsorTimes)
|
||||
const confirmMessage = chrome.i18n.getMessage("clearThis") + getSegmentsMessage(sponsorTimes)
|
||||
+ "\n" + chrome.i18n.getMessage("confirmMSG")
|
||||
if(!confirm(confirmMessage)) return;
|
||||
|
||||
@@ -1367,7 +1376,7 @@ function vote(type: number, UUID: string, category?: string, skipNotice?: SkipNo
|
||||
skipNotice.setNoticeInfoMessage.bind(skipNotice)();
|
||||
}
|
||||
|
||||
let sponsorIndex = utils.getSponsorIndexFromUUID(sponsorTimes, UUID);
|
||||
const sponsorIndex = utils.getSponsorIndexFromUUID(sponsorTimes, UUID);
|
||||
|
||||
// Don't vote for preview sponsors
|
||||
if (sponsorIndex == -1 || sponsorTimes[sponsorIndex].UUID === null) return;
|
||||
@@ -1410,7 +1419,7 @@ function vote(type: number, UUID: string, category?: string, skipNotice?: SkipNo
|
||||
|
||||
//Closes all notices that tell the user that a sponsor was just skipped
|
||||
function closeAllSkipNotices(){
|
||||
let notices = document.getElementsByClassName("sponsorSkipNotice");
|
||||
const notices = document.getElementsByClassName("sponsorSkipNotice");
|
||||
for (let i = 0; i < notices.length; i++) {
|
||||
notices[i].remove();
|
||||
}
|
||||
@@ -1421,7 +1430,7 @@ function dontShowNoticeAgain() {
|
||||
closeAllSkipNotices();
|
||||
}
|
||||
|
||||
function sponsorMessageStarted(callback) {
|
||||
function sponsorMessageStarted(callback: (response: MessageResponse) => void) {
|
||||
video = document.querySelector('video');
|
||||
|
||||
//send back current time
|
||||
@@ -1446,8 +1455,6 @@ function submitSponsorTimes() {
|
||||
//it can't update to this info yet
|
||||
closeInfoMenu();
|
||||
|
||||
let currentVideoID = sponsorVideoID;
|
||||
|
||||
if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) {
|
||||
submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage);
|
||||
}
|
||||
@@ -1456,7 +1463,7 @@ function submitSponsorTimes() {
|
||||
|
||||
//send the message to the background js
|
||||
//called after all the checks have been made that it's okay to do so
|
||||
async function sendSubmitMessage(){
|
||||
async function sendSubmitMessage(): Promise<void> {
|
||||
//add loading animation
|
||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png");
|
||||
document.getElementById("submitButton").style.animation = "rotate 1s 0s infinite";
|
||||
@@ -1475,7 +1482,7 @@ async function sendSubmitMessage(){
|
||||
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" +
|
||||
const confirmShort = chrome.i18n.getMessage("shortCheck") + "\n\n" +
|
||||
getSegmentsMessage(sponsorTimesSubmitting);
|
||||
|
||||
if(!confirm(confirmShort)) return;
|
||||
@@ -1483,7 +1490,7 @@ async function sendSubmitMessage(){
|
||||
}
|
||||
}
|
||||
|
||||
let response = await utils.asyncRequestToServer("POST", "/api/skipSegments", {
|
||||
const response = await utils.asyncRequestToServer("POST", "/api/skipSegments", {
|
||||
videoID: sponsorVideoID,
|
||||
userID: Config.config.userID,
|
||||
segments: sponsorTimesSubmitting
|
||||
@@ -1491,11 +1498,11 @@ async function sendSubmitMessage(){
|
||||
|
||||
if (response.status === 200) {
|
||||
//hide loading message
|
||||
let submitButton = document.getElementById("submitButton");
|
||||
const submitButton = document.getElementById("submitButton");
|
||||
submitButton.style.animation = "rotate 1s";
|
||||
//finish this animation
|
||||
//when the animation is over, hide the button
|
||||
let animationEndListener = function() {
|
||||
const animationEndListener = function() {
|
||||
changeStartSponsorButton(true, false);
|
||||
|
||||
submitButton.style.animation = "none";
|
||||
@@ -1569,10 +1576,10 @@ function isUnlisted(): boolean {
|
||||
function addCSS() {
|
||||
if (!utils.isFirefox() && Config.config.invidiousInstances.includes(new URL(document.URL).host)) {
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
let head = document.getElementsByTagName("head")[0];
|
||||
const head = document.getElementsByTagName("head")[0];
|
||||
|
||||
for (const file of utils.css) {
|
||||
let fileref = document.createElement("link");
|
||||
const fileref = document.createElement("link");
|
||||
|
||||
fileref.rel = "stylesheet";
|
||||
fileref.type = "text/css";
|
||||
@@ -1585,7 +1592,7 @@ function addCSS() {
|
||||
}
|
||||
|
||||
function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
const xmlhttp = new XMLHttpRequest();
|
||||
|
||||
xmlhttp.open(type, fullAddress, true);
|
||||
|
||||
@@ -1594,7 +1601,7 @@ function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||
callback(xmlhttp, false);
|
||||
};
|
||||
|
||||
xmlhttp.onerror = function(ev) {
|
||||
xmlhttp.onerror = function() {
|
||||
callback(xmlhttp, true);
|
||||
};
|
||||
}
|
||||
@@ -1606,8 +1613,8 @@ function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||
/**
|
||||
* Update the isAdPlaying flag and hide preview bar/controls if ad is playing
|
||||
*/
|
||||
function updateAdFlag() {
|
||||
let wasAdPlaying = isAdPlaying;
|
||||
function updateAdFlag(): void {
|
||||
const wasAdPlaying = isAdPlaying;
|
||||
isAdPlaying = document.getElementsByClassName('ad-showing').length > 0;
|
||||
|
||||
if(wasAdPlaying != isAdPlaying) {
|
||||
@@ -1616,37 +1623,28 @@ function updateAdFlag() {
|
||||
}
|
||||
}
|
||||
|
||||
function showTimeWithoutSkips(allSponsorTimes): void {
|
||||
function showTimeWithoutSkips(skippedDuration: number): void {
|
||||
if (onMobileYouTube || onInvidious) return;
|
||||
|
||||
let skipDuration = 0;
|
||||
|
||||
// Calculate skipDuration based from the segments in the preview bar
|
||||
for (let i = 0; i < allSponsorTimes.length; i++) {
|
||||
// If an end time exists
|
||||
if (allSponsorTimes[i].segment[1]) {
|
||||
skipDuration += allSponsorTimes[i].segment[1] - allSponsorTimes[i].segment[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// YouTube player time display
|
||||
let display = document.getElementsByClassName("ytp-time-display notranslate")[0];
|
||||
if (!display) return;
|
||||
|
||||
let formatedTime = utils.getFormattedTime(video.duration - skipDuration);
|
||||
|
||||
const durationID = "sponsorBlockDurationAfterSkips";
|
||||
if (isNaN(skippedDuration) || skippedDuration < 0) {
|
||||
skippedDuration = 0;
|
||||
}
|
||||
|
||||
// YouTube player time display
|
||||
const display = document.querySelector(".ytp-time-display.notranslate");
|
||||
if (!display) return;
|
||||
|
||||
const durationID = "sponsorBlockDurationAfterSkips";
|
||||
let duration = document.getElementById(durationID);
|
||||
|
||||
// Create span if needed
|
||||
if(duration === null) {
|
||||
duration = document.createElement('span');
|
||||
// Create span if needed
|
||||
if (duration === null) {
|
||||
duration = document.createElement('span');
|
||||
duration.id = durationID;
|
||||
duration.classList.add("ytp-time-duration");
|
||||
|
||||
display.appendChild(duration);
|
||||
}
|
||||
|
||||
duration.innerText = (skipDuration <= 0 || isNaN(skipDuration) || formatedTime.includes("NaN")) ? "" : " ("+formatedTime+")";
|
||||
display.appendChild(duration);
|
||||
}
|
||||
|
||||
duration.innerText = skippedDuration <= 0 ? "" : " (" + utils.getFormattedTime(video.duration - skippedDuration) + ")";
|
||||
}
|
||||
|
||||
19
src/globals.d.ts
vendored
Normal file
19
src/globals.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { SBObject } from "./config";
|
||||
declare global {
|
||||
interface Window { SB: SBObject; }
|
||||
// Remove this once the API becomes stable and types are shipped in @types/chrome
|
||||
namespace chrome {
|
||||
namespace declarativeContent {
|
||||
export interface RequestContentScriptOptions {
|
||||
allFrames?: boolean;
|
||||
css?: string[];
|
||||
instanceType?: "declarativeContent.RequestContentScript";
|
||||
js?: string[];
|
||||
matchAboutBlanck?: boolean;
|
||||
}
|
||||
export class RequestContentScript {
|
||||
constructor(options: RequestContentScriptOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,187 +1,226 @@
|
||||
/*
|
||||
This is based on code from VideoSegments.
|
||||
https://github.com/videosegments/videosegments/commits/f1e111bdfe231947800c6efdd51f62a4e7fef4d4/segmentsbar/segmentsbar.js
|
||||
This is based on code from VideoSegments.
|
||||
https://github.com/videosegments/videosegments/commits/f1e111bdfe231947800c6efdd51f62a4e7fef4d4/segmentsbar/segmentsbar.js
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import Config from "../config";
|
||||
import Utils from "../utils";
|
||||
let utils = new Utils();
|
||||
const utils = new Utils();
|
||||
|
||||
class PreviewBar {
|
||||
container: HTMLUListElement;
|
||||
parent: any;
|
||||
onMobileYouTube: boolean;
|
||||
onInvidious: boolean;
|
||||
const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible';
|
||||
|
||||
timestamps: number[][];
|
||||
types: string;
|
||||
|
||||
constructor(parent, onMobileYouTube, onInvidious) {
|
||||
this.container = document.createElement('ul');
|
||||
this.container.id = 'previewbar';
|
||||
this.parent = parent;
|
||||
|
||||
this.onMobileYouTube = onMobileYouTube;
|
||||
this.onInvidious = onInvidious;
|
||||
|
||||
this.updatePosition(parent);
|
||||
|
||||
this.setupHoverText();
|
||||
}
|
||||
|
||||
setupHoverText() {
|
||||
if (this.onMobileYouTube || this.onInvidious) return;
|
||||
|
||||
let seekBar = document.querySelector(".ytp-progress-bar-container");
|
||||
|
||||
// Create label placeholder
|
||||
let tooltipTextWrapper = document.querySelector(".ytp-tooltip-text-wrapper");
|
||||
let titleTooltip = document.querySelector(".ytp-tooltip-title");
|
||||
let categoryTooltip = document.createElement("div");
|
||||
categoryTooltip.className = "sbHidden ytp-tooltip-title";
|
||||
categoryTooltip.id = "sponsor-block-category-tooltip"
|
||||
|
||||
tooltipTextWrapper.insertBefore(categoryTooltip, titleTooltip.nextSibling);
|
||||
|
||||
let mouseOnSeekBar = false;
|
||||
|
||||
seekBar.addEventListener("mouseenter", (event) => {
|
||||
mouseOnSeekBar = true;
|
||||
});
|
||||
|
||||
seekBar.addEventListener("mouseleave", (event) => {
|
||||
mouseOnSeekBar = false;
|
||||
categoryTooltip.classList.add("sbHidden");
|
||||
});
|
||||
|
||||
const observer = new MutationObserver((mutations, observer) => {
|
||||
if (!mouseOnSeekBar) return;
|
||||
|
||||
// See if mutation observed is only this ID (if so, ignore)
|
||||
if (mutations.length == 1 && (mutations[0].target as HTMLElement).id === "sponsor-block-category-tooltip") {
|
||||
return;
|
||||
}
|
||||
|
||||
let tooltips = document.querySelectorAll(".ytp-tooltip-text");
|
||||
for (const tooltip of tooltips) {
|
||||
let splitData = tooltip.textContent.split(":");
|
||||
if (splitData.length === 2 && !isNaN(parseInt(splitData[0])) && !isNaN(parseInt(splitData[1]))) {
|
||||
// Add label
|
||||
let timeInSeconds = parseInt(splitData[0]) * 60 + parseInt(splitData[1]);
|
||||
|
||||
// Find category at that location
|
||||
let category = null;
|
||||
for (let i = 0; i < this.timestamps?.length; i++) {
|
||||
if (this.timestamps[i][0] < timeInSeconds && this.timestamps[i][1] > timeInSeconds){
|
||||
category = this.types[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (category === null && !categoryTooltip.classList.contains("sbHidden")) {
|
||||
categoryTooltip.classList.add("sbHidden");
|
||||
tooltipTextWrapper.classList.remove("sbTooltipTwoTitleThumbnailOffset");
|
||||
tooltipTextWrapper.classList.remove("sbTooltipOneTitleThumbnailOffset");
|
||||
} else if (category !== null) {
|
||||
categoryTooltip.classList.remove("sbHidden");
|
||||
categoryTooltip.textContent = utils.shortCategoryName(category)
|
||||
|| (chrome.i18n.getMessage("preview") + " " + utils.shortCategoryName(category.split("preview-")[1]));
|
||||
|
||||
// There is a title now
|
||||
tooltip.classList.remove("ytp-tooltip-text-no-title");
|
||||
|
||||
// Add the correct offset for the number of titles there are
|
||||
if (titleTooltip.textContent !== "") {
|
||||
if (!tooltipTextWrapper.classList.contains("sbTooltipTwoTitleThumbnailOffset")) {
|
||||
tooltipTextWrapper.classList.add("sbTooltipTwoTitleThumbnailOffset");
|
||||
}
|
||||
} else if (!tooltipTextWrapper.classList.contains("sbTooltipOneTitleThumbnailOffset")) {
|
||||
tooltipTextWrapper.classList.add("sbTooltipOneTitleThumbnailOffset");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(tooltipTextWrapper, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
|
||||
updatePosition(parent) {
|
||||
//below the seek bar
|
||||
// this.parent.insertAdjacentElement("afterEnd", this.container);
|
||||
|
||||
this.parent = parent;
|
||||
|
||||
if (this.onMobileYouTube) {
|
||||
parent.style.backgroundColor = "rgba(255, 255, 255, 0.3)";
|
||||
parent.style.opacity = "1";
|
||||
|
||||
this.container.style.transform = "none";
|
||||
}
|
||||
|
||||
//on the seek bar
|
||||
this.parent.insertAdjacentElement("afterBegin", this.container);
|
||||
}
|
||||
|
||||
updateColor(segment, color, opacity) {
|
||||
let bars = <NodeListOf<HTMLElement>> document.querySelectorAll('[data-vs-segment-type=' + segment + ']');
|
||||
for (let bar of bars) {
|
||||
bar.style.backgroundColor = color;
|
||||
bar.style.opacity = opacity;
|
||||
}
|
||||
}
|
||||
|
||||
set(timestamps, types, duration) {
|
||||
while (this.container.firstChild) {
|
||||
this.container.removeChild(this.container.firstChild);
|
||||
}
|
||||
|
||||
if (!timestamps || !types) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.timestamps = timestamps;
|
||||
this.types = types;
|
||||
|
||||
// to avoid rounding error resulting in width more than 100%
|
||||
duration = Math.floor(duration * 100) / 100;
|
||||
let width;
|
||||
for (let i = 0; i < timestamps.length; i++) {
|
||||
if (types[i] == null) continue;
|
||||
|
||||
width = (timestamps[i][1] - timestamps[i][0]) / duration * 100;
|
||||
width = Math.floor(width * 100) / 100;
|
||||
|
||||
let bar = this.createBar();
|
||||
bar.setAttribute('data-vs-segment-type', types[i]);
|
||||
|
||||
bar.style.backgroundColor = Config.config.barTypes[types[i]].color;
|
||||
if (!this.onMobileYouTube) bar.style.opacity = Config.config.barTypes[types[i]].opacity;
|
||||
bar.style.width = width + '%';
|
||||
bar.style.left = (timestamps[i][0] / duration * 100) + "%";
|
||||
bar.style.position = "absolute"
|
||||
|
||||
this.container.insertAdjacentElement("beforeend", bar);
|
||||
}
|
||||
}
|
||||
|
||||
createBar() {
|
||||
let bar = document.createElement('li');
|
||||
bar.classList.add('previewbar');
|
||||
bar.innerHTML = ' ';
|
||||
return bar;
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.container.remove();
|
||||
this.container = undefined;
|
||||
}
|
||||
export interface PreviewBarSegment {
|
||||
segment: [number, number];
|
||||
category: string;
|
||||
preview: boolean;
|
||||
}
|
||||
|
||||
export default PreviewBar;
|
||||
class PreviewBar {
|
||||
container: HTMLUListElement;
|
||||
categoryTooltip?: HTMLDivElement;
|
||||
tooltipContainer?: HTMLElement;
|
||||
|
||||
parent: HTMLElement;
|
||||
onMobileYouTube: boolean;
|
||||
onInvidious: boolean;
|
||||
|
||||
segments: PreviewBarSegment[] = [];
|
||||
videoDuration = 0;
|
||||
|
||||
constructor(parent: HTMLElement, onMobileYouTube: boolean, onInvidious: boolean) {
|
||||
this.container = document.createElement('ul');
|
||||
this.container.id = 'previewbar';
|
||||
|
||||
this.parent = parent;
|
||||
this.onMobileYouTube = onMobileYouTube;
|
||||
this.onInvidious = onInvidious;
|
||||
|
||||
this.updatePosition(parent);
|
||||
|
||||
this.setupHoverText();
|
||||
}
|
||||
|
||||
setupHoverText(): void {
|
||||
if (this.onMobileYouTube || this.onInvidious) return;
|
||||
|
||||
// Create label placeholder
|
||||
this.categoryTooltip = document.createElement("div");
|
||||
this.categoryTooltip.className = "ytp-tooltip-title sponsorCategoryTooltip";
|
||||
|
||||
const tooltipTextWrapper = document.querySelector(".ytp-tooltip-text-wrapper");
|
||||
if (!tooltipTextWrapper || !tooltipTextWrapper.parentElement) return;
|
||||
|
||||
// Grab the tooltip from the text wrapper as the tooltip doesn't have its classes on init
|
||||
this.tooltipContainer = tooltipTextWrapper.parentElement;
|
||||
const titleTooltip = tooltipTextWrapper.querySelector(".ytp-tooltip-title");
|
||||
if (!this.tooltipContainer || !titleTooltip) return;
|
||||
|
||||
tooltipTextWrapper.insertBefore(this.categoryTooltip, titleTooltip.nextSibling);
|
||||
|
||||
const seekBar = document.querySelector(".ytp-progress-bar-container");
|
||||
if (!seekBar) return;
|
||||
|
||||
let mouseOnSeekBar = false;
|
||||
|
||||
seekBar.addEventListener("mouseenter", () => {
|
||||
mouseOnSeekBar = true;
|
||||
});
|
||||
|
||||
seekBar.addEventListener("mouseleave", () => {
|
||||
mouseOnSeekBar = false;
|
||||
});
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
if (!mouseOnSeekBar || !this.categoryTooltip || !this.tooltipContainer) return;
|
||||
|
||||
// If the mutation observed is only for our tooltip text, ignore
|
||||
if (mutations.length === 1 && (mutations[0].target as HTMLElement).classList.contains("sponsorCategoryTooltip")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tooltipTextElements = tooltipTextWrapper.querySelectorAll(".ytp-tooltip-text");
|
||||
let timeInSeconds: number | null = null;
|
||||
let noYoutubeChapters = false;
|
||||
|
||||
for (const tooltipTextElement of tooltipTextElements) {
|
||||
if (tooltipTextElement.classList.contains('ytp-tooltip-text-no-title')) noYoutubeChapters = true;
|
||||
|
||||
const tooltipText = tooltipTextElement.textContent;
|
||||
if (tooltipText === null || tooltipText.length === 0) continue;
|
||||
|
||||
timeInSeconds = utils.getFormattedTimeToSeconds(tooltipText);
|
||||
|
||||
if (timeInSeconds !== null) break;
|
||||
}
|
||||
|
||||
if (timeInSeconds === null) return;
|
||||
|
||||
// Find the segment at that location, using the shortest if multiple found
|
||||
let segment: PreviewBarSegment | null = null;
|
||||
let currentSegmentLength = Infinity;
|
||||
|
||||
for (const seg of this.segments) {
|
||||
if (seg.segment[0] <= timeInSeconds && seg.segment[1] > timeInSeconds) {
|
||||
const segmentLength = seg.segment[1] - seg.segment[0];
|
||||
|
||||
if (segmentLength < currentSegmentLength) {
|
||||
currentSegmentLength = segmentLength;
|
||||
segment = seg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (segment === null && this.tooltipContainer.classList.contains(TOOLTIP_VISIBLE_CLASS)) {
|
||||
this.tooltipContainer.classList.remove(TOOLTIP_VISIBLE_CLASS);
|
||||
} else if (segment !== null) {
|
||||
this.tooltipContainer.classList.add(TOOLTIP_VISIBLE_CLASS);
|
||||
|
||||
if (segment.preview) {
|
||||
this.categoryTooltip.textContent = chrome.i18n.getMessage("preview") + " " + utils.shortCategoryName(segment.category);
|
||||
} else {
|
||||
this.categoryTooltip.textContent = utils.shortCategoryName(segment.category);
|
||||
}
|
||||
|
||||
// Use the class if the timestamp text uses it to prevent overlapping
|
||||
this.categoryTooltip.classList.toggle("ytp-tooltip-text-no-title", noYoutubeChapters);
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(tooltipTextWrapper, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
|
||||
updatePosition(parent: HTMLElement): void {
|
||||
this.parent = parent;
|
||||
|
||||
if (this.onMobileYouTube) {
|
||||
parent.style.backgroundColor = "rgba(255, 255, 255, 0.3)";
|
||||
parent.style.opacity = "1";
|
||||
|
||||
this.container.style.transform = "none";
|
||||
}
|
||||
|
||||
// On the seek bar
|
||||
this.parent.prepend(this.container);
|
||||
}
|
||||
|
||||
// TODO: call on config changes
|
||||
updateColor(segmentType: string, color: string, opacity: number): void {
|
||||
const bars = <NodeListOf<HTMLElement>> document.querySelectorAll('[data-vs-segment-type=' + segmentType + ']');
|
||||
|
||||
for (const bar of bars) {
|
||||
bar.style.backgroundColor = color;
|
||||
bar.style.opacity = String(opacity);
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.videoDuration = 0;
|
||||
this.segments = [];
|
||||
|
||||
while (this.container.firstChild) {
|
||||
this.container.removeChild(this.container.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
set(segments: PreviewBarSegment[], videoDuration: number): void {
|
||||
this.clear();
|
||||
|
||||
if (!segments) return;
|
||||
|
||||
this.segments = segments;
|
||||
this.videoDuration = videoDuration;
|
||||
|
||||
this.segments.sort(({segment: a}, {segment: b}) => {
|
||||
// Sort longer segments before short segments to make shorter segments render later
|
||||
return (b[1] - b[0]) - (a[1] - a[0]);
|
||||
}).forEach((segment) => {
|
||||
const bar = this.createBar(segment);
|
||||
|
||||
this.container.appendChild(bar);
|
||||
});
|
||||
}
|
||||
|
||||
createBar({category, preview, segment}: PreviewBarSegment): HTMLLIElement {
|
||||
const bar = document.createElement('li');
|
||||
bar.classList.add('previewbar');
|
||||
bar.innerHTML = ' ';
|
||||
|
||||
const barSegmentType = (preview ? 'preview-' : '') + category;
|
||||
|
||||
bar.setAttribute('data-vs-segment-type', barSegmentType);
|
||||
|
||||
bar.style.backgroundColor = Config.config.barTypes[barSegmentType].color;
|
||||
if (!this.onMobileYouTube) bar.style.opacity = Config.config.barTypes[barSegmentType].opacity;
|
||||
|
||||
bar.style.position = "absolute";
|
||||
bar.style.width = this.timeToPercentage(segment[1] - segment[0]);
|
||||
bar.style.left = this.timeToPercentage(segment[0]);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
remove(): void {
|
||||
this.container.remove();
|
||||
|
||||
if (this.categoryTooltip) {
|
||||
this.categoryTooltip.remove();
|
||||
this.categoryTooltip = undefined;
|
||||
}
|
||||
|
||||
if (this.tooltipContainer) {
|
||||
this.tooltipContainer.classList.remove(TOOLTIP_VISIBLE_CLASS);
|
||||
this.tooltipContainer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
timeToPercentage(time: number): string {
|
||||
return Math.min(100, time / this.videoDuration * 100) + '%';
|
||||
}
|
||||
}
|
||||
|
||||
export default PreviewBar;
|
||||
|
||||
63
src/messageTypes.ts
Normal file
63
src/messageTypes.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Message and Response Types
|
||||
//
|
||||
|
||||
import { SponsorTime } from "./types";
|
||||
|
||||
interface BaseMessage {
|
||||
from?: string;
|
||||
}
|
||||
|
||||
interface DefaultMessage {
|
||||
message:
|
||||
"update"
|
||||
| "sponsorStart"
|
||||
| "sponsorDataChanged"
|
||||
| "isInfoFound"
|
||||
| "getVideoID"
|
||||
| "getChannelID"
|
||||
| "isChannelWhitelisted"
|
||||
| "submitTimes";
|
||||
}
|
||||
|
||||
interface BoolValueMessage {
|
||||
message: "whitelistChange";
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
interface ChangeStartSponsorButtonMessage {
|
||||
message: "changeStartSponsorButton";
|
||||
showStartSponsor: boolean;
|
||||
uploadButtonVisible: boolean;
|
||||
}
|
||||
|
||||
export type Message = BaseMessage & (DefaultMessage | BoolValueMessage | ChangeStartSponsorButtonMessage);
|
||||
|
||||
interface IsInfoFoundMessageResponse {
|
||||
found: boolean;
|
||||
sponsorTimes: SponsorTime[];
|
||||
}
|
||||
|
||||
interface GetVideoIdResponse {
|
||||
videoID: string;
|
||||
}
|
||||
|
||||
interface GetChannelIDResponse {
|
||||
channelID: string;
|
||||
}
|
||||
|
||||
interface SponsorStartResponse {
|
||||
time: number;
|
||||
}
|
||||
|
||||
interface IsChannelWhitelistedResponse {
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export type MessageResponse =
|
||||
IsInfoFoundMessageResponse
|
||||
| GetVideoIdResponse
|
||||
| GetChannelIDResponse
|
||||
| SponsorStartResponse
|
||||
| IsChannelWhitelistedResponse;
|
||||
|
||||
146
src/options.ts
146
src/options.ts
@@ -2,11 +2,11 @@ import Config from "./config";
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
// Make the config public for debugging purposes
|
||||
(<any> window).SB = Config;
|
||||
window.SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
import CategoryChooser from "./render/CategoryChooser";
|
||||
var utils = new Utils();
|
||||
const utils = new Utils();
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
@@ -27,19 +27,19 @@ async function init() {
|
||||
await utils.wait(() => Config.config !== null);
|
||||
|
||||
// Set all of the toggle options to the correct option
|
||||
let optionsContainer = document.getElementById("options");
|
||||
let optionsElements = optionsContainer.querySelectorAll("*");
|
||||
const optionsContainer = document.getElementById("options");
|
||||
const optionsElements = optionsContainer.querySelectorAll("*");
|
||||
|
||||
for (let i = 0; i < optionsElements.length; i++) {
|
||||
switch (optionsElements[i].getAttribute("option-type")) {
|
||||
case "toggle":
|
||||
let option = optionsElements[i].getAttribute("sync-option");
|
||||
let optionResult = Config.config[option];
|
||||
case "toggle": {
|
||||
const option = optionsElements[i].getAttribute("sync-option");
|
||||
const optionResult = Config.config[option];
|
||||
|
||||
let checkbox = optionsElements[i].querySelector("input");
|
||||
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
||||
const checkbox = optionsElements[i].querySelector("input");
|
||||
const reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
||||
|
||||
let confirmMessage = optionsElements[i].getAttribute("confirm-message");
|
||||
const confirmMessage = optionsElements[i].getAttribute("confirm-message");
|
||||
|
||||
if (optionResult != undefined) {
|
||||
checkbox.checked = optionResult;
|
||||
@@ -76,7 +76,7 @@ async function init() {
|
||||
// Enable the notice
|
||||
Config.config["dontShowNotice"] = false;
|
||||
|
||||
let showNoticeSwitch = <HTMLInputElement> document.querySelector("[sync-option='dontShowNotice'] > label > label > input");
|
||||
const showNoticeSwitch = <HTMLInputElement> document.querySelector("[sync-option='dontShowNotice'] > label > label > input");
|
||||
showNoticeSwitch.checked = true;
|
||||
}
|
||||
|
||||
@@ -84,19 +84,20 @@ async function init() {
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "text-change":
|
||||
let textChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
let textChangeInput = <HTMLInputElement> optionsElements[i].querySelector(".option-text-box");
|
||||
}
|
||||
case "text-change": {
|
||||
const textChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
const textChangeInput = <HTMLInputElement> optionsElements[i].querySelector(".option-text-box");
|
||||
|
||||
let textChangeSetButton = <HTMLElement> optionsElements[i].querySelector(".text-change-set");
|
||||
const textChangeSetButton = <HTMLElement> optionsElements[i].querySelector(".text-change-set");
|
||||
|
||||
textChangeInput.value = Config.config[textChangeOption];
|
||||
|
||||
textChangeSetButton.addEventListener("click", async () => {
|
||||
// See if anything extra must be done
|
||||
switch (textChangeOption) {
|
||||
case "serverAddress":
|
||||
let result = validateServerAddress(textChangeInput.value);
|
||||
case "serverAddress": {
|
||||
const result = validateServerAddress(textChangeInput.value);
|
||||
|
||||
if (result !== null) {
|
||||
textChangeInput.value = result;
|
||||
@@ -106,7 +107,7 @@ async function init() {
|
||||
|
||||
// Permission needed on Firefox
|
||||
if (utils.isFirefox()) {
|
||||
let permissionSuccess = await new Promise((resolve, reject) => {
|
||||
const permissionSuccess = await new Promise((resolve) => {
|
||||
chrome.permissions.request({
|
||||
origins: [textChangeInput.value + "/"],
|
||||
permissions: []
|
||||
@@ -117,13 +118,14 @@ async function init() {
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Config.config[textChangeOption] = textChangeInput.value;
|
||||
});
|
||||
|
||||
// Reset to the default if needed
|
||||
let textChangeResetButton = <HTMLElement> optionsElements[i].querySelector(".text-change-reset");
|
||||
const textChangeResetButton = <HTMLElement> optionsElements[i].querySelector(".text-change-reset");
|
||||
textChangeResetButton.addEventListener("click", () => {
|
||||
if (!confirm(chrome.i18n.getMessage("areYouSureReset"))) return;
|
||||
|
||||
@@ -133,11 +135,12 @@ async function init() {
|
||||
});
|
||||
|
||||
break;
|
||||
case "private-text-change":
|
||||
let button = optionsElements[i].querySelector(".trigger-button");
|
||||
}
|
||||
case "private-text-change": {
|
||||
const button = optionsElements[i].querySelector(".trigger-button");
|
||||
button.addEventListener("click", () => activatePrivateTextChange(<HTMLElement> optionsElements[i]));
|
||||
|
||||
let privateTextChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
const privateTextChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
// See if anything extra must be done
|
||||
switch (privateTextChangeOption) {
|
||||
case "invidiousInstances":
|
||||
@@ -145,8 +148,9 @@ async function init() {
|
||||
}
|
||||
|
||||
break;
|
||||
case "button-press":
|
||||
let actionButton = optionsElements[i].querySelector(".trigger-button");
|
||||
}
|
||||
case "button-press": {
|
||||
const actionButton = optionsElements[i].querySelector(".trigger-button");
|
||||
|
||||
switch(optionsElements[i].getAttribute("sync-option")) {
|
||||
case "copyDebugInformation":
|
||||
@@ -155,19 +159,21 @@ async function init() {
|
||||
}
|
||||
|
||||
break;
|
||||
case "keybind-change":
|
||||
let keybindButton = optionsElements[i].querySelector(".trigger-button");
|
||||
}
|
||||
case "keybind-change": {
|
||||
const keybindButton = optionsElements[i].querySelector(".trigger-button");
|
||||
keybindButton.addEventListener("click", () => activateKeybindChange(<HTMLElement> optionsElements[i]));
|
||||
|
||||
break;
|
||||
case "display":
|
||||
}
|
||||
case "display":{
|
||||
updateDisplayElement(<HTMLElement> optionsElements[i])
|
||||
|
||||
break;
|
||||
case "number-change":
|
||||
let numberChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
let configValue = Config.config[numberChangeOption];
|
||||
let numberInput = optionsElements[i].querySelector("input");
|
||||
}
|
||||
case "number-change": {
|
||||
const numberChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
const configValue = Config.config[numberChangeOption];
|
||||
const numberInput = optionsElements[i].querySelector("input");
|
||||
|
||||
if (isNaN(configValue) || configValue < 0) {
|
||||
numberInput.value = Config.defaults[numberChangeOption];
|
||||
@@ -180,6 +186,7 @@ async function init() {
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
case "react-CategoryChooserComponent":
|
||||
new CategoryChooser(optionsElements[i]);
|
||||
break;
|
||||
@@ -195,9 +202,9 @@ async function init() {
|
||||
*
|
||||
* @param {String} element
|
||||
*/
|
||||
function optionsConfigUpdateListener(changes) {
|
||||
let optionsContainer = document.getElementById("options");
|
||||
let optionsElements = optionsContainer.querySelectorAll("*");
|
||||
function optionsConfigUpdateListener() {
|
||||
const optionsContainer = document.getElementById("options");
|
||||
const optionsElements = optionsContainer.querySelectorAll("*");
|
||||
|
||||
for (let i = 0; i < optionsElements.length; i++) {
|
||||
switch (optionsElements[i].getAttribute("option-type")) {
|
||||
@@ -213,8 +220,8 @@ function optionsConfigUpdateListener(changes) {
|
||||
* @param element
|
||||
*/
|
||||
function updateDisplayElement(element: HTMLElement) {
|
||||
let displayOption = element.getAttribute("sync-option")
|
||||
let displayText = Config.config[displayOption];
|
||||
const displayOption = element.getAttribute("sync-option")
|
||||
const displayText = Config.config[displayOption];
|
||||
element.innerText = displayText;
|
||||
|
||||
// See if anything extra must be run
|
||||
@@ -232,11 +239,11 @@ function updateDisplayElement(element: HTMLElement) {
|
||||
* @param option
|
||||
*/
|
||||
function invidiousInstanceAddInit(element: HTMLElement, option: string) {
|
||||
let textBox = <HTMLInputElement> element.querySelector(".option-text-box");
|
||||
let button = element.querySelector(".trigger-button");
|
||||
const textBox = <HTMLInputElement> element.querySelector(".option-text-box");
|
||||
const button = element.querySelector(".trigger-button");
|
||||
|
||||
let setButton = element.querySelector(".text-change-set");
|
||||
setButton.addEventListener("click", async function(e) {
|
||||
const setButton = element.querySelector(".text-change-set");
|
||||
setButton.addEventListener("click", async function() {
|
||||
if (textBox.value == "" || textBox.value.includes("/") || textBox.value.includes("http")) {
|
||||
alert(chrome.i18n.getMessage("addInvidiousInstanceError"));
|
||||
} else {
|
||||
@@ -248,7 +255,7 @@ function invidiousInstanceAddInit(element: HTMLElement, option: string) {
|
||||
|
||||
Config.config[option] = instanceList;
|
||||
|
||||
let checkbox = <HTMLInputElement> document.querySelector("#support-invidious input");
|
||||
const checkbox = <HTMLInputElement> document.querySelector("#support-invidious input");
|
||||
checkbox.checked = true;
|
||||
|
||||
invidiousOnClick(checkbox, "supportInvidious");
|
||||
@@ -261,8 +268,8 @@ function invidiousInstanceAddInit(element: HTMLElement, option: string) {
|
||||
}
|
||||
});
|
||||
|
||||
let resetButton = element.querySelector(".invidious-instance-reset");
|
||||
resetButton.addEventListener("click", function(e) {
|
||||
const resetButton = element.querySelector(".invidious-instance-reset");
|
||||
resetButton.addEventListener("click", function() {
|
||||
if (confirm(chrome.i18n.getMessage("resetInvidiousInstanceAlert"))) {
|
||||
// Set to a clone of the default
|
||||
Config.config[option] = Config.defaults[option].slice(0);
|
||||
@@ -298,7 +305,7 @@ function invidiousInit(checkbox: HTMLInputElement, option: string) {
|
||||
* @param checkbox
|
||||
* @param option
|
||||
*/
|
||||
async function invidiousOnClick(checkbox: HTMLInputElement, option: string) {
|
||||
async function invidiousOnClick(checkbox: HTMLInputElement, option: string): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (checkbox.checked) {
|
||||
utils.setupExtraSitePermissions(function (granted) {
|
||||
@@ -323,20 +330,20 @@ async function invidiousOnClick(checkbox: HTMLInputElement, option: string) {
|
||||
* @param element
|
||||
*/
|
||||
function activateKeybindChange(element: HTMLElement) {
|
||||
let button = element.querySelector(".trigger-button");
|
||||
const button = element.querySelector(".trigger-button");
|
||||
if (button.classList.contains("disabled")) return;
|
||||
|
||||
button.classList.add("disabled");
|
||||
|
||||
let option = element.getAttribute("sync-option");
|
||||
const option = element.getAttribute("sync-option");
|
||||
|
||||
let currentlySet = Config.config[option] !== null ? chrome.i18n.getMessage("keybindCurrentlySet") : "";
|
||||
const currentlySet = Config.config[option] !== null ? chrome.i18n.getMessage("keybindCurrentlySet") : "";
|
||||
|
||||
let status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
const status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
status.innerText = chrome.i18n.getMessage("keybindDescription") + currentlySet;
|
||||
|
||||
if (Config.config[option] !== null) {
|
||||
let statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
const statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
statusKey.innerText = Config.config[option];
|
||||
}
|
||||
|
||||
@@ -352,19 +359,19 @@ function activateKeybindChange(element: HTMLElement) {
|
||||
* @param e
|
||||
*/
|
||||
function keybindKeyPressed(element: HTMLElement, e: KeyboardEvent) {
|
||||
var key = e.key;
|
||||
const key = e.key;
|
||||
|
||||
if (["Shift", "Control", "Meta", "Alt", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Tab"].indexOf(key) !== -1) {
|
||||
|
||||
// Wait for more
|
||||
document.addEventListener("keydown", (e) => keybindKeyPressed(element, e), {once: true});
|
||||
} else {
|
||||
let button: HTMLElement = element.querySelector(".trigger-button");
|
||||
let option = element.getAttribute("sync-option");
|
||||
const button: HTMLElement = element.querySelector(".trigger-button");
|
||||
const option = element.getAttribute("sync-option");
|
||||
|
||||
// Make sure keybind isn't used by the other listener
|
||||
// TODO: If other keybindings are going to be added, we need a better way to find the other keys used.
|
||||
let otherKeybind = (option === "startSponsorKeybind") ? Config.config['submitKeybind'] : Config.config['startSponsorKeybind'];
|
||||
const otherKeybind = (option === "startSponsorKeybind") ? Config.config['submitKeybind'] : Config.config['startSponsorKeybind'];
|
||||
if (key === otherKeybind) {
|
||||
closeKeybindOption(element, button);
|
||||
|
||||
@@ -381,10 +388,10 @@ function keybindKeyPressed(element: HTMLElement, e: KeyboardEvent) {
|
||||
|
||||
Config.config[option] = key;
|
||||
|
||||
let status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
const status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
status.innerText = chrome.i18n.getMessage("keybindDescriptionComplete");
|
||||
|
||||
let statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
const statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
statusKey.innerText = key;
|
||||
|
||||
button.classList.remove("disabled");
|
||||
@@ -408,13 +415,13 @@ function closeKeybindOption(element: HTMLElement, button: HTMLElement) {
|
||||
* @param element
|
||||
*/
|
||||
function activatePrivateTextChange(element: HTMLElement) {
|
||||
let button = element.querySelector(".trigger-button");
|
||||
const button = element.querySelector(".trigger-button");
|
||||
if (button.classList.contains("disabled")) return;
|
||||
|
||||
button.classList.add("disabled");
|
||||
|
||||
let textBox = <HTMLInputElement> element.querySelector(".option-text-box");
|
||||
let option = element.getAttribute("sync-option");
|
||||
const textBox = <HTMLInputElement> element.querySelector(".option-text-box");
|
||||
const option = element.getAttribute("sync-option");
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
@@ -427,21 +434,22 @@ function activatePrivateTextChange(element: HTMLElement) {
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
case "*":
|
||||
let jsonData = JSON.parse(JSON.stringify(Config.localConfig));
|
||||
case "*": {
|
||||
const jsonData = JSON.parse(JSON.stringify(Config.localConfig));
|
||||
|
||||
// Fix segmentTimes data as it is destroyed from the JSON stringify
|
||||
jsonData.segmentTimes = Config.encodeStoredItem(Config.localConfig.segmentTimes);
|
||||
|
||||
result = JSON.stringify(jsonData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
textBox.value = result;
|
||||
|
||||
let setButton = element.querySelector(".text-change-set");
|
||||
const setButton = element.querySelector(".text-change-set");
|
||||
setButton.addEventListener("click", async () => {
|
||||
let confirmMessage = element.getAttribute("confirm-message");
|
||||
const confirmMessage = element.getAttribute("confirm-message");
|
||||
|
||||
if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) {
|
||||
|
||||
@@ -449,14 +457,14 @@ function activatePrivateTextChange(element: HTMLElement) {
|
||||
switch (option) {
|
||||
case "*":
|
||||
try {
|
||||
let newConfig = JSON.parse(textBox.value);
|
||||
const newConfig = JSON.parse(textBox.value);
|
||||
for (const key in newConfig) {
|
||||
Config.config[key] = newConfig[key];
|
||||
}
|
||||
Config.convertJSON();
|
||||
|
||||
if (newConfig.supportInvidious) {
|
||||
let checkbox = <HTMLInputElement> document.querySelector("#support-invidious > label > label > input");
|
||||
const checkbox = <HTMLInputElement> document.querySelector("#support-invidious > label > label > input");
|
||||
|
||||
checkbox.checked = true;
|
||||
await invidiousOnClick(checkbox, "supportInvidious");
|
||||
@@ -503,7 +511,7 @@ function validateServerAddress(input: string): string {
|
||||
|
||||
function copyDebugOutputToClipboard() {
|
||||
// Build output debug information object
|
||||
let output = {
|
||||
const output = {
|
||||
debug: {
|
||||
userAgent: navigator.userAgent,
|
||||
platform: navigator.platform,
|
||||
@@ -528,7 +536,7 @@ function copyDebugOutputToClipboard() {
|
||||
.then(() => {
|
||||
alert(chrome.i18n.getMessage("copyDebugInformationComplete"));
|
||||
})
|
||||
.catch(err => {
|
||||
.catch(() => {
|
||||
alert(chrome.i18n.getMessage("copyDebugInformationFailed"));
|
||||
});;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
782
src/popup.ts
782
src/popup.ts
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ class SkipNotice {
|
||||
|
||||
skipNoticeRef: React.MutableRefObject<SkipNoticeComponent>;
|
||||
|
||||
constructor(segments: SponsorTime[], autoSkip: boolean = false, contentContainer: ContentContainer) {
|
||||
constructor(segments: SponsorTime[], autoSkip = false, contentContainer: ContentContainer) {
|
||||
this.segments = segments;
|
||||
this.autoSkip = autoSkip;
|
||||
this.contentContainer = contentContainer;
|
||||
@@ -24,7 +24,7 @@ class SkipNotice {
|
||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||
if (referenceNode == null) {
|
||||
//for embeds
|
||||
let player = document.getElementById("player");
|
||||
const player = document.getElementById("player");
|
||||
referenceNode = player.firstChild as HTMLElement;
|
||||
let index = 1;
|
||||
|
||||
@@ -40,7 +40,7 @@ class SkipNotice {
|
||||
referenceNode = document.querySelector("#main-panel.ytmusic-player-page");
|
||||
}
|
||||
|
||||
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
const amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
//this is the suffix added at the end of every id
|
||||
let idSuffix = "";
|
||||
for (const segment of this.segments) {
|
||||
@@ -63,7 +63,7 @@ class SkipNotice {
|
||||
);
|
||||
}
|
||||
|
||||
close() {
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
|
||||
this.noticeElement.remove();
|
||||
|
||||
@@ -2,18 +2,19 @@ import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import SubmissionNoticeComponent from "../components/SubmissionNoticeComponent";
|
||||
import { ContentContainer } from "../types";
|
||||
|
||||
class SubmissionNotice {
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: () => any;
|
||||
contentContainer: () => unknown;
|
||||
|
||||
callback: () => any;
|
||||
callback: () => unknown;
|
||||
|
||||
noticeRef: React.MutableRefObject<SubmissionNoticeComponent>;
|
||||
|
||||
noticeElement: HTMLDivElement;
|
||||
|
||||
constructor(contentContainer: () => any, callback: () => any) {
|
||||
constructor(contentContainer: ContentContainer, callback: () => unknown) {
|
||||
this.noticeRef = React.createRef();
|
||||
|
||||
this.contentContainer = contentContainer;
|
||||
@@ -24,7 +25,7 @@ class SubmissionNotice {
|
||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||
if (referenceNode == null) {
|
||||
//for embeds
|
||||
let player = document.getElementById("player");
|
||||
const player = document.getElementById("player");
|
||||
referenceNode = player.firstChild as HTMLElement;
|
||||
let index = 1;
|
||||
|
||||
@@ -51,11 +52,11 @@ class SubmissionNotice {
|
||||
);
|
||||
}
|
||||
|
||||
update() {
|
||||
update(): void {
|
||||
this.noticeRef.current.forceUpdate();
|
||||
}
|
||||
|
||||
close() {
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
|
||||
this.noticeElement.remove();
|
||||
|
||||
107
src/types.ts
107
src/types.ts
@@ -3,7 +3,7 @@ import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
|
||||
interface ContentContainer {
|
||||
(): {
|
||||
vote: (type: any, UUID: any, category?: string, skipNotice?: SkipNoticeComponent) => void,
|
||||
vote: (type: number, UUID: string, category?: string, skipNotice?: SkipNoticeComponent) => void,
|
||||
dontShowNoticeAgain: () => void,
|
||||
unskipSponsorTime: (segment: SponsorTime) => void,
|
||||
sponsorTimes: SponsorTime[],
|
||||
@@ -15,9 +15,9 @@ interface ContentContainer {
|
||||
onMobileYouTube: boolean,
|
||||
sponsorSubmissionNotice: SubmissionNotice,
|
||||
resetSponsorSubmissionNotice: () => void,
|
||||
changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise<boolean>,
|
||||
changeStartSponsorButton: (showStartSponsor: boolean, uploadButtonVisible: boolean) => Promise<boolean>,
|
||||
previewTime: (time: number, unpause?: boolean) => void,
|
||||
videoInfo: any,
|
||||
videoInfo: VideoInfo,
|
||||
getRealCurrentTime: () => number
|
||||
}
|
||||
}
|
||||
@@ -63,8 +63,101 @@ interface PreviewBarOption {
|
||||
opacity: string
|
||||
}
|
||||
|
||||
|
||||
interface Registration {
|
||||
message: string,
|
||||
id: string,
|
||||
allFrames: boolean,
|
||||
js: browser.extensionTypes.ExtensionFileOrCode[],
|
||||
css: browser.extensionTypes.ExtensionFileOrCode[],
|
||||
matches: string[]
|
||||
}
|
||||
|
||||
interface BackgroundScriptContainer {
|
||||
registerFirefoxContentScript: (opts: Registration) => void,
|
||||
unregisterFirefoxContentScript: (id: string) => void
|
||||
}
|
||||
|
||||
interface VideoInfo {
|
||||
responseContext: {
|
||||
serviceTrackingParams: Array<{service: string, params: Array<{key: string, value: string}>}>,
|
||||
webResponseContextExtensionData: {
|
||||
hasDecorated: boolean
|
||||
}
|
||||
},
|
||||
playabilityStatus: {
|
||||
status: string,
|
||||
playableInEmbed: boolean,
|
||||
miniplayer: {
|
||||
miniplayerRenderer: {
|
||||
playbackMode: string
|
||||
}
|
||||
}
|
||||
};
|
||||
streamingData: unknown;
|
||||
playbackTracking: unknown;
|
||||
videoDetails: {
|
||||
videoId: string,
|
||||
title: string,
|
||||
lengthSeconds: string,
|
||||
keywords: string[],
|
||||
channelId: string,
|
||||
isOwnerViewing: boolean,
|
||||
shortDescription: string,
|
||||
isCrawlable: boolean,
|
||||
thumbnail: {
|
||||
thumbnails: Array<{url: string, width: number, height: number}>
|
||||
},
|
||||
averageRating: number,
|
||||
allowRatings: boolean,
|
||||
viewCount: string,
|
||||
author: string,
|
||||
isPrivate: boolean,
|
||||
isUnpluggedCorpus: boolean,
|
||||
isLiveContent: boolean,
|
||||
};
|
||||
playerConfig: unknown;
|
||||
storyboards: unknown;
|
||||
microformat: {
|
||||
playerMicroformatRenderer: {
|
||||
thumbnail: {
|
||||
thumbnails: Array<{url: string, width: number, height: number}>
|
||||
},
|
||||
embed: {
|
||||
iframeUrl: string,
|
||||
flashUrl: string,
|
||||
width: number,
|
||||
height: number,
|
||||
flashSecureUrl: string,
|
||||
},
|
||||
title: {
|
||||
simpleText: string,
|
||||
},
|
||||
description: {
|
||||
simpleText: string,
|
||||
},
|
||||
lengthSeconds: string,
|
||||
ownerProfileUrl: string,
|
||||
externalChannelId: string,
|
||||
availableCountries: string[],
|
||||
isUnlisted: boolean,
|
||||
hasYpcMetadata: boolean,
|
||||
viewCount: string,
|
||||
category: string,
|
||||
publishDate: string,
|
||||
ownerChannelName: string,
|
||||
uploadDate: string,
|
||||
}
|
||||
};
|
||||
trackingParams: string;
|
||||
attestation: unknown;
|
||||
messages: unknown;
|
||||
}
|
||||
|
||||
type VideoID = string;
|
||||
|
||||
type StorageChangesObject = { [key: string]: chrome.storage.StorageChange };
|
||||
|
||||
export {
|
||||
FetchResponse,
|
||||
VideoDurationResponse,
|
||||
@@ -74,5 +167,9 @@ export {
|
||||
SponsorTime,
|
||||
VideoID,
|
||||
SponsorHideType,
|
||||
PreviewBarOption
|
||||
};
|
||||
PreviewBarOption,
|
||||
Registration,
|
||||
BackgroundScriptContainer,
|
||||
VideoInfo,
|
||||
StorageChangesObject,
|
||||
};
|
||||
|
||||
153
src/utils.ts
153
src/utils.ts
@@ -1,12 +1,12 @@
|
||||
import Config from "./config";
|
||||
import { CategorySelection, SponsorTime, FetchResponse } from "./types";
|
||||
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration } from "./types";
|
||||
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
class Utils {
|
||||
|
||||
// Contains functions needed from the background script
|
||||
backgroundScriptContainer: any = null;
|
||||
backgroundScriptContainer: BackgroundScriptContainer | null = null;
|
||||
|
||||
// Used to add content scripts and CSS required
|
||||
js = [
|
||||
@@ -19,24 +19,24 @@ class Utils {
|
||||
"popup.css"
|
||||
];
|
||||
|
||||
constructor(backgroundScriptContainer?: any) {
|
||||
constructor(backgroundScriptContainer?: BackgroundScriptContainer) {
|
||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||
}
|
||||
|
||||
// Function that can be used to wait for a condition before returning
|
||||
async wait(condition, timeout = 5000, check = 100) {
|
||||
async wait(condition: () => HTMLElement | boolean, timeout = 5000, check = 100): Promise<HTMLElement | boolean> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
setTimeout(() => reject("TIMEOUT"), timeout);
|
||||
|
||||
let intervalCheck = () => {
|
||||
let result = condition();
|
||||
const intervalCheck = () => {
|
||||
const result = condition();
|
||||
if (result !== false) {
|
||||
resolve(result);
|
||||
clearInterval(interval);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let interval = setInterval(intervalCheck, check);
|
||||
const interval = setInterval(intervalCheck, check);
|
||||
|
||||
//run the check once first, this speeds it up a lot
|
||||
intervalCheck();
|
||||
@@ -51,21 +51,19 @@ class Utils {
|
||||
*
|
||||
* @param {CallableFunction} callback
|
||||
*/
|
||||
setupExtraSitePermissions(callback) {
|
||||
setupExtraSitePermissions(callback: (granted: boolean) => void): void {
|
||||
// Request permission
|
||||
let permissions = ["declarativeContent"];
|
||||
if (this.isFirefox()) permissions = [];
|
||||
|
||||
let self = this;
|
||||
if (this.isFirefox()) permissions = [];
|
||||
|
||||
chrome.permissions.request({
|
||||
origins: this.getInvidiousInstancesRegex(),
|
||||
permissions: permissions
|
||||
}, async function (granted) {
|
||||
}, async (granted) => {
|
||||
if (granted) {
|
||||
self.setupExtraSiteContentScripts();
|
||||
this.setupExtraSiteContentScripts();
|
||||
} else {
|
||||
self.removeExtraSiteRegistration();
|
||||
this.removeExtraSiteRegistration();
|
||||
}
|
||||
|
||||
callback(granted);
|
||||
@@ -79,20 +77,19 @@ class Utils {
|
||||
*
|
||||
* For now, it is just SB.config.invidiousInstances.
|
||||
*/
|
||||
setupExtraSiteContentScripts() {
|
||||
let self = this;
|
||||
setupExtraSiteContentScripts(): void {
|
||||
|
||||
if (this.isFirefox()) {
|
||||
let firefoxJS = [];
|
||||
const firefoxJS = [];
|
||||
for (const file of this.js) {
|
||||
firefoxJS.push({file});
|
||||
}
|
||||
let firefoxCSS = [];
|
||||
const firefoxCSS = [];
|
||||
for (const file of this.css) {
|
||||
firefoxCSS.push({file});
|
||||
}
|
||||
|
||||
let registration = {
|
||||
const registration: Registration = {
|
||||
message: "registerContentScript",
|
||||
id: "invidious",
|
||||
allFrames: true,
|
||||
@@ -107,23 +104,22 @@ class Utils {
|
||||
chrome.runtime.sendMessage(registration);
|
||||
}
|
||||
} else {
|
||||
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() {
|
||||
let conditions = [];
|
||||
for (const regex of self.getInvidiousInstancesRegex()) {
|
||||
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], () => {
|
||||
const conditions = [];
|
||||
for (const regex of this.getInvidiousInstancesRegex()) {
|
||||
conditions.push(new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { urlMatches: regex }
|
||||
}));
|
||||
}
|
||||
|
||||
// Add page rule
|
||||
let rule = {
|
||||
const rule = {
|
||||
id: "invidious",
|
||||
conditions,
|
||||
// This API is experimental and not visible by the TypeScript compiler
|
||||
actions: [new (<any> chrome.declarativeContent).RequestContentScript({
|
||||
actions: [new chrome.declarativeContent.RequestContentScript({
|
||||
allFrames: true,
|
||||
js: self.js,
|
||||
css: self.css
|
||||
js: this.js,
|
||||
css: this.css
|
||||
})]
|
||||
};
|
||||
|
||||
@@ -135,9 +131,9 @@ class Utils {
|
||||
/**
|
||||
* Removes the permission and content script registration.
|
||||
*/
|
||||
removeExtraSiteRegistration() {
|
||||
removeExtraSiteRegistration(): void {
|
||||
if (this.isFirefox()) {
|
||||
let id = "invidious";
|
||||
const id = "invidious";
|
||||
|
||||
if (this.backgroundScriptContainer) {
|
||||
this.backgroundScriptContainer.unregisterFirefoxContentScript(id);
|
||||
@@ -158,17 +154,54 @@ class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets just the timestamps from a sponsorTimes array
|
||||
*
|
||||
* @param sponsorTimes
|
||||
* Merges any overlapping timestamp ranges into single segments and returns them as a new array.
|
||||
*/
|
||||
getSegmentsFromSponsorTimes(sponsorTimes: SponsorTime[]): number[][] {
|
||||
let segments: number[][] = [];
|
||||
for (const sponsorTime of sponsorTimes) {
|
||||
segments.push(sponsorTime.segment);
|
||||
}
|
||||
getMergedTimestamps(timestamps: number[][]): [number, number][] {
|
||||
let deduped: [number, number][] = [];
|
||||
|
||||
return segments;
|
||||
// Cases ([] = another segment, <> = current range):
|
||||
// [<]>, <[>], <[]>, [<>], [<][>]
|
||||
timestamps.forEach((range) => {
|
||||
// Find segments the current range overlaps
|
||||
const startOverlaps = deduped.findIndex((other) => range[0] >= other[0] && range[0] <= other[1]);
|
||||
const endOverlaps = deduped.findIndex((other) => range[1] >= other[0] && range[1] <= other[1]);
|
||||
|
||||
if (~startOverlaps && ~endOverlaps) {
|
||||
// [<][>] Both the start and end of this range overlap another segment
|
||||
// [<>] This range is already entirely contained within an existing segment
|
||||
if (startOverlaps === endOverlaps) return;
|
||||
|
||||
// Remove the range with the higher index first to avoid the index shifting
|
||||
const other1 = deduped.splice(Math.max(startOverlaps, endOverlaps), 1)[0];
|
||||
const other2 = deduped.splice(Math.min(startOverlaps, endOverlaps), 1)[0];
|
||||
|
||||
// Insert a new segment spanning the start and end of the range
|
||||
deduped.push([Math.min(other1[0], other2[0]), Math.max(other1[1], other2[1])]);
|
||||
} else if (~startOverlaps) {
|
||||
// [<]> The start of this range overlaps another segment, extend its end
|
||||
deduped[startOverlaps][1] = range[1];
|
||||
} else if (~endOverlaps) {
|
||||
// <[>] The end of this range overlaps another segment, extend its beginning
|
||||
deduped[endOverlaps][0] = range[0];
|
||||
} else {
|
||||
// No overlaps, just push in a copy
|
||||
deduped.push(range.slice() as [number, number]);
|
||||
}
|
||||
|
||||
// <[]> Remove other segments contained within this range
|
||||
deduped = deduped.filter((other) => !(other[0] > range[0] && other[1] < range[1]));
|
||||
});
|
||||
|
||||
return deduped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total duration of the timestamps, taking into account overlaps.
|
||||
*/
|
||||
getTimestampsDuration(timestamps: number[][]): number {
|
||||
return this.getMergedTimestamps(timestamps).reduce((acc, range) => {
|
||||
return acc + range[1] - range[0];
|
||||
}, 0);
|
||||
}
|
||||
|
||||
getSponsorIndexFromUUID(sponsorTimes: SponsorTime[], UUID: string): number {
|
||||
@@ -193,20 +226,20 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
localizeHtmlPage() {
|
||||
localizeHtmlPage(): void {
|
||||
//Localize by replacing __MSG_***__ meta tags
|
||||
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
for (var j = 0; j < objects.length; j++) {
|
||||
var obj = objects[j];
|
||||
const objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
for (let j = 0; j < objects.length; j++) {
|
||||
const obj = objects[j];
|
||||
|
||||
let localizedMessage = this.getLocalizedMessage(obj.innerHTML.toString());
|
||||
const localizedMessage = this.getLocalizedMessage(obj.innerHTML.toString());
|
||||
if (localizedMessage) obj.innerHTML = localizedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
getLocalizedMessage(text) {
|
||||
var valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) {
|
||||
return v1 ? chrome.i18n.getMessage(v1) : "";
|
||||
getLocalizedMessage(text: string): string | false {
|
||||
const valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) {
|
||||
return v1 ? chrome.i18n.getMessage(v1).replace("\n", "<br/>") : "";
|
||||
});
|
||||
|
||||
if(valNewH != text) {
|
||||
@@ -219,8 +252,8 @@ class Utils {
|
||||
/**
|
||||
* @returns {String[]} Invidious Instances in regex form
|
||||
*/
|
||||
getInvidiousInstancesRegex() {
|
||||
var invidiousInstancesRegex = [];
|
||||
getInvidiousInstancesRegex(): string[] {
|
||||
const invidiousInstancesRegex: string[] = [];
|
||||
for (const url of Config.config.invidiousInstances) {
|
||||
invidiousInstancesRegex.push("https://*." + url + "/*");
|
||||
invidiousInstancesRegex.push("http://*." + url + "/*");
|
||||
@@ -229,11 +262,11 @@ class Utils {
|
||||
return invidiousInstancesRegex;
|
||||
}
|
||||
|
||||
generateUserID(length = 36) {
|
||||
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
generateUserID(length = 36): string {
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let result = "";
|
||||
if (window.crypto && window.crypto.getRandomValues) {
|
||||
let values = new Uint32Array(length);
|
||||
const values = new Uint32Array(length);
|
||||
window.crypto.getRandomValues(values);
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += charset[values[i] % charset.length];
|
||||
@@ -253,7 +286,7 @@ class Utils {
|
||||
* @param {int} statusCode
|
||||
* @returns {string} errorMessage
|
||||
*/
|
||||
getErrorMessage(statusCode) {
|
||||
getErrorMessage(statusCode: number): string {
|
||||
let errorMessage = "";
|
||||
|
||||
if([400, 429, 409, 502, 0].includes(statusCode)) {
|
||||
@@ -298,7 +331,7 @@ class Utils {
|
||||
* @param callback
|
||||
*/
|
||||
async asyncRequestToServer(type: string, address: string, data = {}): Promise<FetchResponse> {
|
||||
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
const serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
|
||||
return await (this.asyncRequestToCustomServer(type, serverAddress + address, data));
|
||||
}
|
||||
@@ -310,8 +343,8 @@ class Utils {
|
||||
* @param address The address to add to the SponsorBlock server address
|
||||
* @param callback
|
||||
*/
|
||||
sendRequestToServer(type: string, address: string, callback?: (response: FetchResponse) => void) {
|
||||
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
sendRequestToServer(type: string, address: string, callback?: (response: FetchResponse) => void): void {
|
||||
const serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
|
||||
// Ask the background script to do the work
|
||||
chrome.runtime.sendMessage({
|
||||
@@ -324,15 +357,15 @@ class Utils {
|
||||
}
|
||||
|
||||
getFormattedTime(seconds: number, precise?: boolean): string {
|
||||
let hours = Math.floor(seconds / 60 / 60);
|
||||
let minutes = Math.floor(seconds / 60) % 60;
|
||||
const hours = Math.floor(seconds / 60 / 60);
|
||||
const minutes = Math.floor(seconds / 60) % 60;
|
||||
let minutesDisplay = String(minutes);
|
||||
let secondsNum = seconds % 60;
|
||||
if (!precise) {
|
||||
secondsNum = Math.floor(secondsNum);
|
||||
}
|
||||
|
||||
let secondsDisplay: string = String(precise ? secondsNum.toFixed(3) : secondsNum);
|
||||
let secondsDisplay = String(precise ? secondsNum.toFixed(3) : secondsNum);
|
||||
|
||||
if (secondsNum < 10) {
|
||||
//add a zero
|
||||
@@ -343,7 +376,7 @@ class Utils {
|
||||
minutesDisplay = "0" + minutesDisplay;
|
||||
}
|
||||
|
||||
let formatted = (hours ? hours + ":" : "") + minutesDisplay + ":" + secondsDisplay;
|
||||
const formatted = (hours ? hours + ":" : "") + minutesDisplay + ":" + secondsDisplay;
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user