mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-06 11:37:02 +03:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1648e104e1 | ||
|
|
c4d7c4511e | ||
|
|
cd78c46ef8 | ||
|
|
758b6f18db | ||
|
|
6d05b2a849 | ||
|
|
4729268083 | ||
|
|
b7a574fc16 | ||
|
|
c8cbd893f7 | ||
|
|
11b01fd3dd | ||
|
|
85e3d3bc18 | ||
|
|
47ea8cd017 | ||
|
|
61e78eb668 | ||
|
|
5ebd44c0c7 | ||
|
|
9888dcc323 | ||
|
|
49a166a6b2 | ||
|
|
2bd1271575 | ||
|
|
5d62b11a6d | ||
|
|
f4cac58322 | ||
|
|
4a532e751c | ||
|
|
4a3b33cb85 | ||
|
|
78e9f41854 | ||
|
|
48cfee57b7 | ||
|
|
b2ef9e5d6e | ||
|
|
c42ebce6e3 | ||
|
|
bc1d6006eb | ||
|
|
727d925879 | ||
|
|
5d48d9ac74 | ||
|
|
83ea183f58 | ||
|
|
a098858035 | ||
|
|
81e85c19ae | ||
|
|
fda4a03541 | ||
|
|
55c84662c0 | ||
|
|
5c9e06468e | ||
|
|
a3d38c57d7 | ||
|
|
7ec09dd385 | ||
|
|
bb7f069254 | ||
|
|
61fc1d2ed3 | ||
|
|
dabc63af73 | ||
|
|
08181c1d5f | ||
|
|
03cd1b535b | ||
|
|
8cc3843ada | ||
|
|
c4701092f4 | ||
|
|
63ef9b44c7 | ||
|
|
d564742339 | ||
|
|
6477e4c1f8 | ||
|
|
eb8a0ae307 | ||
|
|
5296c437cc | ||
|
|
36efe139ba | ||
|
|
eaabd3149e | ||
|
|
6166ab3006 | ||
|
|
f1498d51fa | ||
|
|
3aabc0d051 | ||
|
|
28904935da | ||
|
|
35d83d257c | ||
|
|
92e078b87c | ||
|
|
75accad06e | ||
|
|
a99823d487 | ||
|
|
1ba1595d0e | ||
|
|
8f7408d815 | ||
|
|
3337fa04b9 | ||
|
|
1a0dd19cf0 | ||
|
|
b45434b374 | ||
|
|
a214fd416e | ||
|
|
38266be174 | ||
|
|
f96419d14c | ||
|
|
280127c9af | ||
|
|
da35e889f2 | ||
|
|
bb8975e93a | ||
|
|
36e8300427 | ||
|
|
fc160e1d09 | ||
|
|
1ace5ea50c | ||
|
|
911ff9b784 | ||
|
|
e1688c3f58 | ||
|
|
e11a320c3f | ||
|
|
0d6a40b9fc | ||
|
|
bbab712a79 | ||
|
|
d9f03a62ee | ||
|
|
577994cc95 | ||
|
|
d573dabf15 | ||
|
|
4c903456ff | ||
|
|
6d1a29019b | ||
|
|
a91025ac23 | ||
|
|
ca931f18f6 | ||
|
|
1d2122c2df | ||
|
|
5b080874f2 |
@@ -23,7 +23,8 @@
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"no-self-assign": "off",
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
"react/prop-types": [2, { "ignore": ["children"] }]
|
||||
"react/prop-types": [2, { "ignore": ["children"] }],
|
||||
"@typescript-eslint/member-delimiter-style": "warn"
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
|
||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,3 +1,3 @@
|
||||
github: ajayyy-org
|
||||
patreon: ajayyy
|
||||
custom: [sponsor.ajay.app/donate]
|
||||
custom: [buy.ajay.app/l/sponsorblock, sponsor.ajay.app/donate]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "SponsorBlock",
|
||||
"version": "5.0.4",
|
||||
"version": "5.1.0",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"homepage_url": "https://sponsor.ajay.app",
|
||||
|
||||
File diff suppressed because one or more lines are too long
4136
package-lock.json
generated
4136
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
42
package.json
42
package.json
@@ -4,36 +4,36 @@
|
||||
"description": "",
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.193",
|
||||
"@types/chrome": "^0.0.197",
|
||||
"@types/firefox-webext-browser": "^94.0.1",
|
||||
"@types/jest": "^28.1.6",
|
||||
"@types/react": "^17.0.47",
|
||||
"@types/react-dom": "^17.0.17",
|
||||
"@types/selenium-webdriver": "^4.1.2",
|
||||
"@types/wicg-mediasession": "^1.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
||||
"@typescript-eslint/parser": "^5.31.0",
|
||||
"chromedriver": "^103.0.0",
|
||||
"concurrently": "^7.3.0",
|
||||
"@types/jest": "^29.1.2",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/selenium-webdriver": "^4.1.5",
|
||||
"@types/wicg-mediasession": "^1.1.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
||||
"@typescript-eslint/parser": "^5.39.0",
|
||||
"chromedriver": "^106.0.1",
|
||||
"concurrently": "^7.4.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"eslint": "^8.20.0",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-plugin-react": "^7.31.8",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.13",
|
||||
"jest": "^28.1.3",
|
||||
"jest-environment-jsdom": "^28.1.0",
|
||||
"jest": "^29.1.2",
|
||||
"jest-environment-jsdom": "^29.1.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"schema-utils": "^4.0.0",
|
||||
"selenium-webdriver": "^4.3.1",
|
||||
"selenium-webdriver": "^4.5.0",
|
||||
"speed-measure-webpack-plugin": "^1.5.0",
|
||||
"ts-jest": "^28.0.7",
|
||||
"ts-loader": "^9.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-loader": "^9.4.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "4.7",
|
||||
"web-ext": "^7.1.1",
|
||||
"typescript": "4.8",
|
||||
"web-ext": "^7.2.0",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-merge": "^5.8.0"
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
"Segments": {
|
||||
"message": "أجزاء"
|
||||
},
|
||||
"Chapters": {
|
||||
"message": "الفصول"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "التصويت على هذا الإرسال"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Изобразяване на сегментите като глави",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Показване на текущия сегмент до времето на клипа"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Одобряване на това предложение"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Затваряне на прозореца"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Икона - затваряне"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Изпращане на сегментите"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Проверете status.sponsor.ajay.app за състоянието на сървъра."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Импортиране/експортиране на вашия UserID"
|
||||
"message": "Импортиране/експортиране на вашия личен UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Това трябва да се пази в тайна. То е като парола и не трябва да се споделя с никого. Ако някой го има, може да се представи за вас. Ако търсите своя публичен потребителски идентификатор, щракнете върху иконата на клипборда в изскачащия прозорец."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Задаване на UserID"
|
||||
"message": "Задаване на личен UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Внимание: Промяната на UserID е постоянна. Наистина ли искате да направите това? Не забравяйте да архивирате стария си за всеки случай."
|
||||
"message": "Внимание: Промяната на личния UserID е постоянна. Наистина ли искате да направите това? Не забравяйте да архивирате стария си за всеки случай."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Създаден от"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Зареждане от файл"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Това е цялата ви конфигурация в JSON. Това включва вашия userID, така че се уверете, че споделяте това разумно."
|
||||
"message": "Това е цялата ви конфигурация в JSON. Това включва вашия личен userID, така че се уверете, че споделяте това разумно."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Задаване на опции"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Пълнеж/Шеги"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Съпътстващи сцени, добавени само за пълнеж или хумор, които не са необходими за разбирането на основното съдържание на видеоклипа. Това не трябва да включва сегменти, предоставящи контекст или справочни данни."
|
||||
"message": "Съпътстващи сцени, добавени само за пълнеж или хумор, които не са необходими за разбирането на основното съдържание на видеоклипа. Това не трябва да включва сегменти, предоставящи контекст или справочни данни. Това е много агресивна категория, предназначена за случаите, когато не сте в настроение за „забавление“."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Пълнеж"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Скриване на сегмента"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Пропускане на сегмент"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Пускане на главата"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Използвайте колелото на мишката, докато държите курсора върху полето за редактиране, за да коригирате бързо времето. Комбинации с клавиша ctrl или shift могат да се използват за фина настройка на промените."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Нова функция: Персонализирани глави с краудсорсинг. Това са секции с персонализирани имена във видеоклипове, които могат да бъдат подредени, за да станат все по-прецизни. Закупете лиценз, за да видите главите, изпратени в това видео, като например: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Нова функция: Персонализирани глави с краудсорсинг. Това са секции с персонализирани имена във видеоклипове, които могат да бъдат подредени, за да станат все по-прецизни. Имате безплатен достъп, активирайте в опциите."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "В момента имате {0} в {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -25,6 +25,16 @@
|
||||
"Segments": {
|
||||
"message": "অংশগুলো"
|
||||
},
|
||||
"SegmentsCap": {
|
||||
"message": "অংশগুলো"
|
||||
},
|
||||
"Chapters": {
|
||||
"message": "অধ্যায়সমূহ"
|
||||
},
|
||||
"renderAsChapters": {
|
||||
"message": "অংশসমূহকে অধ্যায়সমূহতে পরিণত করুন",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "এই জমাটিকে সমর্থন করুন"
|
||||
},
|
||||
@@ -115,6 +125,9 @@
|
||||
"SubmitTimes": {
|
||||
"message": "সেগমেন্ট জমা দিন"
|
||||
},
|
||||
"sortSegments": {
|
||||
"message": "সংক্ষিপ্ত অংশ"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "আপনি কি এটি জমা দেওয়ার বিষয়ে নিশ্চিত?"
|
||||
},
|
||||
@@ -233,12 +246,21 @@
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "যদি ভিডিওটি নতুন হয়, এবং কোন অংশ পাওয়া না যায়, আপনার দেখার সময় কয়েক মিনিট পর পরই এটি তথ্য আনতে থাকবে।"
|
||||
},
|
||||
"enableShowCategoryWithoutPermission": {
|
||||
"message": "জমার অনুমতি ছাড়াই বিভাগসমূহকে জমা মেনুতে দেখান"
|
||||
},
|
||||
"whatShowCategoryWithoutPermission": {
|
||||
"message": "নূন্যতম খ্যাতি প্রয়োজনীয়তার কারণে কিছু বিভাগ জমা দিতে অনুমতি প্রয়োজন"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "নোটিশ পুনরায় প্রদর্শন করুন"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "একটি অংশ এড়ানোর পরে নোটিস প্রদর্শন করুন"
|
||||
},
|
||||
"showCategoryGuidelines": {
|
||||
"message": "বিভাগের সাহায্য দেখান"
|
||||
},
|
||||
"noticeVisibilityMode0": {
|
||||
"message": "পূর্ণ আকারের স্কিপ নোটিস"
|
||||
},
|
||||
@@ -286,6 +308,14 @@
|
||||
"message": "সেগমেন্ট জমা দিন",
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"nextChapterKeybind": {
|
||||
"message": "পরবর্তী অধ্যায়",
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"previousChapterKeybind": {
|
||||
"message": "পূর্ববর্তী অধ্যায়",
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "এটি টাইপ করে একটি কী নির্বাচন করুন এবং আপনি যে কোনও সংশোধক কীগুলি ব্যবহার করতে চান তা চয়ন করুন।"
|
||||
},
|
||||
@@ -384,18 +414,9 @@
|
||||
"statusReminder": {
|
||||
"message": "সার্ভারের স্ট্যাটাস এর জন্য status.sponsor.ajay.app দেখুন করুন।"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "আপনার ইউজার আইডি ইম্পোর্ট/এক্সপোর্ট করুন"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "এটি ব্যক্তিগত রাখা উচিত। এটি একটি পাসওয়ার্ডের মতো এবং কারও সাথে ভাগ করা উচিত নয়। কারও যদি এটি থাকে তবে তারা আপনার ছদ্মবেশ ধারণ করতে পারে। আপনি যদি আপনার পাবলিক ইউজারআইডি খুঁজছেন তবে পপআপে ক্লিপবোর্ড আইকনটি ক্লিক করুন।"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "ইউজার আইডি দিন"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "সতর্কতা: ইউজারআইডি পরিবর্তন করা চিরস্থায়ী। আপনি কি নিশ্চিত যে আপনি এটি করতে চান? আপনার পুরানোটিকে সাবধানতার সার্থে ব্যাকআপ করার বিষয়টি নিশ্চিত করুন।"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "সৃষ্টি করেছেন"
|
||||
},
|
||||
@@ -439,6 +460,9 @@
|
||||
"minDurationDescription": {
|
||||
"message": "সেট করা মান (সেকেন্ডে) থেকে ছোট সেগমেন্টগুলি প্লেয়ারে এড়িয়ে যাওয়া হবে বা দেখানো হবে না"
|
||||
},
|
||||
"enableManualSkipOnFullVideo": {
|
||||
"message": "সম্পূর্ণ ভিডিওর লেবেল যুক্ত থাকলে ম্যানুয়াল স্কিপ দেখান"
|
||||
},
|
||||
"skipNoticeDuration": {
|
||||
"message": "নোটিশ প্রদর্শন করার দৈর্ঘ্য (সেকেন্ড):"
|
||||
},
|
||||
@@ -487,9 +511,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "ফাইল থেকে লোড করুন"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "এটি আপনার সম্পূর্ণ কনফিগারেশন এতে আপনার ইউজারআইডি অন্তর্ভুক্ত রয়েছে, তাই বিজ্ঞতার সাথে শেয়ার করতে ভুলবেন না।."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "অপশন সেট করুন"
|
||||
},
|
||||
@@ -594,9 +615,6 @@
|
||||
"category_filler": {
|
||||
"message": "ফিলার ট্যানজেন্ট/জোকস"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "স্পর্শকাতর দৃশ্য যেগুলি কেবল ফিলার বা হাস্যরসের জন্য যুক্ত হয়েছে যা ভিডিওর মূল বিষয়বস্তু বোঝার জন্য প্রয়োজন হয় না। এর মধ্যে প্রসঙ্গ বা পটভূমির বিশদ সরবরাহকারী বিভাগগুলি অন্তর্ভুক্ত করা উচিত নয়।"
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "ফিলার"
|
||||
},
|
||||
|
||||
@@ -217,9 +217,6 @@
|
||||
"statusReminder": {
|
||||
"message": "Visiteu status.sponsor.ajay.app per conèixer l'estat del servidor."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importa/exporta la vostra identificació d'usuari"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Això hauria de romandre privat: és semblant a una contrasenya i no s'hauria de compartir amb cap persona. Si algú hi té accés, poden suplantar-vos. Si esteu cercant el vostre identificador d'usuari públic, premeu la icona del portanotes a la finestra."
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Zobrazit segmenty jako kapitoly",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Zobrazit aktuální segment vedle času videa"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Hlasovat pro tento příspěvek"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Zavřít vyskakovací okno"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Ikona pro zavření"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Odeslat segmenty"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Podívejte se na status.sponsor.ajay.app pro stav serverů."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importovat / exportovat vaše UserID"
|
||||
"message": "Importovat / exportovat vaše soukromé UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Toto by mělo být ponecháno v soukromí. Je to jako heslo a nemělo by být s nikým sdíleno. Pokud to někdo má, může se za vás vydávat. Pokud hledáte vaše veřejné uživatelské ID, klikněte na ikonu schránky ve vyskakovacím okně."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Nastavit UserID"
|
||||
"message": "Nastavit soukromé UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Varování: Změna UserID je nevratná. Opravdu to chcete udělat? Pro jistotu si zálohujte vaše staré ID, jen kdyby něco."
|
||||
"message": "Varování: Změna soukromého UserID je nevratná. Opravdu to chcete udělat? Pro jistotu si zálohujte vaše staré ID, jen kdyby něco."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Vytvořil"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Načíst ze souboru"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Toto je celá vaše konfigurace ve formátu JSON. Zahrnuje vaše userID, takže s ní nakládejte opatrně."
|
||||
"message": "Toto je celá vaše konfigurace ve formátu JSON. Zahrnuje vaše soukromé UserID, takže s ní nakládejte opatrně."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Nastavit možnosti"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Výplň / vtipy"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Výplňové scény přidané jen jako přídavek nebo humor, které nejsou vyžadovány pro pochopení hlavního obsahu videa. Toto by nemělo zahrnovat segmenty poskytující kontext nebo podrobnosti na pozadí."
|
||||
"message": "Scény přidané pouze jako výplň nebo humor, které nejsou nutné k pochopení hlavního obsahu videa. Kategorie by neměla zahrnovat segmenty poskytující podrobnosti o kontextu nebo pozadí. Jedná se o velmi agresivní kategorii myšlenou pro chvíle, kdy nemáte náladu na „zábavu“."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Výplň"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Skrýt segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Přeskočit segment"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Přehrát kapitolu"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Použijte kolečko myši při přechodu přes editační okno pro rychlou úpravu času. Kombinace kláves Ctrl nebo Shift mohou být použity k doladění změn."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Nová funkce: komunitní vlastní kapitoly. Jedná se o komunitou vytvořené sekce ve videích, které lze slučovat, aby byly stále přesnější. Zakupte si licenci pro zobrazení kapitol u tohoto videa, jako například: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Nová funkce: komunitní vlastní kapitoly. Jedná se o komunitou vytvořené sekce ve videích, které lze slučovat, aby byly stále přesnější. Přístup máte zdarma, povolte jej v možnostech."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Momentálně máte {0} na {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Render segmenter som kapitler",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Vis nuværende segmenter ved siden af videotid"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Stem for dette forslag"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Luk Pop-op"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Luk ikon"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Indsend Segmenter"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Tjek status.sponsor.ajay.app for serverstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importer/Eksporter Dit Bruger-ID"
|
||||
"message": "Importer/Eksporter Dit Private User-ID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Dette bør holdes privat. Det er ligesom en adgangskode og bør ikke deles med nogen. Hvis nogen har dette, kan de udgive sig for at være dig. Hvis du leder efter dit offentlige bruger-ID, skal du klikke på udklipsholderikonet i popup-vinduet."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Indstil Bruger-ID"
|
||||
"message": "Set Privat Bruger-ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Advarsel: Ændring af Bruger-IDet er permanent. Er du sikker på, at du vil gøre det? Sørg for at sikkerhedskopiere din gamle for en sikkerheds skyld."
|
||||
"message": "Advarsel: Ændring af private Bruger-IDet er permanent. Er du sikker på, at du vil gøre det? Sørg for at sikkerhedskopiere din gamle for en sikkerheds skyld."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Oprettet Af"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Indlæs fra fil"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Dette er hele din konfiguration i JSON. Dette inkluderer dit bruger-ID, så sørg for at dele dette med omtanke."
|
||||
"message": "Dette er hele din konfiguration i JSON. Dette inkluderer dit private bruger-ID, så sørg for at dele dette med omtanke."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Indstil Indstillinger"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Fyldningstangent/Jokes"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Tangential scener kun tilføjet for fyldstof eller humor, som ikke er nødvendige for at forstå videoens hovedindhold. Dette bør ikke omfatte segmenter, der gtiver kontekst eller bagrundsoplysninger."
|
||||
"message": "Tangential scener kun tilføjet for fyldstof eller humor, som ikke er nødvendige for at forstå videoens hovedindhold. Dette bør ikke omfatte segmenter, der gtiver kontekst eller bagrundsoplysninger\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Fyldstof"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Skjul segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Spring segment over"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Afspil kapitel"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Brug musehjulet, mens du holder musen over redigeringsfeltet for hurtigt at justere tiden. Kombinationer af ctrl eller shift-tastenerne kan bruges til at finjustere ændringerne."
|
||||
},
|
||||
@@ -1166,6 +1178,17 @@
|
||||
"chaptersPage1": {
|
||||
"message": "SponsorBlock crowd-sourced kapitler funktion er kun tilgængelig for personer, der køber en licens, eller for personer, der har fået gratis adgang på grund af deres tidligere bidrag"
|
||||
},
|
||||
"chaptersPage2": {
|
||||
"message": "Bemærk: Tilladelse til at indsende kapitler er stadig baseret på beregnet omdømme. Indkøb af en licens giver dig kun mulighed for at se kapitler indsendt af andre",
|
||||
"description": "On the chapters page for getting access to the paid chapters feature"
|
||||
},
|
||||
"chapterNewFeature": {
|
||||
"message": "Ny funktion: Crowd-sourced brugerdefinerede kapitler. Disse er brugerdefinerede sektioner i videoer, der kan stables for at få mere og mere præcise. Køb en licens til at se kapitlerne indsendt på denne video såsom: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Ny funktion: Crowd-sourced brugerdefinerede kapitler. Disse er brugerdefinerede sektioner i videoer, der kan stables for at få mere og mere præcise. Du har gratis adgang, aktiver i indstillinger."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Du har lige nu {0} på {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Zeige Segmente als Kapitel",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Aktuelles Segment neben der Videozeit anzeigen"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Diese Einreichung positiv bewerten"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Pop-up schließen"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Symbol schließen"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Senden"
|
||||
},
|
||||
@@ -250,7 +256,7 @@
|
||||
"message": "Zeige Kategorien im Einsendungsmenü auch ohne Einreichungsberechtigungen"
|
||||
},
|
||||
"whatShowCategoryWithoutPermission": {
|
||||
"message": "Einige Kategorien benötigen Erlaubnis zum übermitteln aufgrund von einem Mindestmass an Reputation"
|
||||
"message": "Einige Kategorien benötigen Erlaubnis zum Übermitteln aufgrund von Mindestanforderungen an Reputation"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Hinweis erneut anzeigen"
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Prüfe status.sponsor.ajay.app für den Serverstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Benutzer-ID importieren/exportieren"
|
||||
"message": "Private Benutzer-ID importieren/exportieren"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Dies sollte geheim gehalten und wie ein Passwort behandelt, also mit niemandem geteilt werden. Andere könnten sich damit als dich ausgeben. Wenn du nach deiner öffentlichen Profilkennung suchst, klicke auf das „Kopieren“-Symbol neben deinem Anmeldenamen im Pop-up."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Interne Benutzer-ID festlegen"
|
||||
"message": "Private Benutzer-ID festlegen"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Warnung: Das Ändern der Benutzer-ID ist permanent. Bist du dir sicher, dass du das tun möchtest? Lege dir zur Sicherheit erst eine Sicherheitskopie deiner alten ID an."
|
||||
"message": "Warnung: Das Ändern deiner privaten Benutzer-ID ist permanent. Bist du dir sicher, dass du das tun möchtest? Zur Sicherheit solltest du vorher ein Backup deiner alten ID erstellen."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Erstellt von"
|
||||
@@ -470,10 +476,10 @@
|
||||
"message": "Videosegmente, die kürzer als der festgelegte Wert sind, werden nicht übersprungen oder im Player angezeigt."
|
||||
},
|
||||
"enableManualSkipOnFullVideo": {
|
||||
"message": "Verwende manuelles überspringen wenn ein vollständiges Video Label existiert"
|
||||
"message": "Verwende manuelles Überspringen, wenn ein vollständiges Video Label existiert"
|
||||
},
|
||||
"whatManualSkipOnFullVideo": {
|
||||
"message": "Für Personen, welche ein Video ohne unterbrechungen schauen wollen, während es eine komplette Eigenwerbung oder gesponsert ist."
|
||||
"message": "Für Personen, welche ein Video ohne Unterbrechungen schauen wollen, während es vollständig gesponsert oder Eigenwerbung ist."
|
||||
},
|
||||
"skipNoticeDuration": {
|
||||
"message": "Dauer des Überspringenhinweises (Sekunden):"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Aus Datei laden"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Dies ist deine gesamte Konfiguration im JSON-Format. Da diese auch deine Benutzer-ID enthält, solltest du dir genau überlegen, mit wem du diese teilen möchtest."
|
||||
"message": "Dies ist deine gesamte Konfiguration in JSON. Sie enthält deine private Benutzer-ID, stelle also sicher, sie nicht mit jedem zu teilen."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Optionen ändern"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Füller/Witze"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Nebensächliche Szenen, die nur als Füller oder Witz dienen und nicht benötigt sind um den Hauptinhalt des Videos zu verstehen. Dies bezieht sich nicht auf Segmente, die Kontext oder Hintergrunddetails liefern."
|
||||
"message": "Nebensächliche Szenen, die nur als Füller oder Witz dienen und nicht benötigt sind, um den Hauptinhalt des Videos zu verstehen. Dies bezieht sich nicht auf Segmente, die Kontext oder Hintergrunddetails liefern. Dies ist eine sehr aggressive Kategorie, die dafür gedacht ist, wenn du nicht in der Stimmung für \"Spaß\" bist."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Füller"
|
||||
@@ -737,7 +743,7 @@
|
||||
"message": "Kapitel"
|
||||
},
|
||||
"category_chapter_description": {
|
||||
"message": "Benutzerdefinierte Kapitel, welche grosse Bereiche eines Videos beschreiben."
|
||||
"message": "Benutzerdefiniert benannte Kapitel, welche große Abschnitte eines Videos beschreiben."
|
||||
},
|
||||
"category_chapter_guideline1": {
|
||||
"message": "Sponsor-Markennamen nicht erwähnen"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Segment verbergen"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Segment überspringen"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Kapitel abspielen"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Benutze das Mausrad während der Mauszeiger über dem Eingabefeld schwebt um die Zeit schnell anzupassen. Benutze Strg bzw. Shift für gröbere/genauere Änderungen."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Neues Feature: Crowdsourced benutzerdefinierte Kapitel. Dies sind benutzerdefinierte Abschnitte in Videos, die gestapelt werden können, um mehr und mehr präzise zu werden. Kauf eine Lizenz, um Kapitel, die in diesem Video eingereicht wurden, anzusehen: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Neues Feature: Crowd-gesourcte benutzerdefinierte Kapitel. Dies sind benutzerdefiniert benannte Abschnitte in Videos, die gestapelt werden können, um mehr und mehr präzise zu werden. Du hast kostenlosen Zugang, aktiviere es in den Optionen."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Du hast derzeit {0} in {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -400,18 +400,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Ελέγξτε το status.sponsor.ajay.app για την κατάσταση διακομιστή."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Εισαγωγή/Εξαγωγή της Ταυτότητας Χρήστη σας"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Κρατείστε το μυστικό. Αυτό είναι σαν ένα κωδικό πρόσβασης όπου δε θα έπρεπε να μοιράζεστε με κανένα. Εάν το αποκτήσει κάποιος, μπορεί να σας υποδυθεί. Εάν ψάχνετε για τη δημόσια ταυτότητα χρήστη σας, πατήστε πάνω στο αναδυόμενο εικονίδιο πρόχειρου."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ορισμός Ταυτότητας Χρήστη"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Προσοχή: Η αλλαγή της Ταυτότητας Χρήστη είναι μόνιμη. Είστε βέβαιοι ότι θέλετε να το κάνετε; Βεβαιωθείτε ότι έχετε δημιουργήσει αντίγραφο ασφαλείας του παλιού σας για παν ενδεχόμενο."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Δημιουργήθηκε από"
|
||||
},
|
||||
@@ -503,9 +494,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Φόρτωση από αρχείο"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Αυτές είναι όλες σας οι ρυθμίσεις σε αρχείο JSON. Αυτό περιλαμβάνει και την Ταυτότητα Χρήστη, οπότε μοιραστείτε το με προσοχή."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Ορισμός Επιλογών"
|
||||
},
|
||||
@@ -661,9 +649,6 @@
|
||||
"category_filler": {
|
||||
"message": "Σπατάλη Χρόνου/Περιττό σχόλιο"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Σκηνές εκτός θέματος προστίθενται μόνο για σπατάλη χρόνου και περιττά σχόλια τα οποία δεν απαιτούνται για να κατανοήσετε το κύριο περιεχόμενο του βίντεο. Δεν πρέπει να περιλαμβάνονται τμήματα που συμβάλουν στην κατανόηση του θέματος του βίντεο ή επιπλέον πληροφορίες."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Περιττό"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Render segments as chapters",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Show Current Segment Beside Video Time"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Upvote this submission"
|
||||
},
|
||||
@@ -87,10 +90,10 @@
|
||||
"message": "No segments found"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Segment Starts Now"
|
||||
"message": "Start Segment Now"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Segment Ends Now"
|
||||
"message": "End Segment Now"
|
||||
},
|
||||
"sponsorCancel": {
|
||||
"message": "Cancel Creating Segment"
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Close Popup"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Close Icon"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Submit Segments"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Check status.sponsor.ajay.app for server status."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Import/Export Your UserID"
|
||||
"message": "Import/Export Your Private UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you. If you are looking for your public userID, click the clipboard icon in the popup."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Set UserID"
|
||||
"message": "Set Private UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Warning: Changing the UserID is permanent. Are you sure you would like to do this? Make sure to backup your old one just in case."
|
||||
"message": "Warning: Changing the Private UserID is permanent. Are you sure you would like to do this? Make sure to backup your old one just in case."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Created By"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Load from file"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "This is your entire configuration in JSON. This includes your userID, so be sure to share this wisely."
|
||||
"message": "This is your entire configuration in JSON. This includes your Private UserID, so be sure to share this wisely."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Set Options"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Filler Tangent/Jokes"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Tangential scenes added only for filler or humor that are not required to understand the main content of the video. This should not include segments providing context or background details."
|
||||
"message": "Tangential scenes added only for filler or humor that are not required to understand the main content of the video. This should not include segments providing context or background details. This is a very aggressive category meant for when you aren't in the mood for \"fun\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Filler"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Hide segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Skip segment"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Play chapter"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Use your mousewheel while hovering over the edit box to quickly adjust the time. Combinations of the ctrl or shift key can be used to fine tune the changes."
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Procesar segmentos como capítulos",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Mostrar segmento actual al lado del tiempo del video"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Votar positivamente este envío"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Cerrar la ventana"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Icono de cerrar"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Enviar Segmentos"
|
||||
},
|
||||
@@ -175,7 +181,7 @@
|
||||
"message": "Escoger Nombre De Usuario"
|
||||
},
|
||||
"copyPublicID": {
|
||||
"message": "Copiar el ID de usuario público"
|
||||
"message": "Copiar el ID de usuario Público"
|
||||
},
|
||||
"copySegmentID": {
|
||||
"message": "Copiar ID de Segmento"
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Comprueba status.sponsor.ajay.app para ver el estado del servidor."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importar/Exportar tu ID de usuario"
|
||||
"message": "Importar/Exportar su ID de usuario Privado"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Esto se debería mantener privado. Esto es como una contraseña y no debe ser compartido con nadie. Si alguien tiene esto, puede suplantarte. Si estás buscando tu ID de usuario público, haz clic en el icono de portapapeles en la ventana emergente."
|
||||
"message": "Esto se debería mantener privado. Esto es como una contraseña y no debe ser compartido con nadie. Si alguien tiene esto, puede suplantarte. Si estás buscando tu ID de usuario Público, haz clic en el icono de portapapeles en la ventana emergente."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Establecer el ID de usuario"
|
||||
"message": "Establecer ID de usuario Privado"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Advertencia: El cambio del ID de usuario es irreversible. ¿Está seguro de que le desea hacerlo? Asegúrese de hacer una copia de respaldo de la anterior por si acaso."
|
||||
"message": "Advertencia: El cambio del ID de usuario Privado es permanente. ¿Está seguro/a de que desea hacer esto? Asegúrese de respaldar el antiguo por si acaso."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Creado Por"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Cargar desde archivo"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Esta es toda su configuración en JSON. Esto incluye tu ID de usuario, así que asegúrate de compartir esto sabiamente."
|
||||
"message": "Esta es toda su configuración en JSON. Esto incluye tu ID de usuario Privado, asegúrese de compartir esto con prudencia."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Configurar opciones"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Tangentes de Relleno/Chistes"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Escenas tangenciales añadidas solo para relleno o humor que no son necesarias para entender el contenido principal del video. Esto no debe incluir segmentos que proporcionen contexto o detalles de fondo."
|
||||
"message": "Escenas tangenciales añadidas solo de relleno o humor que no son necesarias para entender el contenido principal del video. Esto no debe incluir segmentos que proporcionen contexto o detalles de fondo. Esta es una categoría muy agresiva para cuando no está de humor para la \"diversión\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Relleno"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Ocultar segmento"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Omitir segmento"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Reproducir capítulo"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Utilice la rueda del ratón mientras pasa el cursor por encima del cuadro de edición para ajustar el tiempo. Se pueden utilizar combinaciones de la tecla ctrl o shift para afinar los cambios."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Nueva Función: Capítulos personalizados marcados por la comunidad. Estos son secciones con nombres personalizados en los videos que pueden ser acumulados para ser cada vez más precisos. Compre una licencia para ver los capítulos enviados en este video, como: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Nueva Función: Capítulos personalizados marcados por la comunidad. Estos son secciones con nombres personalizados en los videos que pueden ser acumulados para ser cada vez más precisos. Tiene acceso gratuito, habilítelo en opciones."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Actualmente tienes {0} en {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Kuva segmendid peatükkidena",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Kuva praegune segment video kõrval"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Anna segmendile poolthääl"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Sulge hüpik"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Sulgemisikoon"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Esita segmendid"
|
||||
},
|
||||
@@ -405,18 +411,9 @@
|
||||
"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.\nKui otsid avalikku UserID'd, klõpsa hüpikus olevat lõikelaua ikooni."
|
||||
},
|
||||
"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"
|
||||
},
|
||||
@@ -505,9 +502,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Laadi failist"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "See on sinu kogu seadistus JSON-formaadis. Selle hulgas on ka UserID, seega jaga seda targalt."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Määra valikud"
|
||||
},
|
||||
@@ -667,9 +661,6 @@
|
||||
"category_filler": {
|
||||
"message": "Täitesisu/naljad"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Video täiteks või huumori eesmärgil lisatud sisu, mis ei ole vajalik video põhieesmärgi mõistmiseks. Selle alla ei kuulu segmendid, mis annavad kontekstiteavet või taustainfot."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Täide"
|
||||
},
|
||||
@@ -983,6 +974,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Peida segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Jäta segment vahele"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Esita peatükk"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Kiireks aja reguleerimiseks keri hiirega muutmiskasti kohal. Täpsemaks reguleerimiseks hoia kerimise ajal all Ctrl või Shift klahvi."
|
||||
},
|
||||
|
||||
@@ -23,18 +23,21 @@
|
||||
"message": "osio"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "osiot"
|
||||
"message": "osiota"
|
||||
},
|
||||
"SegmentsCap": {
|
||||
"message": "Osiot"
|
||||
},
|
||||
"Chapters": {
|
||||
"message": "Osiot"
|
||||
"message": "Kappaleet"
|
||||
},
|
||||
"renderAsChapters": {
|
||||
"message": "Piirrä osiot kappaleina",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Näytä nykyinen osio videon ajan vieressä"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Äänestä lähetystä"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Sulje ponnahdusikkuna"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Sulkukuvake"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Lähetä osiot"
|
||||
},
|
||||
@@ -175,7 +181,7 @@
|
||||
"message": "Aseta käyttäjänimi"
|
||||
},
|
||||
"copyPublicID": {
|
||||
"message": "Kopio julkinen UserID"
|
||||
"message": "Kopioi julkinen UserID"
|
||||
},
|
||||
"copySegmentID": {
|
||||
"message": "Kopioi osion ID"
|
||||
@@ -232,7 +238,7 @@
|
||||
"message": "Negatiivisesti äänestämäsi osiot pysyvät piilotettuina myös päivityksen jälkeen"
|
||||
},
|
||||
"trackDownvotesWarning": {
|
||||
"message": "Varoitus: Tämän käytöstä poisto poistaa kaikki negatiiviset äänet"
|
||||
"message": "Varoitus: Tämän poistaminen käytöstä poistaa kaikki aiemmin tallennetut alaäänet"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "Kysely tiiviste-etuliittellä"
|
||||
@@ -309,11 +315,11 @@
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"nextChapterKeybind": {
|
||||
"message": "Seuraava osio",
|
||||
"message": "Seuraava kappale",
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"previousChapterKeybind": {
|
||||
"message": "Edellinen osio",
|
||||
"message": "Edellinen kappale",
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"keybindDescription": {
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Tarkista palvelimen tila osoitteessa status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Tuo/vie UserID:si"
|
||||
"message": "Tuo/vie yksityinen UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Tämä pitäisi pitää yksityisenä. Tämä on kuin salasana, eikä sitä pitäisi jakaa kenenkään kanssa. Jos jollakulla on tämä, he voivat esiintyä sinuna. Jos etsit julkista userID:täsi, napsauta leikepöydän kuvaketta ponnahdusikkunassa."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Aseta UserID"
|
||||
"message": "Määritä yksityinen UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Varoitus: UserID:n vaihtaminen on pysyvää. Oletko varma, että haluat tehdä tämän? Varmuuskopioi vanha UserID:si varmuuden vuoksi."
|
||||
"message": "Varoitus: Yksityisen UserID:n vaihto on pysyvää. Haluatko varmasti tehdä tämän? Varmuuskopioi vanha UserID varmuuden vuoksi."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Luonut"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Lataa tiedostosta"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Tämä on koko konfiguraatiosi JSON-tiedostona. Tämä sisältää userID:si, joten jaa sitä viisaasti."
|
||||
"message": "Tässä ovat kaikki määrityksesi JSON-muodossa. Myös yksityinen UserID sisältyy näihin tietoihin, joten jaa tiedostoa harkiten."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Käytä asetuksia"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Epäolennainen täytesisältö/Vitsit"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Täytteeksi tai huumoriksi lisättyjä toissijaisia kohtauksia, joita videon pääsisällön ymmärrys ei edellytä. Tämän ei tulisi sisältää aiheeseen liittyviä tai taustatietoja tarjoavia osioita."
|
||||
"message": "Täytteeksi tai huumoriksi lisättyjä toissijaisia kohtauksia, joita videon pääsisällön ymmärrys ei edellytä. Tämän ei tulisi sisältää aiheeseen liittyviä tai taustatietoja tarjoavia osioita. Tämä on erittäin aggressiivinen kategoria niihin hetkiin, kun et välitä \"huvituksista\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Täytesisältö"
|
||||
@@ -734,19 +740,19 @@
|
||||
"message": "Voi ohittaa otsikon tai pikkukuvan viittaamaan kohtaan"
|
||||
},
|
||||
"category_chapter": {
|
||||
"message": "Osio"
|
||||
"message": "Kappale"
|
||||
},
|
||||
"category_chapter_description": {
|
||||
"message": "Nimetyt osiot, jotka kuvaavat videon merkittäviä jaksoja."
|
||||
"message": "Nimetyt kappaleet, jotka kuvaavat videon merkittäviä osia."
|
||||
},
|
||||
"category_chapter_guideline1": {
|
||||
"message": "Älä mainitse sponsoreiden tuotemerkkejä"
|
||||
},
|
||||
"category_chapter_guideline2": {
|
||||
"message": "Käytä yleisille jaksoille suurempia osioita"
|
||||
"message": "Käytä yleisille osille suurempia kappaleita"
|
||||
},
|
||||
"category_chapter_guideline3": {
|
||||
"message": "Pienemmät osiot voidaan sijoittaa suurempien osioiden sisään"
|
||||
"message": "Pienemmät kappaleet voidaan sijoittaa suurempien kappaleiden sisälle"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Livestream: lahjoitusten/viestien lukeminen"
|
||||
@@ -779,7 +785,7 @@
|
||||
"message": "Näytä merkki"
|
||||
},
|
||||
"showOverlay_chapter": {
|
||||
"message": "Näytä osiot"
|
||||
"message": "Näytä kappaleet"
|
||||
},
|
||||
"autoSkipOnMusicVideos": {
|
||||
"message": "Ohita kaikki osiot automaattisesti, kun videossa on \"Musiikiton\" osio"
|
||||
@@ -923,7 +929,7 @@
|
||||
"message": "Koko video on merkitty tällä kategorialla ja on erotettavaksi liian tiiviisti integroitu"
|
||||
},
|
||||
"chapterNameTooltipWarning": {
|
||||
"message": "Jonkin osion ja kategorian nimet ovat samankaltaisia. Kun mahdollista, osioiden sijaan on suositeltavaa käyttää kategorioita."
|
||||
"message": "Jonkin kappaleesi nimi on samankaltainen kategorian kanssa. Kun mahdollista, kappaleiden sijaan on suositeltavaa käyttää kategorioita."
|
||||
},
|
||||
"experiementOptOut": {
|
||||
"message": "Jättäydy pois kaikista tulevista kokeiluista",
|
||||
@@ -933,7 +939,7 @@
|
||||
"message": "Piilota ikuisesti"
|
||||
},
|
||||
"warningChatInfo": {
|
||||
"message": "Huomasimme, että teit joitakin yleisiä virheitä, jotka eivät ole pahansuopia"
|
||||
"message": "Huomasimme, että teit joitakin yleisiä virheitä, jotka eivät ole tahalleen tehtyjä"
|
||||
},
|
||||
"warningTitle": {
|
||||
"message": "Sait varoituksen"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Piilota osio"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Ohita osio"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Toista kappale"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Käytä hiiren rullaa samalla kun osoitin on muokkauslaatikon päällä säätääksesi aikaa nopeasti. Ctrl- tai Shift-näppäimen yhdistelmiä voi käyttää muutoksien hienosäätelyyn."
|
||||
},
|
||||
@@ -1135,7 +1147,7 @@
|
||||
"message": "Et ole oikeutettu alennukseen"
|
||||
},
|
||||
"discountLink": {
|
||||
"message": "Alennuslinkki (ks. vaaleanpunainen hinta)"
|
||||
"message": "Alennuslinkki (ks. pinkki hinta)"
|
||||
},
|
||||
"selectYourCountry": {
|
||||
"message": "Valitse maasi"
|
||||
@@ -1164,12 +1176,19 @@
|
||||
"message": "Syötä lisenssiavain"
|
||||
},
|
||||
"chaptersPage1": {
|
||||
"message": "SponsorBlockin joukkolähteinen osiotoiminto on vain lisenssin ostaneiden tai aiempien tukien perusteella veloituksettoman käyttöoikeuden saaneiden henkilöiden käytettävissä"
|
||||
"message": "SponsorBlockin joukkolähteinen kappaletoiminto on vain lisenssin ostaneiden tai aiempien tukien perusteella veloituksettoman käyttöoikeuden saaneiden henkilöiden käytettävissä"
|
||||
},
|
||||
"chaptersPage2": {
|
||||
"message": "Huomioi: Osioiden lähetysoikeus perustuu edelleen laskettuun maineeseen. Lisenssin hankinta sallii sinun ainoastaan tarkastella muiden lähettämiä osioita",
|
||||
"message": "Huomioi: Kappaleiden lähetysoikeus perustuu edelleen laskettuun maineeseen. Lisenssin hankinta sallii sinun ainoastaan tarkastella muiden lähettämiä kappaleita",
|
||||
"description": "On the chapters page for getting access to the paid chapters feature"
|
||||
},
|
||||
"chapterNewFeature": {
|
||||
"message": "Uusi ominaisuus: Joukkolähteisesti nimetyt kappaleet. Nämä ovat nimettyjä osia videoissa, joita voi pinota yhä paremman tarkkuuden saavuttamiseksi. Osta lisenssi nähdäksesi tähän videoon lisätyt kappaleet, kuten: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Uusi ominaisuus: Joukkolähteisesti nimetyt kappaleet. Nämä ovat nimettyjä osia videoissa, joita voi pinota yhä paremman tarkkuuden saavuttamiseksi. Sinulla on pääsy ominaisuuteen ilmaiseksi, ota se käyttöön asetuksissa."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Sinulla on tällä hetkellä {0} {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
@@ -1211,7 +1230,7 @@
|
||||
"description": "Show/hide button for the unsubmitted segments list"
|
||||
},
|
||||
"videoID": {
|
||||
"message": "Videon tunniste",
|
||||
"message": "Videon ID",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"segmentCount": {
|
||||
@@ -1223,6 +1242,6 @@
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"exportSegmentsAsURL": {
|
||||
"message": "Jaa URLina"
|
||||
"message": "Jaa URL-osoitteena"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,18 +408,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Vérifiez status.sponsor.ajay.app pour le status du serveur."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importer/Exporter Votre ID d'Utilisateur"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Il doit rester privé. 0 l'instar d'un mot de passe, il ne doit être partagé avec personne. Si une autre personne est en possession de cette information, elle peut usurper votre identité SponsorBlock. Si vous cherchez votre UserID public, cliquez sur l'icône du presse-papiers dans l'encart."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Définir \"UserID\""
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Avertissement : La modification de \"UserID\" est permanente. Êtes-vous sûr de vouloir faire ça ? Assurez-vous de sauvegarder votre ancien au cas où."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Créé par"
|
||||
},
|
||||
@@ -517,9 +508,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Charger à partir du fichier"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Contient toute votre configuration au format JSON. Inclut votre UserID privé, donc ne partagez pas ce fichier."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Définir les options"
|
||||
},
|
||||
@@ -682,9 +670,6 @@
|
||||
"category_filler": {
|
||||
"message": "Digressions/Blagues"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Digressions ajoutées uniquement dans un but de remplissage ou de l'humour non requis pour comprendre le sujet principal de la vidéo. Ne doit pas inclure des segments fournissant du contexte ou des détails de fond."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Remplissage"
|
||||
},
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
"Segments": {
|
||||
"message": "מקטעים"
|
||||
},
|
||||
"SegmentsCap": {
|
||||
"message": "מקטעים"
|
||||
},
|
||||
"Chapters": {
|
||||
"message": "פרקים"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "הצבע לדיווח הזה"
|
||||
},
|
||||
@@ -211,6 +217,14 @@
|
||||
"message": "קוד מקור",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"nextChapterKeybind": {
|
||||
"message": "הפרק הבא",
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "העבודה שלך",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "קוד שגיאה: "
|
||||
},
|
||||
|
||||
@@ -383,15 +383,6 @@
|
||||
"statusReminder": {
|
||||
"message": "Provjerite status.sponsor.ajay.app za status poslužitelja."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Uvezi/Izvezi svoj korisnički ID"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Postavi UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Oprez: Promjena UserID-a je trajna. Jesi li siguran da želiš ovo napraviti? Napravi kopiju starog UserID-a za svaki slučaj."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Izradio"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Szegmensek megjelenítése fejezetekként",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Aktuális szegmens megjelenítése a videó ideje mellett"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Részlet felszavazása"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Felugró ablak bezárása"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Bezárás ikon"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Szegmensek beküldése"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "A szerver állapotához tekintsd meg a status.sponsor.ajay.app oldalt."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "UserID importálása / exportálása"
|
||||
"message": "Titkos UserID importálása / exportálása"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ez privát információnak minősül. Ez olyan, mint egy jelszó, így nem ajánlott megosztani senkivel. Ha valakinek birtokában van, megszemélyesíthet téged. Ha a nyilvános userID-dat keresed, kattints a vágólap ikonra a felugró ablakban."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "UserID beállítása"
|
||||
"message": "Titkos UserID beállítása"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Figyelem: A UserID megváltoztatása végleges. Biztosan szeretnéd megtenni? Minden esetben készíts biztonsági másolatot a régiről!"
|
||||
"message": "Figyelem: A Titkos UserID megváltoztatása végleges. Biztosan szeretnéd megtenni? Minden esetben készíts biztonsági másolatot a régiről!"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Készítette"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Betöltés fájlból"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Ez az összes beállításod JSON formátumban. Ebbe bele tartozik a userID-d is, úgyhogy csak elővigyázatosan oszd meg."
|
||||
"message": "Ez az összes beállításod JSON formátumban. Ebbe bele tartozik a Titkos UserID-d is, úgyhogy csak elővigyázatosan oszd meg."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Beállítások módosítása"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Témától eltérő töltelék/viccek"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Csak töltelékként, vagy humornak hozzáadott részek, amik nem szükségesek a videó fő tartalmának megértéséhez. Ne tartalmazzon olyan szegmenseket, amik kontextust, vagy alapvető információkat szolgáltatnak."
|
||||
"message": "Csak töltelékként, vagy humornak hozzáadott részek, amik nem szükségesek a videó fő tartalmának megértéséhez. Ne tartalmazzon olyan szegmenseket, amik kontextust, vagy alapvető információkat szolgáltatnak\". Ez egy nagyon agresszív kategória arra, amikor nincs kedved a \"szórakozáshoz\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Töltelék"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Szegmens elrejtése"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Szegmens átugrása"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Fejezet lejátszása"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Használd egérgörgődet a szerkesztő mező fölött, hogy gyorsan módosíthasd az időt. A ctrl vagy shift billentyűk kombinációjával finomhangolhatod a változás mértékét."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Új funkció: Közösség által karbantartott fejezetek. Ezek egyedileg elnevezett részei a videóknak, amiket egymásba is lehet ágyazni, hogy egyre pontosabbak lehessenek. Vásárolj licencet, hogy láthasd az ezen a videón beküldött fejezeteket, mint: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Új funkció: Közösség által karbantartott fejezetek. Ezek egyedileg elnevezett részei a videóknak, amiket egymásba is lehet ágyazni, hogy egyre pontosabbak lehessenek. Neked van igyenes hozzáférésed, engedélyezd a beállításokban."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Jelenleg {0} van {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -387,18 +387,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Cek status.sponsor.ajay.app untuk status server."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Impor/Ekspor UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ini harus dirahasiakan. Ini seperti kata sandi dan tidak boleh dibagikan kepada siapa pun. Jika seseorang mempunyai ini, mereka bisa menyamar jadi anda. Jika anda mencari UserID publik anda, klik ikon papan tulis di popup."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Atur UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Peringatan: Pengubahan UserID bersifat permanen. Apakah anda yakin ingin melakukan ini? Pastikan kamu sudah mencadangkan yang lama untuk berjaga."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Dibuat Oleh"
|
||||
},
|
||||
@@ -493,9 +484,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Muat dari file"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Ini adalah seluruh konfigurasi anda di JSON. Ini mencakup userID anda, maka pastikan anda membagikan ini dengan bijak."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Atur Opsi"
|
||||
},
|
||||
@@ -651,9 +639,6 @@
|
||||
"category_filler": {
|
||||
"message": "Pengisi Tak berkaitan/Lawakan"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Adegan tangensial ditambahkan hanya untuk pengisi atau humor yang tidak diperlukan untuk memahami isi utama video. Ini tidak boleh mencakup segmen yang memberikan detail konteks atau latar belakang."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Isian"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Visualizza segmenti come capitoli",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Mostra il Segmento Corrente Affianco al Tempo del Video"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Vota questo contributo"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Chiudi il popup"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Icona Chiudi"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Invia i segmenti"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Controlla status.sponsor.ajay.app per lo stato del server."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importa/Esporta Il Tuo ID Utente"
|
||||
"message": "Importa/Esporta il Tuo UserID Privato"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Questo dovrebbe esser mantenuto privato. È come una password e non dovrebbe esser condiviso con nessuno. Se qualcuno lo possiede, può impersonarti. Se stai cercando il tuo userID pubblico, clicca l'icona degli appunti nel popup."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Imposta ID utente"
|
||||
"message": "Imposta UserID Privato"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Attenzione: cambiare l'ID utente è permanente. Sei sicuro di volerlo fare? Assicurati di eseguire il backup del tuo vecchio nel caso."
|
||||
"message": "Attenzione: La modifica dell'UserID Privato è permanente. Sei sicuro di volerlo fare? Assicurati di effettuare il backup di quello precedente."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Creato da"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Carica da file"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Questa è la tua intera configurazione in formaro JSON. Questo include il tuo ID utente, quindi presta attenzione se vuoi condividerlo."
|
||||
"message": "Questa è la tua intera configurazione in JSON. Ciò include il tuo UserID Privato, quindi assicurati di condividerla saggiamente."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Imposta Opzioni"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Riempitivi irrilevanti/Battute"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Le scene riempitive sono aggiunte solo per riempire o per umorismo che non sono richieste per comprendere il contenuto principale del video. Questo non dovrebbe includere segmenti che forniscono contesto o dettagli di sfondo."
|
||||
"message": "Scene tangenziali aggiunte solo come riempimento o per umorismo, non necessarie alla comprensione del contenuto principale del video. Questo non dovrebbe includere i segmenti che forniscono contesto o dettagli di background. Questa è una categoria molto aggressiva, pensata per quanto non hai voglia di \"divertirti\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Filler"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Nascondi segmento"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Salta segmento"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Riproduci capitolo"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Usa la rotellina del mouse passando sulla casella di modifica per regolare rapidamente il tempo. Le combinazioni dei tasti ctrl o shift sono utilizzabili per perfezionare le modifiche."
|
||||
},
|
||||
@@ -1170,6 +1182,13 @@
|
||||
"message": "Nota: L'autorizzazione a inviare i capitoli si basa ancora sulla reputazione calcolata. Acquistare una licenza ti consente di visualizzare soltanto i capitoli inviati dagli altri",
|
||||
"description": "On the chapters page for getting access to the paid chapters feature"
|
||||
},
|
||||
"chapterNewFeature": {
|
||||
"message": "Nuova Funzionalità: Capitoli personalizzati in crowdsourcing. Sono sezioni dal nome personalizzato nei video, che possono esser impilate per essere sempre più precise. Acquista una licenza per visualizzare i capitoli inviati in questo video come: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Nuova Funzionalità: Capitoli personalizzati in crowdsourcing. Sono sezioni dal nome personalizzato nei video, che possono esser impilate per essere sempre più precise. Hai accesso gratuitamente, abilitalo nelle opzioni."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Al momento hai {0} su {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "セグメントをチャプターとしてレンダリングする",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "動画時間の横に現在のセグメントを表示"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "この提案を支持"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "ポップアップを閉じる"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "閉じるアイコン"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "セグメントを送信"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "サーバーの状態についてはstatus.sponsor.ajay.appを確認してください。"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "ユーザーIDのインポート/エクスポート"
|
||||
"message": "プライベートユーザーIDをインポート/エクスポート"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "これは厳重に保管してください。これはパスワードのようなもので、誰とも共有すべきではありません。 他の誰かがこれを使って、あなたになりすますことができてしまいます。なおパブリックユーザーIDを探している場合は、ポップアップ内のクリップボードアイコンをクリックしてください。"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "ユーザーIDを設定"
|
||||
"message": "プライベートユーザーIDを設定"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "警告: ユーザーIDの変更は恒久的です。本当に実行しますか? 念のため以前のユーザーIDは控えておいてください。"
|
||||
"message": "警告: プライベートユーザーIDの変更は恒久的です。本当に実行しますか? 念のため以前のユーザーIDは控えておいてください。"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "作成者:"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "ファイルから読み込み"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "JSON形式のすべての個人設定です。これにはあなたのユーザーIDが含まれているので、共有するときは注意してください。"
|
||||
"message": "これがJSON形式の設定項目全体になります。これにはあなたのプライベートユーザーIDが含まれているので、共有するときは注意してください。"
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "オプション設定"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "繋ぎの話/冗談"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "動画の本編を理解するのに必要のない、繋ぎの話やユーモアによって脱線したシーン。これには、文脈や背景の詳細を提供しているセグメントを含めないでください。"
|
||||
"message": "動画の本編を理解するのに必要のない、繋ぎの話やユーモアによって脱線したシーン。これには、文脈や背景にある情報を含むセグメントを含めないでください。これは、あなたが楽しい気分になれないときなどのための、非常にアグレッシブなカテゴリーです。"
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "繋ぎの話"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "セグメントを表示しない"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "セグメントをスキップ"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "チャプターを再生"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "編集ボックスにカーソルを合わせながらマウスホイールを使用すると、時間をすばやく調整できます。 CtrlキーまたはShiftキーの組み合わせを使用して変更を微調整できます。"
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "新機能: クラウドソーシングによるカスタムチャプター。動画内のセクションを入れ子構造にできるので、より精密な区分けができます。この動画に登録されたチャプターを表示するにはライセンスをご購入ください。チャプターはこのように表示されます: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "新機能: クラウドソーシングによるカスタムチャプター。動画内のセクションを入れ子構造にできるので、より精密な区分けができます。あなたはこの機能に無料でアクセスできます。オプションより有効化してください。"
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "現在、{1} に {0} があります",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "서버에서 유효하지 않은 요청이라고 응답했어요"
|
||||
"message": "서버에서 잘못된 요청이라고 응답했어요"
|
||||
},
|
||||
"429": {
|
||||
"message": "이 영상에 많은 스폰서 광고 구간을 제출했어요. 정말로 확실하신가요?"
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "챕터처럼 구간을 불러오기",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "동영상 시간 옆에 현재 구간 표시"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "이 제출을 추천해요"
|
||||
},
|
||||
@@ -42,7 +45,7 @@
|
||||
"message": "신고"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "이 제출을 잘못된 제출로 신고해요"
|
||||
"message": "잘못된 제출로 신고해요"
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "무시"
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "팝업 닫기"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "닫기 아이콘"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "구간 제출"
|
||||
},
|
||||
@@ -144,7 +150,7 @@
|
||||
"message": "제출"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "나 덕분에 다른 사람들이 건너뛴 구간: "
|
||||
"message": "나 덕분에 다른 분이 건너뛴 구간: "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "순위표"
|
||||
@@ -217,13 +223,13 @@
|
||||
"message": "YouTube 탐색 바에서 삭제 버튼 표시"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "건너뛴 횟수 추적 활성화"
|
||||
"message": "건너뛴 횟수 추적 사용"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "이 기능으로 건너뛴 구간을 추적해서 사용자가 제출한 내용이 다른 분께 얼마나 도움이 되는지 알려주고 잘못된 구간이 데이터베이스에 들어가지 않도록 추천과 함께 분석에 사용해요. 이 확장 프로그램이 구간을 건너뛸 때마다 서버에 메시지를 보낼 거예요. 조회수가 정확하기 위해서는 이 설정을 변경하지 않기를 바라요. :)"
|
||||
},
|
||||
"enableViewTrackingInPrivate": {
|
||||
"message": "시크릿/사생활 보호 탭에서 건너뛴 횟수 추적 활성화"
|
||||
"message": "시크릿/사생활 보호 탭에서 건너뛴 횟수 추적 사용"
|
||||
},
|
||||
"enableTrackDownvotes": {
|
||||
"message": "비추천한 구간 저장"
|
||||
@@ -232,7 +238,7 @@
|
||||
"message": "비추천한 구간을 새로고침 이후에도 계속 숨겨요"
|
||||
},
|
||||
"trackDownvotesWarning": {
|
||||
"message": "경고: 비활성화하면 이전에 저장된 비추천 구간이 삭제돼요"
|
||||
"message": "경고: 사용하지 않으면 이전에 저장된 비추천 구간이 삭제돼요"
|
||||
},
|
||||
"enableQueryByHashPrefix": {
|
||||
"message": "해시 접두사로 요청 전송"
|
||||
@@ -317,10 +323,10 @@
|
||||
"description": "Keybind label"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "등록하고 싶은 키를 눌러주세요. 필요하다면 Ctrl/Alt/Shift 키를 선택하실 수도 있어요."
|
||||
"message": "등록하고 싶은 키를 눌러주세요. 필요하다면 보조 키를 선택하실 수도 있어요."
|
||||
},
|
||||
"0": {
|
||||
"message": "연결에 오류가 발생했어요. 인터넷 연결을 확인하세요. 인터넷 연결이 되어 있는 경우, 서버가 과부화됐거나 다운된 것일 수도 있어요."
|
||||
"message": "연결에 실패했어요. 인터넷 연결을 확인하세요. 인터넷 연결이 되어 있는 경우, 서버가 과부화됐거나 다운된 것일 수도 있어요."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "건너뛰기 켜짐"
|
||||
@@ -367,20 +373,20 @@
|
||||
"description": "Example: Sponsor Muted"
|
||||
},
|
||||
"skipped_to_category": {
|
||||
"message": "{0}로 이동했어요",
|
||||
"message": "{0}로 건너뛰었어요",
|
||||
"description": "Used for skipping to things (Skipped to Highlight)"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "자동 건너뛰기 비활성화"
|
||||
"message": "자동 건너뛰기 사용 안 함"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "자동 건너뛰기 활성화"
|
||||
"message": "자동 건너뛰기 사용"
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "건너뛸 때 소리 재생"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "구간을 건너뛸 때마다 소리를 재생해요. 자동 건너뛰기가 비활성화된 경우, 아무 소리도 재생되지 않아요."
|
||||
"message": "구간을 건너뛸 때마다 소리를 재생해요. 자동 건너뛰기를 사용하지 않는 경우, 아무 소리도 재생되지 않아요."
|
||||
},
|
||||
"showTimeWithSkips": {
|
||||
"message": "건너뛰기로 제외된 시간 표시"
|
||||
@@ -404,27 +410,27 @@
|
||||
"message": "시간"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "나 덕분에 다른 사람들이 건너뛴 구간:",
|
||||
"message": "나 덕분에 다른 분이 건너뛴 구간:",
|
||||
"description": "You've saved people from 887,362 segments (236d 15h 5.3 minutes of their lives)."
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": "의 시간을 절약함",
|
||||
"message": " 정도를 절약함",
|
||||
"description": "You've saved people from 887,362 segments (236d 15h 5.3 minutes of their lives)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Status.sponsor.ajay.app 사이트를 확인하여 서버 상태를 확인하세요."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "사용자 ID 가져오기/내보내기"
|
||||
"message": "비공개 사용자 ID 가져오기/내보내기"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "이 정보를 다른 분께 공개하지 마세요. 비밀번호처럼 알려주면 위험한 정보랍니다. 다른 분이 이 정보를 가지고 나를 사칭할 수도 있어요. 공개 사용자 ID를 찾고 있다면, 팝업 내 클립보드 아이콘을 눌러주세요."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "사용자 ID 설정"
|
||||
"message": "비공개 사용자 ID 설정"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "경고: 사용자 ID를 변경하면 되돌릴 수 없어요. 정말로 확실한가요? 혹시 모르니 예전 사용자 ID를 백업해두는 걸 권장해요."
|
||||
"message": "경고: 비공개 사용자 ID를 변경하면 되돌릴 수 없어요. 정말로 확실한가요? 혹시 모르니 예전 사용자 ID를 백업해두는 걸 권장해요."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "개발자: "
|
||||
@@ -440,7 +446,7 @@
|
||||
"message": "지원되는 사이트: "
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Invidious 지원을 활성화하고, 자동 건너뛰기 기능을 끄거나, 사용하지 않는 버튼을 숨겨보세요."
|
||||
"message": "Invidious 지원 활성화, 자동 건너뛰기 사용 안 함, 버튼 숨기기 등이 있어요."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "제3자 클라이언트 인스턴스 추가"
|
||||
@@ -452,13 +458,13 @@
|
||||
"message": "추가"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "유효하지 않은 도메인이에요. 도메인 형식으로 되어있어야 해요. 예: invious.ajay.app"
|
||||
"message": "잘못된 도메인이에요. 도메인 부분만 포함해야 해요. 예시: invious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Invidious 인스턴스 목록 초기화"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Invidious 인스턴스 목록을 초기화할까요?"
|
||||
"message": "Invidious 인스턴스 목록을 초기화하시겠어요?"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "현재 인스턴스:"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "파일에서 불러오기"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "JSON의 전체 구성 파일이에요. 사용자 ID가 포함되어 있으니, 공유할 때 주의하세요."
|
||||
"message": "JSON의 전체 구성 파일이에요. 나의 비공개 사용자 ID가 포함되어 있으니, 공유할 때 주의하세요."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "옵션 저장"
|
||||
@@ -539,7 +545,7 @@
|
||||
"message": "구간 제출"
|
||||
},
|
||||
"submit": {
|
||||
"message": "제출"
|
||||
"message": "제출하기"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "취소"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "주제와 관련 없는 구간"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "이 구간은 전반적인 동영상의 주제를 이해하는 데 필요 없는 내용이 포함됐어요. 상세한 배경지식이나 맥락을 설명하는 구간은 여기에 해당하지 않아요."
|
||||
"message": "이 구간은 전반적인 동영상의 주제를 이해하는 데 필요 없는 내용이 포함됐어요. 상세한 배경지식이나 맥락을 설명하는 구간은 여기에 해당하지 않아요. \"재미\"가 없다는 걸 의미하는 적극적인 카테고리예요."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "주제와 관련 없는 구간"
|
||||
@@ -815,16 +821,16 @@
|
||||
"message": "제출과 투표가 테스트 서버에 연결하는 동안은 메인 서버에 반영되지 않을 거예요. 실제 제출을 원하시면 비활성화하는 걸 잊지 마세요."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(지금)"
|
||||
"message": "(현재)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "많은 카테고리"
|
||||
"message": "추가 카테고리"
|
||||
},
|
||||
"chooseACategory": {
|
||||
"message": "카테고리 선택"
|
||||
},
|
||||
"enableThisCategoryFirst": {
|
||||
"message": "\"{0}\" 카테고리의 구간을 제출하려면, 설정에서 활성화를 해주셔야 해요. 설정 창으로 이동할까요?",
|
||||
"message": "\"{0}\" 카테고리의 구간을 제출하려면, 설정에서 사용을 해주셔야 해요. 바로 설정 창으로 이동하실 거예요.",
|
||||
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
|
||||
},
|
||||
"poiOnlyOneSegment": {
|
||||
@@ -866,7 +872,7 @@
|
||||
"message": "권한 요청에 실패했어요. 거부를 누르셨나요?"
|
||||
},
|
||||
"adblockerIssueWhitelist": {
|
||||
"message": "이 문제를 해결할 수 없는 경우 SponsorBlock이 이 동영상의 채널 정보를 찾을 수 없는 것일 수 있으니, '건너뛰기 전 채널 강제 확인' 설정을 비활성화해주세요."
|
||||
"message": "이 문제를 해결할 수 없는 경우 SponsorBlock이 이 동영상의 채널 정보를 찾을 수 없는 것일 수 있으니, '건너뛰기 전 채널 강제 확인' 설정을 사용하지 않아야 해요"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "건너뛰기 전 채널 강제 확인"
|
||||
@@ -888,10 +894,10 @@
|
||||
"description": "Used for chapter segments when the text is harmful/offensive to remove it faster"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "카테고리를 변경해요"
|
||||
"message": "카테고리 변경"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "이 동영상은 음악 동영상으로 분류되어 있어요. 동영상에 스폰서 광고 구간이 있나요? \"음악이 아닌 구간\"으로 지정된 카테고리인 경우, 확장 프로그램 설정을 열어 이 카테고리를 활성화하세요. 그리고, 이 구간을 \"스폰서 광고 구간\" 대신 \"음악이 아닌 구간\"으로 지정하세요. 혼동된다면 가이드라인을 읽어주세요."
|
||||
"message": "이 동영상은 음악 동영상으로 분류되어 있어요. 동영상에 스폰서 광고 구간이 있나요? \"음악이 아닌 구간\"으로 지정된 카테고리인 경우, 확장 프로그램 설정을 열어 이 카테고리를 사용하세요. 그리고, 이 구간을 \"스폰서 광고 구간\" 대신 \"음악이 아닌 구간\"으로 지정하세요. 혼동된다면 가이드라인을 읽어주세요."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "여러 구간"
|
||||
@@ -920,7 +926,7 @@
|
||||
"message": "제출될 구간이 길어요. 전반적인 동영상의 내용이 한 주제에 대한 것이라면, \"건너뛰기\"를 \"동영상 전체\"로 변경해주세요. 자세한 정보는 가이드라인을 확인하세요."
|
||||
},
|
||||
"categoryPillTitleText": {
|
||||
"message": "동영상 전체가 해당 카테고리로 지정됐고 부분적으로 나누기 어려워요."
|
||||
"message": "동영상 전체가 해당 카테고리로 지정됐고 부분적으로 나누기 어려워요"
|
||||
},
|
||||
"chapterNameTooltipWarning": {
|
||||
"message": "챕터의 이름 중 하나가 카테고리와 유사해요. 가능한 경우 카테고리를 대신 사용해 주세요."
|
||||
@@ -939,10 +945,10 @@
|
||||
"message": "경고를 받으셨어요"
|
||||
},
|
||||
"questionButton": {
|
||||
"message": "아직 질문이 있어요"
|
||||
"message": "질문이 있어요"
|
||||
},
|
||||
"warningConfirmButton": {
|
||||
"message": "네, 이해했어요"
|
||||
"message": "사유를 이해했어요"
|
||||
},
|
||||
"warningError": {
|
||||
"message": "경고를 확인하던 도중 오류가 발생했어요:"
|
||||
@@ -966,7 +972,7 @@
|
||||
"message": "아래 설정을 확인해 보세요"
|
||||
},
|
||||
"helpPageFeatureDisclaimer": {
|
||||
"message": "기본값으로 많은 기능이 비활성화되어 있어요. 인트로, 아웃트로 같은 부분을 건너뛰고 싶으시다면 아래 설정을 켜야 해요. 또한 UI 요소를 숨기거나 표시할 수 있답니다."
|
||||
"message": "기본값으로 많은 기능이 사용되지 않아요. 인트로, 아웃트로 같은 부분을 건너뛰고 싶으시다면 아래 설정을 사용해야 해요. 또한 UI 요소를 숨기거나 표시할 수 있답니다."
|
||||
},
|
||||
"helpPageHowSkippingWorks": {
|
||||
"message": "건너뛰기가 작동하는 방법"
|
||||
@@ -993,10 +999,10 @@
|
||||
"message": "구간을 잘못 설정했다면, 위쪽 화살표 버튼을 누른 다음 구간을 수정하거나 삭제할 수 있어요."
|
||||
},
|
||||
"helpPageTooSlow": {
|
||||
"message": "구간 수정이 오래 걸리시나요?"
|
||||
"message": "이건 너무 느린 거 같아요"
|
||||
},
|
||||
"helpPageTooSlow1": {
|
||||
"message": "원하는 경우 단축키를 이용할 수 있어요. 쌍반점(세미콜론) 키를 눌러 스폰서 광고 구간의 시점/종점을 설정할 수 있으며 작은따옴표 키를 눌러 구간을 제출할 수 있답니다. 언제든지 설정에서 변경할 수 있어요. QWERTY 자판을 사용하지 않는 경우, 단축키를 변경해야 할 수도 있어요."
|
||||
"message": "원하는 경우 단축키를 사용할 수 있어요. 쌍반점(세미콜론) 키를 눌러 스폰서 광고 구간의 시점/종점을 설정할 수 있으며 작은따옴표 키를 눌러 구간을 제출할 수 있답니다. 언제든지 설정에서 변경할 수 있어요. QWERTY 자판을 사용하지 않는 경우, 단축키를 변경해야 할 수도 있어요."
|
||||
},
|
||||
"helpPageCopyOfDatabase": {
|
||||
"message": "데이터베이스의 복사본을 구할 수 있나요? 개발자분께 무슨 일이 생기면 어떻게 되는 거죠?"
|
||||
@@ -1005,7 +1011,7 @@
|
||||
"message": "데이터베이스는 여기에서 확인하실 수 있어요:"
|
||||
},
|
||||
"helpPageCopyOfDatabase2": {
|
||||
"message": "또한 소스 코드는 자유롭게 이용할 수 있어요. 따라서 데이터베이스에 무슨 일이 생기더라도, 제출된 구간이 사라지는 일은 없을 거예요."
|
||||
"message": "또한 소스 코드는 자유롭게 사용할 수 있어요. 따라서 데이터베이스에 무슨 일이 생기더라도, 제출된 구간이 사라지는 일은 없을 거예요."
|
||||
},
|
||||
"helpPageNews": {
|
||||
"message": "새로운 변경 사항은 어디에서 확인하나요?"
|
||||
@@ -1020,7 +1026,7 @@
|
||||
"message": "자세히 보기"
|
||||
},
|
||||
"FullDetails": {
|
||||
"message": "자세한 정보"
|
||||
"message": "전체 세부 정보"
|
||||
},
|
||||
"CopyDownvoteButtonInfo": {
|
||||
"message": "비추천 후 다시 제출할 수 있는 제출되지 않은 복사본을 생성해요"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "구간 숨기기"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "구간 건너뛰기"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "챕터 재생"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "편집 상자 위에 마우스 커서를 올린 채 스크롤해서 시간을 빠르게 조정해 보세요. Ctrl이나 Shift 키를 누른 채로 스크롤하면 세밀하게 조정할 수 있어요."
|
||||
},
|
||||
@@ -1095,10 +1107,10 @@
|
||||
"message": "변경"
|
||||
},
|
||||
"youtubeKeybindWarning": {
|
||||
"message": "설정한 키와 기존 YouTube 단축키가 중복돼요. 그래도 진행하시겠어요?"
|
||||
"message": "설정한 키와 기존 YouTube 단축키가 중복돼요. 그래도 사용하시겠어요?"
|
||||
},
|
||||
"betaServerWarning": {
|
||||
"message": "현재 테스트 서버를 이용 중이에요!"
|
||||
"message": "테스트 서버가 활성화됐어요!"
|
||||
},
|
||||
"openOptionsPage": {
|
||||
"message": "설정 페이지 열기"
|
||||
@@ -1107,7 +1119,7 @@
|
||||
"message": "기본 설정으로 초기화"
|
||||
},
|
||||
"confirmResetToDefault": {
|
||||
"message": "모든 설정을 기본값으로 초기화할까요? 되돌릴 수 없어요!"
|
||||
"message": "모든 설정을 기본값으로 초기화하시겠어요? 되돌릴 수 없어요."
|
||||
},
|
||||
"exportSegments": {
|
||||
"message": "구간 내보내기"
|
||||
@@ -1126,7 +1138,7 @@
|
||||
"message": "라이선스 키가 유효하지 않아요"
|
||||
},
|
||||
"hideUpsells": {
|
||||
"message": "추가 결제 없이는 숨김 설정을 이용하실 수 없어요"
|
||||
"message": "(추가 결제 없이는 숨김 설정을 사용할 수 없어요)"
|
||||
},
|
||||
"chooseACountry": {
|
||||
"message": "국가 선택"
|
||||
@@ -1145,7 +1157,7 @@
|
||||
"description": "After the colon is an email address"
|
||||
},
|
||||
"cantAfford": {
|
||||
"message": "요금을 결제할 여력이 아니시라면, {여기}서 할인 혜택을 받을 수 있는지 확인해보세요",
|
||||
"message": "요금을 결제할 여력이 아니시라면, {여기}서 할인 혜택을 받을 수 있는지 확인해 보세요",
|
||||
"description": "Keep the curly braces. The word 'here' should be translated as well."
|
||||
},
|
||||
"patreonSignIn": {
|
||||
@@ -1164,16 +1176,43 @@
|
||||
"message": "라이선스 키를 입력하세요"
|
||||
},
|
||||
"chaptersPage1": {
|
||||
"message": "SponsorBlock 사용자 참여 챕터 기능은 라이선스 결제 사용자나, 이전 기여를 통해 접근을 허가받은 사용자만 이용할 수 있어요"
|
||||
"message": "SponsorBlock 사용자 참여 챕터 기능은 라이선스 결제 사용자나, 이전 기여를 통해 접근을 허가받은 사용자만 사용할 수 있어요"
|
||||
},
|
||||
"chaptersPage2": {
|
||||
"message": "참고: 여전히 챕터 제출 권한은 산정된 평판만을 바탕으로 부여돼요. 라이선스를 결제하면 다른 분이 제출한 챕터를 확인하는 기능만 추가로 이용할 수 있어요",
|
||||
"message": "참고: 여전히 챕터 제출 권한은 산정된 평판만을 바탕으로 부여돼요. 라이선스를 결제하면 다른 분이 제출한 챕터를 확인하는 기능만 추가로 사용할 수 있어요",
|
||||
"description": "On the chapters page for getting access to the paid chapters feature"
|
||||
},
|
||||
"chapterNewFeature": {
|
||||
"message": "새로운 기능: 사용자 참여 챕터 기능. 챕터는 사용자가 직접 이름을 지정할 수 있고 중첩시킬 수 있어 더욱 더 정확해요. 이 동영상에 제출된 챕터를 보려면 라이선스를 결제하세요. 챕터 목록 미리보기: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "새로운 기능: 사용자 참여 챕터 기능. 챕터는 사용자가 직접 이름을 지정할 수 있고 중첩시킬 수 있어 더욱 더 정확해요. 설정에서 사용해서 무료로 사용할 수 있어요."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "You currently have {0} on {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
},
|
||||
"unsubmittedSegmentCountsZero": {
|
||||
"message": "You currently have no unsubmitted segments",
|
||||
"description": "Replaces 'unsubmittedSegmentCounts' string when there are no unsubmitted segments"
|
||||
},
|
||||
"unsubmittedSegmentsSingular": {
|
||||
"message": "unsubmitted segment",
|
||||
"description": "Example: You currently have 1 *unsubmitted segment* on 1 video"
|
||||
},
|
||||
"unsubmittedSegmentsPlural": {
|
||||
"message": "unsubmitted segments",
|
||||
"description": "Example: You currently have 12 *unsubmitted segments* on 5 videos"
|
||||
},
|
||||
"videosSingular": {
|
||||
"message": "video",
|
||||
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"
|
||||
},
|
||||
"videosPlural": {
|
||||
"message": "videos",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 *videos*"
|
||||
},
|
||||
"clearUnsubmittedSegments": {
|
||||
"message": "모든 구간 초기화",
|
||||
"description": "Label for a button in settings"
|
||||
|
||||
@@ -295,15 +295,6 @@
|
||||
"statusReminder": {
|
||||
"message": "സെർവർ നിലയ്ക്കായി status.sponsor.ajay.app പരിശോധിക്കുക."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "നിങ്ങളുടെ യൂസർ ഐഡി ഇറക്കുമതി ചെയ്യുക / കയറ്റുമതി ചെയ്യുക"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "യൂസർ ഐഡി സജ്ജമാക്കുക"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "മുന്നറിയിപ്പ്: യൂസർ ഐഡി മാറ്റുന്നത് ശാശ്വതമാണ്. ഇത് ചെയ്യാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെന്ന് ഉറപ്പാണോ? നിങ്ങളുടെ പഴയത് ബാക്കപ്പ് ചെയ്യുന്നത് ഉറപ്പാക്കുക."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "ഉണ്ടാക്കിയത്"
|
||||
},
|
||||
@@ -361,9 +352,6 @@
|
||||
"exportOptions": {
|
||||
"message": "എല്ലാ ഓപ്ഷനുകളും ഇറക്കുമതി ചെയ്യുക / കയറ്റുമതി ചെയ്യുക"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "JSON ലെ നിങ്ങളുടെ മുഴുവൻ കോൺഫിഗറേഷനും ഇതാണ്. ഇതിൽ നിങ്ങളുടെ യൂസർ ഐഡി ഉൾപ്പെടുന്നു, അതിനാൽ ഇത് വിവേകത്തോടെ പങ്കിടുന്നത് ഉറപ്പാക്കുക."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "ഓപ്ഷനുകൾ സജ്ജമാക്കുക"
|
||||
},
|
||||
|
||||
@@ -295,15 +295,6 @@
|
||||
"statusReminder": {
|
||||
"message": "Periksa status.sponsor.ajay.app untuk status pelayan."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Import / Eksport Id Pengguna Anda"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Tetapkan Id Pengguna"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Amaran: Mengubah UserID adalah kekal. Adakah anda pasti mahu melakukan ini? Pastikan untuk membuat sandaran lama anda sekiranya berlaku."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Dicipta oleh"
|
||||
},
|
||||
@@ -361,9 +352,6 @@
|
||||
"exportOptions": {
|
||||
"message": "Import / Eksport Semua Pilihan"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Ini adalah keseluruhan konfigurasi anda di JSON. Ini termasuk ID pengguna anda, jadi pastikan untuk membagikannya dengan bijak."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Tetapkan Pilihan"
|
||||
},
|
||||
|
||||
@@ -415,16 +415,16 @@
|
||||
"message": "Controleer status.sponsor.ajay.app voor de serverstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Uw gebruikers-ID importeren/exporteren"
|
||||
"message": "Uw privé-gebruikers-ID importeren/exporteren"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Dit moet privé gehouden worden. Dit is als een wachtwoord en mag met niemand gedeeld worden. Als iemand dit heeft, kan hij zich voordoen als u. Klik op het klembordpictogram in de pop-up als u op zoek bent naar uw publieke gebruikers-ID."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Gebruikers-ID instellen"
|
||||
"message": "Privé-gebruikers-ID instellen"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Waarschuwing: wijzigen van de gebruikers-ID is permanent. Weet u zeker dat u dit wilt doen? Zorg ervoor dat u een back-up maakt van uw oude ID, voor het geval dat."
|
||||
"message": "Waarschuwing: wijzigen van de privé-gebruikers-ID is permanent. Weet u zeker dat u dit wilt doen? Zorg ervoor dat u een back-up maakt van uw oude ID, voor het geval dat."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Gemaakt door"
|
||||
@@ -524,7 +524,7 @@
|
||||
"message": "Laden uit bestand"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Dit is uw volledige configuratie in JSON. Dit is inclusief uw gebruikers-ID, dus zorg ervoor dat u dit verstandig deelt."
|
||||
"message": "Dit is uw volledige configuratie in JSON. Dit is inclusief uw privé-gebruikers-ID, dus zorg ervoor dat u dit verstandig deelt."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Opties instellen"
|
||||
@@ -689,7 +689,7 @@
|
||||
"message": "Opvulling zijspoor/humor"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Zijspoor-scènes die alleen ter opvulling of als humor worden toegevoegd en niet noodzakelijk zijn om de hoofdinhoud van de video te begrijpen. Segmenten die context of achtergrondinformatie verschaffen, mogen hier niet onder vallen."
|
||||
"message": "Zijspoor-scènes die alleen ter opvulling of als humor worden toegevoegd en niet noodzakelijk zijn om de hoofdinhoud van de video te begrijpen. Segmenten die context of achtergrondinformatie verschaffen, mogen hier niet onder vallen. Dit is een zeer agressieve categorie, bedoeld voor als u niet in de stemming bent voor \"plezier\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Opvulling"
|
||||
@@ -1174,6 +1174,9 @@
|
||||
"message": "Nieuwe functie: gecrowdsourcete aangepaste hoofdstukken. Dit zijn hoofdstukken met een eigen naam in video's die gestapeld kunnen worden om steeds preciezer te worden. Koop een licentie om de ingezonden hoofdstukken op deze video te bekijken, zoals: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Nieuwe functie: gecrowdsourcete aangepaste hoofdstukken. Dit zijn hoofdstukken met een eigen naam in video's die gestapeld kunnen worden om steeds preciezer te worden. U heeft gratis toegang. In te schakelen via de opties."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "U hebt momenteel {0} in {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -372,18 +372,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Sjekk status.sponsor.ajay.app for tjenerstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importer/Eksporter din bruker-ID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Dette bør holdes privat. Det er som et passord og bør ikke deles med noen. Hvis noen har dette kan de utgi seg som deg. Hvis du leter etter din offentlige bruker-ID, klikker du på utklippstavlen i oppsprettsvinduet."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Angi bruker-ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Advarsel: Å endre bruker-ID-en din er permanent. Er du sikker på at du vil gjøre dette? Sørg for å ta sikkerhetskopi av din gamle for sikkerhets skyld."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Opprettet av"
|
||||
},
|
||||
@@ -475,9 +466,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Last fra fil"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Dette er hele oppsettet ditt i JSON. Det inkluderer bruker-ID-en din, så sørg for å være beskjeden med å dele det."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Angi innstillinger"
|
||||
},
|
||||
@@ -579,9 +567,6 @@
|
||||
"category_preview": {
|
||||
"message": "Forhåndsvisning/Oppsummering"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Intetsigende segmenter kun lagt til som fyllstoff eller humor som ikke er nødvendig for å forstå hovedinnholdet i videoen. Dette bør ikke inkludere segmenter som gir kontekst eller bakgrunnsdetaljer."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Fyllstoff"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Pokazuj segmenty jako rozdziały",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Pokaż bieżący segment poza czasem wideo"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Zagłosuj na ten segment"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Zamknij okno"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Wyłącz ikonę"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Prześlij segmenty"
|
||||
},
|
||||
@@ -246,6 +252,9 @@
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Jeśli film jest nowy i nie znaleziono żadnych segmentów, dane będą pobierane na nowo co kilka minut w czasie oglądania."
|
||||
},
|
||||
"enableShowCategoryWithoutPermission": {
|
||||
"message": "Pokaż kategorie w menu zgłoszeń, nawet bez uprawnień do zgłaszania"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
@@ -409,16 +418,16 @@
|
||||
"message": "Sprawdź status serwera na status.sponsor.ajay.app"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importuj/Eksportuj swój identyfikator użytkownika"
|
||||
"message": "Importuj/Eksportuj swój prywatny UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "To powinno pozostać prywatne. Jest to niczym hasło i nie powinno zostać nikomu udostępnione. Przy jego użyciu ktoś może się pod ciebie podszywać. Jeśli szukasz publicznego ID użytkownika, kliknij ikonę schowka w wyskakującym oknie."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ustaw identyfikator użytkownika"
|
||||
"message": "Ustaw prywatny UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Uwaga: Zmiana identyfikatora użytkownika jest trwała. Czy na pewno chcesz to zrobić? Na wszelki wypadek skopiuj swój poprzedni."
|
||||
"message": "Uwaga: Zmiana ID użytkownika jest trwała. Czy na pewno chcesz to zrobić? Na wszelki wypadek skopiuj swój poprzedni ID."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
@@ -463,6 +472,9 @@
|
||||
"minDurationDescription": {
|
||||
"message": "Segmenty krótsze niż ustawiona wartość nie będą pomijane ani pokazywane w odtwarzaczu."
|
||||
},
|
||||
"enableManualSkipOnFullVideo": {
|
||||
"message": "Użyj ręcznego pomijania, gdy istnieje etykieta na całym filmie"
|
||||
},
|
||||
"skipNoticeDuration": {
|
||||
"message": "Czas trwania powiadomienia pominięcia (sekundy):"
|
||||
},
|
||||
@@ -512,7 +524,7 @@
|
||||
"message": "Wczytaj z pliku"
|
||||
},
|
||||
"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."
|
||||
"message": "Jest to cała twoja konfiguracja w formacie JSON. Zawarty jest w niej twój prywatny UserID, więc uważaj, komu ją udostępniasz."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Zapisz ustawienia"
|
||||
@@ -676,9 +688,6 @@
|
||||
"category_filler": {
|
||||
"message": "Wypełniacz nietematyczny/żart"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Sceny nietematyczne dodawane tylko jako wypełniacz lub dla humoru, które nie są wymagane do zrozumienia głównej treści filmu. Nie powinno to obejmować segmentów zawierających informacje kontekstowe lub szczegółowe."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Wypełniacz"
|
||||
},
|
||||
@@ -1034,6 +1043,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Ukryj segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Pomiń segment"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Odtwórz rozdział"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Użyj scroll'a myszy po najechaniu nad pole edycji, aby szybko dostosować czas. Kombinacje z ctrl'em i shift'em mogą być użyte, aby doszlifować zmiany."
|
||||
},
|
||||
@@ -1100,6 +1115,9 @@
|
||||
"exportSegments": {
|
||||
"message": "Eksportuj segmenty"
|
||||
},
|
||||
"importSegments": {
|
||||
"message": "Importuj segmenty"
|
||||
},
|
||||
"Import": {
|
||||
"message": "Importuj",
|
||||
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
|
||||
@@ -1116,9 +1134,23 @@
|
||||
"chooseACountry": {
|
||||
"message": "Wybierz kraj"
|
||||
},
|
||||
"noDiscount": {
|
||||
"message": "Nie kwalifikujesz się do przeceny"
|
||||
},
|
||||
"discountLink": {
|
||||
"message": "Link rabatowy"
|
||||
},
|
||||
"selectYourCountry": {
|
||||
"message": "Wybierz swój kraj"
|
||||
},
|
||||
"alreadyDonated": {
|
||||
"message": "Jeśli do tej pory przekazałeś jakąkolwiek darowiznę, możesz odebrać darmowy dostęp poprzez wysyłanie maila do:",
|
||||
"description": "After the colon is an email address"
|
||||
},
|
||||
"cantAfford": {
|
||||
"message": "Jeśli nie możesz sobie pozwolić na zakup licencji, kliknij {tutaj} aby sprawdzić, czy kwalifikujesz się do zniżki",
|
||||
"description": "Keep the curly braces. The word 'here' should be translated as well."
|
||||
},
|
||||
"patreonSignIn": {
|
||||
"message": "Zaloguj się za pomocą Patreon"
|
||||
},
|
||||
@@ -1134,10 +1166,20 @@
|
||||
"enterLicenseKey": {
|
||||
"message": "Wprowadź klucz licencyjny"
|
||||
},
|
||||
"chaptersPage1": {
|
||||
"message": "Funkcja społecznościowych rozdziałów SponsorBlock jest dostępna tylko dla osób, które wykupią licencję, albo którym przyznano dostęp za darmo ze względu na swoje wcześniejszy wkład"
|
||||
},
|
||||
"chaptersPage2": {
|
||||
"message": "Uwaga: Przesyłanie rozdziałów jest nadal oparte na skalkulowanej reputacji. Kupowanie licencji pozwala tylko przeglądać rozdziały przesłane przez innych",
|
||||
"description": "On the chapters page for getting access to the paid chapters feature"
|
||||
},
|
||||
"chapterNewFeature": {
|
||||
"message": "Nowa funkcja: niestandardowe rozdziały ze źródeł społecznościowych. Są to sekcje niestandardowo nazwane w filmach, które mogą być ustawione w sposób bardziej precyzyjny. Kup licencję, aby wyświetlić rozdziały przedstawione na tym filmie, takie jak: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Nowa funkcja: niestandardowe rozdziały ze źródeł społecznościowych. Są to sekcje niestandardowo nazwane w filmach, które mogą być ustawione w sposób bardziej precyzyjny."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Aktualnie masz {0} na {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Renderizar segmentos como capítulos",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Mostrar Segmento Atual ao Lado do Tempo do Vídeo"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Votar nesse segmento positivamente"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Fechar Popup"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Ícone de Fechar"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Enviar Segmentos"
|
||||
},
|
||||
@@ -246,6 +252,12 @@
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Se o vídeo for novo e nenhum segmento for encontrado, continuaremos buscando enquanto você assiste."
|
||||
},
|
||||
"enableShowCategoryWithoutPermission": {
|
||||
"message": "Mostrar categorias no menu de envios mesmo sem permissão de envio"
|
||||
},
|
||||
"whatShowCategoryWithoutPermission": {
|
||||
"message": "Algumas categorias exigem autorização de envio devido a requisitos mínimos de reputação"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Mostrar notificação outra vez"
|
||||
},
|
||||
@@ -409,16 +421,16 @@
|
||||
"message": "Verifique status.sponsor.ajay.app para o status do servidor."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importar/Exportar seu ID de usuário"
|
||||
"message": "Importar/Exportar Seu UserID Privado"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Esta informação deve se mantida privada. Ela é como uma senha e não deve ser compartilhada. Outras pessoas poderão se passar por você caso obtenham acesso. Se estiver procurando por sua ID Pública de Usuário, clique no ícone de prancheta no popup."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Definir ID de usuário"
|
||||
"message": "Definir UserID Privado"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Atenção: A alteração do ID de usuário é permanente. Você tem certeza que deseja fazer isso? Certifique-se de fazer backup de seu ID antigo por precaução."
|
||||
"message": "Aviso: A modificação do ID de usuário privado é permanente. Você tem certeza de que quer fazer isso? Certifique-se de fazer backup do anterior."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Criado por"
|
||||
@@ -463,6 +475,12 @@
|
||||
"minDurationDescription": {
|
||||
"message": "Segmentos menores do que o valor definido não serão pulados ou mostrados no reprodutor."
|
||||
},
|
||||
"enableManualSkipOnFullVideo": {
|
||||
"message": "Usar o pulo manual quando houver um rótulo de vídeo completo"
|
||||
},
|
||||
"whatManualSkipOnFullVideo": {
|
||||
"message": "Para pessoas que desejam assistir ao vídeo sem interrupção se ele for totalmente patrocinado ou autopromoção."
|
||||
},
|
||||
"skipNoticeDuration": {
|
||||
"message": "Duração do aviso prévio de pular (segundos):"
|
||||
},
|
||||
@@ -511,9 +529,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Importar de um arquivo"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Essas são suas preferências no formato JSON. Isso inclui seu ID de usuário, então lembre-se de compartilhar com cuidado."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Definir Opções"
|
||||
},
|
||||
@@ -676,9 +691,6 @@
|
||||
"category_filler": {
|
||||
"message": "Enrolação/Piadas"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Cenas tangenciais inseridas apenas por enrolação ou humor que não são necessárias para compreender o tópico principal do vídeo. Isto não deve incluir segmentos que fornecem contexto ou detalhes de segundo plano."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Enrolação"
|
||||
},
|
||||
@@ -724,6 +736,12 @@
|
||||
"category_chapter": {
|
||||
"message": "Capítulo"
|
||||
},
|
||||
"category_chapter_description": {
|
||||
"message": "Capítulos personalizados que descrevem as principais seções de um vídeo."
|
||||
},
|
||||
"category_chapter_guideline1": {
|
||||
"message": "Não mencione os nomes dos patrocinadores"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Livestream: Leituras de Doação/Mensagem"
|
||||
},
|
||||
@@ -754,6 +772,9 @@
|
||||
"showOverlay_full": {
|
||||
"message": "Mostrar Rótulo"
|
||||
},
|
||||
"showOverlay_chapter": {
|
||||
"message": "Mostrar Capítulos"
|
||||
},
|
||||
"autoSkipOnMusicVideos": {
|
||||
"message": "Pular automaticamente todos os segmentos quando há um segmento que não é música"
|
||||
},
|
||||
@@ -881,6 +902,9 @@
|
||||
"categoryPillTitleText": {
|
||||
"message": "Este vídeo inteiro está rotulado como esta categoria e está muito integrado para poder ser separado"
|
||||
},
|
||||
"chapterNameTooltipWarning": {
|
||||
"message": "Um de seus nomes de capítulo é semelhante a uma categoria. Sempre que possível, você deve usar categorias."
|
||||
},
|
||||
"experiementOptOut": {
|
||||
"message": "Optar por sair de todos os experimentos futuros",
|
||||
"description": "This is used in a popup about a new experiment to get a list of unlisted videos to back up since all unlisted videos uploaded before 2017 will be set to private."
|
||||
@@ -888,6 +912,9 @@
|
||||
"hideForever": {
|
||||
"message": "Ocultar para sempre"
|
||||
},
|
||||
"warningChatInfo": {
|
||||
"message": "Percebemos que você estava cometendo alguns erros comuns que não são prejudiciais"
|
||||
},
|
||||
"Donate": {
|
||||
"message": "Doar"
|
||||
},
|
||||
@@ -960,6 +987,9 @@
|
||||
"LearnMore": {
|
||||
"message": "Saiba mais"
|
||||
},
|
||||
"FullDetails": {
|
||||
"message": "Ver Detalhes Completos"
|
||||
},
|
||||
"CopyDownvoteButtonInfo": {
|
||||
"message": "Dá voto negativo e cria uma cópia local para você reenviar"
|
||||
},
|
||||
@@ -984,6 +1014,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Ocultar segmento"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Pular segmento"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Reproduzir capítulo"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Use a roda do mouse enquanto mantêm o cursor sobre a caixa de edição para ajustar o tempo rapidamente. Combinações das teclas ctrl e shift podem ser usadas para refinar as mudanças."
|
||||
},
|
||||
@@ -1046,5 +1082,69 @@
|
||||
},
|
||||
"confirmResetToDefault": {
|
||||
"message": "Tem certeza de que deseja redefinir todas as configurações para os valores padrão? Essa ação não poderá ser desfeita."
|
||||
},
|
||||
"exportSegments": {
|
||||
"message": "Exportar segmentos"
|
||||
},
|
||||
"importSegments": {
|
||||
"message": "Importar segmentos"
|
||||
},
|
||||
"Import": {
|
||||
"message": "Importar",
|
||||
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
|
||||
},
|
||||
"selectYourCountry": {
|
||||
"message": "Selecione o seu país"
|
||||
},
|
||||
"unsubmittedSegmentCountsZero": {
|
||||
"message": "No momento, você não tem segmentos não enviados",
|
||||
"description": "Replaces 'unsubmittedSegmentCounts' string when there are no unsubmitted segments"
|
||||
},
|
||||
"unsubmittedSegmentsSingular": {
|
||||
"message": "segmento não enviado",
|
||||
"description": "Example: You currently have 1 *unsubmitted segment* on 1 video"
|
||||
},
|
||||
"unsubmittedSegmentsPlural": {
|
||||
"message": "segmentos não enviados",
|
||||
"description": "Example: You currently have 12 *unsubmitted segments* on 5 videos"
|
||||
},
|
||||
"videosSingular": {
|
||||
"message": "vídeo",
|
||||
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"
|
||||
},
|
||||
"videosPlural": {
|
||||
"message": "vídeos",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 *videos*"
|
||||
},
|
||||
"clearUnsubmittedSegments": {
|
||||
"message": "Excluir todos os segmentos",
|
||||
"description": "Label for a button in settings"
|
||||
},
|
||||
"clearUnsubmittedSegmentsConfirm": {
|
||||
"message": "Tem certeza de que deseja excluir todos os segmentos não enviados?",
|
||||
"description": "Confirmation message for the Clear unsubmitted segments button"
|
||||
},
|
||||
"showUnsubmittedSegments": {
|
||||
"message": "Mostrar segmentos",
|
||||
"description": "Show/hide button for the unsubmitted segments list"
|
||||
},
|
||||
"hideUnsubmittedSegments": {
|
||||
"message": "Ocultar segmentos",
|
||||
"description": "Show/hide button for the unsubmitted segments list"
|
||||
},
|
||||
"videoID": {
|
||||
"message": "ID do Vídeo",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"segmentCount": {
|
||||
"message": "Número de segmentos",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"actions": {
|
||||
"message": "Ações",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"exportSegmentsAsURL": {
|
||||
"message": "Compartilhar como URL"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,12 +307,6 @@
|
||||
"message": " das suas vidas",
|
||||
"description": "You've saved people from 887,362 segments (236d 15h 5.3 minutes of their lives)."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Definir ID de utilizador"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Atenção: A alteração do ID de utilizador é permanente. Tem certeza que a deseja? Certifique-se de fazer uma cópia de segurança do seu ID antigo por precaução."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Tem certeza que deseja redefinir?"
|
||||
},
|
||||
|
||||
@@ -387,18 +387,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Verificați status.sponsor.ajay.app pentru starea serverului."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importă/Exportă Id-ul Tău De Utilizator"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Aceste informații sunt private și nu ar trebui să fie dezvăluite nimănui. Dacă cineva are aceste informații, pot fi folosite pentru a vă imita. În cazul în care vă căutați ID-ul public de utilizator, dați click pe icoana de clipboard din popup."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Setează Id-ul Utilizatorului"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Atenție: Schimbarea Id-ului Utilizatorului este permanentă. Sunteți sigur că doriți să faceți asta? Asigurați-vă că ați făcut o copie de rezervă."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Creat De"
|
||||
},
|
||||
@@ -481,9 +472,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Încarcă din fișier"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Aceasta este întreaga configurație în format JSON. Asta include si ID-ul tău de utilizator, așa că fi sigur să împărtășești asta cu înțelepciune."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Setează Opțiuni"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Отображать сегменты как эпизоды",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Показывать название текущего сегмента рядом со временем"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Проголосовать за этот сегмент"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Закрыть окно"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Кнопка закрытия"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Отправить сегменты"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Смотрите состояние сервера на status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Импорт/Экспорт Вашего идентификатора пользователя"
|
||||
"message": "Импорт/Экспорт приватного UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Держите его в тайне. Относитесь к нему как к паролю и не передавайте никому. Если кто-то им завладеет, то сможет выдать себя за вас. Если вы ищете публичный ID пользователя, нажмите значок буфера обмена во всплывающем окне."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Установить идентификатор пользователя"
|
||||
"message": "Установить приватный UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Внимание: изменение идентификатора пользователя необратимо. Вы действительно хотите это сделать? Сделайте резервную копию на всякий случай."
|
||||
"message": "Внимание: изменение приватного UserID необратимо. Вы действительно хотите это сделать? Сделайте резервную копию на всякий случай."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Создано"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Загрузить из файла"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Все настройки в формате JSON. Этот файл содержит Ваш идентификатор пользователя, будьте осторожны когда делитесь этими данными."
|
||||
"message": "Все настройки в формате JSON. Этот файл содержит Ваш приватный UserID, будьте осторожны когда делитесь этими данными."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Параметры установки"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Заполнение отвлечёнными темами/шутками"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Сегменты, которые увеличивают длительность видео за счёт отвлечённых тем или шуток, но не требуются для понимания основного содержания. Не должно иметь сегментов, объясняющие контекст или предысторию."
|
||||
"message": "Сегменты, которые увеличивают длительность видео за счёт отвлечённых тем или шуток, но не требуются для понимания основного содержания. Не должно иметь сегментов, объясняющих контекст или предысторию. Это очень агрессивная категория, используется тогда, когда вам не до \"веселья\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Заполнитель"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Скрыть сегмент"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Пропустить сегмент"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Воспроизвести эпизод"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Наведите курсор на поле редактирования и используйте колесо мыши для быстрой настройки времени. Клавиши Ctrl или Shift могут быть использованы для точной настройки."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Новая функция: эпизоды от сообщества. Это разделы видео с пользовательскими названиями, которые могут быть помещены внутри других эпизодов для более точной разметки. Приобретите лицензию, чтобы видеть названия эпизодов, как, например, эпизоды в этом видео: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Новая функция: эпизоды от сообщества. Это разделы видео с пользовательскими названиями, которые могут быть помещены внутри других эпизодов для более точной разметки. У вас есть бесплатный доступ к этой функции, включите её в настройках."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Сейчас у вас есть {0} в {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Zobraziť segmenty ako kapitoly",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Zobraziť aktuálny segment vedľa času videa"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Hlasovať pre tento príspevok"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Zavrieť okno"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Ikona pre zatvorenie"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Odoslať segmenty"
|
||||
},
|
||||
@@ -387,18 +393,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Stav servera skontrolujete na status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Import/export vášho ID používateľa"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Toto si starostlivo uchovajte. Podobne ako heslo by ste to nemali s nikým zdieľať. Ak by to získal niekto ďalší, mohol by vám uškodiť. Ak hľadáte vaše verejné ID používateľa, stlačte ikonu schránky v podokne."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Nastaviť Používateľove ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Varovanie: Zmena ID používateľa je nezvratná. Naozaj to chcete spraviť? Pre istotu si staré ID používateľa zazálohujte."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Vytvoril"
|
||||
},
|
||||
@@ -481,9 +478,6 @@
|
||||
"exportOptions": {
|
||||
"message": "Import/export všetkých nastavení"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Toto sú vaše kompletné nastavenia vo formáte JSON. Obsahuje aj vaše Používateľské ID, takže s ním narábajte opatrne."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Nastaviť Nastavenia"
|
||||
},
|
||||
@@ -640,9 +634,6 @@
|
||||
"category_preview_guideline3": {
|
||||
"message": "Nie pre sekcie, ktoré majú dodatočný obsah"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Odbočky mimo tému pridané len pre zábavu, nepotrebné pre pochopenie hlavného obsahu videa. Nemalo by zahŕňať segmenty, ktoré vysvetľujú kontext alebo vedľajšie detaily."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Odbočka"
|
||||
},
|
||||
@@ -989,6 +980,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Skryť segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Preskočiť segment"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Prehrať kapitolu"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Čas môžete rýchlo zmeniť kolieskom myši, ak je kurzor nad zadávacím políčkom. Pre jemné zmeny pritom držte kláves ctrl alebo shift."
|
||||
},
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
"message": "Gör segment som kapitel",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Visa nuvarande segment bredvid videotid"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Rösta på detta inskick"
|
||||
},
|
||||
@@ -122,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "Stäng popup"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Stäng ikon"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Skicka in segment"
|
||||
},
|
||||
@@ -415,16 +421,16 @@
|
||||
"message": "Gå till status.sponsor.ajay.app för serverstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importera/Exportera ditt Användar-ID"
|
||||
"message": "Importera/Exportera ditt privata Användar-ID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Detta ska hållas privat. Detta är som ett lösenord och ska inte delas med någon. Om andra får tag i det kan de utge sig för att vara dig. Om du letar efter ditt offentliga Användar-ID kan du klicka på urklippsikonen i popupen."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ange Användar-ID"
|
||||
"message": "Ange privat Användar-ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Varning: Ändring av Användar-ID är permanent. Är du säker att du vill göra detta? Se till att ta en säkerhetskopia av ditt gamla för säkerhets skull."
|
||||
"message": "Varning: Ändring av ditt Användar-ID är permanent. Är du säker att du vill göra detta? Se till att ta en säkerhetskopia av ditt gamla för säkerhets skull."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Skapad av"
|
||||
@@ -524,7 +530,7 @@
|
||||
"message": "Ladda från fil"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Detta är alla dina alternativ i JSON-format. Det inkluderar ditt Användar-ID, så var noga med hur du hanterar informationen."
|
||||
"message": "Detta är hela din konfiguration i JSON-format. Det inkluderar ditt Användar-ID, så var noga med hur du hanterar informationen."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Ange alternativ"
|
||||
@@ -689,7 +695,7 @@
|
||||
"message": "Ämnesavvikelse/Skämt"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Tangentiella scener endast tillagda för utfyllnad eller humor som inte krävs för att förstå det huvudsakliga innehållet i videon. Detta bör inte omfatta segment som tillhandahåller innehåll eller bakgrundsdetaljer."
|
||||
"message": "Tangentiella scener endast för utfyllnad eller humor som inte krävs för att förstå det huvudsakliga innehållet i videon. Detta bör inte omfatta segment som tillhandahåller kontext eller bakgrundsdetaljer. Detta är en mycket aggressiv kategori avsedd för när du inte är på humör för \"kul\"."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Utfyllnad"
|
||||
@@ -1046,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Dölj segment"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Hoppa över segment"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Spela kapitel"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Använd mushjulet medan du håller muspekaren över redigeringsrutan för att snabbt justera tiden. Kombinationer av CTRL- eller SKIFT-tangenten kan användas för att finjustera tiden."
|
||||
},
|
||||
@@ -1174,6 +1186,9 @@
|
||||
"message": "Ny funktion: Crowd-sourced anpassade kapitel. Dessa är anpassade namngivna avsnitt i videor som kan staplas för att få mer och mer exakt. Köp en licens för att se de kapitel som lämnats på denna video såsom: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Ny funktion: Crowd-sourced anpassade kapitel. Dessa är anpassade namngivna avsnitt i videor som kan staplas för att få mer och mer exakt. För dig är det gratis, aktivera det i alternativen."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Du har för närvarande {0} på {1}",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
|
||||
@@ -381,18 +381,9 @@
|
||||
"statusReminder": {
|
||||
"message": "சேவையக நிலைக்கு status.sponsor.ajay.app ஐச் சரிபார்க்கவும்."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "உங்கள் பயனர் ஐடியை இறக்குமதி / ஏற்றுமதி செய்யுங்கள்"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "இதை தனிப்பட்டதாக வைத்திருக்க வேண்டும். இது கடவுச்சொல் போன்றது, அதை யாருடனும் பகிரக்கூடாது. யாரிடமாவது இது இருந்தால், அவர் உங்களைப் போல் ஆள்மாறாட்டம் செய்யலாம். உங்கள் பொது பயனர் IDயை நீங்கள் தேடுகிறீர்களானால், பாப்அப்பில் உள்ள கிளிப்போர்டு ஐகானைக் கிளிக் செய்யவும்."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "UserID ஐ அமைக்கவும்"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "எச்சரிக்கை: பயனர் ஐடியை மாற்றுவது நிரந்தரமானது. இதை நிச்சயமாக செய்ய விரும்புகிறீர்களா? உங்கள் பழையதை காப்புப்பிரதி எடுக்க உறுதிசெய்க."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "உருவாக்கியது"
|
||||
},
|
||||
@@ -481,9 +472,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "கோப்பிலிருந்து ஏற்று"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "இது JSON இல் உங்கள் முழு உள்ளமைவு. இது உங்கள் பயனர் ஐடியை உள்ளடக்கியது, எனவே இதை புத்திசாலித்தனமாக பகிர்ந்து கொள்ளுங்கள்."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "விருப்பங்களை அமைக்கவும்"
|
||||
},
|
||||
|
||||
@@ -295,15 +295,6 @@
|
||||
"statusReminder": {
|
||||
"message": "సర్వర్ స్థితి కోసం status.sponsor.ajay.app ని తనిఖీ చేయండి."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "మీ యూజర్ఐడిని దిగుమతి / ఎగుమతి చేయండి"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "UserID ని సెట్ చేయండి"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "హెచ్చరిక: యూజర్ఐడిని మార్చడం శాశ్వతం. మీరు దీన్ని ఖచ్చితంగా చేయాలనుకుంటున్నారా? ఒకవేళ మీ పాతదాన్ని బ్యాకప్ చేయాలని నిర్ధారించుకోండి."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "సృష్టికర్త"
|
||||
},
|
||||
@@ -361,9 +352,6 @@
|
||||
"exportOptions": {
|
||||
"message": "అన్ని ఎంపికలను దిగుమతి / ఎగుమతి చేయండి"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "ఇది JSON లో మీ మొత్తం కాన్ఫిగరేషన్. ఇది మీ యూజర్ఐడిని కలిగి ఉంది, కాబట్టి దీన్ని తెలివిగా పంచుకోండి."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "ఎంపికలను సెట్ చేయండి"
|
||||
},
|
||||
|
||||
@@ -26,11 +26,18 @@
|
||||
"message": "kısım"
|
||||
},
|
||||
"SegmentsCap": {
|
||||
"message": "Segmentler"
|
||||
"message": "Kısımlar"
|
||||
},
|
||||
"Chapters": {
|
||||
"message": "Bölümler"
|
||||
},
|
||||
"renderAsChapters": {
|
||||
"message": "Kısımları bölüm olarak göster",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "Geçerli kısmı video zamanının yanında göster"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Bu öneriye oy ver"
|
||||
},
|
||||
@@ -118,9 +125,15 @@
|
||||
"closePopup": {
|
||||
"message": "Açılır Pencereyi kapat"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "Kapat Simgesi"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Kısımları gönder"
|
||||
},
|
||||
"sortSegments": {
|
||||
"message": "Kısımları Sırala"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Bunu göndermek istediğinize emin misiniz?"
|
||||
},
|
||||
@@ -239,6 +252,12 @@
|
||||
"whatRefetchWhenNotFound": {
|
||||
"message": "Eğer video yeni ve kısımları bulunmuyorsa, sen videoyu izlerken her birkaç dakikada bir kısımları edinmeye çalışır."
|
||||
},
|
||||
"enableShowCategoryWithoutPermission": {
|
||||
"message": "Gönderim izni olmasa bile gönderim menüsünde kategorileri gösterme"
|
||||
},
|
||||
"whatShowCategoryWithoutPermission": {
|
||||
"message": "Bazı kategoriler, minimum itibar gereksinimleri nedeniyle göndermek için izin gerektirir"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Uyarıyı Tekrar Göster"
|
||||
},
|
||||
@@ -402,16 +421,16 @@
|
||||
"message": "Sunucu durumu için status.sponsor.ajay.app kontrol edin."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Kullanıcı kimliğini Dışarı/İçeri Aktar"
|
||||
"message": "Özel Kullanıcı Kimliğini İçe/Dışa Aktar"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Bu gizli tutulmalıdır. Bu bir şifre gibidir ve kimseyle paylaşılmamalıdır. Eğer birisi buna sahipse, seni taklit edebilir. Herkese açık kullanıcı kimliğinizi arıyorsanız, açılır pencerede pano simgesine tıklayın."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Kullanıcı kimliği Belirle"
|
||||
"message": "Özel Kullanıcı Kimliğini Ayarla"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Uyarı: Kullanıcı kimliği değiştirmek kalıcıdır. Bunu yapmak istediğinizden emin misiniz? Eskisini yedeklediğinizden emin olun."
|
||||
"message": "Uyarı: Özel Kullanıcı Kimliğini değiştirmek kalıcıdır. Bunu yapmak istediğinizden emin misiniz? Her ihtimale karşı eskisini yedeklediğinizden emin olun."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Oluşturan"
|
||||
@@ -456,6 +475,12 @@
|
||||
"minDurationDescription": {
|
||||
"message": "Ayarlanan değerden daha kısa kısımlar atlanmayacak veya oynatıcıda gösterilmeyecektir."
|
||||
},
|
||||
"enableManualSkipOnFullVideo": {
|
||||
"message": "Tam bir video etiketi mevcut olduğunda manuel atlama özelliğini kullanın"
|
||||
},
|
||||
"whatManualSkipOnFullVideo": {
|
||||
"message": "Video boyunca sponsorlu veya kendi reklamını yapıyorsa videoyu kesintisiz izlemek isteyenler için."
|
||||
},
|
||||
"skipNoticeDuration": {
|
||||
"message": "Atlandı uyarısı süresi (saniye cinsinden):"
|
||||
},
|
||||
@@ -505,7 +530,7 @@
|
||||
"message": "Dosyadan yükle"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Bu, JSON formatında bütün kurulumunuzu gösterir. Kullanıcı kimliğinizi içerir, bu sebeple paylaşırken dikkatli olun."
|
||||
"message": "Bu, JSON'daki tüm yapılandırmanızdır. Buna Özel Kullanıcı Kimliğiniz de dahildir, bu yüzden bunu paylaşırken dikkatli olun."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Seçenekleri Ayarla"
|
||||
@@ -654,6 +679,9 @@
|
||||
"category_preview": {
|
||||
"message": "Ön İzleme/Özet"
|
||||
},
|
||||
"category_preview_description": {
|
||||
"message": "Bu videoda veya diğer videolarda neler olduğunu gösteren, videonun ilerleyen zamanında tüm bilgilerin tekrarlandığı bir dizi klip koleksiyonudur."
|
||||
},
|
||||
"category_preview_guideline1": {
|
||||
"message": "Daha sonra veya gelecekteki bir videoda görünen klipler"
|
||||
},
|
||||
@@ -667,7 +695,7 @@
|
||||
"message": "Konuyla Alakasız / Şaka"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Videonun ana içeriğini anlamak için gerekli olmayan, yalnızca alakasız konu veya mizah için eklenen sahneler. Bu, alakalı veya arka plan ayrıntısı veren kısımları içermemelidir."
|
||||
"message": "Videonun ana içeriğini anlamak için gerekli olmayan, yalnızca zaman geçirme veya mizah için eklenen teğet sahnelerdir. Bu, bağlam veya arka plan ayrıntılarını sağlayan kısımları içermemelidir. Bu, \"eğlence\" havasında olmadığınız zamanlar için tasarlanmış çok agresif bir kategoridir."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Alakasız Konu"
|
||||
@@ -714,9 +742,18 @@
|
||||
"category_chapter": {
|
||||
"message": "Bölüm"
|
||||
},
|
||||
"category_chapter_description": {
|
||||
"message": "Bir videonun ana kısımlarını açıklayan özel adlandırılmış bölümler."
|
||||
},
|
||||
"category_chapter_guideline1": {
|
||||
"message": "Sponsor marka isimlerinden bahsetme"
|
||||
},
|
||||
"category_chapter_guideline2": {
|
||||
"message": "Genel kısımlar için daha büyük bölümler kullanın"
|
||||
},
|
||||
"category_chapter_guideline3": {
|
||||
"message": "Daha küçük bölümler daha büyük bölümlerin içine yerleştirilebilir"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Canlı Yayın: Bağış/Mesaj Okuma"
|
||||
},
|
||||
@@ -822,6 +859,9 @@
|
||||
"description": "This error appears in an alert when they try to whitelist a channel and the extension is unable to determine what channel they are looking at.",
|
||||
"message": "Kanal kimliği henüz yüklenmedi. Gömülü bir video kullanıyorsanız, bunun yerine YouTube ana sayfasından izlemeyi deneyin. Bu, YouTube düzenindeki değişikliklerden de kaynaklanabilir, eğer öyleyse, buraya bir yorum yazın:"
|
||||
},
|
||||
"invidiousPermissionRefresh": {
|
||||
"message": "Tarayıcınız, eklentinin Invidious ve diğer 3. taraf sitelerde çalışması için gerekli izni kaldırdı. Bu izni yeniden etkinleştirmek için lütfen aşağıdaki butona tıklayın."
|
||||
},
|
||||
"acceptPermission": {
|
||||
"message": "İzni kabul et"
|
||||
},
|
||||
@@ -888,6 +928,9 @@
|
||||
"categoryPillTitleText": {
|
||||
"message": "Bu videonun bütünü bu şekilde sınıflandırılmış ve kısımları birbirinden ayrılamayacak kadar sıkı bütünleştirilmiş"
|
||||
},
|
||||
"chapterNameTooltipWarning": {
|
||||
"message": "Bölüm adlarınızdan biri bir kategoriye benziyor. Bunun yerine mümkün olduğunda kategorileri kullanmalısınız."
|
||||
},
|
||||
"experiementOptOut": {
|
||||
"message": "Gelecekteki deneylerin hiçbirine katılma",
|
||||
"description": "This is used in a popup about a new experiment to get a list of unlisted videos to back up since all unlisted videos uploaded before 2017 will be set to private."
|
||||
@@ -895,6 +938,9 @@
|
||||
"hideForever": {
|
||||
"message": "Asla gösterme"
|
||||
},
|
||||
"warningChatInfo": {
|
||||
"message": "Kötü amaçlı olmayan bazı yaygın hatalar yaptığınızı fark ettik"
|
||||
},
|
||||
"warningTitle": {
|
||||
"message": "Bir uyarı aldın"
|
||||
},
|
||||
@@ -904,6 +950,9 @@
|
||||
"warningConfirmButton": {
|
||||
"message": "Nedenini anlıyorum"
|
||||
},
|
||||
"warningError": {
|
||||
"message": "Uyarıyı tanımlamaya çalışırken hata oluştu:"
|
||||
},
|
||||
"Donate": {
|
||||
"message": "Bağış Yap"
|
||||
},
|
||||
@@ -1003,6 +1052,12 @@
|
||||
"hideSegment": {
|
||||
"message": "Segmenti gizleyin"
|
||||
},
|
||||
"skipSegment": {
|
||||
"message": "Kısmı atla"
|
||||
},
|
||||
"playChapter": {
|
||||
"message": "Bölümü oynat"
|
||||
},
|
||||
"SponsorTimeEditScrollNewFeature": {
|
||||
"message": "Zaman aralığını hızlı bir şekilde ayarlamak için düzenleme kutusunun üzerinde fare tekerini kullanın. Değişikliklere ince ayar yapmak için ctrl veya shift tuşunun kombinasyonları kullanılabilir."
|
||||
},
|
||||
@@ -1010,11 +1065,11 @@
|
||||
"message": "Yeni! Videonun bütünü sponsor veya kendi reklamıysa bu uyarıyı görün"
|
||||
},
|
||||
"dayAbbreviation": {
|
||||
"message": "d",
|
||||
"message": "g",
|
||||
"description": "100d"
|
||||
},
|
||||
"hourAbbreviation": {
|
||||
"message": "h",
|
||||
"message": "s",
|
||||
"description": "100h"
|
||||
},
|
||||
"optionsTabBehavior": {
|
||||
@@ -1069,22 +1124,48 @@
|
||||
"exportSegments": {
|
||||
"message": "Segmentleri dışa aktar"
|
||||
},
|
||||
"importSegments": {
|
||||
"message": "Kısımları içe aktar"
|
||||
},
|
||||
"Import": {
|
||||
"message": "İçeri aktar",
|
||||
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
|
||||
},
|
||||
"redeemSuccess": {
|
||||
"message": "Kullanım Başarılı!"
|
||||
},
|
||||
"redeemFailed": {
|
||||
"message": "Lisans anahtarı geçersiz"
|
||||
},
|
||||
"hideUpsells": {
|
||||
"message": "Ekstra ödeme olmadan kullanılamayan özellikleri gizle"
|
||||
},
|
||||
"chooseACountry": {
|
||||
"message": "Bir ülke seçiniz"
|
||||
},
|
||||
"noDiscount": {
|
||||
"message": "İndirim için uygun değilsiniz"
|
||||
},
|
||||
"discountLink": {
|
||||
"message": "İndirim Bağlantısı (Pembe fiyatı gör)"
|
||||
},
|
||||
"selectYourCountry": {
|
||||
"message": "Ülkenizi seçin"
|
||||
},
|
||||
"alreadyDonated": {
|
||||
"message": "Şimdiye kadar herhangi bir miktarda bağış yaptıysanız, bu adrese e-posta göndererek ücretsiz erişim hakkına sahip olabilirsin:",
|
||||
"description": "After the colon is an email address"
|
||||
},
|
||||
"cantAfford": {
|
||||
"message": "Lisans satın almaya gücünüz yetmiyorsa, indirim almaya uygun olup olmadığınızı görmek için {here} tıklayın",
|
||||
"description": "Keep the curly braces. The word 'here' should be translated as well."
|
||||
},
|
||||
"patreonSignIn": {
|
||||
"message": "Patreon ile giriş yap"
|
||||
},
|
||||
"redeem": {
|
||||
"message": "Kullan"
|
||||
},
|
||||
"joinOnPatreon": {
|
||||
"message": "Patreon'da Destekle"
|
||||
},
|
||||
@@ -1093,5 +1174,74 @@
|
||||
},
|
||||
"enterLicenseKey": {
|
||||
"message": "Lisans Anahtarını Girin"
|
||||
},
|
||||
"chaptersPage1": {
|
||||
"message": "SponsorBlock'un topluluk kaynaklı bölümler özelliği yalnızca lisans satın alan veya geçmiş katkılarından dolayı ücretsiz erişim hakkı verilen kişiler tarafından kullanılabilir"
|
||||
},
|
||||
"chaptersPage2": {
|
||||
"message": "Not: Bölüm gönderme izni hala hesaplanan itibara dayanmaktadır. Bir lisans satın almak, yalnızca başkaları tarafından gönderilen bölümleri görüntülemenize izin verir",
|
||||
"description": "On the chapters page for getting access to the paid chapters feature"
|
||||
},
|
||||
"chapterNewFeature": {
|
||||
"message": "Yeni Özellik: Topluluk kaynaklı özel bölümler. Bunlar, giderek daha doğru hale gelmek için istiflenebilen videolardaki özel adlandırılmış bölümlerdir. Bu videodaki gibi gönderilen bölümleri görüntülemek için bir lisans satın alın: ",
|
||||
"description": "After the comma, a list of chapters for this video will appear"
|
||||
},
|
||||
"chapterNewFeature2": {
|
||||
"message": "Yeni Özellik: Topluluk kaynaklı özel bölümler. Bunlar, giderek daha doğru hale gelmek için istiflenebilen videolardaki özel adlandırılmış bölümlerdir. Ücretsiz erişiminiz var, seçeneklerden etkinleştirin."
|
||||
},
|
||||
"unsubmittedSegmentCounts": {
|
||||
"message": "Şu anda {1} da {0} var",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
|
||||
},
|
||||
"unsubmittedSegmentCountsZero": {
|
||||
"message": "Gönderilmemiş kısmınız bulunmamaktadır",
|
||||
"description": "Replaces 'unsubmittedSegmentCounts' string when there are no unsubmitted segments"
|
||||
},
|
||||
"unsubmittedSegmentsSingular": {
|
||||
"message": "gönderilmemiş kısım",
|
||||
"description": "Example: You currently have 1 *unsubmitted segment* on 1 video"
|
||||
},
|
||||
"unsubmittedSegmentsPlural": {
|
||||
"message": "gönderilmemiş kısımlar",
|
||||
"description": "Example: You currently have 12 *unsubmitted segments* on 5 videos"
|
||||
},
|
||||
"videosSingular": {
|
||||
"message": "video",
|
||||
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"
|
||||
},
|
||||
"videosPlural": {
|
||||
"message": "videolar",
|
||||
"description": "Example: You currently have 12 unsubmitted segments on 5 *videos*"
|
||||
},
|
||||
"clearUnsubmittedSegments": {
|
||||
"message": "Tüm kısımları temizle",
|
||||
"description": "Label for a button in settings"
|
||||
},
|
||||
"clearUnsubmittedSegmentsConfirm": {
|
||||
"message": "Gönderilmemiş tüm kısımları temizlemek istediğinizden emin misiniz?",
|
||||
"description": "Confirmation message for the Clear unsubmitted segments button"
|
||||
},
|
||||
"showUnsubmittedSegments": {
|
||||
"message": "Kısımları göster",
|
||||
"description": "Show/hide button for the unsubmitted segments list"
|
||||
},
|
||||
"hideUnsubmittedSegments": {
|
||||
"message": "Kısımları gizle",
|
||||
"description": "Show/hide button for the unsubmitted segments list"
|
||||
},
|
||||
"videoID": {
|
||||
"message": "Video ID",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"segmentCount": {
|
||||
"message": "Kısım Sayısı",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"actions": {
|
||||
"message": "İşlemler",
|
||||
"description": "Header of the unsubmitted segments list"
|
||||
},
|
||||
"exportSegmentsAsURL": {
|
||||
"message": "URL olarak paylaş"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,18 +408,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Дивіться стан сервера на status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Імпортувати/Експортувати Ваш ідентифікатор користувача"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Тримайте його в таємниці. Ставтеся до нього як до паролю і не передавайте нікому. Якщо хтось їм заволодіє, то зможе видати себе за вас. Якщо ви шукаєте публічний ID користувача, натисніть значок буфера обміну у спливаючому вікні."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Встановити ідентифікатор користувача"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Увага: зміна ідентифікатора користувача є незворотнім. Ви дійсно хочете це зробити? Зробіть резервну копію вашого старого про всяк випадок."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Створено"
|
||||
},
|
||||
@@ -511,9 +502,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Завантажити з файлу"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Це вся конфігурація в форматі JSON. Цей файл містить Ваш ідентифікатор користувача, тому не забудьте ділитися з цим розумно."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Встановити параметри"
|
||||
},
|
||||
@@ -634,9 +622,6 @@
|
||||
"category_filler": {
|
||||
"message": "Дотичне наповнення/Жарти"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Дотичні сцени додані лише для наповнення або гумору, які не потрібні для розуміння основного вмісту відео. Це не повинно включати сегменти, що надають контекст або передісторію."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Наповнення"
|
||||
},
|
||||
|
||||
@@ -387,18 +387,9 @@
|
||||
"statusReminder": {
|
||||
"message": "Truy cập trang status.sponsor.ajay.app để biết tình trạng máy chủ."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Nhập/Xuất mã người dùng của bạn"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Đây là mã cần được giữ bí mật. Nó giống như mật khẩu và không nên được chia sẻ cho bất kì ai khác. Nếu có ai đó lấy được mã này, họ có thể mạo danh bạn. Còn nếu như bạn đang tìm khoá ID công khai, hãy nhấn vào nút \"Sao chép Public UserID\" trong popup của SponsorBlock."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Đặt mã người dùng"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Cảnh báo: Việc thay đổi mã người dùng có tác dụng vĩnh viễn. Bạn có chắc muốn thay đổi không? Hãy nhớ sao lưu lại mã người dùng cũ để đề phòng."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Được tạo bởi"
|
||||
},
|
||||
@@ -490,9 +481,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "Tải từ tệp"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Đây là toàn bộ cấu hình của bạn trong tệp JSON. Nó chứa cả mã người dùng của bạn, nên hãy chia sẻ cẩn thận."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Đặt tùy chọn"
|
||||
},
|
||||
@@ -645,9 +633,6 @@
|
||||
"category_filler": {
|
||||
"message": "Cảnh phụ"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "Tập hợp các cảnh không bắt buộc để xem trong video. Điều này không bao gồm các đoạn chứa nội dung hoặc nói về ngữ cảnh của video."
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "Cảnh phụ"
|
||||
},
|
||||
|
||||
@@ -25,6 +25,19 @@
|
||||
"Segments": {
|
||||
"message": "片段"
|
||||
},
|
||||
"SegmentsCap": {
|
||||
"message": "片段"
|
||||
},
|
||||
"Chapters": {
|
||||
"message": "章节"
|
||||
},
|
||||
"renderAsChapters": {
|
||||
"message": "将片段显示为章节",
|
||||
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
|
||||
},
|
||||
"showSegmentNameInChapterBar": {
|
||||
"message": "在视频时间旁显示当前片段"
|
||||
},
|
||||
"upvoteButtonInfo": {
|
||||
"message": "为这个提交点赞"
|
||||
},
|
||||
@@ -52,6 +65,9 @@
|
||||
"reskip": {
|
||||
"message": "继续跳过"
|
||||
},
|
||||
"unmute": {
|
||||
"message": "取消静音"
|
||||
},
|
||||
"paused": {
|
||||
"message": "已暂停"
|
||||
},
|
||||
@@ -85,6 +101,9 @@
|
||||
"noVideoID": {
|
||||
"message": "未找到 YouTube 视频。\n如果识别错误,请刷新此页面。"
|
||||
},
|
||||
"refreshSegments": {
|
||||
"message": "刷新片段"
|
||||
},
|
||||
"success": {
|
||||
"message": "成功 !"
|
||||
},
|
||||
@@ -106,6 +125,9 @@
|
||||
"closePopup": {
|
||||
"message": "关闭弹窗"
|
||||
},
|
||||
"closeIcon": {
|
||||
"message": "关闭图标"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "提交片段"
|
||||
},
|
||||
@@ -155,6 +177,9 @@
|
||||
"setUsername": {
|
||||
"message": "设定用户名"
|
||||
},
|
||||
"copySegmentID": {
|
||||
"message": "复制片段 ID"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "快加入官方 Discord 服务器来提供建议与反馈!"
|
||||
},
|
||||
@@ -179,6 +204,9 @@
|
||||
"hideInfoButton": {
|
||||
"message": "在 Youtube 播放器上隐藏信息按钮"
|
||||
},
|
||||
"autoHideInfoButton": {
|
||||
"message": "自动隐藏信息按钮"
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "在 Youtube 播放器上隐藏删除按钮"
|
||||
},
|
||||
@@ -251,6 +279,13 @@
|
||||
"skip": {
|
||||
"message": "跳过"
|
||||
},
|
||||
"mute": {
|
||||
"message": "静音"
|
||||
},
|
||||
"full": {
|
||||
"message": "整个视频",
|
||||
"description": "Used for the name of the option to label an entire video as sponsor or self promotion."
|
||||
},
|
||||
"skip_category": {
|
||||
"message": "跳过{0}?"
|
||||
},
|
||||
@@ -298,21 +333,15 @@
|
||||
"statusReminder": {
|
||||
"message": "在 status.sponsor.ajay.app 检查服务器状态。"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "导入/导出您的用户 ID"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "设定用户 ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "警告:更改用户 ID 是永久性的。您确定要这么做吗?请务必备份您的旧用户 ID 以防万一。"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "创建者"
|
||||
},
|
||||
"supportOtherSites": {
|
||||
"message": "支持第三方 YouTube 网站"
|
||||
},
|
||||
"supportedSites": {
|
||||
"message": "支持的站点: "
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "启用 Invidious 支持,禁用自动跳过,隐藏按钮等等。"
|
||||
},
|
||||
@@ -367,8 +396,14 @@
|
||||
"exportOptions": {
|
||||
"message": "导入/导出所有选项"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "这是您全部配置的 JSON 格式。它包含了您的用户 ID ,所以您一定要谨慎的保管它。"
|
||||
"exportOptionsCopy": {
|
||||
"message": "编辑/复制"
|
||||
},
|
||||
"exportOptionsDownload": {
|
||||
"message": "保存到文件"
|
||||
},
|
||||
"exportOptionsUpload": {
|
||||
"message": "从文件加载"
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "设定选项"
|
||||
@@ -394,6 +429,9 @@
|
||||
"preview": {
|
||||
"message": "预览"
|
||||
},
|
||||
"unsubmitted": {
|
||||
"message": "未提交"
|
||||
},
|
||||
"inspect": {
|
||||
"message": "检查"
|
||||
},
|
||||
@@ -412,22 +450,38 @@
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "调试信息已复制到剪切板中。 您可以随意移除任何您不想分享的信息。请将其另存为 .txt 文件或粘贴到错误报告中。"
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "此快捷键已绑定到另一个动作。请选择其他快捷键。"
|
||||
},
|
||||
"to": {
|
||||
"message": "到",
|
||||
"description": "Used between segments. Example: 1:20 to 1:30"
|
||||
},
|
||||
"CopiedExclamation": {
|
||||
"message": "复制成功!",
|
||||
"description": "Used after something has been copied to the clipboard. Example: 'Copied!'"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "赞助商广告"
|
||||
},
|
||||
"category_sponsor_description": {
|
||||
"message": "付费推广、付费推荐和直接广告。不应用于自我推广或免费提及、推荐他们喜欢的事物/创作者/网站/产品。"
|
||||
},
|
||||
"category_sponsor_guideline1": {
|
||||
"message": "付费推广"
|
||||
},
|
||||
"category_sponsor_guideline2": {
|
||||
"message": "捐赠或自制周边不属于此项"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "未收钱的/自我推销"
|
||||
},
|
||||
"category_selfpromo_description": {
|
||||
"message": "类似于 “赞助商广告” ,但为无报酬或自我推广。包括有关商品、捐赠的部分或合作者的信息。"
|
||||
},
|
||||
"category_selfpromo_guideline1": {
|
||||
"message": "捐赠、会员和自制周边"
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "互动提醒(订阅)"
|
||||
},
|
||||
|
||||
@@ -408,18 +408,9 @@
|
||||
"statusReminder": {
|
||||
"message": "在 status.sponsor.ajay.app 檢查伺服器狀態"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "匯入/匯出您的使用者 ID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "密鑰應被保密。它就像是密碼,不應與他人分享。若密鑰落入他人手中,他人將可以冒充你。若你在尋找你的公開使用者ID,點擊彈出視窗上的剪貼簿圖示"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "設定使用者 ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "警告:更改用戶 ID 是永久性的。您確定要這麼做嗎?請務必備份您的舊用戶 ID 來以防萬一。"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "作者"
|
||||
},
|
||||
@@ -517,9 +508,6 @@
|
||||
"exportOptionsUpload": {
|
||||
"message": "從檔案載入"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "這是您全部設定的 JSON 格式。它包含了您的用戶 ID ,所以您一定要謹慎的保管它。"
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "設定選項"
|
||||
},
|
||||
@@ -682,9 +670,6 @@
|
||||
"category_filler": {
|
||||
"message": "離題閒聊/玩笑"
|
||||
},
|
||||
"category_filler_description": {
|
||||
"message": "與影片主要內容無關的填充詞或笑話,但不應包含與前後或背景有關者"
|
||||
},
|
||||
"category_filler_short": {
|
||||
"message": "填充詞"
|
||||
},
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
transform: scaleY(0.625) translateY(-30%) translateY(1.5px);
|
||||
}
|
||||
|
||||
.ytp-big-mode .sponsorTwoTooltips .sponsorCategoryTooltip {
|
||||
top: 75px !important;
|
||||
}
|
||||
|
||||
.progress-bar-line > #previewbar {
|
||||
height: 3px;
|
||||
}
|
||||
@@ -738,7 +742,7 @@ input::-webkit-inner-spin-button {
|
||||
}
|
||||
|
||||
.sponsorBlockLockedColor {
|
||||
color: #ffc83d;
|
||||
color: #ffc83d !important;
|
||||
}
|
||||
|
||||
.sponsorBlockRectangleTooltip {
|
||||
|
||||
@@ -317,12 +317,12 @@ input[type='number'] {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.disabled .slider {
|
||||
.sb-toggle-option.disabled .slider {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* To hide everything except upsell button */
|
||||
.disabled td:not(.skipOption), .disabled td.skipOption > :not(.upsellButton) {
|
||||
.disabled td:not(.skipOption, .categoryExtraOptions), .disabled td.skipOption > :not(.upsellButton) {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,37 +50,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
object-assign
|
||||
4.1.1 <https://github.com/sindresorhus/object-assign>
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
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.
|
||||
|
||||
|
||||
******************************
|
||||
|
||||
react
|
||||
17.0.2 <https://github.com/facebook/react>
|
||||
18.2.0 <https://github.com/facebook/react>
|
||||
MIT License
|
||||
|
||||
Copyright (c) Facebook, Inc. and its affiliates.
|
||||
@@ -107,7 +80,7 @@ SOFTWARE.
|
||||
******************************
|
||||
|
||||
react-dom
|
||||
17.0.2 <https://github.com/facebook/react>
|
||||
18.2.0 <https://github.com/facebook/react>
|
||||
MIT License
|
||||
|
||||
Copyright (c) Facebook, Inc. and its affiliates.
|
||||
@@ -134,7 +107,7 @@ SOFTWARE.
|
||||
******************************
|
||||
|
||||
scheduler
|
||||
0.20.2 <https://github.com/facebook/react>
|
||||
0.23.0 <https://github.com/facebook/react>
|
||||
MIT License
|
||||
|
||||
Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
||||
@@ -403,7 +403,7 @@
|
||||
*/
|
||||
#mainControls {
|
||||
margin: 16px;
|
||||
padding: 8px 12px;
|
||||
padding: 8px 14px;
|
||||
text-align: left;
|
||||
border-radius: 8px;
|
||||
border: 2px solid var(--sb-grey-bg-color);
|
||||
@@ -411,10 +411,11 @@
|
||||
.sponsorStartHint {
|
||||
display: block;
|
||||
text-align: left;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic buttons used for "Segment Starts Now" and "Submit Times"
|
||||
* Generic red buttons used for "Start Segment Now", "Submit Times" etc.
|
||||
*/
|
||||
.sbMediumButton {
|
||||
border: none;
|
||||
@@ -448,24 +449,23 @@
|
||||
/*
|
||||
* Your Work box
|
||||
*/
|
||||
.sbYourWorkCols {
|
||||
.sbYourWorkBox {
|
||||
margin: 16px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 8px;
|
||||
border: 2px solid var(--sb-grey-bg-color);
|
||||
}
|
||||
.sbYourWorkCols > div {
|
||||
.sbYourWorkCols {
|
||||
display: flex;
|
||||
border-top: 2px solid var(--sb-grey-bg-color);
|
||||
border-bottom: 2px solid var(--sb-grey-bg-color);
|
||||
}
|
||||
|
||||
.sbStatsSentence {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding: 6px 14px;
|
||||
}
|
||||
|
||||
.sbStatsSentence .sbExtraInfo {
|
||||
.sbExtraInfo {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -473,37 +473,28 @@
|
||||
* Increase font size of username input and display
|
||||
*/
|
||||
#usernameValue,
|
||||
#usernameInput,
|
||||
#sponsorTimesContributionsDisplay {
|
||||
#usernameInput {
|
||||
font-size: 16px;
|
||||
flex: 1 0;
|
||||
}
|
||||
#sponsorTimesContributionsDisplay {
|
||||
font-size: 16px;
|
||||
}
|
||||
/*
|
||||
* Improve alignment of username and submissions
|
||||
*/
|
||||
#usernameElement,
|
||||
#usernameElement > p,
|
||||
#sponsorTimesContributionsContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
}
|
||||
#usernameElement > span,
|
||||
#sponsorTimesContributionsContainer {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#sponsorTimesContributionsContainer {
|
||||
margin-left: 8px;
|
||||
padding-left: 8px;
|
||||
border-left: 2px solid var(--sb-grey-bg-color);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Username
|
||||
*/
|
||||
#usernameElement {
|
||||
padding: 8px;
|
||||
padding: 8px 14px;
|
||||
min-width: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
#setUsernameContainer {
|
||||
display: flex;
|
||||
@@ -549,14 +540,15 @@
|
||||
width: calc(100% - 68px);
|
||||
text-overflow: ellipsis;
|
||||
color: var(--sb-main-fg-color);
|
||||
background: var(--sb-grey-bg-color);
|
||||
background-color: var(--sb-grey-bg-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Submissions
|
||||
*/
|
||||
#sponsorTimesContributionsContainer {
|
||||
padding: 8px;
|
||||
padding: 8px 14px;
|
||||
border-left: 2px solid var(--sb-grey-bg-color);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -571,14 +563,13 @@
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
background: #333;
|
||||
cursor: pointer;
|
||||
background-color: #333;
|
||||
padding: 4px 8px;
|
||||
font-weight: 500;
|
||||
margin: 2px 1px;
|
||||
}
|
||||
#sbFooter a:hover {
|
||||
background: #444;
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
#sponsorTimesDonateContainer a {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div id="sponsorblockPopup" class="sponsorBlockPageBody sb-preload">
|
||||
|
||||
<button id="sbCloseButton" title="__MSG_closePopup__" class="sbCloseButton hidden">
|
||||
<img src="icons/close.png" width="15" height="15">
|
||||
<img src="icons/close.png" width="15" height="15" alt="Close icon">
|
||||
</button>
|
||||
|
||||
<div id="sbBetaServerWarning" class="hidden" title="__MSG_openOptionsPage__">
|
||||
@@ -24,7 +24,7 @@
|
||||
<img src="icons/IconSponsorBlocker256px.png" alt="SponsorBlock" width="40" height="40" id="sponsorBlockPopupLogo">
|
||||
<p class="u-mZ">SponsorBlock</p>
|
||||
</header>
|
||||
|
||||
|
||||
<div id="videoInfo">
|
||||
<!-- Loading text -->
|
||||
<p id="loadingIndicator" class="u-mZ grey-text">__MSG_noVideoID__</p>
|
||||
@@ -64,11 +64,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Toggle Box -->
|
||||
<div class="sbControlsMenu">
|
||||
<label id="whitelistButton" for="whitelistToggle" class="hidden sbControlsMenu-item">
|
||||
<input type="checkbox" style="display:none;" id="whitelistToggle">
|
||||
<input type="checkbox" style="display: none" id="whitelistToggle">
|
||||
<svg viewBox="0 0 24 24" width="23" height="23" class="SBWhitelistIcon sbControlsMenu-itemIcon">
|
||||
<path d="M24 10H14V0h-4v10H0v4h10v10h4V14h10z" />
|
||||
</svg>
|
||||
@@ -78,7 +78,7 @@
|
||||
<!--github: mbledkowski/toggle-switch-->
|
||||
<label id="disableExtension" for="toggleSwitch" class="toggleSwitchContainer sbControlsMenu-item">
|
||||
<span class="toggleSwitchContainer-switch">
|
||||
<input type="checkbox" style="display:none;" id="toggleSwitch" checked>
|
||||
<input type="checkbox" style="display: none" id="toggleSwitch" checked>
|
||||
<span class="switchBg shadow"></span>
|
||||
<span class="switchBg white"></span>
|
||||
<span class="switchBg green"></span>
|
||||
@@ -99,29 +99,29 @@
|
||||
|
||||
<!-- Submit box -->
|
||||
<div id="mainControls" style="display: none">
|
||||
<p class="sbHeader">
|
||||
<h1 class="sbHeader">
|
||||
__MSG_recordTimesDescription__
|
||||
</p>
|
||||
</h1>
|
||||
<sub class="sponsorStartHint grey-text">__MSG_popupHint__</sub>
|
||||
<div align="center" style="margin: 8px 0;">
|
||||
<div style="text-align: center; margin: 8px 0;">
|
||||
<button id="sponsorStart" class="sbMediumButton" style="margin-right: 8px">__MSG_sponsorStart__</button>
|
||||
<button id="submitTimes" class="sbMediumButton" style="display: none;">__MSG_submitTimesButton__</button>
|
||||
<button id="submitTimes" class="sbMediumButton" style="display: none">__MSG_submitTimesButton__</button>
|
||||
</div>
|
||||
<span id="submissionHint" style="display: none;">__MSG_submissionEditHint__</span>
|
||||
<span id="submissionHint" style="display: none">__MSG_submissionEditHint__</span>
|
||||
</div>
|
||||
|
||||
<!-- Your Work box -->
|
||||
<div class="sbYourWorkCols">
|
||||
<p class="sbHeader" style="padding: 8px 16px;">
|
||||
<div class="sbYourWorkBox">
|
||||
<h1 class="sbHeader" style="padding: 8px 15px;">
|
||||
__MSG_yourWork__
|
||||
</p>
|
||||
<div>
|
||||
</h1>
|
||||
<div class="sbYourWorkCols">
|
||||
<!-- Username -->
|
||||
<div id="usernameElement">
|
||||
<span class="u-mZ grey-text">__MSG_Username__:
|
||||
<p class="u-mZ grey-text">__MSG_Username__:
|
||||
<!-- loading/errors -->
|
||||
<span id="setUsernameStatus" class="u-mZ white-text" style="display: none"></span>
|
||||
</span>
|
||||
</p>
|
||||
<div id="setUsernameContainer">
|
||||
<p id="usernameValue"></p>
|
||||
<button id="setUsernameButton" title="__MSG_setUsername__">
|
||||
@@ -141,7 +141,7 @@
|
||||
<!-- Submissions -->
|
||||
<div id="sponsorTimesContributionsContainer" class="hidden">
|
||||
<p class="u-mZ grey-text">__MSG_Submissions__:</p>
|
||||
<span id="sponsorTimesContributionsDisplay">0</span>
|
||||
<p id="sponsorTimesContributionsDisplay" class="u-mZ">0</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
<a id="sbConsiderDonateLink" href="https://sponsor.ajay.app/donate" target="_blank" rel="noopener">
|
||||
__MSG_considerDonating__
|
||||
</a>
|
||||
<img id="sbCloseDonate" src="/icons/close.png" alt="Close icon" height="8" style="padding-left: 5px; cursor: pointer;" />
|
||||
<img id="sbCloseDonate" src="/icons/close.png" alt="__MSG_closeIcon__" height="8" style="padding-left: 5px; cursor: pointer;" />
|
||||
</div>
|
||||
|
||||
<footer id="sbFooter">
|
||||
|
||||
@@ -24,7 +24,7 @@ if (utils.isFirefox()) {
|
||||
utils.wait(() => Config.config !== null).then(function() {
|
||||
if (Config.config.supportInvidious) utils.setupExtraSiteContentScripts();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onTabUpdatedListener(tabId: number) {
|
||||
chrome.tabs.sendMessage(tabId, {
|
||||
@@ -77,17 +77,17 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
ok: response.ok
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return true;
|
||||
case "submitVote":
|
||||
submitVote(request.type, request.UUID, request.category).then(callback);
|
||||
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "registerContentScript":
|
||||
case "registerContentScript":
|
||||
registerFirefoxContentScript(request);
|
||||
return false;
|
||||
case "unregisterContentScript":
|
||||
case "unregisterContentScript":
|
||||
unregisterFirefoxContentScript(request.id)
|
||||
return false;
|
||||
case "tabs": {
|
||||
@@ -106,6 +106,8 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
return true;
|
||||
}
|
||||
case "time":
|
||||
case "infoUpdated":
|
||||
case "videoChanged":
|
||||
if (sender.tab) {
|
||||
popupPort[sender.tab.id]?.postMessage(request);
|
||||
}
|
||||
@@ -156,8 +158,8 @@ chrome.runtime.onInstalled.addListener(function () {
|
||||
/**
|
||||
* Only works on Firefox.
|
||||
* Firefox requires that it be applied after every extension restart.
|
||||
*
|
||||
* @param {JSON} options
|
||||
*
|
||||
* @param {JSON} options
|
||||
*/
|
||||
function registerFirefoxContentScript(options: Registration) {
|
||||
const oldRegistration = contentScriptRegistrations[options.id];
|
||||
@@ -174,7 +176,7 @@ function registerFirefoxContentScript(options: Registration) {
|
||||
/**
|
||||
* Only works on Firefox.
|
||||
* Firefox requires that this is handled by the background script
|
||||
*
|
||||
*
|
||||
*/
|
||||
function unregisterFirefoxContentScript(id: string) {
|
||||
contentScriptRegistrations[id].unregister();
|
||||
@@ -225,10 +227,10 @@ async function asyncRequestToServer(type: string, address: string, data = {}) {
|
||||
|
||||
/**
|
||||
* Sends a request to the specified url
|
||||
*
|
||||
*
|
||||
* @param type The request type "GET", "POST", etc.
|
||||
* @param address The address to add to the SponsorBlock server address
|
||||
* @param callback
|
||||
* @param callback
|
||||
*/
|
||||
async function sendRequestToCustomServer(type: string, url: string, data = {}) {
|
||||
// If GET, convert JSON to parameters
|
||||
@@ -248,4 +250,4 @@ async function sendRequestToCustomServer(type: string, url: string, data = {}) {
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,41 +8,42 @@ enum CountdownMode {
|
||||
}
|
||||
|
||||
export interface NoticeProps {
|
||||
noticeTitle: string,
|
||||
noticeTitle: string;
|
||||
|
||||
maxCountdownTime?: () => number,
|
||||
dontPauseCountdown?: boolean,
|
||||
amountOfPreviousNotices?: number,
|
||||
showInSecondSlot?: boolean,
|
||||
timed?: boolean,
|
||||
idSuffix?: string,
|
||||
maxCountdownTime?: () => number;
|
||||
dontPauseCountdown?: boolean;
|
||||
amountOfPreviousNotices?: number;
|
||||
showInSecondSlot?: boolean;
|
||||
timed?: boolean;
|
||||
idSuffix?: string;
|
||||
|
||||
fadeIn?: boolean,
|
||||
startFaded?: boolean,
|
||||
firstColumn?: React.ReactElement[] | React.ReactElement,
|
||||
firstRow?: React.ReactElement,
|
||||
bottomRow?: React.ReactElement[],
|
||||
fadeIn?: boolean;
|
||||
startFaded?: boolean;
|
||||
firstColumn?: React.ReactElement[] | React.ReactElement;
|
||||
firstRow?: React.ReactElement;
|
||||
bottomRow?: React.ReactElement[];
|
||||
|
||||
smaller?: boolean,
|
||||
limitWidth?: boolean,
|
||||
extraClass?: string,
|
||||
hideLogo?: boolean,
|
||||
hideRightInfo?: boolean,
|
||||
smaller?: boolean;
|
||||
limitWidth?: boolean;
|
||||
extraClass?: string;
|
||||
hideLogo?: boolean;
|
||||
hideRightInfo?: boolean;
|
||||
|
||||
// Callback for when this is closed
|
||||
closeListener: () => void,
|
||||
onMouseEnter?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void,
|
||||
closeListener: () => void;
|
||||
onMouseEnter?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
||||
|
||||
zIndex?: number,
|
||||
style?: React.CSSProperties
|
||||
zIndex?: number;
|
||||
style?: React.CSSProperties;
|
||||
biggerCloseButton?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface NoticeState {
|
||||
maxCountdownTime: () => number,
|
||||
maxCountdownTime: () => number;
|
||||
|
||||
countdownTime: number,
|
||||
countdownMode: CountdownMode,
|
||||
countdownTime: number;
|
||||
countdownMode: CountdownMode;
|
||||
|
||||
mouseHovering: boolean;
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface NoticeTextSelectionProps {
|
||||
icon?: string,
|
||||
text: string,
|
||||
idSuffix: string,
|
||||
onClick?: (event: React.MouseEvent) => unknown
|
||||
icon?: string;
|
||||
text: string;
|
||||
idSuffix: string;
|
||||
onClick?: (event: React.MouseEvent) => unknown;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface NoticeTextSelectionState {
|
||||
|
||||
@@ -8,6 +8,8 @@ export interface SelectorProps {
|
||||
id: string;
|
||||
options: SelectorOption[];
|
||||
onChange: (value: string) => void;
|
||||
onMouseEnter?: () => void;
|
||||
onMouseLeave?: () => void;
|
||||
}
|
||||
|
||||
export interface SelectorState {
|
||||
@@ -30,7 +32,9 @@ class SelectorComponent extends React.Component<SelectorProps, SelectorState> {
|
||||
<div id={this.props.id}
|
||||
style={{display: this.props.options.length > 0 ? "inherit" : "none"}}
|
||||
className="sbSelector">
|
||||
<div className="sbSelectorBackground">
|
||||
<div onMouseEnter={this.props.onMouseEnter}
|
||||
onMouseLeave={this.props.onMouseLeave}
|
||||
className="sbSelectorBackground">
|
||||
{this.getOptions()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,15 +14,16 @@ import { DEFAULT_CATEGORY } from "../utils/categoryUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
export interface SponsorTimeEditProps {
|
||||
index: number,
|
||||
index: number;
|
||||
|
||||
idSuffix: string,
|
||||
idSuffix: string;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer,
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
submissionNotice: SubmissionNoticeComponent;
|
||||
categoryList?: Category[];
|
||||
categoryChangeListener?: (index: number, category: Category) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface SponsorTimeEditState {
|
||||
@@ -32,6 +33,7 @@ export interface SponsorTimeEditState {
|
||||
description: string;
|
||||
suggestedNames: SelectorOption[];
|
||||
chapterNameSelectorOpen: boolean;
|
||||
chapterNameSelectorHovering: boolean;
|
||||
}
|
||||
|
||||
const categoryNamesGrams: string[] = [].concat(...CompileConfig.categoryList.filter((name) => name !== "chapter")
|
||||
@@ -73,7 +75,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
selectedCategory: DEFAULT_CATEGORY as Category,
|
||||
description: sponsorTime.description || "",
|
||||
suggestedNames: [],
|
||||
chapterNameSelectorOpen: false
|
||||
chapterNameSelectorOpen: false,
|
||||
chapterNameSelectorHovering: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -230,7 +233,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
{/* Chapter Name */}
|
||||
{sponsorTime.actionType === ActionType.Chapter ? (
|
||||
<div>
|
||||
<div onBlur={() => this.setState({chapterNameSelectorOpen: false})}>
|
||||
<input id={"chapterName" + this.idSuffix}
|
||||
className="sponsorTimeEdit sponsorTimeEditInput sponsorChapterNameInput"
|
||||
style={{color: "inherit", backgroundColor: "inherit"}}
|
||||
@@ -239,13 +242,15 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
value={this.state.description}
|
||||
onContextMenu={(e) => e.stopPropagation()}
|
||||
onChange={(e) => this.descriptionUpdate(e.target.value)}
|
||||
onBlur={() => this.setState({chapterNameSelectorOpen: false})}
|
||||
onFocus={() => this.setState({chapterNameSelectorOpen: true})}>
|
||||
</input>
|
||||
{this.state.chapterNameSelectorOpen && this.state.description &&
|
||||
{this.state.description
|
||||
&& (this.state.chapterNameSelectorOpen || this.state.chapterNameSelectorHovering) &&
|
||||
<SelectorComponent
|
||||
id={"chapterNameSelector" + this.idSuffix}
|
||||
options={this.state.suggestedNames}
|
||||
onMouseEnter={() => this.setState({chapterNameSelectorHovering: true})}
|
||||
onMouseLeave={() => this.setState({chapterNameSelectorHovering: false})}
|
||||
onChange={(v) => this.descriptionUpdate(v)}
|
||||
/>
|
||||
}
|
||||
@@ -262,12 +267,12 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
{chrome.i18n.getMessage("delete")}
|
||||
</span>
|
||||
|
||||
{(!isNaN(segment[1]) && ![ActionType.Poi, ActionType.Full].includes(sponsorTime.actionType)) ? (
|
||||
{(!isNaN(segment[1]) && ![ActionType.Poi, ActionType.Full].includes(sponsorTime.actionType))
|
||||
&& sponsorTime.actionType !== ActionType.Chapter ? (
|
||||
<span id={"sponsorTimePreviewButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={(e) => this.previewTime(e.ctrlKey, e.shiftKey)}>
|
||||
{sponsorTime.actionType !== ActionType.Chapter ? chrome.i18n.getMessage("preview")
|
||||
: chrome.i18n.getMessage("End")}
|
||||
{chrome.i18n.getMessage("preview")}
|
||||
</span>
|
||||
): ""}
|
||||
|
||||
@@ -279,6 +284,15 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
</span>
|
||||
): ""}
|
||||
|
||||
{(!isNaN(segment[1]) && ![ActionType.Poi, ActionType.Full].includes(sponsorTime.actionType))
|
||||
&& sponsorTime.actionType === ActionType.Chapter ? (
|
||||
<span id={"sponsorTimePreviewButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={(e) => this.previewTime(e.ctrlKey, e.shiftKey)}>
|
||||
{chrome.i18n.getMessage("End")}
|
||||
</span>
|
||||
): ""}
|
||||
|
||||
{(!isNaN(segment[1]) && sponsorTime.actionType != ActionType.Full) ? (
|
||||
<span id={"sponsorTimeEditButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
@@ -527,9 +541,14 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
if (time === null) time = sponsorTime.segment[0];
|
||||
|
||||
const addedTime = sponsorTime.segment.length === 1;
|
||||
sponsorTime.segment[index] = time;
|
||||
if (sponsorTime.actionType === ActionType.Poi) sponsorTime.segment[1] = time;
|
||||
|
||||
if (addedTime) {
|
||||
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||
}, () => this.saveEditTimes());
|
||||
@@ -561,6 +580,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
saveEditTimes(): void {
|
||||
const sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const category = this.categoryOptionRef.current.value as Category
|
||||
|
||||
if (this.state.editing) {
|
||||
const startTime = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]);
|
||||
@@ -568,11 +588,18 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
// Change segment time only if the format was correct
|
||||
if (startTime !== null && endTime !== null) {
|
||||
const addingTime = sponsorTimesSubmitting[this.props.index].segment.length === 1;
|
||||
sponsorTimesSubmitting[this.props.index].segment = [startTime, endTime];
|
||||
|
||||
if (addingTime) {
|
||||
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||
}
|
||||
}
|
||||
} else if (this.state.sponsorTimeEdits[1] === null && category === "outro") {
|
||||
sponsorTimesSubmitting[this.props.index].segment[1] = this.props.contentContainer().v.duration;
|
||||
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||
}
|
||||
|
||||
const category = this.categoryOptionRef.current.value as Category
|
||||
sponsorTimesSubmitting[this.props.index].category = category;
|
||||
|
||||
const actionType = this.getNextActionType(category, this.actionTypeOptionRef?.current?.value as ActionType);
|
||||
|
||||
@@ -20,8 +20,8 @@ export interface SubmissionNoticeProps {
|
||||
}
|
||||
|
||||
export interface SubmissionNoticeState {
|
||||
noticeTitle: string,
|
||||
messages: string[],
|
||||
noticeTitle: string;
|
||||
messages: string[];
|
||||
idSuffix: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as CompileConfig from "../../../config.json";
|
||||
import { Category, CategorySkipOption } from "../../types";
|
||||
|
||||
import { getCategorySuffix } from "../../utils/categoryUtils";
|
||||
import ToggleOptionComponent, { ToggleOptionProps } from "./ToggleOptionComponent";
|
||||
import ToggleOptionComponent from "./ToggleOptionComponent";
|
||||
import { fetchingChaptersAllowed } from "../../utils/licenseKey";
|
||||
import LockSvg from "../../svg-icons/lock_svg";
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface CategorySkipOptionsProps {
|
||||
category: Category;
|
||||
defaultColor?: string;
|
||||
defaultPreviewColor?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface CategorySkipOptionsState {
|
||||
@@ -21,6 +22,12 @@ export interface CategorySkipOptionsState {
|
||||
hideChapter: boolean;
|
||||
}
|
||||
|
||||
export interface ToggleOption {
|
||||
configKey: string;
|
||||
label: string;
|
||||
dontDisable?: boolean;
|
||||
}
|
||||
|
||||
class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsProps, CategorySkipOptionsState> {
|
||||
setBarColorTimeout: NodeJS.Timeout;
|
||||
|
||||
@@ -237,7 +244,7 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
|
||||
<ToggleOptionComponent
|
||||
configKey={option.configKey}
|
||||
label={option.label}
|
||||
disabled={disabled}
|
||||
disabled={!option.dontDisable && disabled}
|
||||
style={{width: "inherit"}}
|
||||
/>
|
||||
</td>
|
||||
@@ -248,12 +255,17 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
|
||||
return result;
|
||||
}
|
||||
|
||||
getExtraOptions(category: string): ToggleOptionProps[] {
|
||||
getExtraOptions(category: string): ToggleOption[] {
|
||||
switch (category) {
|
||||
case "chapter":
|
||||
return [{
|
||||
configKey: "renderSegmentsAsChapters",
|
||||
label: chrome.i18n.getMessage("renderAsChapters"),
|
||||
dontDisable: true
|
||||
}, {
|
||||
configKey: "showSegmentNameInChapterBar",
|
||||
label: chrome.i18n.getMessage("showSegmentNameInChapterBar"),
|
||||
dontDisable: true
|
||||
}];
|
||||
case "music_offtopic":
|
||||
return [{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import Config from "../../config";
|
||||
import { Keybind } from "../../types";
|
||||
import KeybindDialogComponent from "./KeybindDialogComponent";
|
||||
@@ -14,6 +14,7 @@ export interface KeybindState {
|
||||
}
|
||||
|
||||
let dialog;
|
||||
let root: Root;
|
||||
|
||||
class KeybindComponent extends React.Component<KeybindProps, KeybindState> {
|
||||
constructor(props: KeybindProps) {
|
||||
@@ -56,11 +57,12 @@ class KeybindComponent extends React.Component<KeybindProps, KeybindState> {
|
||||
dialog = parent.document.createElement("div");
|
||||
dialog.id = "keybind-dialog";
|
||||
parent.document.body.prepend(dialog);
|
||||
ReactDOM.render(<KeybindDialogComponent option={this.props.option} closeListener={(updateWith) => this.closeEditDialog(updateWith)} />, dialog);
|
||||
root = createRoot(dialog);
|
||||
root.render(<KeybindDialogComponent option={this.props.option} closeListener={(updateWith) => this.closeEditDialog(updateWith)} />);
|
||||
}
|
||||
|
||||
closeEditDialog(updateWith: Keybind): void {
|
||||
ReactDOM.unmountComponentAtNode(dialog);
|
||||
root.unmount();
|
||||
dialog.remove();
|
||||
if (updateWith != null)
|
||||
this.setState({keybind: updateWith});
|
||||
|
||||
@@ -26,7 +26,7 @@ class ToggleOptionComponent extends React.Component<ToggleOptionProps, ToggleOpt
|
||||
|
||||
render(): React.ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<div className={`sb-toggle-option ${this.props.disabled ? "disabled" : ""}`}>
|
||||
<div className="switch-container" style={this.props.style}>
|
||||
<label className="switch">
|
||||
<input id={this.props.configKey}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { exportTimes, exportTimesAsHashParam } from "../../utils/exporter";
|
||||
|
||||
export interface UnsubmittedVideosListItemProps {
|
||||
videoID: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface UnsubmittedVideosListItemState {
|
||||
|
||||
@@ -7,7 +7,7 @@ export interface UnsubmittedVideosProps {
|
||||
}
|
||||
|
||||
export interface UnsubmittedVideosState {
|
||||
tableVisible: boolean,
|
||||
tableVisible: boolean;
|
||||
}
|
||||
|
||||
class UnsubmittedVideosComponent extends React.Component<UnsubmittedVideosProps, UnsubmittedVideosState> {
|
||||
|
||||
194
src/config.ts
194
src/config.ts
@@ -8,120 +8,122 @@ export interface Permission {
|
||||
}
|
||||
|
||||
interface SBConfig {
|
||||
userID: string,
|
||||
isVip: boolean,
|
||||
permissions: Record<Category, Permission>,
|
||||
userID: string;
|
||||
isVip: boolean;
|
||||
permissions: Record<Category, Permission>;
|
||||
/* Contains unsubmitted segments that the user has created. */
|
||||
unsubmittedSegments: Record<string, SponsorTime[]>,
|
||||
defaultCategory: Category,
|
||||
renderSegmentsAsChapters: boolean,
|
||||
whitelistedChannels: string[],
|
||||
forceChannelCheck: boolean,
|
||||
minutesSaved: number,
|
||||
skipCount: number,
|
||||
sponsorTimesContributed: number,
|
||||
submissionCountSinceCategories: number, // New count used to show the "Read The Guidelines!!" message
|
||||
showTimeWithSkips: boolean,
|
||||
disableSkipping: boolean,
|
||||
muteSegments: boolean,
|
||||
fullVideoSegments: boolean,
|
||||
manualSkipOnFullVideo: boolean,
|
||||
trackViewCount: boolean,
|
||||
trackViewCountInPrivate: boolean,
|
||||
trackDownvotes: boolean,
|
||||
dontShowNotice: boolean,
|
||||
noticeVisibilityMode: NoticeVisbilityMode,
|
||||
hideVideoPlayerControls: boolean,
|
||||
hideInfoButtonPlayerControls: boolean,
|
||||
hideDeleteButtonPlayerControls: boolean,
|
||||
hideUploadButtonPlayerControls: boolean,
|
||||
hideSkipButtonPlayerControls: boolean,
|
||||
hideDiscordLaunches: number,
|
||||
hideDiscordLink: boolean,
|
||||
invidiousInstances: string[],
|
||||
supportInvidious: boolean,
|
||||
serverAddress: string,
|
||||
minDuration: number,
|
||||
skipNoticeDuration: number,
|
||||
audioNotificationOnSkip: boolean,
|
||||
checkForUnlistedVideos: boolean,
|
||||
testingServer: boolean,
|
||||
refetchWhenNotFound: boolean,
|
||||
ytInfoPermissionGranted: boolean,
|
||||
allowExpirements: boolean,
|
||||
showDonationLink: boolean,
|
||||
showPopupDonationCount: number,
|
||||
showUpsells: boolean,
|
||||
donateClicked: number,
|
||||
autoHideInfoButton: boolean,
|
||||
autoSkipOnMusicVideos: boolean,
|
||||
unsubmittedSegments: Record<string, SponsorTime[]>;
|
||||
defaultCategory: Category;
|
||||
renderSegmentsAsChapters: boolean;
|
||||
whitelistedChannels: string[];
|
||||
forceChannelCheck: boolean;
|
||||
minutesSaved: number;
|
||||
skipCount: number;
|
||||
sponsorTimesContributed: number;
|
||||
submissionCountSinceCategories: number; // New count used to show the "Read The Guidelines!!" message
|
||||
showTimeWithSkips: boolean;
|
||||
disableSkipping: boolean;
|
||||
muteSegments: boolean;
|
||||
fullVideoSegments: boolean;
|
||||
manualSkipOnFullVideo: boolean;
|
||||
trackViewCount: boolean;
|
||||
trackViewCountInPrivate: boolean;
|
||||
trackDownvotes: boolean;
|
||||
dontShowNotice: boolean;
|
||||
noticeVisibilityMode: NoticeVisbilityMode;
|
||||
hideVideoPlayerControls: boolean;
|
||||
hideInfoButtonPlayerControls: boolean;
|
||||
hideDeleteButtonPlayerControls: boolean;
|
||||
hideUploadButtonPlayerControls: boolean;
|
||||
hideSkipButtonPlayerControls: boolean;
|
||||
hideDiscordLaunches: number;
|
||||
hideDiscordLink: boolean;
|
||||
invidiousInstances: string[];
|
||||
supportInvidious: boolean;
|
||||
serverAddress: string;
|
||||
minDuration: number;
|
||||
skipNoticeDuration: number;
|
||||
audioNotificationOnSkip: boolean;
|
||||
checkForUnlistedVideos: boolean;
|
||||
testingServer: boolean;
|
||||
refetchWhenNotFound: boolean;
|
||||
ytInfoPermissionGranted: boolean;
|
||||
allowExpirements: boolean;
|
||||
showDonationLink: boolean;
|
||||
showPopupDonationCount: number;
|
||||
showUpsells: boolean;
|
||||
donateClicked: number;
|
||||
autoHideInfoButton: boolean;
|
||||
autoSkipOnMusicVideos: boolean;
|
||||
colorPalette: {
|
||||
red: string,
|
||||
white: string,
|
||||
locked: string
|
||||
},
|
||||
scrollToEditTimeUpdate: boolean,
|
||||
categoryPillUpdate: boolean,
|
||||
showChapterInfoMessage: boolean,
|
||||
darkMode: boolean,
|
||||
showCategoryGuidelines: boolean,
|
||||
showCategoryWithoutPermission: boolean,
|
||||
red: string;
|
||||
white: string;
|
||||
locked: string;
|
||||
};
|
||||
scrollToEditTimeUpdate: boolean;
|
||||
categoryPillUpdate: boolean;
|
||||
showChapterInfoMessage: boolean;
|
||||
darkMode: boolean;
|
||||
showCategoryGuidelines: boolean;
|
||||
showCategoryWithoutPermission: boolean;
|
||||
showSegmentNameInChapterBar: boolean;
|
||||
|
||||
// Used to cache calculated text color info
|
||||
categoryPillColors: {
|
||||
[key in Category]: {
|
||||
lastColor: string,
|
||||
textColor: string
|
||||
lastColor: string;
|
||||
textColor: string;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
skipKeybind: Keybind,
|
||||
startSponsorKeybind: Keybind,
|
||||
submitKeybind: Keybind,
|
||||
nextChapterKeybind: Keybind,
|
||||
previousChapterKeybind: Keybind,
|
||||
skipKeybind: Keybind;
|
||||
startSponsorKeybind: Keybind;
|
||||
submitKeybind: Keybind;
|
||||
nextChapterKeybind: Keybind;
|
||||
previousChapterKeybind: Keybind;
|
||||
|
||||
// What categories should be skipped
|
||||
categorySelections: CategorySelection[],
|
||||
categorySelections: CategorySelection[];
|
||||
|
||||
payments: {
|
||||
licenseKey: string,
|
||||
lastCheck: number,
|
||||
freeAccess: boolean,
|
||||
chaptersAllowed: boolean
|
||||
}
|
||||
licenseKey: string;
|
||||
lastCheck: number;
|
||||
lastFreeCheck: number;
|
||||
freeAccess: boolean;
|
||||
chaptersAllowed: boolean;
|
||||
};
|
||||
|
||||
// Preview bar
|
||||
barTypes: {
|
||||
"preview-chooseACategory": PreviewBarOption,
|
||||
"sponsor": PreviewBarOption,
|
||||
"preview-sponsor": PreviewBarOption,
|
||||
"selfpromo": PreviewBarOption,
|
||||
"preview-selfpromo": PreviewBarOption,
|
||||
"exclusive_access": PreviewBarOption,
|
||||
"interaction": PreviewBarOption,
|
||||
"preview-interaction": PreviewBarOption,
|
||||
"intro": PreviewBarOption,
|
||||
"preview-intro": PreviewBarOption,
|
||||
"outro": PreviewBarOption,
|
||||
"preview-outro": PreviewBarOption,
|
||||
"preview": PreviewBarOption,
|
||||
"preview-preview": PreviewBarOption,
|
||||
"music_offtopic": PreviewBarOption,
|
||||
"preview-music_offtopic": PreviewBarOption,
|
||||
"poi_highlight": PreviewBarOption,
|
||||
"preview-poi_highlight": PreviewBarOption,
|
||||
"filler": PreviewBarOption,
|
||||
"preview-filler": PreviewBarOption,
|
||||
}
|
||||
"preview-chooseACategory": PreviewBarOption;
|
||||
"sponsor": PreviewBarOption;
|
||||
"preview-sponsor": PreviewBarOption;
|
||||
"selfpromo": PreviewBarOption;
|
||||
"preview-selfpromo": PreviewBarOption;
|
||||
"exclusive_access": PreviewBarOption;
|
||||
"interaction": PreviewBarOption;
|
||||
"preview-interaction": PreviewBarOption;
|
||||
"intro": PreviewBarOption;
|
||||
"preview-intro": PreviewBarOption;
|
||||
"outro": PreviewBarOption;
|
||||
"preview-outro": PreviewBarOption;
|
||||
"preview": PreviewBarOption;
|
||||
"preview-preview": PreviewBarOption;
|
||||
"music_offtopic": PreviewBarOption;
|
||||
"preview-music_offtopic": PreviewBarOption;
|
||||
"poi_highlight": PreviewBarOption;
|
||||
"preview-poi_highlight": PreviewBarOption;
|
||||
"filler": PreviewBarOption;
|
||||
"preview-filler": PreviewBarOption;
|
||||
};
|
||||
}
|
||||
|
||||
export type VideoDownvotes = { segments: { uuid: HashedValue, hidden: SponsorHideType }[] , lastAccess: number };
|
||||
export type VideoDownvotes = { segments: { uuid: HashedValue; hidden: SponsorHideType }[] ; lastAccess: number };
|
||||
|
||||
interface SBStorage {
|
||||
/* VideoID prefixes to UUID prefixes */
|
||||
downvotedSegments: Record<VideoID & HashedValue, VideoDownvotes>,
|
||||
navigationApiAvailable: boolean,
|
||||
downvotedSegments: Record<VideoID & HashedValue, VideoDownvotes>;
|
||||
navigationApiAvailable: boolean;
|
||||
}
|
||||
|
||||
export interface SBObject {
|
||||
@@ -197,6 +199,7 @@ const Config: SBObject = {
|
||||
darkMode: true,
|
||||
showCategoryGuidelines: true,
|
||||
showCategoryWithoutPermission: false,
|
||||
showSegmentNameInChapterBar: true,
|
||||
|
||||
categoryPillColors: {},
|
||||
|
||||
@@ -227,6 +230,7 @@ const Config: SBObject = {
|
||||
payments: {
|
||||
licenseKey: null,
|
||||
lastCheck: 0,
|
||||
lastFreeCheck: 0,
|
||||
freeAccess: false,
|
||||
chaptersAllowed: false
|
||||
},
|
||||
@@ -336,7 +340,7 @@ const Config: SBObject = {
|
||||
|
||||
// Function setup
|
||||
|
||||
function configProxy(): { sync: SBConfig, local: SBStorage } {
|
||||
function configProxy(): { sync: SBConfig; local: SBStorage } {
|
||||
chrome.storage.onChanged.addListener((changes: {[key: string]: chrome.storage.StorageChange}, areaName) => {
|
||||
if (areaName === "sync") {
|
||||
for (const key in changes) {
|
||||
|
||||
180
src/content.ts
180
src/content.ts
@@ -8,6 +8,7 @@ import {
|
||||
ContentContainer,
|
||||
HashedValue,
|
||||
Keybind,
|
||||
PageType,
|
||||
ScheduledTime,
|
||||
SegmentUUID,
|
||||
SkipToTimeParams,
|
||||
@@ -18,7 +19,6 @@ import {
|
||||
ToggleSkippable,
|
||||
VideoID,
|
||||
VideoInfo,
|
||||
PageType
|
||||
} from "./types";
|
||||
import Utils from "./utils";
|
||||
import PreviewBar, { PreviewBarSegment } from "./js-components/previewBar";
|
||||
@@ -55,6 +55,7 @@ let sponsorVideoID: VideoID = null;
|
||||
// List of open skip notices
|
||||
const skipNotices: SkipNotice[] = [];
|
||||
let activeSkipKeybindElement: ToggleSkippable = null;
|
||||
let retryFetchTimeout: NodeJS.Timeout = null;
|
||||
|
||||
// JSON video info
|
||||
let videoInfo: VideoInfo = null;
|
||||
@@ -67,7 +68,7 @@ let channelIDInfo: ChannelIDInfo;
|
||||
// Locked Categories in this tab, like: ["sponsor","intro","outro"]
|
||||
let lockedCategories: Category[] = [];
|
||||
// Used to calculate a more precise "virtual" video time
|
||||
let lastKnownVideoTime: { videoTime: number, preciseTime: number } = {
|
||||
let lastKnownVideoTime: { videoTime: number; preciseTime: number } = {
|
||||
videoTime: null,
|
||||
preciseTime: null
|
||||
};
|
||||
@@ -124,13 +125,14 @@ let categoryPill: CategoryPill = null;
|
||||
let controls: HTMLElement | null = null;
|
||||
|
||||
/** Contains buttons created by `createButton()`. */
|
||||
const playerButtons: Record<string, {button: HTMLButtonElement, image: HTMLImageElement, setupListener: boolean}> = {};
|
||||
const playerButtons: Record<string, {button: HTMLButtonElement; image: HTMLImageElement; setupListener: boolean}> = {};
|
||||
|
||||
// Direct Links after the config is loaded
|
||||
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document)));
|
||||
// wait for hover preview to appear, and refresh attachments if ever found
|
||||
utils.waitForElement(".ytp-inline-preview-ui").then(() => refreshVideoAttachments())
|
||||
utils.waitForElement("a.ytp-title-link[data-sessionlink='feature=player-title']").then(() => videoIDChange(getYouTubeVideoID(document)).then())
|
||||
utils.waitForElement(".ytp-inline-preview-ui").then(() => refreshVideoAttachments());
|
||||
utils.waitForElement("a.ytp-title-link[data-sessionlink='feature=player-title']")
|
||||
.then(() => videoIDChange(getYouTubeVideoID(document)));
|
||||
addPageListeners();
|
||||
addHotkeyListener();
|
||||
|
||||
@@ -213,7 +215,6 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
||||
case "getVideoID":
|
||||
sendResponse({
|
||||
videoID: sponsorVideoID,
|
||||
creatingSegment: isSegmentCreationInProgress(),
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -241,15 +242,9 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
||||
// update video on refresh if videoID invalid
|
||||
if (!sponsorVideoID) videoIDChange(getYouTubeVideoID(document));
|
||||
// fetch segments
|
||||
sponsorsLookup(false).then(() => sendResponse({
|
||||
found: sponsorDataFound,
|
||||
status: lastResponseStatus,
|
||||
sponsorTimes: sponsorTimes,
|
||||
time: video.currentTime,
|
||||
onMobileYouTube
|
||||
}));
|
||||
sponsorsLookup(false);
|
||||
|
||||
return true;
|
||||
break;
|
||||
case "unskip":
|
||||
unskipSponsorTime(sponsorTimes.find((segment) => segment.UUID === request.UUID), null, true);
|
||||
break;
|
||||
@@ -274,7 +269,7 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
||||
const importedSegments = importTimes(request.data, video.duration);
|
||||
let addedSegments = false;
|
||||
for (const segment of importedSegments) {
|
||||
if (!sponsorTimesSubmitting.concat(sponsorTimes ?? []).some(
|
||||
if (!sponsorTimesSubmitting.some(
|
||||
(s) => Math.abs(s.segment[0] - segment.segment[0]) < 1
|
||||
&& Math.abs(s.segment[1] - segment.segment[1]) < 1)
|
||||
&& (segment.category !== "chapter" || utils.getCategorySelection("chapter"))) {
|
||||
@@ -382,7 +377,9 @@ function resetValues() {
|
||||
categoryPill?.setVisibility(false);
|
||||
}
|
||||
|
||||
async function videoIDChange(id): Promise<void> {
|
||||
async function videoIDChange(id: string): Promise<void> {
|
||||
// don't switch to invalid value
|
||||
if (!id && sponsorVideoID && !document?.URL?.includes("youtube.com/clip/")) return;
|
||||
//if the id has not changed return unless the video element has changed
|
||||
if (sponsorVideoID === id && (isVisible(video) || !video)) return;
|
||||
|
||||
@@ -434,10 +431,14 @@ async function videoIDChange(id): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
//close popup
|
||||
closeInfoMenu();
|
||||
// Notify the popup about the video change
|
||||
chrome.runtime.sendMessage({
|
||||
message: "videoChanged",
|
||||
videoID: sponsorVideoID,
|
||||
whitelisted: channelWhitelisted
|
||||
});
|
||||
|
||||
sponsorsLookup(id);
|
||||
sponsorsLookup();
|
||||
|
||||
// Make sure all player buttons are properly added
|
||||
updateVisibilityOfPlayerControlsButton();
|
||||
@@ -507,7 +508,7 @@ function createPreviewBar(): void {
|
||||
|
||||
if (el) {
|
||||
const chapterVote = new ChapterVote(voteAsync);
|
||||
previewBar = new PreviewBar(el, onMobileYouTube, onInvidious, chapterVote);
|
||||
previewBar = new PreviewBar(el, onMobileYouTube, onInvidious, chapterVote, () => importExistingChapters(false));
|
||||
|
||||
updatePreviewBar();
|
||||
|
||||
@@ -532,7 +533,7 @@ function durationChangeListener(): void {
|
||||
function videoOnReadyListener(): void {
|
||||
createPreviewBar();
|
||||
updatePreviewBar();
|
||||
createButtons();
|
||||
updateVisibilityOfPlayerControlsButton()
|
||||
}
|
||||
|
||||
function cancelSponsorSchedule(): void {
|
||||
@@ -944,29 +945,30 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
||||
setupVideoMutationListener();
|
||||
|
||||
const showChapterMessage = Config.config.showUpsells
|
||||
&& Config.config.payments.lastCheck !== 0
|
||||
&& Config.config.payments.lastCheck !== 0
|
||||
&& !noRefreshFetchingChaptersAllowed()
|
||||
&& Config.config.showChapterInfoMessage
|
||||
&& Config.config.skipCount > 200
|
||||
&& Math.random() > 0.8;
|
||||
&& Config.config.skipCount > 200;
|
||||
|
||||
if (!showChapterMessage
|
||||
&& Config.config.showChapterInfoMessage
|
||||
&& Config.config.payments.freeAccess
|
||||
&& !utils.getCategorySelection("chapter")) {
|
||||
if (!showChapterMessage
|
||||
&& Config.config.showChapterInfoMessage
|
||||
&& Config.config.payments.freeAccess) {
|
||||
Config.config.showChapterInfoMessage = false;
|
||||
const prependElement = document.querySelector(".ytp-chrome-bottom") as HTMLElement;
|
||||
if (prependElement) {
|
||||
Config.config.showChapterInfoMessage = false;
|
||||
new Tooltip({
|
||||
text: chrome.i18n.getMessage("chapterNewFeature2"),
|
||||
linkOnClick: () => void chrome.runtime.sendMessage({ "message": "openConfig" }),
|
||||
referenceNode: prependElement.parentElement,
|
||||
prependElement,
|
||||
timeout: 1500,
|
||||
leftOffset: "20px",
|
||||
positionRealtive: false
|
||||
});
|
||||
|
||||
if (!utils.getCategorySelection("chapter")) {
|
||||
const prependElement = document.querySelector(".ytp-chrome-bottom") as HTMLElement;
|
||||
if (prependElement) {
|
||||
Config.config.showChapterInfoMessage = false;
|
||||
new Tooltip({
|
||||
text: chrome.i18n.getMessage("chapterNewFeature2"),
|
||||
linkOnClick: () => void chrome.runtime.sendMessage({ "message": "openConfig" }),
|
||||
referenceNode: prependElement.parentElement,
|
||||
prependElement,
|
||||
timeout: 1500,
|
||||
leftOffset: "20px",
|
||||
positionRealtive: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,6 +1001,14 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
||||
?.sort((a, b) => a.segment[0] - b.segment[0]);
|
||||
if (!recievedSegments || !recievedSegments.length) {
|
||||
// return if no video found
|
||||
chrome.runtime.sendMessage({
|
||||
message: "infoUpdated",
|
||||
found: false,
|
||||
status: lastResponseStatus,
|
||||
sponsorTimes: sponsorTimes,
|
||||
time: video.currentTime,
|
||||
onMobileYouTube
|
||||
});
|
||||
retryFetch(404);
|
||||
return;
|
||||
}
|
||||
@@ -1088,6 +1098,16 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
||||
|
||||
importExistingChapters(true);
|
||||
|
||||
// notify popup of segment changes
|
||||
chrome.runtime.sendMessage({
|
||||
message: "infoUpdated",
|
||||
found: sponsorDataFound,
|
||||
status: lastResponseStatus,
|
||||
sponsorTimes: sponsorTimes,
|
||||
time: video.currentTime,
|
||||
onMobileYouTube
|
||||
});
|
||||
|
||||
if (Config.config.isVip) {
|
||||
lockedCategoriesLookup();
|
||||
}
|
||||
@@ -1133,18 +1153,19 @@ async function lockedCategoriesLookup(): Promise<void> {
|
||||
}
|
||||
|
||||
function retryFetch(errorCode: number): void {
|
||||
if (!Config.config.refetchWhenNotFound) return;
|
||||
sponsorDataFound = false;
|
||||
if (!Config.config.refetchWhenNotFound) return;
|
||||
|
||||
if (errorCode !== 404 && retryCount > 1) {
|
||||
if (retryFetchTimeout) clearTimeout(retryFetchTimeout);
|
||||
if ((errorCode !== 404 && retryCount > 1) || (errorCode !== 404 && retryCount > 10)) {
|
||||
// Too many errors (50x), give up
|
||||
return;
|
||||
}
|
||||
|
||||
retryCount++;
|
||||
|
||||
const delay = errorCode === 404 ? (10000 + Math.random() * 30000) : (2000 + Math.random() * 10000);
|
||||
setTimeout(() => {
|
||||
const delay = errorCode === 404 ? (30000 + Math.random() * 30000) : (2000 + Math.random() * 10000);
|
||||
retryFetchTimeout = setTimeout(() => {
|
||||
if (sponsorVideoID && sponsorTimes?.length === 0
|
||||
|| sponsorTimes.every((segment) => segment.source !== SponsorSourceType.Server)) {
|
||||
sponsorsLookup();
|
||||
@@ -1213,14 +1234,14 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
}
|
||||
}
|
||||
|
||||
function getYouTubeVideoID(document: Document, url?: string): string | boolean {
|
||||
function getYouTubeVideoID(document: Document, url?: string): string {
|
||||
url ||= document.URL;
|
||||
// pageType shortcut
|
||||
if (pageType === PageType.Channel) return getYouTubeVideoIDFromDocument()
|
||||
if (pageType === PageType.Channel) return getYouTubeVideoIDFromDocument();
|
||||
// clips should never skip, going from clip to full video has no indications.
|
||||
if (url.includes("youtube.com/clip/")) return false;
|
||||
if (url.includes("youtube.com/clip/")) return null;
|
||||
// skip to document and don't hide if on /embed/
|
||||
if (url.includes("/embed/") && url.includes("youtube.com")) return getYouTubeVideoIDFromDocument(false);
|
||||
if (url.includes("/embed/") && url.includes("youtube.com")) return getYouTubeVideoIDFromDocument(false, PageType.Embed);
|
||||
// skip to URL if matches youtube watch or invidious or matches youtube pattern
|
||||
if ((!url.includes("youtube.com")) || url.includes("/watch") || url.includes("/shorts/") || url.includes("playlist")) return getYouTubeVideoIDFromURL(url);
|
||||
// skip to document if matches pattern
|
||||
@@ -1229,9 +1250,11 @@ function getYouTubeVideoID(document: Document, url?: string): string | boolean {
|
||||
return getYouTubeVideoIDFromURL(url) || getYouTubeVideoIDFromDocument(false);
|
||||
}
|
||||
|
||||
function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watch): string | boolean {
|
||||
function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watch): string {
|
||||
const selector = "a.ytp-title-link[data-sessionlink='feature=player-title']";
|
||||
// get ID from document (channel trailer / embedded playlist)
|
||||
const element = video?.parentElement?.parentElement?.querySelector("a.ytp-title-link[data-sessionlink='feature=player-title']");
|
||||
const element = pageHint === PageType.Embed ? document.querySelector(selector)
|
||||
: video?.parentElement?.parentElement?.querySelector(selector);
|
||||
const videoURL = element?.getAttribute("href");
|
||||
if (videoURL) {
|
||||
onInvidious = hideIcon;
|
||||
@@ -1239,11 +1262,11 @@ function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watc
|
||||
pageType = pageHint;
|
||||
return getYouTubeVideoIDFromURL(videoURL);
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getYouTubeVideoIDFromURL(url: string): string | boolean {
|
||||
function getYouTubeVideoIDFromURL(url: string): string {
|
||||
if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", "");
|
||||
|
||||
//Attempt to parse url
|
||||
@@ -1252,7 +1275,7 @@ function getYouTubeVideoIDFromURL(url: string): string | boolean {
|
||||
urlObject = new URL(url);
|
||||
} catch (e) {
|
||||
console.error("[SB] Unable to parse URL: " + url);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if valid hostname
|
||||
@@ -1266,7 +1289,7 @@ function getYouTubeVideoIDFromURL(url: string): string | boolean {
|
||||
utils.wait(() => Config.config !== null).then(() => videoIDChange(getYouTubeVideoIDFromURL(url)));
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
} else {
|
||||
onInvidious = false;
|
||||
}
|
||||
@@ -1274,17 +1297,17 @@ function getYouTubeVideoIDFromURL(url: string): string | boolean {
|
||||
//Get ID from searchParam
|
||||
if (urlObject.searchParams.has("v") && ["/watch", "/watch/"].includes(urlObject.pathname) || urlObject.pathname.startsWith("/tv/watch")) {
|
||||
const id = urlObject.searchParams.get("v");
|
||||
return id.length == 11 ? id : false;
|
||||
return id.length == 11 ? id : null;
|
||||
} else if (urlObject.pathname.startsWith("/embed/") || urlObject.pathname.startsWith("/shorts/")) {
|
||||
try {
|
||||
const id = urlObject.pathname.split("/")[2]
|
||||
if (id?.length >=11 ) return id.slice(0, 11);
|
||||
} catch (e) {
|
||||
console.error("[SB] Video ID not valid for " + url);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1395,7 +1418,7 @@ async function whitelistCheck() {
|
||||
* Returns info about the next upcoming sponsor skip
|
||||
*/
|
||||
function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean):
|
||||
{array: ScheduledTime[], index: number, endIndex: number, extraIndexes: number[], openNotice: boolean} {
|
||||
{array: ScheduledTime[]; index: number; endIndex: number; extraIndexes: number[]; openNotice: boolean} {
|
||||
|
||||
const autoSkipSorter = (segment: ScheduledTime) => {
|
||||
const skipOption = utils.getCategorySelection(segment.category)?.option;
|
||||
@@ -1507,7 +1530,7 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
|
||||
* the current time, but end after
|
||||
*/
|
||||
function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean,
|
||||
minimum?: number, hideHiddenSponsors = false): {includedTimes: ScheduledTime[], scheduledTimes: number[]} {
|
||||
minimum?: number, hideHiddenSponsors = false): {includedTimes: ScheduledTime[]; scheduledTimes: number[]} {
|
||||
if (!sponsorTimes) return {includedTimes: [], scheduledTimes: []};
|
||||
|
||||
const includedTimes: ScheduledTime[] = [];
|
||||
@@ -1569,7 +1592,9 @@ function sendTelemetryAndCount(skippingSegments: SponsorTime[], secondsSkipped:
|
||||
sponsorSkipped[index] = true;
|
||||
if (!counted) {
|
||||
Config.config.minutesSaved = Config.config.minutesSaved + secondsSkipped / 60;
|
||||
Config.config.skipCount = Config.config.skipCount + 1;
|
||||
if (segment.actionType !== ActionType.Chapter) {
|
||||
Config.config.skipCount = Config.config.skipCount + 1;
|
||||
}
|
||||
counted = true;
|
||||
}
|
||||
|
||||
@@ -1741,7 +1766,7 @@ function createButton(baseID: string, title: string, callback: () => void, image
|
||||
}
|
||||
|
||||
function shouldAutoSkip(segment: SponsorTime): boolean {
|
||||
return (!Config.config.manualSkipOnFullVideo || !sponsorTimes?.some((s) => s.category === segment.category && s.actionType === ActionType.Full))
|
||||
return (!Config.config.manualSkipOnFullVideo || !sponsorTimes?.some((s) => s.category === segment.category && s.actionType === ActionType.Full))
|
||||
&& (utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
||||
(Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic")
|
||||
&& segment.actionType !== ActionType.Poi));
|
||||
@@ -1756,16 +1781,14 @@ function shouldSkip(segment: SponsorTime): boolean {
|
||||
|
||||
/** Creates any missing buttons on the YouTube player if possible. */
|
||||
async function createButtons(): Promise<void> {
|
||||
if (onMobileYouTube) return;
|
||||
|
||||
controls = await utils.wait(getControls).catch();
|
||||
|
||||
// Add button if does not already exist in html
|
||||
createButton("startSegment", "sponsorStart", () => startOrEndTimingNewSegment(), "PlayerStartIconSponsorBlocker.svg");
|
||||
createButton("cancelSegment", "sponsorCancel", () => cancelCreatingSegment(), "PlayerCancelSegmentIconSponsorBlocker.svg");
|
||||
createButton("delete", "clearTimes", () => clearSponsorTimes(), "PlayerDeleteIconSponsorBlocker.svg");
|
||||
createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker.svg");
|
||||
createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker.svg");
|
||||
createButton("submit", "SubmitTimes", () => submitSponsorTimes(), "PlayerUploadIconSponsorBlocker.svg");
|
||||
createButton("info", "openPopup", () => openInfoMenu(), "PlayerInfoIconSponsorBlocker.svg");
|
||||
|
||||
const controlsContainer = getControls();
|
||||
if (Config.config.autoHideInfoButton && !onInvidious && controlsContainer
|
||||
@@ -1786,7 +1809,8 @@ async function updateVisibilityOfPlayerControlsButton(): Promise<void> {
|
||||
updateEditButtonsOnPlayer();
|
||||
|
||||
// Don't show the info button on embeds
|
||||
if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) {
|
||||
if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious
|
||||
|| document.getElementById("sponsorBlockPopupContainer") != null) {
|
||||
playerButtons.info.button.style.display = "none";
|
||||
} else {
|
||||
playerButtons.info.button.style.removeProperty("display");
|
||||
@@ -1896,11 +1920,15 @@ function isSegmentCreationInProgress(): boolean {
|
||||
|
||||
function cancelCreatingSegment() {
|
||||
if (isSegmentCreationInProgress()) {
|
||||
sponsorTimesSubmitting.splice(sponsorTimesSubmitting.length - 1, 1);
|
||||
Config.config.unsubmittedSegments[sponsorVideoID] = sponsorTimesSubmitting;
|
||||
if (sponsorTimesSubmitting.length > 1) { // If there's more than one segment: remove last
|
||||
sponsorTimesSubmitting.pop();
|
||||
Config.config.unsubmittedSegments[sponsorVideoID] = sponsorTimesSubmitting;
|
||||
} else { // Otherwise delete the video entry & close submission menu
|
||||
resetSponsorSubmissionNotice();
|
||||
sponsorTimesSubmitting = [];
|
||||
delete Config.config.unsubmittedSegments[sponsorVideoID];
|
||||
}
|
||||
Config.forceSyncUpdate("unsubmittedSegments");
|
||||
|
||||
if (sponsorTimesSubmitting.length <= 0) resetSponsorSubmissionNotice();
|
||||
}
|
||||
|
||||
updateEditButtonsOnPlayer();
|
||||
@@ -1964,7 +1992,7 @@ function openInfoMenu() {
|
||||
frame.src = chrome.extension.getURL("popup.html");
|
||||
popup.appendChild(frame);
|
||||
|
||||
const parentNodes = document.querySelectorAll("#secondary");
|
||||
const parentNodes = document.querySelectorAll("#secondary-inner");
|
||||
let parentNode = null;
|
||||
for (let i = 0; i < parentNodes.length; i++) {
|
||||
if (parentNodes[i].firstElementChild !== null) {
|
||||
@@ -2252,7 +2280,8 @@ function getSegmentsMessage(sponsorTimes: SponsorTime[]): string {
|
||||
function windowListenerHandler(event: MessageEvent): void {
|
||||
const data = event.data;
|
||||
const dataType = data.type;
|
||||
if (data.source !== "sponsorblock") return;
|
||||
|
||||
if (data.source !== "sponsorblock" || document?.URL?.includes("youtube.com/clip/")) return;
|
||||
|
||||
if (dataType === "navigation" && data.videoID) {
|
||||
pageType = data.pageType;
|
||||
@@ -2279,11 +2308,16 @@ function windowListenerHandler(event: MessageEvent): void {
|
||||
}
|
||||
|
||||
function updateActiveSegment(currentTime: number): void {
|
||||
previewBar?.updateChapterText(sponsorTimes, sponsorTimesSubmitting, currentTime);
|
||||
const activeSegments = previewBar?.updateChapterText(sponsorTimes, sponsorTimesSubmitting, currentTime);
|
||||
chrome.runtime.sendMessage({
|
||||
message: "time",
|
||||
time: currentTime
|
||||
});
|
||||
|
||||
const chapterSegments = activeSegments?.filter((segment) => segment.actionType === ActionType.Chapter);
|
||||
if (chapterSegments?.length > 0) {
|
||||
sendTelemetryAndCount(chapterSegments, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
function nextChapter(): void {
|
||||
|
||||
@@ -6,26 +6,26 @@
|
||||
import { PageType } from "./types";
|
||||
|
||||
interface StartMessage {
|
||||
type: "navigation",
|
||||
pageType: PageType
|
||||
videoID: string | null,
|
||||
type: "navigation";
|
||||
pageType: PageType;
|
||||
videoID: string | null;
|
||||
}
|
||||
|
||||
interface FinishMessage extends StartMessage {
|
||||
channelID: string,
|
||||
channelTitle: string
|
||||
channelID: string;
|
||||
channelTitle: string;
|
||||
}
|
||||
|
||||
interface AdMessage {
|
||||
type: "ad",
|
||||
playing: boolean
|
||||
type: "ad";
|
||||
playing: boolean;
|
||||
}
|
||||
|
||||
interface VideoData {
|
||||
type: "data",
|
||||
videoID: string,
|
||||
isLive: boolean,
|
||||
isPremiere: boolean
|
||||
type: "data";
|
||||
videoID: string;
|
||||
isLive: boolean;
|
||||
isPremiere: boolean;
|
||||
}
|
||||
|
||||
type WindowMessage = StartMessage | FinishMessage | AdMessage | VideoData;
|
||||
|
||||
2
src/globals.d.ts
vendored
2
src/globals.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
import { SBObject } from "./config";
|
||||
declare global {
|
||||
interface Window { SB: SBObject; }
|
||||
interface Window { SB: SBObject }
|
||||
// Remove this once the API becomes stable and types are shipped in @types/chrome
|
||||
namespace chrome {
|
||||
namespace declarativeContent {
|
||||
|
||||
@@ -46,6 +46,8 @@ class PreviewBar {
|
||||
segments: PreviewBarSegment[] = [];
|
||||
existingChapters: PreviewBarSegment[] = [];
|
||||
videoDuration = 0;
|
||||
updateExistingChapters: () => void;
|
||||
lastChapterUpdate = 0;
|
||||
|
||||
// For chapter bar
|
||||
hoveredSection: HTMLElement;
|
||||
@@ -58,7 +60,7 @@ class PreviewBar {
|
||||
unfilteredChapterGroups: ChapterGroup[];
|
||||
chapterGroups: ChapterGroup[];
|
||||
|
||||
constructor(parent: HTMLElement, onMobileYouTube: boolean, onInvidious: boolean, chapterVote: ChapterVote, test=false) {
|
||||
constructor(parent: HTMLElement, onMobileYouTube: boolean, onInvidious: boolean, chapterVote: ChapterVote, updateExistingChapters: () => void, test=false) {
|
||||
if (test) return;
|
||||
this.container = document.createElement('ul');
|
||||
this.container.id = 'previewbar';
|
||||
@@ -67,6 +69,7 @@ class PreviewBar {
|
||||
this.onMobileYouTube = onMobileYouTube;
|
||||
this.onInvidious = onInvidious;
|
||||
this.chapterVote = chapterVote;
|
||||
this.updateExistingChapters = updateExistingChapters;
|
||||
|
||||
this.updatePageElements();
|
||||
this.createElement(parent);
|
||||
@@ -214,6 +217,16 @@ class PreviewBar {
|
||||
while (this.container.firstChild) {
|
||||
this.container.removeChild(this.container.firstChild);
|
||||
}
|
||||
|
||||
if (this.customChaptersBar) this.customChaptersBar.style.display = "none";
|
||||
this.originalChapterBar?.style?.removeProperty("display");
|
||||
this.chapterVote?.setVisibility(false);
|
||||
|
||||
document.querySelectorAll(`.sponsorBlockChapterBar`).forEach((e) => {
|
||||
if (e !== this.customChaptersBar) {
|
||||
e.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set(segments: PreviewBarSegment[], videoDuration: number): void {
|
||||
@@ -314,8 +327,11 @@ class PreviewBar {
|
||||
|
||||
createChaptersBar(segments: PreviewBarSegment[]): void {
|
||||
if (!this.progressBar || !this.originalChapterBar || this.originalChapterBar.childElementCount <= 0) {
|
||||
if (this.customChaptersBar) this.customChaptersBar.style.display = "none";
|
||||
if (this.originalChapterBar) this.originalChapterBar.style.removeProperty("display");
|
||||
|
||||
// Make sure other video types lose their chapter bar
|
||||
document.querySelectorAll(".sponsorBlockChapterBar").forEach((element) => element.remove());
|
||||
this.customChaptersBar = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -634,11 +650,17 @@ class PreviewBar {
|
||||
|
||||
cursor += sectionWidthDecimal;
|
||||
}
|
||||
|
||||
if (sections.length !== 0 && sections.length !== this.existingChapters?.length
|
||||
&& Date.now() - this.lastChapterUpdate > 3000) {
|
||||
this.lastChapterUpdate = Date.now();
|
||||
this.updateExistingChapters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private findLeftAndScale(selector: string, currentElement: HTMLElement, progressBar: HTMLElement):
|
||||
{ left: number, scale: number } {
|
||||
{ left: number; scale: number } {
|
||||
const sections = currentElement.parentElement.parentElement.parentElement.children;
|
||||
let currentWidth = 0;
|
||||
let lastWidth = 0;
|
||||
@@ -713,8 +735,9 @@ class PreviewBar {
|
||||
}
|
||||
}
|
||||
|
||||
updateChapterText(segments: SponsorTime[], submittingSegments: SponsorTime[], currentTime: number): void {
|
||||
if ((!segments || segments.length <= 0) && submittingSegments?.length <= 0) {
|
||||
updateChapterText(segments: SponsorTime[], submittingSegments: SponsorTime[], currentTime: number): SponsorTime[] {
|
||||
if (!Config.config.showSegmentNameInChapterBar
|
||||
|| ((!segments || segments.length <= 0) && submittingSegments?.length <= 0)) {
|
||||
const chaptersContainer = this.getChaptersContainer();
|
||||
const chapterButton = this.getChapterButton(chaptersContainer);
|
||||
if (chapterButton.classList.contains("ytp-chapter-container-disabled")) {
|
||||
@@ -733,6 +756,7 @@ class PreviewBar {
|
||||
});
|
||||
|
||||
this.setActiveSegments(activeSegments);
|
||||
return activeSegments;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -761,9 +785,14 @@ class PreviewBar {
|
||||
|
||||
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;
|
||||
chapterTitle.innerText = chosenSegment.description || shortCategoryName(chosenSegment.category);
|
||||
if (chosenSegment.actionType !== ActionType.Chapter) {
|
||||
chapterTitle.classList.add("sponsorBlock-segment-title");
|
||||
} else {
|
||||
chapterTitle.classList.remove("sponsorBlock-segment-title");
|
||||
}
|
||||
|
||||
const chapterVoteContainer = this.chapterVote.getContainer();
|
||||
if (chosenSegment.source === SponsorSourceType.Server) {
|
||||
const chapterVoteContainer = this.chapterVote.getContainer();
|
||||
if (!chapterButton.contains(chapterVoteContainer)) {
|
||||
const oldVoteContainers = document.querySelectorAll("#chapterVote");
|
||||
if (oldVoteContainers.length > 0) {
|
||||
|
||||
@@ -9,7 +9,7 @@ interface BaseMessage {
|
||||
}
|
||||
|
||||
interface DefaultMessage {
|
||||
message:
|
||||
message:
|
||||
"update"
|
||||
| "sponsorStart"
|
||||
| "getVideoID"
|
||||
@@ -83,19 +83,19 @@ interface GetVideoIdResponse {
|
||||
videoID: string;
|
||||
}
|
||||
|
||||
interface GetChannelIDResponse {
|
||||
export interface GetChannelIDResponse {
|
||||
channelID: string;
|
||||
}
|
||||
|
||||
interface SponsorStartResponse {
|
||||
export interface SponsorStartResponse {
|
||||
creatingSegment: boolean;
|
||||
}
|
||||
|
||||
interface IsChannelWhitelistedResponse {
|
||||
export interface IsChannelWhitelistedResponse {
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export type MessageResponse =
|
||||
export type MessageResponse =
|
||||
IsInfoFoundMessageResponse
|
||||
| GetVideoIdResponse
|
||||
| GetChannelIDResponse
|
||||
@@ -111,7 +111,7 @@ export interface VoteResponse {
|
||||
responseText: string;
|
||||
}
|
||||
|
||||
export interface ImportSegmentsResponse {
|
||||
interface ImportSegmentsResponse {
|
||||
importedSegments: SponsorTime[];
|
||||
}
|
||||
|
||||
@@ -120,4 +120,14 @@ export interface TimeUpdateMessage {
|
||||
time: number;
|
||||
}
|
||||
|
||||
export type PopupMessage = TimeUpdateMessage;
|
||||
export type InfoUpdatedMessage = IsInfoFoundMessageResponse & {
|
||||
message: "infoUpdated";
|
||||
}
|
||||
|
||||
export interface VideoChangedPopupMessage {
|
||||
message: "videoChanged";
|
||||
videoID: string;
|
||||
whitelisted: boolean;
|
||||
}
|
||||
|
||||
export type PopupMessage = TimeUpdateMessage | InfoUpdatedMessage | VideoChangedPopupMessage;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import Config from "./config";
|
||||
import * as CompileConfig from "../config.json";
|
||||
@@ -258,7 +258,8 @@ async function init() {
|
||||
break;
|
||||
}
|
||||
case "keybind-change": {
|
||||
ReactDOM.render(React.createElement(KeybindComponent, {option: option}), optionsElements[i].querySelector("div"));
|
||||
const root = createRoot(optionsElements[i].querySelector("div"));
|
||||
root.render(React.createElement(KeybindComponent, {option: option}));
|
||||
break;
|
||||
}
|
||||
case "display": {
|
||||
|
||||
474
src/popup.ts
474
src/popup.ts
@@ -1,8 +1,24 @@
|
||||
import Config from "./config";
|
||||
|
||||
import Utils from "./utils";
|
||||
import { SponsorTime, SponsorHideType, ActionType, SegmentUUID, SponsorSourceType, StorageChangesObject } from "./types";
|
||||
import { Message, MessageResponse, IsInfoFoundMessageResponse, ImportSegmentsResponse, PopupMessage } from "./messageTypes";
|
||||
import {
|
||||
ActionType,
|
||||
SegmentUUID,
|
||||
SponsorHideType,
|
||||
SponsorSourceType,
|
||||
SponsorTime,
|
||||
StorageChangesObject,
|
||||
} from "./types";
|
||||
import {
|
||||
GetChannelIDResponse,
|
||||
IsChannelWhitelistedResponse,
|
||||
IsInfoFoundMessageResponse,
|
||||
Message,
|
||||
MessageResponse,
|
||||
PopupMessage,
|
||||
SponsorStartResponse,
|
||||
VoteResponse,
|
||||
} from "./messageTypes";
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
import { AnimationUtils } from "./utils/animationUtils";
|
||||
import { GenericUtils } from "./utils/genericUtils";
|
||||
@@ -10,6 +26,8 @@ import { shortCategoryName } from "./utils/categoryUtils";
|
||||
import { localizeHtmlPage } from "./utils/pageUtils";
|
||||
import { exportTimes } from "./utils/exporter";
|
||||
import GenericNotice from "./render/GenericNotice";
|
||||
import { noRefreshFetchingChaptersAllowed } from "./utils/licenseKey";
|
||||
|
||||
const utils = new Utils();
|
||||
|
||||
interface MessageListener {
|
||||
@@ -60,14 +78,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
localizeHtmlPage();
|
||||
|
||||
type InputPageElements = {
|
||||
whitelistToggle?: HTMLInputElement,
|
||||
toggleSwitch?: HTMLInputElement,
|
||||
usernameInput?: HTMLInputElement,
|
||||
whitelistToggle?: HTMLInputElement;
|
||||
toggleSwitch?: HTMLInputElement;
|
||||
usernameInput?: HTMLInputElement;
|
||||
};
|
||||
type PageElements = { [key: string]: HTMLElement } & InputPageElements
|
||||
|
||||
/** If true, the content script is in the process of creating a new segment. */
|
||||
let creatingSegment = false;
|
||||
let stopLoadingAnimation = null;
|
||||
|
||||
//the start and end time pairs (2d)
|
||||
let sponsorTimes: SponsorTime[] = [];
|
||||
@@ -83,6 +100,9 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
let segmentTab = SegmentTab.Segments;
|
||||
let port: chrome.runtime.Port = null;
|
||||
|
||||
//saves which detail elemts are opened, by saving the uuids
|
||||
const openedUUIDs: SegmentUUID[] = [];
|
||||
|
||||
const PageElements: PageElements = {};
|
||||
|
||||
[
|
||||
@@ -184,7 +204,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
}
|
||||
|
||||
PageElements.exportSegmentsButton.addEventListener("click", exportSegments);
|
||||
PageElements.importSegmentsButton.addEventListener("click",
|
||||
PageElements.importSegmentsButton.addEventListener("click",
|
||||
() => PageElements.importSegmentsMenu.classList.toggle("hidden"));
|
||||
PageElements.importSegmentsSubmit.addEventListener("click", importSegments);
|
||||
|
||||
@@ -257,8 +277,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
PageElements.showNoticeAgain.style.display = "unset";
|
||||
}
|
||||
|
||||
utils.sendRequestToServer("GET", "/api/userInfo?value=userName&value=viewCount&value=minutesSaved&value=vip&value=permissions&value=freeChaptersAccess&userID="
|
||||
+ Config.config.userID, (res) => {
|
||||
const values = ["userName", "viewCount", "minutesSaved", "vip", "permissions"];
|
||||
if (!Config.config.payments.freeAccess && !noRefreshFetchingChaptersAllowed()) values.push("freeChaptersAccess");
|
||||
|
||||
utils.asyncRequestToServer("GET", "/api/userInfo", {
|
||||
userID: Config.config.userID,
|
||||
values
|
||||
}).then((res) => {
|
||||
if (res.status === 200) {
|
||||
const userInfo = JSON.parse(res.responseText);
|
||||
PageElements.usernameValue.innerText = userInfo.userName;
|
||||
@@ -367,7 +392,6 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
messageHandler.sendMessage(tabs[0].id, { message: 'getVideoID' }, function (result) {
|
||||
if (result !== undefined && result.videoID) {
|
||||
currentVideoID = result.videoID;
|
||||
creatingSegment = result.creatingSegment;
|
||||
|
||||
loadTabData(tabs, updating);
|
||||
} else if (result === undefined && chrome.runtime.lastError) {
|
||||
@@ -402,7 +426,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
}, (tabs) => onTabs(tabs, updating));
|
||||
}
|
||||
|
||||
function infoFound(request: IsInfoFoundMessageResponse) {
|
||||
async function infoFound(request: IsInfoFoundMessageResponse) {
|
||||
// End any loading animation
|
||||
if (stopLoadingAnimation != null) {
|
||||
stopLoadingAnimation();
|
||||
stopLoadingAnimation = null;
|
||||
}
|
||||
|
||||
if (chrome.runtime.lastError) {
|
||||
//This page doesn't have the injected content script, or at least not yet
|
||||
displayNoVideo();
|
||||
@@ -418,16 +448,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
PageElements.loadingIndicator.style.display = "none";
|
||||
|
||||
downloadedTimes = request.sponsorTimes ?? [];
|
||||
displayDownloadedSponsorTimes(downloadedTimes, request.time);
|
||||
if (request.found) {
|
||||
PageElements.videoFound.innerHTML = chrome.i18n.getMessage("sponsorFound");
|
||||
|
||||
PageElements.issueReporterImportExport.classList.remove("hidden");
|
||||
if (request.sponsorTimes) {
|
||||
displayDownloadedSponsorTimes(request.sponsorTimes, request.time);
|
||||
}
|
||||
} else if (request.status == 404 || request.status == 200) {
|
||||
PageElements.videoFound.innerHTML = chrome.i18n.getMessage("sponsor404");
|
||||
PageElements.issueReporterImportExport.classList.add("hidden");
|
||||
PageElements.issueReporterImportExport.classList.remove("hidden");
|
||||
} else {
|
||||
PageElements.videoFound.innerHTML = chrome.i18n.getMessage("connectionError") + request.status;
|
||||
PageElements.issueReporterImportExport.classList.add("hidden");
|
||||
@@ -435,62 +462,40 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
}
|
||||
|
||||
//see if whitelist button should be swapped
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{ message: 'isChannelWhitelisted' },
|
||||
function (response) {
|
||||
if (response.value) {
|
||||
PageElements.whitelistChannel.style.display = "none";
|
||||
PageElements.unwhitelistChannel.style.display = "unset";
|
||||
PageElements.whitelistToggle.checked = true;
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated");
|
||||
}
|
||||
});
|
||||
const response = await sendTabMessageAsync({ message: 'isChannelWhitelisted' }) as IsChannelWhitelistedResponse;
|
||||
if (response.value) {
|
||||
PageElements.whitelistChannel.style.display = "none";
|
||||
PageElements.unwhitelistChannel.style.display = "unset";
|
||||
PageElements.whitelistToggle.checked = true;
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function sendSponsorStartMessage() {
|
||||
async function sendSponsorStartMessage() {
|
||||
//the content script will get the message if a YouTube page is open
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
}, (tabs) => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{ from: 'popup', message: 'sponsorStart' },
|
||||
async (response) => {
|
||||
startSponsorCallback(response);
|
||||
const response = await sendTabMessageAsync({ from: 'popup', message: 'sponsorStart' }) as SponsorStartResponse;
|
||||
startSponsorCallback(response);
|
||||
|
||||
// Perform a second update after the config changes take effect as a workaround for a race condition
|
||||
const removeListener = (listener: typeof lateUpdate) => {
|
||||
const index = Config.configSyncListeners.indexOf(listener);
|
||||
if (index !== -1) Config.configSyncListeners.splice(index, 1);
|
||||
};
|
||||
// Perform a second update after the config changes take effect as a workaround for a race condition
|
||||
const removeListener = (listener: typeof lateUpdate) => {
|
||||
const index = Config.configSyncListeners.indexOf(listener);
|
||||
if (index !== -1) Config.configSyncListeners.splice(index, 1);
|
||||
};
|
||||
|
||||
const lateUpdate = () => {
|
||||
startSponsorCallback(response);
|
||||
removeListener(lateUpdate);
|
||||
};
|
||||
const lateUpdate = () => {
|
||||
startSponsorCallback(response);
|
||||
removeListener(lateUpdate);
|
||||
};
|
||||
|
||||
Config.configSyncListeners.push(lateUpdate);
|
||||
Config.configSyncListeners.push(lateUpdate);
|
||||
|
||||
// Remove the listener after 200ms in case the changes were propagated by the time we got the response
|
||||
setTimeout(() => removeListener(lateUpdate), 200);
|
||||
},
|
||||
);
|
||||
});
|
||||
// Remove the listener after 200ms in case the changes were propagated by the time we got the response
|
||||
setTimeout(() => removeListener(lateUpdate), 200);
|
||||
}
|
||||
|
||||
function startSponsorCallback(response: { creatingSegment: boolean }) {
|
||||
creatingSegment = response.creatingSegment;
|
||||
|
||||
function startSponsorCallback(response: SponsorStartResponse) {
|
||||
// Only update the segments after a segment was created
|
||||
if (!creatingSegment) {
|
||||
if (!response.creatingSegment) {
|
||||
sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] || [];
|
||||
}
|
||||
|
||||
@@ -505,7 +510,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
PageElements.issueReporterTabs.classList.add("hidden");
|
||||
currentSegmentTab = SegmentTab.Segments;
|
||||
} else {
|
||||
PageElements.issueReporterTabs.classList.remove("hidden");
|
||||
if (currentSegmentTab === SegmentTab.Segments
|
||||
&& sponsorTimes.every((segment) => segment.actionType === ActionType.Chapter)) {
|
||||
PageElements.issueReporterTabs.classList.add("hidden");
|
||||
currentSegmentTab = SegmentTab.Chapters;
|
||||
} else {
|
||||
PageElements.issueReporterTabs.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Sort list by start time
|
||||
@@ -514,7 +525,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
if (currentSegmentTab === SegmentTab.Segments) {
|
||||
return segment.actionType !== ActionType.Chapter;
|
||||
} else if (currentSegmentTab === SegmentTab.Chapters) {
|
||||
return segment.actionType === ActionType.Chapter
|
||||
return segment.actionType === ActionType.Chapter
|
||||
&& segment.source !== SponsorSourceType.YouTube;
|
||||
} else {
|
||||
return true;
|
||||
@@ -531,7 +542,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
|
||||
if (downloadedTimes.length > 0) {
|
||||
PageElements.exportSegmentsButton.classList.remove("hidden");
|
||||
} else {
|
||||
} else {
|
||||
PageElements.exportSegmentsButton.classList.add("hidden");
|
||||
}
|
||||
|
||||
@@ -575,7 +586,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
if (downloadedTimes[i].actionType === ActionType.Full) {
|
||||
segmentTimeFromToNode.innerText = chrome.i18n.getMessage("full");
|
||||
} else {
|
||||
segmentTimeFromToNode.innerText = GenericUtils.getFormattedTime(downloadedTimes[i].segment[0], true) +
|
||||
segmentTimeFromToNode.innerText = GenericUtils.getFormattedTime(downloadedTimes[i].segment[0], true) +
|
||||
(actionType !== ActionType.Poi
|
||||
? " " + chrome.i18n.getMessage("to") + " " + GenericUtils.getFormattedTime(downloadedTimes[i].segment[1], true)
|
||||
: "");
|
||||
@@ -597,6 +608,18 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
|
||||
const votingButtons = document.createElement("details");
|
||||
votingButtons.classList.add("votingButtons");
|
||||
votingButtons.id = "votingButtons" + UUID;
|
||||
votingButtons.addEventListener("toggle", () => {
|
||||
if (votingButtons.open) {
|
||||
openedUUIDs.push(UUID);
|
||||
} else {
|
||||
const index = openedUUIDs.indexOf(UUID);
|
||||
if (index !== -1) {
|
||||
openedUUIDs.splice(openedUUIDs.indexOf(UUID), 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
votingButtons.open = openedUUIDs.some((u) => u === UUID);
|
||||
|
||||
//thumbs up and down buttons
|
||||
const voteButtonsContainer = document.createElement("div");
|
||||
@@ -649,25 +672,19 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
downloadedTimes[i].hidden = SponsorHideType.Hidden;
|
||||
}
|
||||
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{
|
||||
message: "hideSegment",
|
||||
type: downloadedTimes[i].hidden,
|
||||
UUID: UUID
|
||||
}
|
||||
);
|
||||
});
|
||||
sendTabMessage({
|
||||
message: "hideSegment",
|
||||
type: downloadedTimes[i].hidden,
|
||||
UUID: UUID
|
||||
})
|
||||
});
|
||||
|
||||
const skipButton = document.createElement("img");
|
||||
skipButton.id = "sponsorTimesSkipButtonContainer" + UUID;
|
||||
skipButton.className = "voteButton";
|
||||
skipButton.src = chrome.runtime.getURL("icons/skip.svg");
|
||||
skipButton.title = actionType === ActionType.Chapter ? chrome.i18n.getMessage("playChapter")
|
||||
: chrome.i18n.getMessage("skipSegment");
|
||||
skipButton.addEventListener("click", () => skipSegment(actionType, UUID, skipButton));
|
||||
votingButtons.addEventListener("dblclick", () => skipSegment(actionType, UUID));
|
||||
|
||||
@@ -679,8 +696,9 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
&& [SponsorHideType.Visible, SponsorHideType.Hidden].includes(downloadedTimes[i].hidden)) {
|
||||
voteButtonsContainer.appendChild(hideButton);
|
||||
}
|
||||
voteButtonsContainer.appendChild(skipButton);
|
||||
|
||||
if (downloadedTimes[i].actionType !== ActionType.Full) {
|
||||
voteButtonsContainer.appendChild(skipButton);
|
||||
}
|
||||
|
||||
// Will contain request status
|
||||
const voteStatusContainer = document.createElement("div");
|
||||
@@ -703,15 +721,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
|
||||
function submitTimes() {
|
||||
if (sponsorTimes.length > 0) {
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{ message: 'submitTimes' },
|
||||
);
|
||||
});
|
||||
sendTabMessage({ message: 'submitTimes' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,9 +731,16 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
PageElements.showNoticeAgain.style.display = "none";
|
||||
}
|
||||
|
||||
function isCreatingSegment(): boolean {
|
||||
const segments = Config.config.unsubmittedSegments[currentVideoID];
|
||||
if (!segments) return false;
|
||||
const lastSegment = segments[segments.length - 1];
|
||||
return lastSegment && lastSegment?.segment?.length !== 2;
|
||||
}
|
||||
|
||||
/** Updates any UI related to segment editing and submission according to the current state. */
|
||||
function updateSegmentEditingUI() {
|
||||
PageElements.sponsorStart.innerText = chrome.i18n.getMessage(creatingSegment ? "sponsorEnd" : "sponsorStart");
|
||||
PageElements.sponsorStart.innerText = chrome.i18n.getMessage(isCreatingSegment() ? "sponsorEnd" : "sponsorStart");
|
||||
|
||||
PageElements.submitTimes.style.display = sponsorTimes && sponsorTimes.length > 0 ? "unset" : "none";
|
||||
PageElements.submissionHint.style.display = sponsorTimes && sponsorTimes.length > 0 ? "unset" : "none";
|
||||
@@ -742,20 +759,22 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
chrome.runtime.sendMessage({ "message": "openHelp" });
|
||||
}
|
||||
|
||||
function sendTabMessage(data: Message): Promise<unknown> {
|
||||
return new Promise((resolve) => {
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
data,
|
||||
(response) => resolve(response)
|
||||
);
|
||||
}
|
||||
function sendTabMessage(data: Message, callback?) {
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
data,
|
||||
callback
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function sendTabMessageAsync(data: Message): Promise<unknown> {
|
||||
return new Promise((resolve) => sendTabMessage(data, (response) => resolve(response)))
|
||||
}
|
||||
|
||||
//make the options username setting option visible
|
||||
@@ -832,186 +851,122 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
thanksForVotingText.removeAttribute("innerText");
|
||||
}
|
||||
|
||||
function vote(type, UUID) {
|
||||
async function vote(type, UUID) {
|
||||
//add loading info
|
||||
addVoteMessage(chrome.i18n.getMessage("Loading"), UUID);
|
||||
const response = await sendTabMessageAsync({
|
||||
message: "submitVote",
|
||||
type: type,
|
||||
UUID: UUID
|
||||
}) as VoteResponse;
|
||||
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{
|
||||
message: "submitVote",
|
||||
type: type,
|
||||
UUID: UUID
|
||||
}, function (response) {
|
||||
if (response != undefined) {
|
||||
//see if it was a success or failure
|
||||
if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) {
|
||||
//success (treat rate limits as a success)
|
||||
addVoteMessage(chrome.i18n.getMessage("voted"), UUID);
|
||||
} else if (response.successType == -1) {
|
||||
addVoteMessage(GenericUtils.getErrorMessage(response.statusCode, response.responseText), UUID);
|
||||
}
|
||||
setTimeout(() => removeVoteMessage(UUID), 1500);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (response != undefined) {
|
||||
//see if it was a success or failure
|
||||
if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) {
|
||||
//success (treat rate limits as a success)
|
||||
addVoteMessage(chrome.i18n.getMessage("voted"), UUID);
|
||||
} else if (response.successType == -1) {
|
||||
addVoteMessage(GenericUtils.getErrorMessage(response.statusCode, response.responseText), UUID);
|
||||
}
|
||||
setTimeout(() => removeVoteMessage(UUID), 1500);
|
||||
}
|
||||
}
|
||||
|
||||
async function whitelistChannel() {
|
||||
//get the channel url
|
||||
const response = await sendTabMessageAsync({ message: 'getChannelID' }) as GetChannelIDResponse;
|
||||
if (!response.channelID) {
|
||||
alert(chrome.i18n.getMessage("channelDataNotFound") + " https://github.com/ajayyy/SponsorBlock/issues/753");
|
||||
return;
|
||||
}
|
||||
|
||||
//get whitelisted channels
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
if (whitelistedChannels == undefined) {
|
||||
whitelistedChannels = [];
|
||||
}
|
||||
|
||||
//add on this channel
|
||||
whitelistedChannels.push(response.channelID);
|
||||
|
||||
//change button
|
||||
PageElements.whitelistChannel.style.display = "none";
|
||||
PageElements.unwhitelistChannel.style.display = "unset";
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated");
|
||||
|
||||
//show 'consider force channel check' alert
|
||||
if (!Config.config.forceChannelCheck) PageElements.whitelistForceCheck.classList.remove("hidden");
|
||||
|
||||
//save this
|
||||
Config.config.whitelistedChannels = whitelistedChannels;
|
||||
|
||||
//send a message to the client
|
||||
sendTabMessage({
|
||||
message: 'whitelistChange',
|
||||
value: true
|
||||
});
|
||||
}
|
||||
|
||||
function whitelistChannel() {
|
||||
async function unwhitelistChannel() {
|
||||
//get the channel url
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{ message: 'getChannelID' },
|
||||
function (response) {
|
||||
if (!response.channelID) {
|
||||
alert(chrome.i18n.getMessage("channelDataNotFound") + " https://github.com/ajayyy/SponsorBlock/issues/753");
|
||||
return;
|
||||
}
|
||||
const response = await sendTabMessageAsync({ message: 'getChannelID' }) as GetChannelIDResponse;
|
||||
|
||||
//get whitelisted channels
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
if (whitelistedChannels == undefined) {
|
||||
whitelistedChannels = [];
|
||||
}
|
||||
//get whitelisted channels
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
if (whitelistedChannels == undefined) {
|
||||
whitelistedChannels = [];
|
||||
}
|
||||
|
||||
//add on this channel
|
||||
whitelistedChannels.push(response.channelID);
|
||||
//remove this channel
|
||||
const index = whitelistedChannels.indexOf(response.channelID);
|
||||
whitelistedChannels.splice(index, 1);
|
||||
|
||||
//change button
|
||||
PageElements.whitelistChannel.style.display = "none";
|
||||
PageElements.unwhitelistChannel.style.display = "unset";
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated");
|
||||
//change button
|
||||
PageElements.whitelistChannel.style.display = "unset";
|
||||
PageElements.unwhitelistChannel.style.display = "none";
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.remove("rotated");
|
||||
|
||||
//show 'consider force channel check' alert
|
||||
if (!Config.config.forceChannelCheck) PageElements.whitelistForceCheck.classList.remove("hidden");
|
||||
//hide 'consider force channel check' alert
|
||||
PageElements.whitelistForceCheck.classList.add("hidden");
|
||||
|
||||
//save this
|
||||
Config.config.whitelistedChannels = whitelistedChannels;
|
||||
//save this
|
||||
Config.config.whitelistedChannels = whitelistedChannels;
|
||||
|
||||
//send a message to the client
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id, {
|
||||
message: 'whitelistChange',
|
||||
value: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
//send a message to the client
|
||||
sendTabMessage({
|
||||
message: 'whitelistChange',
|
||||
value: false
|
||||
});
|
||||
}
|
||||
|
||||
function unwhitelistChannel() {
|
||||
//get the channel url
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{ message: 'getChannelID' },
|
||||
function (response) {
|
||||
//get whitelisted channels
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
if (whitelistedChannels == undefined) {
|
||||
whitelistedChannels = [];
|
||||
}
|
||||
|
||||
//remove this channel
|
||||
const index = whitelistedChannels.indexOf(response.channelID);
|
||||
whitelistedChannels.splice(index, 1);
|
||||
|
||||
//change button
|
||||
PageElements.whitelistChannel.style.display = "unset";
|
||||
PageElements.unwhitelistChannel.style.display = "none";
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.remove("rotated");
|
||||
|
||||
//hide 'consider force channel check' alert
|
||||
PageElements.whitelistForceCheck.classList.add("hidden");
|
||||
|
||||
//save this
|
||||
Config.config.whitelistedChannels = whitelistedChannels;
|
||||
|
||||
//send a message to the client
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id, {
|
||||
message: 'whitelistChange',
|
||||
value: false
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
function startLoadingAnimation() {
|
||||
stopLoadingAnimation = AnimationUtils.applyLoadingAnimation(PageElements.refreshSegmentsButton, 0.3);
|
||||
}
|
||||
|
||||
function refreshSegments() {
|
||||
const stopAnimation = AnimationUtils.applyLoadingAnimation(PageElements.refreshSegmentsButton, 0.3);
|
||||
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{ message: 'refreshSegments' },
|
||||
(response) => {
|
||||
infoFound(response);
|
||||
stopAnimation();
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
startLoadingAnimation();
|
||||
sendTabMessage({ message: 'refreshSegments' });
|
||||
}
|
||||
|
||||
function skipSegment(actionType: ActionType, UUID: SegmentUUID, element?: HTMLElement): void {
|
||||
if (actionType === ActionType.Chapter) {
|
||||
sendMessage({
|
||||
sendTabMessage({
|
||||
message: "unskip",
|
||||
UUID: UUID
|
||||
});
|
||||
} else {
|
||||
sendMessage({
|
||||
sendTabMessage({
|
||||
message: "reskip",
|
||||
UUID: UUID
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (element) {
|
||||
const stopAnimation = AnimationUtils.applyLoadingAnimation(element, 0.3);
|
||||
stopAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage(request: Message): void {
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
request
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Should skipping be disabled (visuals stay)
|
||||
*/
|
||||
@@ -1044,10 +999,10 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
async function importSegments() {
|
||||
const text = (PageElements.importSegmentsText as HTMLInputElement).value;
|
||||
|
||||
await sendTabMessage({
|
||||
sendTabMessage({
|
||||
message: "importSegments",
|
||||
data: text
|
||||
}) as ImportSegmentsResponse;
|
||||
});
|
||||
|
||||
PageElements.importSegmentsMenu.classList.add("hidden");
|
||||
}
|
||||
@@ -1112,6 +1067,27 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
case "time":
|
||||
displayDownloadedSponsorTimes(downloadedTimes, msg.time);
|
||||
break;
|
||||
case "infoUpdated":
|
||||
infoFound(msg);
|
||||
break;
|
||||
case "videoChanged":
|
||||
currentVideoID = msg.videoID
|
||||
sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] ?? [];
|
||||
updateSegmentEditingUI();
|
||||
|
||||
if (msg.whitelisted) {
|
||||
PageElements.whitelistChannel.style.display = "none";
|
||||
PageElements.unwhitelistChannel.style.display = "unset";
|
||||
PageElements.whitelistToggle.checked = true;
|
||||
document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated");
|
||||
}
|
||||
|
||||
// Clear segments list & start loading animation
|
||||
// We'll get a ping once they're loaded
|
||||
startLoadingAnimation();
|
||||
PageElements.videoFound.innerHTML = chrome.i18n.getMessage("Loading");
|
||||
displayDownloadedSponsorTimes([], 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import CategoryChooserComponent from "../components/options/CategoryChooserComponent";
|
||||
|
||||
class CategoryChooser {
|
||||
@@ -9,9 +10,9 @@ class CategoryChooser {
|
||||
constructor(element: Element) {
|
||||
this.ref = React.createRef();
|
||||
|
||||
ReactDOM.render(
|
||||
<CategoryChooserComponent ref={this.ref} />,
|
||||
element
|
||||
const root = createRoot(element);
|
||||
root.render(
|
||||
<CategoryChooserComponent ref={this.ref} />
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from "react-dom/client";
|
||||
import CategoryPillComponent, { CategoryPillState } from "../components/CategoryPillComponent";
|
||||
import Config from "../config";
|
||||
import { VoteResponse } from "../messageTypes";
|
||||
@@ -10,6 +10,7 @@ import { Tooltip } from "./Tooltip";
|
||||
export class CategoryPill {
|
||||
container: HTMLElement;
|
||||
ref: React.RefObject<CategoryPillComponent>;
|
||||
root: Root;
|
||||
|
||||
unsavedState: CategoryPillState;
|
||||
|
||||
@@ -38,10 +39,8 @@ export class CategoryPill {
|
||||
this.unsavedState = this.ref.current.state;
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<CategoryPillComponent ref={this.ref} vote={vote} />,
|
||||
this.container
|
||||
);
|
||||
this.root = createRoot(this.container);
|
||||
this.root.render(<CategoryPillComponent ref={this.ref} vote={vote} />);
|
||||
|
||||
if (this.unsavedState) {
|
||||
this.ref.current?.setState(this.unsavedState);
|
||||
@@ -64,7 +63,7 @@ export class CategoryPill {
|
||||
}
|
||||
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.container);
|
||||
this.root.unmount();
|
||||
this.container.remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import ChapterVoteComponent, { ChapterVoteState } from "../components/ChapterVoteComponent";
|
||||
import { VoteResponse } from "../messageTypes";
|
||||
import { Category, SegmentUUID, SponsorTime } from "../types";
|
||||
@@ -7,6 +7,7 @@ import { Category, SegmentUUID, SponsorTime } from "../types";
|
||||
export class ChapterVote {
|
||||
container: HTMLElement;
|
||||
ref: React.RefObject<ChapterVoteComponent>;
|
||||
root: Root;
|
||||
|
||||
unsavedState: ChapterVoteState;
|
||||
|
||||
@@ -19,10 +20,8 @@ export class ChapterVote {
|
||||
this.container.id = "chapterVote";
|
||||
this.container.style.height = "100%";
|
||||
|
||||
ReactDOM.render(
|
||||
<ChapterVoteComponent ref={this.ref} vote={vote} />,
|
||||
this.container
|
||||
);
|
||||
this.root = createRoot(this.container);
|
||||
this.root.render(<ChapterVoteComponent ref={this.ref} vote={vote} />);
|
||||
}
|
||||
|
||||
getContainer(): HTMLElement {
|
||||
@@ -30,7 +29,7 @@ export class ChapterVote {
|
||||
}
|
||||
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.container);
|
||||
this.root.unmount();
|
||||
this.container.remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import NoticeComponent from "../components/NoticeComponent";
|
||||
|
||||
import Utils from "../utils";
|
||||
@@ -9,17 +9,17 @@ import { ButtonListener, ContentContainer } from "../types";
|
||||
import NoticeTextSelectionComponent from "../components/NoticeTextSectionComponent";
|
||||
|
||||
export interface TextBox {
|
||||
icon: string,
|
||||
text: string
|
||||
icon: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface NoticeOptions {
|
||||
title: string,
|
||||
referenceNode?: HTMLElement,
|
||||
textBoxes?: TextBox[],
|
||||
buttons?: ButtonListener[],
|
||||
fadeIn?: boolean,
|
||||
timed?: boolean
|
||||
title: string;
|
||||
referenceNode?: HTMLElement;
|
||||
textBoxes?: TextBox[];
|
||||
buttons?: ButtonListener[];
|
||||
fadeIn?: boolean;
|
||||
timed?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
extraClass?: string;
|
||||
maxCountdownTime?: () => number;
|
||||
@@ -35,6 +35,7 @@ export default class GenericNotice {
|
||||
noticeElement: HTMLDivElement;
|
||||
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||
idSuffix: string;
|
||||
root: Root;
|
||||
|
||||
constructor(contentContainer: ContentContainer, idSuffix: string, options: NoticeOptions) {
|
||||
this.noticeRef = React.createRef();
|
||||
@@ -49,11 +50,13 @@ export default class GenericNotice {
|
||||
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
this.update(options);
|
||||
this.root = createRoot(this.noticeElement);
|
||||
|
||||
this.update(options);
|
||||
}
|
||||
|
||||
update(options: NoticeOptions): void {
|
||||
ReactDOM.render(
|
||||
this.root.render(
|
||||
<NoticeComponent
|
||||
noticeTitle={options.title}
|
||||
idSuffix={this.idSuffix}
|
||||
@@ -92,8 +95,7 @@ export default class GenericNotice {
|
||||
</>
|
||||
: null}
|
||||
|
||||
</NoticeComponent>,
|
||||
this.noticeElement
|
||||
</NoticeComponent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -137,7 +139,7 @@ export default class GenericNotice {
|
||||
}
|
||||
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
this.root.unmount();
|
||||
|
||||
this.noticeElement.remove();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
|
||||
export interface RectangleTooltipProps {
|
||||
text: string,
|
||||
link?: string,
|
||||
referenceNode: HTMLElement,
|
||||
prependElement?: HTMLElement, // Element to append before
|
||||
bottomOffset?: string,
|
||||
leftOffset?: string,
|
||||
timeout?: number,
|
||||
htmlId?: string,
|
||||
maxHeight?: string,
|
||||
maxWidth?: string,
|
||||
backgroundColor?: string,
|
||||
fontSize?: string,
|
||||
text: string;
|
||||
link?: string;
|
||||
referenceNode: HTMLElement;
|
||||
prependElement?: HTMLElement; // Element to append before
|
||||
bottomOffset?: string;
|
||||
leftOffset?: string;
|
||||
timeout?: number;
|
||||
htmlId?: string;
|
||||
maxHeight?: string;
|
||||
maxWidth?: string;
|
||||
backgroundColor?: string;
|
||||
fontSize?: string;
|
||||
buttonFunction?: () => void;
|
||||
}
|
||||
|
||||
export class RectangleTooltip {
|
||||
text: string;
|
||||
container: HTMLDivElement;
|
||||
|
||||
root: Root;
|
||||
timer: NodeJS.Timeout;
|
||||
|
||||
constructor(props: RectangleTooltipProps) {
|
||||
@@ -47,7 +47,8 @@ export class RectangleTooltip {
|
||||
this.timer = setTimeout(() => this.close(), props.timeout * 1000);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
this.root = createRoot(this.container);
|
||||
this.root.render(
|
||||
<div style={{
|
||||
bottom: props.bottomOffset,
|
||||
left: props.leftOffset,
|
||||
@@ -81,13 +82,12 @@ export class RectangleTooltip {
|
||||
|
||||
{chrome.i18n.getMessage("GotIt")}
|
||||
</button>
|
||||
</div>,
|
||||
this.container
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.container);
|
||||
this.root.unmount();
|
||||
this.container.remove();
|
||||
|
||||
if (this.timer) clearTimeout(this.timer);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
|
||||
import Utils from "../utils";
|
||||
const utils = new Utils();
|
||||
@@ -18,6 +18,7 @@ class SkipNotice {
|
||||
noticeElement: HTMLDivElement;
|
||||
|
||||
skipNoticeRef: React.MutableRefObject<SkipNoticeComponent>;
|
||||
root: Root;
|
||||
|
||||
constructor(segments: SponsorTime[], autoSkip = false, contentContainer: ContentContainer, unskipTime: number = null, startReskip = false) {
|
||||
this.skipNoticeRef = React.createRef();
|
||||
@@ -41,7 +42,8 @@ class SkipNotice {
|
||||
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
ReactDOM.render(
|
||||
this.root = createRoot(this.noticeElement);
|
||||
this.root.render(
|
||||
<SkipNoticeComponent segments={segments}
|
||||
autoSkip={autoSkip}
|
||||
startReskip={startReskip}
|
||||
@@ -50,8 +52,7 @@ class SkipNotice {
|
||||
closeListener={() => this.close()}
|
||||
smaller={Config.config.noticeVisibilityMode >= NoticeVisbilityMode.MiniForAll
|
||||
|| (Config.config.noticeVisibilityMode >= NoticeVisbilityMode.MiniForAutoSkip && autoSkip)}
|
||||
unskipTime={unskipTime} />,
|
||||
this.noticeElement
|
||||
unskipTime={unskipTime} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +63,7 @@ class SkipNotice {
|
||||
}
|
||||
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
this.root.unmount();
|
||||
|
||||
this.noticeElement.remove();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
|
||||
import Utils from "../utils";
|
||||
const utils = new Utils();
|
||||
@@ -17,6 +17,8 @@ class SubmissionNotice {
|
||||
|
||||
noticeElement: HTMLDivElement;
|
||||
|
||||
root: Root;
|
||||
|
||||
constructor(contentContainer: ContentContainer, callback: () => unknown) {
|
||||
this.noticeRef = React.createRef();
|
||||
|
||||
@@ -30,13 +32,13 @@ class SubmissionNotice {
|
||||
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
ReactDOM.render(
|
||||
this.root = createRoot(this.noticeElement);
|
||||
this.root.render(
|
||||
<SubmissionNoticeComponent
|
||||
contentContainer={contentContainer}
|
||||
callback={callback}
|
||||
ref={this.noticeRef}
|
||||
closeListener={() => this.close(false)} />,
|
||||
this.noticeElement
|
||||
closeListener={() => this.close(false)} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +48,7 @@ class SubmissionNotice {
|
||||
|
||||
close(callRef = true): void {
|
||||
if (callRef) this.noticeRef.current.cancel();
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
this.root.unmount();
|
||||
|
||||
this.noticeElement.remove();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import { ButtonListener } from "../types";
|
||||
|
||||
export interface TooltipProps {
|
||||
@@ -26,6 +26,7 @@ export class Tooltip {
|
||||
container: HTMLDivElement;
|
||||
|
||||
timer: NodeJS.Timeout;
|
||||
root: Root;
|
||||
|
||||
constructor(props: TooltipProps) {
|
||||
props.bottomOffset ??= "70px";
|
||||
@@ -54,8 +55,9 @@ export class Tooltip {
|
||||
}
|
||||
|
||||
const backgroundColor = `rgba(28, 28, 28, ${props.opacity})`;
|
||||
|
||||
ReactDOM.render(
|
||||
|
||||
this.root = createRoot(this.container);
|
||||
this.root.render(
|
||||
<div style={{bottom: props.bottomOffset, left: props.leftOffset, right: props.rightOffset, backgroundColor}}
|
||||
className={"sponsorBlockTooltip" + (props.displayTriangle ? " sbTriangle" : "") + ` ${props.extraClass}`}>
|
||||
<div>
|
||||
@@ -93,8 +95,7 @@ export class Tooltip {
|
||||
{chrome.i18n.getMessage("GotIt")}
|
||||
</button>
|
||||
: null}
|
||||
</div>,
|
||||
this.container
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@ export class Tooltip {
|
||||
}
|
||||
|
||||
close(): void {
|
||||
ReactDOM.unmountComponentAtNode(this.container);
|
||||
this.root.unmount();
|
||||
this.container.remove();
|
||||
|
||||
if (this.timer) clearTimeout(this.timer);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import UnsubmittedVideosComponent from "../components/options/UnsubmittedVideosComponent";
|
||||
|
||||
class UnsubmittedVideos {
|
||||
@@ -9,9 +9,9 @@ class UnsubmittedVideos {
|
||||
constructor(element: Element) {
|
||||
this.ref = React.createRef();
|
||||
|
||||
ReactDOM.render(
|
||||
<UnsubmittedVideosComponent ref={this.ref} />,
|
||||
element
|
||||
const root = createRoot(element);
|
||||
root.render(
|
||||
<UnsubmittedVideosComponent ref={this.ref} />
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
201
src/types.ts
201
src/types.ts
@@ -4,32 +4,32 @@ import SkipNotice from "./render/SkipNotice";
|
||||
|
||||
export interface ContentContainer {
|
||||
(): {
|
||||
vote: (type: number, UUID: SegmentUUID, category?: Category, skipNotice?: SkipNoticeComponent) => void,
|
||||
dontShowNoticeAgain: () => void,
|
||||
unskipSponsorTime: (segment: SponsorTime, unskipTime: number, forceSeek?: boolean) => void,
|
||||
sponsorTimes: SponsorTime[],
|
||||
sponsorTimesSubmitting: SponsorTime[],
|
||||
skipNotices: SkipNotice[],
|
||||
v: HTMLVideoElement,
|
||||
sponsorVideoID,
|
||||
reskipSponsorTime: (segment: SponsorTime, forceSeek?: boolean) => void,
|
||||
updatePreviewBar: () => void,
|
||||
onMobileYouTube: boolean,
|
||||
sponsorSubmissionNotice: SubmissionNotice,
|
||||
resetSponsorSubmissionNotice: (callRef?: boolean) => void,
|
||||
updateEditButtonsOnPlayer: () => void,
|
||||
previewTime: (time: number, unpause?: boolean) => void,
|
||||
videoInfo: VideoInfo,
|
||||
getRealCurrentTime: () => number,
|
||||
lockedCategories: string[],
|
||||
channelIDInfo: ChannelIDInfo
|
||||
}
|
||||
vote: (type: number, UUID: SegmentUUID, category?: Category, skipNotice?: SkipNoticeComponent) => void;
|
||||
dontShowNoticeAgain: () => void;
|
||||
unskipSponsorTime: (segment: SponsorTime, unskipTime: number, forceSeek?: boolean) => void;
|
||||
sponsorTimes: SponsorTime[];
|
||||
sponsorTimesSubmitting: SponsorTime[];
|
||||
skipNotices: SkipNotice[];
|
||||
v: HTMLVideoElement;
|
||||
sponsorVideoID;
|
||||
reskipSponsorTime: (segment: SponsorTime, forceSeek?: boolean) => void;
|
||||
updatePreviewBar: () => void;
|
||||
onMobileYouTube: boolean;
|
||||
sponsorSubmissionNotice: SubmissionNotice;
|
||||
resetSponsorSubmissionNotice: (callRef?: boolean) => void;
|
||||
updateEditButtonsOnPlayer: () => void;
|
||||
previewTime: (time: number, unpause?: boolean) => void;
|
||||
videoInfo: VideoInfo;
|
||||
getRealCurrentTime: () => number;
|
||||
lockedCategories: string[];
|
||||
channelIDInfo: ChannelIDInfo;
|
||||
};
|
||||
}
|
||||
|
||||
export interface FetchResponse {
|
||||
responseText: string,
|
||||
status: number,
|
||||
ok: boolean
|
||||
responseText: string;
|
||||
status: number;
|
||||
ok: boolean;
|
||||
}
|
||||
|
||||
export type HashedValue = string & { __hashBrand: unknown };
|
||||
@@ -46,7 +46,7 @@ export enum CategorySkipOption {
|
||||
|
||||
export interface CategorySelection {
|
||||
name: Category;
|
||||
option: CategorySkipOption
|
||||
option: CategorySkipOption;
|
||||
}
|
||||
|
||||
export enum SponsorHideType {
|
||||
@@ -97,95 +97,95 @@ export interface ScheduledTime extends SponsorTime {
|
||||
}
|
||||
|
||||
export interface PreviewBarOption {
|
||||
color: string,
|
||||
opacity: string
|
||||
color: string;
|
||||
opacity: string;
|
||||
}
|
||||
|
||||
|
||||
export interface Registration {
|
||||
message: string,
|
||||
id: string,
|
||||
allFrames: boolean,
|
||||
js: browser.extensionTypes.ExtensionFileOrCode[],
|
||||
css: browser.extensionTypes.ExtensionFileOrCode[],
|
||||
matches: string[]
|
||||
message: string;
|
||||
id: string;
|
||||
allFrames: boolean;
|
||||
js: browser.extensionTypes.ExtensionFileOrCode[];
|
||||
css: browser.extensionTypes.ExtensionFileOrCode[];
|
||||
matches: string[];
|
||||
}
|
||||
|
||||
export interface BackgroundScriptContainer {
|
||||
registerFirefoxContentScript: (opts: Registration) => void,
|
||||
unregisterFirefoxContentScript: (id: string) => void
|
||||
registerFirefoxContentScript: (opts: Registration) => void;
|
||||
unregisterFirefoxContentScript: (id: string) => void;
|
||||
}
|
||||
|
||||
export interface VideoInfo {
|
||||
responseContext: {
|
||||
serviceTrackingParams: Array<{service: string, params: Array<{key: string, value: string}>}>,
|
||||
serviceTrackingParams: Array<{service: string; params: Array<{key: string; value: string}>}>;
|
||||
webResponseContextExtensionData: {
|
||||
hasDecorated: boolean
|
||||
}
|
||||
},
|
||||
hasDecorated: boolean;
|
||||
};
|
||||
};
|
||||
playabilityStatus: {
|
||||
status: string,
|
||||
playableInEmbed: boolean,
|
||||
status: string;
|
||||
playableInEmbed: boolean;
|
||||
miniplayer: {
|
||||
miniplayerRenderer: {
|
||||
playbackMode: string
|
||||
}
|
||||
}
|
||||
playbackMode: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
streamingData: unknown;
|
||||
playbackTracking: unknown;
|
||||
videoDetails: {
|
||||
videoId: string,
|
||||
title: string,
|
||||
lengthSeconds: string,
|
||||
keywords: string[],
|
||||
channelId: string,
|
||||
isOwnerViewing: boolean,
|
||||
shortDescription: string,
|
||||
isCrawlable: boolean,
|
||||
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,
|
||||
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}>
|
||||
},
|
||||
thumbnails: Array<{url: string; width: number; height: number}>;
|
||||
};
|
||||
embed: {
|
||||
iframeUrl: string,
|
||||
flashUrl: string,
|
||||
width: number,
|
||||
height: number,
|
||||
flashSecureUrl: string,
|
||||
},
|
||||
iframeUrl: string;
|
||||
flashUrl: string;
|
||||
width: number;
|
||||
height: number;
|
||||
flashSecureUrl: string;
|
||||
};
|
||||
title: {
|
||||
simpleText: string,
|
||||
},
|
||||
simpleText: string;
|
||||
};
|
||||
description: {
|
||||
simpleText: string,
|
||||
},
|
||||
lengthSeconds: string,
|
||||
ownerProfileUrl: string,
|
||||
externalChannelId: string,
|
||||
availableCountries: string[],
|
||||
isUnlisted: boolean,
|
||||
hasYpcMetadata: boolean,
|
||||
viewCount: string,
|
||||
category: Category,
|
||||
publishDate: string,
|
||||
ownerChannelName: string,
|
||||
uploadDate: string,
|
||||
}
|
||||
simpleText: string;
|
||||
};
|
||||
lengthSeconds: string;
|
||||
ownerProfileUrl: string;
|
||||
externalChannelId: string;
|
||||
availableCountries: string[];
|
||||
isUnlisted: boolean;
|
||||
hasYpcMetadata: boolean;
|
||||
viewCount: string;
|
||||
category: Category;
|
||||
publishDate: string;
|
||||
ownerChannelName: string;
|
||||
uploadDate: string;
|
||||
};
|
||||
};
|
||||
trackingParams: string;
|
||||
attestation: unknown;
|
||||
@@ -205,17 +205,17 @@ export enum ChannelIDStatus {
|
||||
}
|
||||
|
||||
export interface ChannelIDInfo {
|
||||
id: string,
|
||||
status: ChannelIDStatus
|
||||
id: string;
|
||||
status: ChannelIDStatus;
|
||||
}
|
||||
|
||||
export interface SkipToTimeParams {
|
||||
v: HTMLVideoElement,
|
||||
skipTime: number[],
|
||||
skippingSegments: SponsorTime[],
|
||||
openNotice: boolean,
|
||||
forceAutoSkip?: boolean,
|
||||
unskipTime?: number
|
||||
v: HTMLVideoElement;
|
||||
skipTime: number[];
|
||||
skippingSegments: SponsorTime[];
|
||||
openNotice: boolean;
|
||||
forceAutoSkip?: boolean;
|
||||
unskipTime?: number;
|
||||
}
|
||||
|
||||
export interface ToggleSkippable {
|
||||
@@ -232,11 +232,11 @@ export enum NoticeVisbilityMode {
|
||||
}
|
||||
|
||||
export type Keybind = {
|
||||
key: string,
|
||||
code?: string,
|
||||
ctrl?: boolean,
|
||||
alt?: boolean,
|
||||
shift?: boolean
|
||||
key: string;
|
||||
code?: string;
|
||||
ctrl?: boolean;
|
||||
alt?: boolean;
|
||||
shift?: boolean;
|
||||
}
|
||||
|
||||
export enum PageType {
|
||||
@@ -244,10 +244,11 @@ export enum PageType {
|
||||
Watch = "watch",
|
||||
Search = "search",
|
||||
Browse = "browse",
|
||||
Channel = "channel"
|
||||
Channel = "channel",
|
||||
Embed = "embed"
|
||||
}
|
||||
|
||||
export interface ButtonListener {
|
||||
name: string,
|
||||
listener: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
|
||||
name: string;
|
||||
listener: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
}
|
||||
@@ -3,11 +3,15 @@ import { checkLicenseKey } from "./utils/licenseKey";
|
||||
import { localizeHtmlPage } from "./utils/pageUtils";
|
||||
|
||||
import * as countries from "../public/res/countries.json";
|
||||
import Utils from "./utils";
|
||||
import { Category, CategorySkipOption } from "./types";
|
||||
|
||||
// This is needed, if Config is not imported before Utils, things break.
|
||||
// Probably due to cyclic dependencies
|
||||
Config.config;
|
||||
|
||||
const utils = new Utils();
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
async function init() {
|
||||
@@ -31,6 +35,13 @@ async function init() {
|
||||
Config.config.payments.licenseKey = licenseKey;
|
||||
Config.forceSyncUpdate("payments");
|
||||
|
||||
if (!utils.getCategorySelection("chapter")) {
|
||||
Config.config.categorySelections.push({
|
||||
name: "chapter" as Category,
|
||||
option: CategorySkipOption.ShowOverlay
|
||||
});
|
||||
}
|
||||
|
||||
alert(chrome.i18n.getMessage("redeemSuccess"));
|
||||
} else {
|
||||
alert(chrome.i18n.getMessage("redeemFailed"));
|
||||
|
||||
23
src/utils.ts
23
src/utils.ts
@@ -24,7 +24,7 @@ export default class Utils {
|
||||
/* Used for waitForElement */
|
||||
creatingWaitingMutationObserver = false;
|
||||
waitingMutationObserver: MutationObserver = null;
|
||||
waitingElements: { selector: string, visibleCheck: boolean, callback: (element: Element) => void }[] = [];
|
||||
waitingElements: { selector: string; visibleCheck: boolean; callback: (element: Element) => void }[] = [];
|
||||
|
||||
constructor(backgroundScriptContainer: BackgroundScriptContainer = null) {
|
||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||
@@ -65,7 +65,7 @@ export default class Utils {
|
||||
|
||||
private setupWaitingMutationListener(): void {
|
||||
if (!this.waitingMutationObserver) {
|
||||
this.waitingMutationObserver = new MutationObserver(() => {
|
||||
const checkForObjects = () => {
|
||||
const foundSelectors = [];
|
||||
for (const { selector, visibleCheck, callback } of this.waitingElements) {
|
||||
const element = this.getElement(selector, visibleCheck);
|
||||
@@ -78,16 +78,23 @@ export default class Utils {
|
||||
this.waitingElements = this.waitingElements.filter((element) => !foundSelectors.includes(element.selector));
|
||||
|
||||
if (this.waitingElements.length === 0) {
|
||||
this.waitingMutationObserver.disconnect();
|
||||
this.waitingMutationObserver?.disconnect();
|
||||
this.waitingMutationObserver = null;
|
||||
this.creatingWaitingMutationObserver = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.waitingMutationObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
// Do an initial check over all objects
|
||||
checkForObjects();
|
||||
|
||||
if (this.waitingElements.length > 0) {
|
||||
this.waitingMutationObserver = new MutationObserver(checkForObjects);
|
||||
|
||||
this.waitingMutationObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ function applyLoadingAnimation(element: HTMLElement, time: number, callback?: ()
|
||||
});
|
||||
}
|
||||
|
||||
function setupCustomHideAnimation(element: Element, container: Element, enabled = true, rightSlide = true): { hide: () => void, show: () => void } {
|
||||
function setupCustomHideAnimation(element: Element, container: Element, enabled = true, rightSlide = true): { hide: () => void; show: () => void } {
|
||||
if (enabled) element.classList.add("autoHiding");
|
||||
element.classList.add("hidden");
|
||||
element.classList.add("animationDone");
|
||||
|
||||
@@ -38,7 +38,7 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[]
|
||||
const match = line.match(/(?:((?:\d+:)?\d+:\d+)+(?:\.\d+)?)|(?:\d+(?=s| second))/g);
|
||||
if (match) {
|
||||
const startTime = GenericUtils.getFormattedTimeToSeconds(match[0]);
|
||||
if (startTime) {
|
||||
if (startTime !== null) {
|
||||
const specialCharsMatcher = /^(?:\s+seconds?)?[-:()\s]*|(?:\s+at)?[-:()\s]+$/g
|
||||
const titleLeft = line.split(match[0])[0].replace(specialCharsMatcher, "");
|
||||
let titleRight = null;
|
||||
|
||||
@@ -93,7 +93,7 @@ function getLuminance(color: string): number {
|
||||
}
|
||||
|
||||
/* From https://stackoverflow.com/a/5624139 */
|
||||
function hexToRgb(hex: string): {r: number, g: number, b: number} {
|
||||
function hexToRgb(hex: string): {r: number; g: number; b: number} {
|
||||
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
||||
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
|
||||
|
||||
@@ -46,7 +46,10 @@ export async function fetchingChaptersAllowed(): Promise<boolean> {
|
||||
|
||||
if (Config.config.payments.chaptersAllowed) return true;
|
||||
|
||||
if (Config.config.payments.lastCheck === 0) {
|
||||
if (Config.config.payments.lastCheck === 0 && Date.now() - Config.config.payments.lastFreeCheck > 2 * 24 * 60 * 60 * 1000) {
|
||||
Config.config.payments.lastFreeCheck = Date.now();
|
||||
Config.forceSyncUpdate("payments");
|
||||
|
||||
// Check for free access if no license key, and it is the first time
|
||||
const result = await utils.asyncRequestToServer("GET", "/api/userInfo", {
|
||||
value: "freeChaptersAccess",
|
||||
@@ -56,7 +59,7 @@ export async function fetchingChaptersAllowed(): Promise<boolean> {
|
||||
try {
|
||||
if (result.ok) {
|
||||
const userInfo = JSON.parse(result.responseText);
|
||||
|
||||
|
||||
Config.config.payments.lastCheck = Date.now();
|
||||
if (userInfo.freeChaptersAccess) {
|
||||
Config.config.payments.freeAccess = true;
|
||||
|
||||
@@ -70,7 +70,8 @@ export function getExistingChapters(currentVideoID: VideoID, duration: number):
|
||||
const chaptersBox = document.querySelector("ytd-macro-markers-list-renderer");
|
||||
|
||||
const chapters: SponsorTime[] = [];
|
||||
if (chaptersBox) {
|
||||
// .ytp-timed-markers-container indicates that key-moments are present, which should not be divided
|
||||
if (chaptersBox && !(document.querySelector(".ytp-timed-markers-container")?.childElementCount > 0)) {
|
||||
let lastSegment: SponsorTime = null;
|
||||
const links = chaptersBox.querySelectorAll("ytd-macro-markers-list-item-renderer > a");
|
||||
for (const link of links) {
|
||||
@@ -78,6 +79,7 @@ export function getExistingChapters(currentVideoID: VideoID, duration: number):
|
||||
const description = link.querySelector("#details h4") as HTMLElement;
|
||||
if (timeElement && description?.innerText?.length > 0 && link.getAttribute("href")?.includes(currentVideoID)) {
|
||||
const time = GenericUtils.getFormattedTimeToSeconds(timeElement.innerText);
|
||||
if (time === null) return [];
|
||||
|
||||
if (lastSegment) {
|
||||
lastSegment.segment[1] = time;
|
||||
|
||||
@@ -6,9 +6,9 @@ import { GenericUtils } from "./genericUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
export interface ChatConfig {
|
||||
displayName: string,
|
||||
composerInitialValue?: string,
|
||||
customDescription?: string
|
||||
displayName: string;
|
||||
composerInitialValue?: string;
|
||||
customDescription?: string;
|
||||
}
|
||||
|
||||
export async function openWarningDialog(contentContainer: ContentContainer): Promise<void> {
|
||||
|
||||
@@ -254,4 +254,25 @@ describe("Import segments", () => {
|
||||
category: "chapter" as Category
|
||||
}]);
|
||||
});
|
||||
|
||||
it ("00:00", () => {
|
||||
const input = ` 00:00 Cap 1
|
||||
00:10 Cap 2
|
||||
00:12 Cap 3`;
|
||||
|
||||
const result = importTimes(input, 8000);
|
||||
expect(result).toMatchObject([{
|
||||
segment: [0, 10],
|
||||
description: "Cap 1",
|
||||
category: "chapter" as Category
|
||||
}, {
|
||||
segment: [10, 12],
|
||||
description: "Cap 2",
|
||||
category: "chapter" as Category
|
||||
}, {
|
||||
segment: [12, 8000],
|
||||
description: "Cap 3",
|
||||
category: "chapter" as Category
|
||||
}]);
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import PreviewBar, { PreviewBarSegment } from "../src/js-components/previewBar";
|
||||
describe("createChapterRenderGroups", () => {
|
||||
let previewBar: PreviewBar;
|
||||
beforeEach(() => {
|
||||
previewBar = new PreviewBar(null, null, null, null, true);
|
||||
previewBar = new PreviewBar(null, null, null, null, null, true);
|
||||
})
|
||||
|
||||
it("Two unrelated times", () => {
|
||||
|
||||
Reference in New Issue
Block a user