Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into chapters

This commit is contained in:
Ajay Ramachandran
2021-10-15 19:57:18 -04:00
32 changed files with 859 additions and 117 deletions

View File

@@ -13,5 +13,17 @@
"music_offtopic": ["skip"], "music_offtopic": ["skip"],
"poi_highlight": ["skip"], "poi_highlight": ["skip"],
"chapter": ["chapter"] "chapter": ["chapter"]
},
"wikiLinks": {
"sponsor": "https://wiki.sponsor.ajay.app/w/Sponsor",
"selfpromo": "https://wiki.sponsor.ajay.app/w/Unpaid/Self_Promotion",
"interaction": "https://wiki.sponsor.ajay.app/w/Interaction_Reminder_(Subscribe)",
"intro": "https://wiki.sponsor.ajay.app/w/Intermission/Intro_Animation",
"outro": "https://wiki.sponsor.ajay.app/w/Endcards/Credits",
"preview": "https://wiki.sponsor.ajay.app/w/Preview/Recap",
"music_offtopic": "https://wiki.sponsor.ajay.app/w/Music:_Non-Music_Section",
"poi_highlight": "https://wiki.sponsor.ajay.app/w/Highlight",
"guidelines": "https://wiki.sponsor.ajay.app/w/Guidelines",
"mute": "https://wiki.sponsor.ajay.app/w/Mute_Segment"
} }
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "__MSG_fullName__", "name": "__MSG_fullName__",
"short_name": "SponsorBlock", "short_name": "SponsorBlock",
"version": "3.3.3", "version": "3.4",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_Description__", "description": "__MSG_Description__",
"homepage_url": "https://sponsor.ajay.app", "homepage_url": "https://sponsor.ajay.app",
@@ -37,6 +37,7 @@
"icons/upvote.png", "icons/upvote.png",
"icons/downvote.png", "icons/downvote.png",
"icons/thumbs_down.svg", "icons/thumbs_down.svg",
"icons/thumbs_down_locked.svg",
"icons/thumbs_up.svg", "icons/thumbs_up.svg",
"icons/help.svg", "icons/help.svg",
"icons/report.png", "icons/report.png",

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Научете повече" "message": "Научете повече"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Използвайте колелото на мишката, докато държите курсора върху полето за редактиране, за да коригирате бързо времето. Комбинации с клавиша ctrl или shift могат да се използват за фина настройка на промените."
} }
} }

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Zjistit více" "message": "Zjistit více"
},
"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."
} }
} }

View File

@@ -183,7 +183,7 @@
"message": "Versteckt die Schaltflächen im YouTube-Videoplayer, um Segmente einzusenden." "message": "Versteckt die Schaltflächen im YouTube-Videoplayer, um Segmente einzusenden."
}, },
"showSkipButton": { "showSkipButton": {
"message": "Behalte \"Zum Highlight springen\"-Knopf in der Navigationsleiste" "message": "\"Zum Highlight springen\"-Knopf im Player behalten"
}, },
"showInfoButton": { "showInfoButton": {
"message": "Zeige Info-Knopf im Youtube-Videoplayer" "message": "Zeige Info-Knopf im Youtube-Videoplayer"
@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Erfahre mehr" "message": "Erfahre mehr"
},
"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."
} }
} }

View File

@@ -706,7 +706,7 @@
"message": "Incorrect/Wrong Timing" "message": "Incorrect/Wrong Timing"
}, },
"incorrectCategory": { "incorrectCategory": {
"message": "Wrong Category" "message": "Change Category"
}, },
"nonMusicCategoryOnMusic": { "nonMusicCategoryOnMusic": {
"message": "This video is categorized as music. Are you sure this has a sponsor? If this is actually a \"Non-Music segment\", open up the extension options and enable this category. Then, you can submit this segment as \"Non-Music\" instead of sponsor. Please read the guidelines if you are confused." "message": "This video is categorized as music. Are you sure this has a sponsor? If this is actually a \"Non-Music segment\", open up the extension options and enable this category. Then, you can submit this segment as \"Non-Music\" instead of sponsor. Please read the guidelines if you are confused."
@@ -816,6 +816,21 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Learn More" "message": "Learn More"
},
"CopyDownvoteButtonInfo": {
"message": "Downvotes and creates a local copy for you to resubmit"
},
"OpenCategoryWikiPage": {
"message": "Open this category's wiki page."
},
"CopyAndDownvote": {
"message": "Copy and downvote"
},
"ContinueVoting": {
"message": "Continue Voting"
},
"ChangeCategoryTooltip": {
"message": "This will instantly apply to your segments"
}, },
"SponsorTimeEditScrollNewFeature": { "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." "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."

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Aprenda Más" "message": "Aprenda Más"
},
"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."
} }
} }

View File

@@ -765,5 +765,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Lisateave" "message": "Lisateave"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Kasuta hiirekursorit muutmiskasti kohal, et kiirelt aega reguleerida. Täpsemaks muutmiseks hoia kerimise ajal all Ctrl või Shift klahvi."
} }
} }

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Opi lisää" "message": "Opi lisää"
},
"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."
} }
} }

View File

@@ -182,6 +182,9 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "Cela permet de cacher du lecteur YouTube les boutons utilisés pour soumettre des segments commerciaux. Je peux \ncomprendre que certaines personnes les trouvent perturbants. Au lieu d'utiliser ces boutons, cette fenêtre peut être utilisée \npour soumettre des segments commerciaux. Pour cacher la notification, utilisez le bouton \"Ne plus montrer\" sur la notification. Vous pouvez toujours réactiver ces paramètres plus tard." "message": "Cela permet de cacher du lecteur YouTube les boutons utilisés pour soumettre des segments commerciaux. Je peux \ncomprendre que certaines personnes les trouvent perturbants. Au lieu d'utiliser ces boutons, cette fenêtre peut être utilisée \npour soumettre des segments commerciaux. Pour cacher la notification, utilisez le bouton \"Ne plus montrer\" sur la notification. Vous pouvez toujours réactiver ces paramètres plus tard."
}, },
"showSkipButton": {
"message": "Conserver le bouton \"Aller au point d'intérêt\" sur le lecteur"
},
"showInfoButton": { "showInfoButton": {
"message": "Montrer le bouton Info sur le lecteur YouTube" "message": "Montrer le bouton Info sur le lecteur YouTube"
}, },
@@ -303,7 +306,7 @@
"message": "Passer {0} ?" "message": "Passer {0} ?"
}, },
"mute_category": { "mute_category": {
"message": "Mute {0}?" "message": "Mettre en sourdine {0} ?"
}, },
"skip_to_category": { "skip_to_category": {
"message": "Passer à {0}?", "message": "Passer à {0}?",
@@ -648,7 +651,7 @@
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options." "description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
}, },
"poiOnlyOneSegment": { "poiOnlyOneSegment": {
"message": "Avertissement: Ce type de segment peut avoir au maximum un seul actif à la fois. En soumettant plusieurs segments, un seul aléatoire sera affiché." "message": "Avertissement : Ce type de segment ne peut avoir qu'un seul segment actif à la fois. Si vous en soumettez plusieurs, le choix sera fait au hasard."
}, },
"youMustSelectACategory": { "youMustSelectACategory": {
"message": "Vous devez sélectionner une catégorie pour tous les segments que vous soumettez !" "message": "Vous devez sélectionner une catégorie pour tous les segments que vous soumettez !"
@@ -732,6 +735,9 @@
"hideForever": { "hideForever": {
"message": "Cacher pour toujours" "message": "Cacher pour toujours"
}, },
"warningChatInfo": {
"message": "Vous avez reçu un avertissement et ne pouvez pas soumettre de segments temporairement. Cela signifie que nous avons remarqué que vous commettiez des erreurs courantes qui ne sont pas malveillantes. Veuillez simplement confirmer que vous comprenez les règles et nous supprimerons l'avertissement. Vous pouvez également rejoindre cette discussion en utilisant discord.gg/SponsorBlock ou matrix.to/#/#sponsor:ajay.app"
},
"voteRejectedWarning": { "voteRejectedWarning": {
"message": "Le vote a été rejeté en raison d'un avertissement. Cliquez pour ouvrir un chat et y mettre fin , ou revenez plus tard lorsque vous avez le temps.", "message": "Le vote a été rejeté en raison d'un avertissement. Cliquez pour ouvrir un chat et y mettre fin , ou revenez plus tard lorsque vous avez le temps.",
"description": "This is an integrated chat panel that will appearing allowing them to talk to the Discord/Matrix chat without leaving their browser." "description": "This is an integrated chat panel that will appearing allowing them to talk to the Discord/Matrix chat without leaving their browser."
@@ -804,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "En savoir plus" "message": "En savoir plus"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Utilisez la molette de votre souris en survolant la boîte d'édition pour ajuster rapidement le minutage. Les combinaisons de touches Ctrl ou Shift peuvent être utilisées pour affiner les modifications."
} }
} }

View File

@@ -53,7 +53,7 @@
"message": "Lewati Ulang" "message": "Lewati Ulang"
}, },
"unmute": { "unmute": {
"message": "Bunyikan" "message": "Batalkan bisu"
}, },
"paused": { "paused": {
"message": "Dijeda" "message": "Dijeda"
@@ -89,7 +89,7 @@
"message": "Video YouTube tidak ditemukan.\nJika terjadi kesalahan, segarkan halaman." "message": "Video YouTube tidak ditemukan.\nJika terjadi kesalahan, segarkan halaman."
}, },
"refreshSegments": { "refreshSegments": {
"message": "Segarkan segmen" "message": "Perbarui segmen"
}, },
"success": { "success": {
"message": "Sukses!" "message": "Sukses!"
@@ -182,6 +182,9 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "Ini akan menyembunyikan tombol yang muncul di pemutar YouTube untuk mengirimkan segmen yang dilewati." "message": "Ini akan menyembunyikan tombol yang muncul di pemutar YouTube untuk mengirimkan segmen yang dilewati."
}, },
"showSkipButton": {
"message": "Tetap lewati ke tombol Highlight di Pemutar"
},
"showInfoButton": { "showInfoButton": {
"message": "Tampilkan Tombol Info Di Pemutar Video YouTube" "message": "Tampilkan Tombol Info Di Pemutar Video YouTube"
}, },
@@ -207,7 +210,7 @@
"message": "Aktifkan Pelacakan Jumlah Lewati Pada Tab Privat/Penyamaran" "message": "Aktifkan Pelacakan Jumlah Lewati Pada Tab Privat/Penyamaran"
}, },
"enableQueryByHashPrefix": { "enableQueryByHashPrefix": {
"message": "Query By Hash Prefix" "message": "Kueri dengan Hash Prefix"
}, },
"whatQueryByHashPrefix": { "whatQueryByHashPrefix": {
"message": "Daripada meminta segmen dari server menggunakan videoID, 4 huruf pertama dari hash dari videoID dikirim. Server akan mengirim kembali data untuk semua video dengan hash yang mirip." "message": "Daripada meminta segmen dari server menggunakan videoID, 4 huruf pertama dari hash dari videoID dikirim. Server akan mengirim kembali data untuk semua video dengan hash yang mirip."
@@ -224,6 +227,21 @@
"showSkipNotice": { "showSkipNotice": {
"message": "Tampilkan pemberitahuan setelah melewati segmen" "message": "Tampilkan pemberitahuan setelah melewati segmen"
}, },
"noticeVisibilityMode0": {
"message": "Lewati maklumat ukuran penuh"
},
"noticeVisibilityMode1": {
"message": "Maklumat lewati kecil untuk lewati otomatis"
},
"noticeVisibilityMode2": {
"message": "Lewati semua maklumat kecil"
},
"noticeVisibilityMode3": {
"message": "Pudar maklumat lewati untuk semua lewati otomatis"
},
"noticeVisibilityMode4": {
"message": "Lewati semua maklumat pudar"
},
"longDescription": { "longDescription": {
"message": "SponsorBlock membuat anda melewati sponsor, intro, outro, pengingat berlangganan dan segmen mengganggu lainnya di video YouTube. SponsorBlock adalah ekstensi browser crowdsourced yang membolehkan siapa saja mengirim waktu awal dan akhir dari segmen sponsor dan segmen video YouTube lainnya. Setelah seseorang mengirim informasi ini, orang lain yang memakai ekstensi ini akan melewati segmen sponsor di video yang sama. Anda juga dapat melewati bagian non-musik di musik video.", "message": "SponsorBlock membuat anda melewati sponsor, intro, outro, pengingat berlangganan dan segmen mengganggu lainnya di video YouTube. SponsorBlock adalah ekstensi browser crowdsourced yang membolehkan siapa saja mengirim waktu awal dan akhir dari segmen sponsor dan segmen video YouTube lainnya. Setelah seseorang mengirim informasi ini, orang lain yang memakai ekstensi ini akan melewati segmen sponsor di video yang sama. Anda juga dapat melewati bagian non-musik di musik video.",
"description": "Full description of the extension on the store pages." "description": "Full description of the extension on the store pages."
@@ -383,7 +401,10 @@
"message": "Aktifkan dukungan Invidious, nonaktifkan lewati otomatis, tombol sembunyi dan lainnya." "message": "Aktifkan dukungan Invidious, nonaktifkan lewati otomatis, tombol sembunyi dan lainnya."
}, },
"addInvidiousInstance": { "addInvidiousInstance": {
"message": "Tambah Instance Klien Pihak Ketiga" "message": "Tambah Instansi Klien Pihak Ketiga"
},
"addInvidiousInstanceDescription": {
"message": "Tambahkan instansi khusus. Ini harus diformat Hanya dengan domain. Contoh: invidious.ajay.app"
}, },
"add": { "add": {
"message": "Tambah" "message": "Tambah"
@@ -406,6 +427,12 @@
"minDurationDescription": { "minDurationDescription": {
"message": "Segmen yang lebih kecil dari nilai yang diatur tidak akan dilewati atau tampil di pemutar." "message": "Segmen yang lebih kecil dari nilai yang diatur tidak akan dilewati atau tampil di pemutar."
}, },
"skipNoticeDuration": {
"message": "Lewati maklumat berdurasi (detik):"
},
"skipNoticeDurationDescription": {
"message": "Maklumat lewati akan tetap di layar setidaknya selama ini. Untuk lewati manual, mungkin akan terlihat lebih lama."
},
"shortCheck": { "shortCheck": {
"message": "Submisi ini lebih pendek dari opsi durasi minimalmu. Ini dapat berarti ini sudah dikirim, dan hanya akan diabaikan karena opsi ini. Apakah anda yakin ingin mengirim?" "message": "Submisi ini lebih pendek dari opsi durasi minimalmu. Ini dapat berarti ini sudah dikirim, dan hanya akan diabaikan karena opsi ini. Apakah anda yakin ingin mengirim?"
}, },
@@ -545,6 +572,12 @@
"category_music_offtopic_short": { "category_music_offtopic_short": {
"message": "Non-Musik" "message": "Non-Musik"
}, },
"category_poi_highlight": {
"message": "Sorotan"
},
"category_poi_highlight_description": {
"message": "Bagian video yang banyak orang lihat. Sama untuk komentar \"Video dimulai di x\"."
},
"category_livestream_messages": { "category_livestream_messages": {
"message": "Livestream: Baca Pesan/Donasi" "message": "Livestream: Baca Pesan/Donasi"
}, },
@@ -563,6 +596,9 @@
"disable": { "disable": {
"message": "Nonaktif" "message": "Nonaktif"
}, },
"autoSkip_POI": {
"message": "Otomatis lewati ke awal"
},
"manualSkip_POI": { "manualSkip_POI": {
"message": "Tanya saat video dimuat" "message": "Tanya saat video dimuat"
}, },
@@ -572,6 +608,9 @@
"autoSkipOnMusicVideos": { "autoSkipOnMusicVideos": {
"message": "Lewati semua segmen secara otomatis ketika ada segmen non-music" "message": "Lewati semua segmen secara otomatis ketika ada segmen non-music"
}, },
"muteSegments": {
"message": "Perbolehkan segmen untuk bisu daripada melewati"
},
"colorFormatIncorrect": { "colorFormatIncorrect": {
"message": "Warna anda tidak diformat dengan benar. Harusnya terdiri dari 3 atau 6 digit kode heksa dengan tagar di awal." "message": "Warna anda tidak diformat dengan benar. Harusnya terdiri dari 3 atau 6 digit kode heksa dengan tagar di awal."
}, },
@@ -611,6 +650,9 @@
"message": "Untuk mengirimkan segmen dengan kategori \"{0}\", Anda harus mengaktifkannya di opsi. Anda akan diarahkan ke opsi sekarang.", "message": "Untuk mengirimkan segmen dengan kategori \"{0}\", Anda harus mengaktifkannya di opsi. Anda akan diarahkan ke opsi sekarang.",
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options." "description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
}, },
"poiOnlyOneSegment": {
"message": "Perhatian: Tipe segmen ini hanya bisa maksimum aktif satu kali. Mengirimkan beberapa dapat mengakibatkan muncul pada kondisi acak."
},
"youMustSelectACategory": { "youMustSelectACategory": {
"message": "Anda harus memilih kategori untuk semua segmen yang anda kirimkan!" "message": "Anda harus memilih kategori untuk semua segmen yang anda kirimkan!"
}, },
@@ -686,9 +728,20 @@
"message": "Mengerti", "message": "Mengerti",
"description": "Used as the button to dismiss a tooltip" "description": "Used as the button to dismiss a tooltip"
}, },
"experiementOptOut": {
"message": "Tidak ikut eksperimen masa depan",
"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."
},
"hideForever": { "hideForever": {
"message": "Sembunyikan selamanya" "message": "Sembunyikan selamanya"
}, },
"warningChatInfo": {
"message": "Anda mendapatkan peringatan dan tidak bisa mengirim segmen sementara. Ini dikarenakan kami melihat kamu melakukan beberapa kesalahan yang umum, mohon konfirmasi bahwa kamu mengerti perundangan dan kami akan hapus peringatan. Kamu bisa bergabung ke obrolan menggunakan discord.gg/SponsorBlock atau matrix.io/#/#sponsor:ajay.app"
},
"voteRejectedWarning": {
"message": "Suara ditolak karena peringatan. Klik untuk buka obrolan untuk menyelesaikannya, atau kembali beberapa saat lagi ketika ada waktu.",
"description": "This is an integrated chat panel that will appearing allowing them to talk to the Discord/Matrix chat without leaving their browser."
},
"Donate": { "Donate": {
"message": "Donasi" "message": "Donasi"
}, },
@@ -701,7 +754,64 @@
"helpPageReviewOptions": { "helpPageReviewOptions": {
"message": "Haram ditinjau opsi di bawah ini" "message": "Haram ditinjau opsi di bawah ini"
}, },
"helpPageFeatureDisclaimer": {
"message": "Banyak fitur yang dinonaktifkan secara bawaan. Jika kamu ingin lewati mula, akhir, gunakan Invidious, dll, aktifkan mereka dibawah ini.\nKamu bisa menyembunyikan/menghadirkan elemen UI."
},
"helpPageHowSkippingWorks": { "helpPageHowSkippingWorks": {
"message": "Cara kerja melewati segmen" "message": "Cara kerja melewati segmen"
},
"helpPageHowSkippingWorks1": {
"message": "Segmen video akan otomatis dilewati jika ditemukan di databasis. Kamu bisa buka munculan dengan klik ikon ekstensi untuk mendapatkan pratinjau apa adanya."
},
"helpPageHowSkippingWorks2": {
"message": "Kapanpun kamu melewati segmen, kamu akan mendapatkan maklumat. Jika waktu terlihat salah dapat menyuarakan turun dengan klik turun-suara! Kamu juga bisa menyuarakan di maklumat."
},
"Submitting": {
"message": "Mengirim"
},
"helpPageSubmitting1": {
"message": "Mengirim bisa baik dilakukan di maklumat dengan menekan tombol \"Mulai Segmen Sekarang\" atau di pemutar video dengan tombol di pemutar."
},
"helpPageSubmitting2": {
"message": "Klik tombol putar indikasikan memulai segmen dan klik tombol ikon stop indikasikan mengakhiri. Kamu bisa persiapkan beberapa sponsor sebelum menekan kirim. Klik tombol unggah akan mengirimkan. Klik tombol sampah akan menghapuskan."
},
"Editing": {
"message": "Sunting"
},
"helpPageEditing1": {
"message": "Jika kamu mengacaukan, kamu bisa sunting atau hapus segmen setelah klik tombol panah atas."
},
"helpPageTooSlow": {
"message": "Ini terlalu lambat"
},
"helpPageTooSlow1": {
"message": "Terdapat tombol pintas jika kamu ingin menggunakannya. Tekan tombol semikolon untuk indikasi mulai/akhir segmen sponsor dan tekan tombol kutip untuk mengirimkan. Ini bisa diganti di opsi. Jika kamu tidak menggunakan QWERTY, kamu dimungkinkan harus mengubah tombol."
},
"helpPageCopyOfDatabase": {
"message": "Bisakah saya mendapatkan salinan Databasis? Apa yang terjadi jika kamu tiada?"
},
"helpPageCopyOfDatabase1": {
"message": "Databasis adalah publik dan tersedia di"
},
"helpPageCopyOfDatabase2": {
"message": "Sumber kode tersedia secara bebas. Jadi, jika sesuatu terjadi pada saya, pengajuan kamu tidak akan hilang."
},
"helpPageNews": {
"message": "Berita dan bagaimana ini diciptakan"
},
"helpPageSourceCode": {
"message": "Dimana saya mendapatkankan sumber kode?"
},
"Credits": {
"message": "Kredit"
},
"highlightNewFeature": {
"message": "Baru! Dapat ke poin video dengan satu klik dengan kategori highlight terbaru"
},
"LearnMore": {
"message": "Pelajari Lebih Lanjut"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Gunakan roda mouse ketika berada di kotak edit untuk mengatur waktu dengan cepat. Kombinasi dengan tombol [Ctrl + Shift] bisa digunakan untuk perubahan yang halus."
} }
} }

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "더보기" "message": "더보기"
},
"SponsorTimeEditScrollNewFeature": {
"message": "편집 상자 위에 커서를 올린 채 스크롤하면 시간을 빠르게 조정할 수 있습니다. Ctrl이나 Shift 키를 누른 채로 스크롤하면 세밀한 조정이 가능합니다."
} }
} }

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Meer informatie" "message": "Meer informatie"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Gebruik het muiswiel terwijl u over het invoerveld beweegt om de tijd snel aan te passen. Combinaties van de ctrl- of shift-toets kunnen worden gebruikt om de wijzigingen te verfijnen."
} }
} }

View File

@@ -183,7 +183,7 @@
"message": "Эта настройка скрывает кнопки для отправки сегментов, расположенные в плеере YouTube." "message": "Эта настройка скрывает кнопки для отправки сегментов, расположенные в плеере YouTube."
}, },
"showSkipButton": { "showSkipButton": {
"message": "Показывать кнопку \"Пропустить до важного\" в плеере" "message": "Не скрывать кнопку \"Пропустить до важного\" в плеере YouTube"
}, },
"showInfoButton": { "showInfoButton": {
"message": "Показывать кнопку информации в плеере YouTube" "message": "Показывать кнопку информации в плеере YouTube"
@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Узнать больше" "message": "Узнать больше"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Наведите курсор на поле редактирования и используйте колесо мыши для быстрой настройки времени. Клавиши Ctrl или Shift могут быть использованы для точной настройки."
} }
} }

View File

@@ -182,6 +182,9 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "Skryje tlačidlá pre preskočenie segmentov, ktoré sa zobrazujú v YouTube prehrávači." "message": "Skryje tlačidlá pre preskočenie segmentov, ktoré sa zobrazujú v YouTube prehrávači."
}, },
"showSkipButton": {
"message": "Zobrazovať tlačidlo preskočiť na hlavný obsah videa"
},
"showInfoButton": { "showInfoButton": {
"message": "Zobraziť info tlačidlo v YouTube prehrávači" "message": "Zobraziť info tlačidlo v YouTube prehrávači"
}, },
@@ -224,6 +227,21 @@
"showSkipNotice": { "showSkipNotice": {
"message": "Zobraziť upozornenie pri preskočení segmentu" "message": "Zobraziť upozornenie pri preskočení segmentu"
}, },
"noticeVisibilityMode0": {
"message": "Veľké upozornenia o preskočení"
},
"noticeVisibilityMode1": {
"message": "Malé upozornenia o automatickom preskočení"
},
"noticeVisibilityMode2": {
"message": "Malé upozornenia o všetkých preskočeniach"
},
"noticeVisibilityMode3": {
"message": "Priehľadné upozornenia o automatickom preskočení"
},
"noticeVisibilityMode4": {
"message": "Priehľadné upozornenia o všetkých preskočeniach"
},
"longDescription": { "longDescription": {
"message": "SponsorBlock umožňuje preskočiť sponzorov, úvodné časti, záverečné časti, pripomienky na odber, nehudobné časti videoklipov alebo iné otravné časti YouTube videí. SponsorBlock je crowdsourceové rozšírenie prehliadača, pomocou ktorého môže ktokoľvek označiť začiatok a koniec takéhoto segmentu. Po odoslaní potom všetci ostatní s týmto rozšírením tieto segmenty automaticky preskočia.", "message": "SponsorBlock umožňuje preskočiť sponzorov, úvodné časti, záverečné časti, pripomienky na odber, nehudobné časti videoklipov alebo iné otravné časti YouTube videí. SponsorBlock je crowdsourceové rozšírenie prehliadača, pomocou ktorého môže ktokoľvek označiť začiatok a koniec takéhoto segmentu. Po odoslaní potom všetci ostatní s týmto rozšírením tieto segmenty automaticky preskočia.",
"description": "Full description of the extension on the store pages." "description": "Full description of the extension on the store pages."

View File

@@ -182,6 +182,9 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "Detta döljer knapparna på YouTube-spelaren som du kan skicka in segment med som ska hoppas över." "message": "Detta döljer knapparna på YouTube-spelaren som du kan skicka in segment med som ska hoppas över."
}, },
"showSkipButton": {
"message": "Behåll knappen hoppa till markerat på spelaren"
},
"showInfoButton": { "showInfoButton": {
"message": "Visa Infoknapp På YouTube-spelaren" "message": "Visa Infoknapp På YouTube-spelaren"
}, },
@@ -807,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Läs mer" "message": "Läs mer"
},
"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."
} }
} }

View File

@@ -52,6 +52,9 @@
"reskip": { "reskip": {
"message": "ரெஸ்கிப்" "message": "ரெஸ்கிப்"
}, },
"unmute": {
"message": "ஒலியடக்கு"
},
"paused": { "paused": {
"message": "இடைநிறுத்தப்பட்டது" "message": "இடைநிறுத்தப்பட்டது"
}, },
@@ -79,9 +82,15 @@
"sponsorEnd": { "sponsorEnd": {
"message": "பிரிவு இப்போது முடிகிறது" "message": "பிரிவு இப்போது முடிகிறது"
}, },
"sponsorCancel": {
"message": "உருவாக்கும் பகுதியை ரத்து செய்"
},
"noVideoID": { "noVideoID": {
"message": "YouTube வீடியோ எதுவும் கிடைக்கவில்லை.\nஇது தவறாக இருந்தால், தாவலைப் புதுப்பிக்கவும்." "message": "YouTube வீடியோ எதுவும் கிடைக்கவில்லை.\nஇது தவறாக இருந்தால், தாவலைப் புதுப்பிக்கவும்."
}, },
"refreshSegments": {
"message": "பிரிவுகளைப் புதுப்பிக்கவும்"
},
"success": { "success": {
"message": "வெற்றி!" "message": "வெற்றி!"
}, },
@@ -152,6 +161,9 @@
"setUsername": { "setUsername": {
"message": "பயனர்பெயரை அமைக்கவும்" "message": "பயனர்பெயரை அமைக்கவும்"
}, },
"copyPublicID": {
"message": "பொது பயனர் IDயை நகலெடுக்கவும்"
},
"discordAdvert": { "discordAdvert": {
"message": "பரிந்துரைகள் மற்றும் கருத்துக்களை வழங்க அதிகாரப்பூர்வ டிஸ்கார்ட் சேவையகத்தில் சேர வாருங்கள்!" "message": "பரிந்துரைகள் மற்றும் கருத்துக்களை வழங்க அதிகாரப்பூர்வ டிஸ்கார்ட் சேவையகத்தில் சேர வாருங்கள்!"
}, },
@@ -170,12 +182,18 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "ஸ்கிப் பிரிவுகளைச் சமர்ப்பிக்க YouTube பிளேயரில் தோன்றும் பொத்தான்களை இது மறைக்கிறது." "message": "ஸ்கிப் பிரிவுகளைச் சமர்ப்பிக்க YouTube பிளேயரில் தோன்றும் பொத்தான்களை இது மறைக்கிறது."
}, },
"showSkipButton": {
"message": "பிளேயரில் Skip To Highlight பொத்தானை வைக்கவும்"
},
"showInfoButton": { "showInfoButton": {
"message": "YouTube பிளேயரில் தகவல் பொத்தானைக் காட்டு" "message": "YouTube பிளேயரில் தகவல் பொத்தானைக் காட்டு"
}, },
"hideInfoButton": { "hideInfoButton": {
"message": "YouTube பிளேயரில் தகவல் பொத்தானை மறைக்கவும்" "message": "YouTube பிளேயரில் தகவல் பொத்தானை மறைக்கவும்"
}, },
"autoHideInfoButton": {
"message": "தகவல் பொத்தானை தானாக மறைக்கவும்"
},
"hideDeleteButton": { "hideDeleteButton": {
"message": "YouTube பிளேயரில் நீக்கு பொத்தானை மறைக்க" "message": "YouTube பிளேயரில் நீக்கு பொத்தானை மறைக்க"
}, },
@@ -188,6 +206,9 @@
"whatViewTracking": { "whatViewTracking": {
"message": "இந்த அம்சம் பயனர்கள் தங்கள் சமர்ப்பிப்பு மற்றவர்களுக்கு எவ்வளவு உதவியது மற்றும் ஸ்பேம் தரவுத்தளத்தில் வரவில்லை என்பதை உறுதிப்படுத்த அப்வோட்களுடன் ஒரு மெட்ரிக்காகப் பயன்படுத்தப்படுவதை பயனர்களுக்குத் தெரியப்படுத்த நீங்கள் எந்த பகுதிகளைத் தவிர்த்துவிட்டீர்கள் என்பதைக் கண்காணிக்கிறது. ஒவ்வொரு முறையும் நீங்கள் ஒரு பகுதியைத் தவிர்க்கும்போது நீட்டிப்பு சேவையகத்திற்கு ஒரு செய்தியை அனுப்புகிறது. பார்வை எண்கள் துல்லியமாக இருக்க பெரும்பாலான மக்கள் இந்த அமைப்பை மாற்ற மாட்டார்கள் என்று நம்புகிறோம். :)" "message": "இந்த அம்சம் பயனர்கள் தங்கள் சமர்ப்பிப்பு மற்றவர்களுக்கு எவ்வளவு உதவியது மற்றும் ஸ்பேம் தரவுத்தளத்தில் வரவில்லை என்பதை உறுதிப்படுத்த அப்வோட்களுடன் ஒரு மெட்ரிக்காகப் பயன்படுத்தப்படுவதை பயனர்களுக்குத் தெரியப்படுத்த நீங்கள் எந்த பகுதிகளைத் தவிர்த்துவிட்டீர்கள் என்பதைக் கண்காணிக்கிறது. ஒவ்வொரு முறையும் நீங்கள் ஒரு பகுதியைத் தவிர்க்கும்போது நீட்டிப்பு சேவையகத்திற்கு ஒரு செய்தியை அனுப்புகிறது. பார்வை எண்கள் துல்லியமாக இருக்க பெரும்பாலான மக்கள் இந்த அமைப்பை மாற்ற மாட்டார்கள் என்று நம்புகிறோம். :)"
}, },
"enableViewTrackingInPrivate": {
"message": "தனிப்பட்ட/மறைநிலை தாவல்களில் ஸ்கிப் கவுண்ட் டிராக்கிங்கை இயக்கவும்"
},
"enableQueryByHashPrefix": { "enableQueryByHashPrefix": {
"message": "ஹாஷ் முன்னொட்டு மூலம் வினவல்" "message": "ஹாஷ் முன்னொட்டு மூலம் வினவல்"
}, },
@@ -206,6 +227,21 @@
"showSkipNotice": { "showSkipNotice": {
"message": "ஒரு பிரிவு தவிர்க்கப்பட்ட பிறகு அறிவிப்பைக் காட்டு" "message": "ஒரு பிரிவு தவிர்க்கப்பட்ட பிறகு அறிவிப்பைக் காட்டு"
}, },
"noticeVisibilityMode0": {
"message": "முழு அளவு தவிர்க்கும் அறிவிப்புகள்"
},
"noticeVisibilityMode1": {
"message": "ஆட்டோ ஸ்கிப்பிற்கான சிறிய ஸ்கிப் அறிவிப்புகள்"
},
"noticeVisibilityMode2": {
"message": "அனைத்து சிறிய தவிர்க்கும் அறிவிப்புகள்"
},
"noticeVisibilityMode3": {
"message": "ஆட்டோ ஸ்கிப்பிற்கான மங்கலான தவிர்க்கும் அறிவிப்புகள்"
},
"noticeVisibilityMode4": {
"message": "அனைத்து மங்கலான தவிர்க்கும் அறிவிப்புகள்"
},
"longDescription": { "longDescription": {
"message": "ஸ்பான்சர்கள், அறிமுகங்கள், அவுட்ரோஸ், சந்தா நினைவூட்டல்கள் மற்றும் YouTube வீடியோக்களின் பிற எரிச்சலூட்டும் பகுதிகளைத் தவிர்க்க ஸ்பான்சர் பிளாக் உங்களை அனுமதிக்கிறது. ஸ்பான்சர் பிளாக் என்பது ஒரு கூட்ட நெரிசலான உலாவி நீட்டிப்பாகும், இது ஸ்பான்சர் செய்யப்பட்ட பிரிவுகளின் தொடக்க மற்றும் இறுதி நேரங்களையும் YouTube வீடியோக்களின் பிற பிரிவுகளையும் எவரும் சமர்ப்பிக்கலாம். ஒரு நபர் இந்த தகவலைச் சமர்ப்பித்தவுடன், இந்த நீட்டிப்பு உள்ள மற்றவர்கள் ஸ்பான்சர் செய்யப்பட்ட பிரிவைத் தவிர்த்து விடுவார்கள். இசை வீடியோக்களின் இசை அல்லாத பிரிவுகளையும் நீங்கள் தவிர்க்கலாம்.", "message": "ஸ்பான்சர்கள், அறிமுகங்கள், அவுட்ரோஸ், சந்தா நினைவூட்டல்கள் மற்றும் YouTube வீடியோக்களின் பிற எரிச்சலூட்டும் பகுதிகளைத் தவிர்க்க ஸ்பான்சர் பிளாக் உங்களை அனுமதிக்கிறது. ஸ்பான்சர் பிளாக் என்பது ஒரு கூட்ட நெரிசலான உலாவி நீட்டிப்பாகும், இது ஸ்பான்சர் செய்யப்பட்ட பிரிவுகளின் தொடக்க மற்றும் இறுதி நேரங்களையும் YouTube வீடியோக்களின் பிற பிரிவுகளையும் எவரும் சமர்ப்பிக்கலாம். ஒரு நபர் இந்த தகவலைச் சமர்ப்பித்தவுடன், இந்த நீட்டிப்பு உள்ள மற்றவர்கள் ஸ்பான்சர் செய்யப்பட்ட பிரிவைத் தவிர்த்து விடுவார்கள். இசை வீடியோக்களின் இசை அல்லாத பிரிவுகளையும் நீங்கள் தவிர்க்கலாம்.",
"description": "Full description of the extension on the store pages." "description": "Full description of the extension on the store pages."
@@ -229,6 +265,9 @@
"setSkipShortcut": { "setSkipShortcut": {
"message": "ஒரு பகுதியைத் தவிர்ப்பதற்கான விசையை அமைக்கவும்" "message": "ஒரு பகுதியைத் தவிர்ப்பதற்கான விசையை அமைக்கவும்"
}, },
"setStartSponsorShortcut": {
"message": "துவக்க/நிறுத்த பிரிவு விசைப்பலகைக்கு விசையை அமைக்கவும்"
},
"setSubmitKeybind": { "setSubmitKeybind": {
"message": "சமர்ப்பிக்கும் விசைப்பலகைக்கு விசையை அமைக்கவும்" "message": "சமர்ப்பிக்கும் விசைப்பலகைக்கு விசையை அமைக்கவும்"
}, },
@@ -260,9 +299,31 @@
"skip": { "skip": {
"message": "தவிர்" "message": "தவிர்"
}, },
"mute": {
"message": "ஒலியடக்கு"
},
"skip_category": { "skip_category": {
"message": "{0} ஐ தவிர்?" "message": "{0} ஐ தவிர்?"
}, },
"mute_category": {
"message": "{0} ஐ ஒலியடக்கவா?"
},
"skip_to_category": {
"message": "{0} க்குச் செல்லவா?",
"description": "Used for skipping to things (Skip to Highlight)"
},
"skipped": {
"message": "{0} தவிர்க்கப்பட்டது",
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} ஒலியடக்கப்பட்டது",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
"message": "{0} தவிர்க்கப்பட்டது",
"description": "Used for skipping to things (Skipped to Highlight)"
},
"disableAutoSkip": { "disableAutoSkip": {
"message": "ஆட்டோ ஸ்கிப்பை முடக்கு" "message": "ஆட்டோ ஸ்கிப்பை முடக்கு"
}, },
@@ -311,6 +372,9 @@
"changeUserID": { "changeUserID": {
"message": "உங்கள் பயனர் ஐடியை இறக்குமதி / ஏற்றுமதி செய்யுங்கள்" "message": "உங்கள் பயனர் ஐடியை இறக்குமதி / ஏற்றுமதி செய்யுங்கள்"
}, },
"whatChangeUserID": {
"message": "இதை தனிப்பட்டதாக வைத்திருக்க வேண்டும். இது கடவுச்சொல் போன்றது, அதை யாருடனும் பகிரக்கூடாது. யாரிடமாவது இது இருந்தால், அவர் உங்களைப் போல் ஆள்மாறாட்டம் செய்யலாம். உங்கள் பொது பயனர் IDயை நீங்கள் தேடுகிறீர்களானால், பாப்அப்பில் உள்ள கிளிப்போர்டு ஐகானைக் கிளிக் செய்யவும்."
},
"setUserID": { "setUserID": {
"message": "UserID ஐ அமைக்கவும்" "message": "UserID ஐ அமைக்கவும்"
}, },
@@ -323,9 +387,25 @@
"keybindCurrentlySet": { "keybindCurrentlySet": {
"message": ". இது தற்போது அமைக்கப்பட்டுள்ளது:" "message": ". இது தற்போது அமைக்கப்பட்டுள்ளது:"
}, },
"supportOtherSites": {
"message": "3 வது தரப்பு YouTube-தளங்களை ஆதரிக்கவும்"
},
"supportOtherSitesDescription": {
"message": "மூன்றாம் தரப்பு YouTube தளங்களை ஆதரிக்கவும். ஆதரவை இயக்க, நீங்கள் கூடுதல் அனுமதிகளை ஏற்க வேண்டும். இது Chrome மற்றும் பிற Chromium வகைகளில் தனிப்பட்ட தாவல்களில் வேலை செய்யாது.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "ஆதரிக்கப்படும் தளங்கள்: "
},
"optionsInfo": { "optionsInfo": {
"message": "ஆக்கிரமிப்பு ஆதரவை இயக்கு, ஆட்டோஸ்கிப்பை முடக்கு, பொத்தான்களை மறை மற்றும் பலவற்றை." "message": "ஆக்கிரமிப்பு ஆதரவை இயக்கு, ஆட்டோஸ்கிப்பை முடக்கு, பொத்தான்களை மறை மற்றும் பலவற்றை."
}, },
"addInvidiousInstance": {
"message": "3 வது தரப்பு தளங்களை சேர்க்கவும்"
},
"addInvidiousInstanceDescription": {
"message": "தனிப்பட்ட தளங்களை சேர்க்கவும். இது Domain வடிவமைப்பில் இருக்க வேண்டும். உதாரணம்: invidious.ajay.app"
},
"add": { "add": {
"message": "சேர்" "message": "சேர்"
}, },
@@ -347,6 +427,12 @@
"minDurationDescription": { "minDurationDescription": {
"message": "தொகுப்பு மதிப்பை விடக் குறைவான பகுதிகள் தவிர்க்கப்படாது அல்லது பிளேயரில் காண்பிக்கப்படாது." "message": "தொகுப்பு மதிப்பை விடக் குறைவான பகுதிகள் தவிர்க்கப்படாது அல்லது பிளேயரில் காண்பிக்கப்படாது."
}, },
"skipNoticeDuration": {
"message": "அறிவிப்பு காலத்தை தவிர்க்கவும் (வினாடிகள்):"
},
"skipNoticeDurationDescription": {
"message": "தவிர்க்கும் அறிவிப்பு குறைந்தபட்சம் இவ்வளவு நேரம் திரையில் இருக்கும். மேனுவல் ஸ்கிப்பிங்கிற்கு, இது நீண்ட நேரம் தெரியும்."
},
"shortCheck": { "shortCheck": {
"message": "பின்வரும் சமர்ப்பிப்பு உங்கள் குறைந்தபட்ச கால விருப்பத்தை விட குறைவாக உள்ளது. இது ஏற்கனவே சமர்ப்பிக்கப்பட்டுள்ளது என்பதையும், இந்த விருப்பத்தின் காரணமாக புறக்கணிக்கப்படுவதையும் இது குறிக்கலாம். நீங்கள் சமர்ப்பிக்க விரும்புகிறீர்களா?" "message": "பின்வரும் சமர்ப்பிப்பு உங்கள் குறைந்தபட்ச கால விருப்பத்தை விட குறைவாக உள்ளது. இது ஏற்கனவே சமர்ப்பிக்கப்பட்டுள்ளது என்பதையும், இந்த விருப்பத்தின் காரணமாக புறக்கணிக்கப்படுவதையும் இது குறிக்கலாம். நீங்கள் சமர்ப்பிக்க விரும்புகிறீர்களா?"
}, },
@@ -404,6 +490,9 @@
"preview": { "preview": {
"message": "முன்னோட்ட" "message": "முன்னோட்ட"
}, },
"unsubmitted": {
"message": "சமர்ப்பிக்கப்படவில்லை"
},
"inspect": { "inspect": {
"message": "ஆய்வு செய்யுங்கள்" "message": "ஆய்வு செய்யுங்கள்"
}, },
@@ -468,6 +557,12 @@
"category_outro_description": { "category_outro_description": {
"message": "வரவுகளை அல்லது YouTube எண்ட்கார்டுகள் தோன்றும் போது. தகவலுடன் முடிவுகளுக்கு அல்ல." "message": "வரவுகளை அல்லது YouTube எண்ட்கார்டுகள் தோன்றும் போது. தகவலுடன் முடிவுகளுக்கு அல்ல."
}, },
"category_preview": {
"message": "முன்னோட்டம்/மறுபரிசீலனை"
},
"category_preview_description": {
"message": "முந்தைய எபிசோடுகளின் விரைவான மறுபரிசீலனை அல்லது தற்போதைய வீடியோவில் பின்னர் என்ன வரப்போகிறது என்பதற்கான முன்னோட்டம். ஒன்றாக தொகுக்கப்பட்ட கிளிப்புகள், பேசப்பட்ட சுருக்கங்களுக்கு அல்ல."
},
"category_music_offtopic": { "category_music_offtopic": {
"message": "இசை: இசை அல்லாத பிரிவு" "message": "இசை: இசை அல்லாத பிரிவு"
}, },
@@ -477,6 +572,12 @@
"category_music_offtopic_short": { "category_music_offtopic_short": {
"message": "இசை அல்லாதது" "message": "இசை அல்லாதது"
}, },
"category_poi_highlight": {
"message": "முன்னிலைப்படுத்த"
},
"category_poi_highlight_description": {
"message": "பெரும்பாலான மக்கள் தேடும் வீடியோவின் பகுதி. \"வீடியோ x இல் தொடங்குகிறது\" போன்றது."
},
"category_livestream_messages": { "category_livestream_messages": {
"message": "லைவ்ஸ்ட்ரீம்: நன்கொடை / செய்தி அளவீடுகள்" "message": "லைவ்ஸ்ட்ரீம்: நன்கொடை / செய்தி அளவீடுகள்"
}, },

View File

@@ -810,5 +810,8 @@
}, },
"LearnMore": { "LearnMore": {
"message": "Дізнатися більше" "message": "Дізнатися більше"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Навівши курсор на поле редагування, користуйтеся колесом прокрутки, щоб швидко відрегулювати час. Комбінації клавіш ctrl або shift можуть бути використані для точнішої настройки змін."
} }
} }

View File

@@ -182,6 +182,9 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "Không hiển thị nút trên trình chạy video Youtube để đăng đoạn quảng cáo." "message": "Không hiển thị nút trên trình chạy video Youtube để đăng đoạn quảng cáo."
}, },
"showSkipButton": {
"message": "Giữ nút bỏ qua Highlight trên trình phát player"
},
"showInfoButton": { "showInfoButton": {
"message": "Hiển thị nút thông tin trên trình chạy video Youtube" "message": "Hiển thị nút thông tin trên trình chạy video Youtube"
}, },
@@ -302,6 +305,14 @@
"skip_category": { "skip_category": {
"message": "Bỏ qua {0}?" "message": "Bỏ qua {0}?"
}, },
"skipped": {
"message": "{0} đã bỏ qua",
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} đã ngắt tiếng (Muted)",
"description": "Example: Sponsor Muted"
},
"disableAutoSkip": { "disableAutoSkip": {
"message": "Tắt tự động bỏ qua" "message": "Tắt tự động bỏ qua"
}, },
@@ -713,6 +724,9 @@
"hideForever": { "hideForever": {
"message": "Ẩn vĩnh viễn" "message": "Ẩn vĩnh viễn"
}, },
"warningChatInfo": {
"message": "Bạn đã nhận được một cảnh báo và tạm thời không thể gửi các phân đoạn. Bạn đã mắc lỗi trong việc tạo phân đoạn quá nhiều lần (có thể là chọn sai kiểu phân đoạn hoặc sai thời gian phân đoạn). Chúng tôi muốn bạn nhận ra điều đó để giúp bạn không mắc lỗi trong tương lai. Bạn có thể gặp các Vip User tại đây: discord.gg/SponsorBlock hoặc matrix.to/#/#sponsor:ajay.app. Bọn họ sẽ giúp bạn gỡ cảnh báo sau khi bạn đã hiểu ra lỗi sai của bạn"
},
"voteRejectedWarning": { "voteRejectedWarning": {
"message": "Bỏ phiếu bị từ chối do có cảnh báo. Nhấp để mở cuộc trò chuyện để giải quyết hoặc quay lại sau.", "message": "Bỏ phiếu bị từ chối do có cảnh báo. Nhấp để mở cuộc trò chuyện để giải quyết hoặc quay lại sau.",
"description": "This is an integrated chat panel that will appearing allowing them to talk to the Discord/Matrix chat without leaving their browser." "description": "This is an integrated chat panel that will appearing allowing them to talk to the Discord/Matrix chat without leaving their browser."
@@ -741,7 +755,49 @@
"helpPageHowSkippingWorks2": { "helpPageHowSkippingWorks2": {
"message": "Bất cứ khi nào bỏ qua một phân đoạn, bạn sẽ nhận được 1 cửa sổ thông báo bât. Nếu phân đoạn có vẻ sai, hãy bỏ phiếu bằng cách nhấp vào nút downvote! Bạn cũng có thể bỏ phiếu trong cửa sổ bật lên khi nhấn vào biểu tượng tiện ích mở rộng. Và bạn có thể tắt việc hiển thị bảng thông báo này trong phần cài đặt tiện ích." "message": "Bất cứ khi nào bỏ qua một phân đoạn, bạn sẽ nhận được 1 cửa sổ thông báo bât. Nếu phân đoạn có vẻ sai, hãy bỏ phiếu bằng cách nhấp vào nút downvote! Bạn cũng có thể bỏ phiếu trong cửa sổ bật lên khi nhấn vào biểu tượng tiện ích mở rộng. Và bạn có thể tắt việc hiển thị bảng thông báo này trong phần cài đặt tiện ích."
}, },
"Submitting": {
"message": "Gửi lên"
},
"helpPageSubmitting1": {
"message": "Việc gửi một phân đoạn mới có thể được thực hiện trong cửa sổ bật lên bằng cách nhấn vào nút \"Đoạn quảng cáo bắt đầu vào lúc này\" hoặc trong trình phát video bằng các nút trên thanh trình phát."
},
"helpPageSubmitting2": {
"message": "Bạn nhấp 1 lần vào nút \"Đoạn quảng cáo bắt đầu vào lúc này\" để bắt đầu 1 phân đoạn, nhấn 2 lần để đánh dấu kết thúc phân đoạn đó. Bạn có thể chuẩn bị nhiều phân đoạn trước khi nhấn gửi. Nhấp vào nút \"Đăng đoạn quảng cáo\" sẽ gửi. Nhấp vào nút \"Xoá đoạn quảng cáo\" để xóa."
},
"Editing": {
"message": "Chỉnh sửa"
},
"helpPageEditing1": {
"message": "Nếu bạn muốn chỉnh sửa thời gian phân đoạn hoặc kiểu của phân đoạn, bạn có thể chỉnh sửa hoặc xóa các phân đoạn của mình sau khi nhấp vào nút \"Đăng đoạn quảng cáo\"."
},
"helpPageTooSlow": { "helpPageTooSlow": {
"message": "Quá chậm" "message": "Nếu như bạn cảm thấy thao tác ở trên quá chậm..."
},
"helpPageTooSlow1": {
"message": "Bạn có thể sử dụng các hotkeys - phím nóng. Nhấn phím dấu chấm phẩy (;) để chỉ ra điểm bắt đầu / kết thúc của phân đoạn nhà tài trợ và nhấp vào dấu nháy đơn (') để gửi. Nếu bạn không sử dụng QWERTY, có lẽ bạn nên thay đổi keybinding bằng cách vào phần cài đặt của tiện ích."
},
"helpPageCopyOfDatabase": {
"message": "Tôi có thể lấy bản sao của database không? Điều gì xảy ra nếu có chuyện tệ (server chết, chủ nhân trang web mất, ...)?"
},
"helpPageCopyOfDatabase1": {
"message": "Database được công khai và luôn có sẵn tại "
},
"helpPageCopyOfDatabase2": {
"message": "Mã nguồn mở cũng luôn có sẵn. Vì vậy, ngay cả khi có điều gì đó tệ, các phân đoạn cũng sẽ không biến mất."
},
"helpPageNews": {
"message": "Tôi có thể cập nhật tin tức ở đâu?"
},
"helpPageSourceCode": {
"message": "Bạn có thể tìm thấy source code ở đâu?"
},
"Credits": {
"message": "Lời cảm ơn đến"
},
"highlightNewFeature": {
"message": "Tính năng mới! Đi đến đoạn quan trọng của video chỉ với 1 cú click với dạng phân đoạn Highlight"
},
"LearnMore": {
"message": "Tìm hiểu thêm"
} }
} }

View File

@@ -217,7 +217,7 @@
/* if two are very close to eachother */ /* if two are very close to eachother */
.secondSkipNotice { .secondSkipNotice {
bottom: 250px; bottom: 290px;
} }
.noticeLeftIcon { .noticeLeftIcon {
@@ -254,12 +254,16 @@
.sponsorTimesVoteButtonsContainer { .sponsorTimesVoteButtonsContainer {
float: left; float: left;
vertical-align:middle;
padding: 2px 5px; padding: 2px 5px;
margin-right: 4px; margin-right: 4px;
} }
.sponsorTimesVoteButtonsContainer div{
display: inline-block;
}
.sponsorSkipNoticeRightSection { .sponsorSkipNoticeRightSection {
right: 0; right: 0;
position: absolute; position: absolute;
@@ -330,7 +334,8 @@
} }
.voteButton { .voteButton {
height: 17px; height: 24px;
width: 24px;
cursor: pointer; cursor: pointer;
} }
.voteButton:hover { .voteButton:hover {
@@ -556,6 +561,10 @@ input::-webkit-inner-spin-button {
border-color: rgba(28, 28, 28, 0.7) transparent transparent transparent; border-color: rgba(28, 28, 28, 0.7) transparent transparent transparent;
} }
.sponsorBlockLockedColor {
color: #ffc83d;
}
.sponsorBlockRectangleTooltip { .sponsorBlockRectangleTooltip {
position: absolute; position: absolute;
border-radius: 5px; border-radius: 5px;
@@ -565,3 +574,4 @@ input::-webkit-inner-spin-button {
white-space: normal; white-space: normal;
line-height: 1.5em; line-height: 1.5em;
} }

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="24"
viewBox="0 0 24 24"
width="24"
version="1.1"
id="svg6"
sodipodi:docname="thumbs_down.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="730"
inkscape:window-height="480"
id="namedview8"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<path
d="M0 0h24v24H0z"
fill="none"
id="path2" />
<path
d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"
id="path4"
style="fill:#ffc83d" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -46,6 +46,7 @@
width: 330px; width: 330px;
padding: 22px; padding: 22px;
text-align: center; text-align: center;
margin-bottom: var(--ytd-margin-6x);
} }
#issueReporterTimeButtons > .votingButtons > .segmentTimeButton { #issueReporterTimeButtons > .votingButtons > .segmentTimeButton {

View File

@@ -4,14 +4,22 @@ import Config from "../config"
import { Category, ContentContainer, CategoryActionType, SponsorHideType, SponsorTime, NoticeVisbilityMode, ActionType } from "../types"; import { Category, ContentContainer, CategoryActionType, SponsorHideType, SponsorTime, NoticeVisbilityMode, ActionType } from "../types";
import NoticeComponent from "./NoticeComponent"; import NoticeComponent from "./NoticeComponent";
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
import SubmissionNotice from "../render/SubmissionNotice";
import Utils from "../utils";
const utils = new Utils();
import { getCategoryActionType, getSkippingText } from "../utils/categoryUtils"; import { getCategoryActionType, getSkippingText } from "../utils/categoryUtils";
import ThumbsUpSvg from "../svg-icons/thumbs_up_svg";
import ThumbsDownSvg from "../svg-icons/thumbs_down_svg";
import PencilSvg from "../svg-icons/pencil_svg";
export enum SkipNoticeAction { export enum SkipNoticeAction {
None, None,
Upvote, Upvote,
Downvote, Downvote,
CategoryVote, CategoryVote,
CopyDownvote,
Unskip Unskip
} }
@@ -43,7 +51,7 @@ export interface SkipNoticeState {
skipButtonCallback?: (index: number) => void; skipButtonCallback?: (index: number) => void;
showSkipButton?: boolean; showSkipButton?: boolean;
downvoting?: boolean; editing?: boolean;
choosingCategory?: boolean; choosingCategory?: boolean;
thanksForVotingText?: string; //null until the voting buttons should be hidden thanksForVotingText?: string; //null until the voting buttons should be hidden
@@ -52,6 +60,10 @@ export interface SkipNoticeState {
showKeybindHint?: boolean; showKeybindHint?: boolean;
smaller?: boolean; smaller?: boolean;
voted?: SkipNoticeAction[];
copied?: SkipNoticeAction[];
} }
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> { class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
@@ -69,6 +81,10 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
noticeRef: React.MutableRefObject<NoticeComponent>; noticeRef: React.MutableRefObject<NoticeComponent>;
categoryOptionRef: React.RefObject<HTMLSelectElement>; categoryOptionRef: React.RefObject<HTMLSelectElement>;
selectedColor: string;
unselectedColor: string;
lockedColor: string;
// Used to update on config change // Used to update on config change
configListener: () => void; configListener: () => void;
@@ -94,12 +110,16 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
this.segments.sort((a, b) => a.segment[0] - b.segment[0]); this.segments.sort((a, b) => a.segment[0] - b.segment[0]);
} }
//this is the suffix added at the end of every id // This is the suffix added at the end of every id
for (const segment of this.segments) { for (const segment of this.segments) {
this.idSuffix += segment.UUID; this.idSuffix += segment.UUID;
} }
this.idSuffix += this.amountOfPreviousNotices; this.idSuffix += this.amountOfPreviousNotices;
this.selectedColor = Config.config.colorPalette.red;
this.unselectedColor = Config.config.colorPalette.white;
this.lockedColor = Config.config.colorPalette.locked;
// Setup state // Setup state
this.state = { this.state = {
noticeTitle, noticeTitle,
@@ -115,7 +135,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
skipButtonCallback: (index) => this.unskip(index), skipButtonCallback: (index) => this.unskip(index),
showSkipButton: true, showSkipButton: true,
downvoting: false, editing: false,
choosingCategory: false, choosingCategory: false,
thanksForVotingText: null, thanksForVotingText: null,
@@ -123,7 +143,11 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
showKeybindHint: this.props.showKeybindHint ?? true, showKeybindHint: this.props.showKeybindHint ?? true,
smaller: this.props.smaller ?? false smaller: this.props.smaller ?? false,
// Keep track of what segment the user interacted with.
voted: new Array(this.props.segments.length).fill(SkipNoticeAction.None),
copied: new Array(this.props.segments.length).fill(SkipNoticeAction.None),
} }
if (!this.autoSkip) { if (!this.autoSkip) {
@@ -191,24 +215,33 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
className="sponsorTimesVoteButtonsContainer"> className="sponsorTimesVoteButtonsContainer">
{/* Upvote Button */} {/* Upvote Button */}
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix} <div id={"sponsorTimesDownvoteButtonsContainerUpvote" + this.idSuffix}
className="sponsorSkipObject voteButton" className="voteButton"
style={{marginRight: "10px"}} style={{marginRight: "5px"}}
src={chrome.extension.getURL("icons/thumbs_up.svg")}
title={chrome.i18n.getMessage("upvoteButtonInfo")} title={chrome.i18n.getMessage("upvoteButtonInfo")}
onClick={() => this.prepAction(SkipNoticeAction.Upvote)}> onClick={() => this.prepAction(SkipNoticeAction.Upvote)}>
<ThumbsUpSvg fill={(this.state.actionState === SkipNoticeAction.Upvote) ? this.selectedColor : this.unselectedColor} />
</img> </div>
{/* Report Button */} {/* Report Button */}
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix} <div id={"sponsorTimesDownvoteButtonsContainerDownvote" + this.idSuffix}
className="sponsorSkipObject voteButton" className="voteButton"
src={chrome.extension.getURL("icons/thumbs_down.svg")} style={{marginRight: "5px", marginLeft: "5px"}}
title={chrome.i18n.getMessage("reportButtonInfo")} title={chrome.i18n.getMessage("reportButtonInfo")}
onClick={() => this.adjustDownvotingState(true)}> onClick={() => this.prepAction(SkipNoticeAction.Downvote)}>
<ThumbsDownSvg fill={this.downvoteButtonColor(SkipNoticeAction.Downvote)} />
</img> </div>
{/* Copy and Downvote Button */}
<div id={"sponsorTimesDownvoteButtonsContainerCopyDownvote" + this.idSuffix}
className="voteButton"
style={{marginLeft: "5px"}}
onClick={() => this.openEditingOptions()}>
<PencilSvg fill={this.state.editing === true
|| this.state.actionState === SkipNoticeAction.CopyDownvote
|| this.state.choosingCategory === true
? this.selectedColor : this.unselectedColor} />
</div>
</td> </td>
: :
@@ -216,7 +249,22 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
<td id={"sponsorTimesVoteButtonInfoMessage" + this.idSuffix} <td id={"sponsorTimesVoteButtonInfoMessage" + this.idSuffix}
className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage" className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
style={{marginRight: "10px"}}> style={{marginRight: "10px"}}>
{/* Submitted string */}
<span style={{marginRight: "10px"}}>
{this.state.thanksForVotingText} {this.state.thanksForVotingText}
</span>
{/* Continue Voting Button */}
<button id={"sponsorTimesContinueVotingContainer" + this.idSuffix}
className="sponsorSkipObject sponsorSkipNoticeButton"
title={"Continue Voting"}
onClick={() => this.setState({
thanksForVotingText: null,
messages: []
})}>
{chrome.i18n.getMessage("ContinueVoting")}
</button>
</td> </td>
} }
@@ -229,45 +277,46 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
key={1}> key={1}>
<button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton" <button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"
onClick={this.contentContainer().dontShowNoticeAgain}> onClick={this.contentContainer().dontShowNoticeAgain}>
{chrome.i18n.getMessage("Hide")} {chrome.i18n.getMessage("Hide")}
</button> </button>
</td> </td>
} }
</tr>), </tr>),
/* Downvote Options Row */ /* Edit Segments Row */
(this.state.downvoting && (this.state.editing && !this.state.thanksForVotingText && !(this.state.choosingCategory || this.state.actionState === SkipNoticeAction.CopyDownvote) &&
<tr id={"sponsorSkipNoticeDownvoteOptionsRow" + this.idSuffix} <tr id={"sponsorSkipNoticeEditSegmentsRow" + this.idSuffix}
key={2}> key={2}>
<td id={"sponsorTimesDownvoteOptionsContainer" + this.idSuffix}> <td id={"sponsorTimesEditSegmentsContainer" + this.idSuffix}>
{/* Normal downvote */} {/* Copy Segment */}
<button className="sponsorSkipObject sponsorSkipNoticeButton" <button className="sponsorSkipObject sponsorSkipNoticeButton"
onClick={() => this.prepAction(SkipNoticeAction.Downvote)}> title={chrome.i18n.getMessage("CopyDownvoteButtonInfo")}
{chrome.i18n.getMessage("downvoteDescription")} style={{color: this.downvoteButtonColor(SkipNoticeAction.Downvote)}}
onClick={() => this.prepAction(SkipNoticeAction.CopyDownvote)}>
{chrome.i18n.getMessage("CopyAndDownvote")}
</button> </button>
{/* Category vote */} {/* Category vote */}
<button className="sponsorSkipObject sponsorSkipNoticeButton" <button className="sponsorSkipObject sponsorSkipNoticeButton"
onClick={() => this.openCategoryChooser()}> title={chrome.i18n.getMessage("ChangeCategoryTooltip")}
style={{color: (this.state.actionState === SkipNoticeAction.CategoryVote && this.state.editing == true) ? this.selectedColor : this.unselectedColor}}
onClick={() => this.resetStateToStart(SkipNoticeAction.CategoryVote, true, true)}>
{chrome.i18n.getMessage("incorrectCategory")} {chrome.i18n.getMessage("incorrectCategory")}
</button> </button>
</td> </td>
</tr> </tr>
), ),
/* Category Chooser Row */ /* Category Chooser Row */
(this.state.choosingCategory && (this.state.choosingCategory && !this.state.thanksForVotingText &&
<tr id={"sponsorSkipNoticeCategoryChooserRow" + this.idSuffix} <tr id={"sponsorSkipNoticeCategoryChooserRow" + this.idSuffix}
key={3}> key={3}>
<td> <td>
{/* Category Selector */} {/* Category Selector */}
<select id={"sponsorTimeCategories" + this.idSuffix} <select id={"sponsorTimeCategories" + this.idSuffix}
className="sponsorTimeCategories sponsorTimeEditSelector" className="sponsorTimeCategories sponsorTimeEditSelector"
defaultValue={this.segments[0].category} //Just default to the first segment, as we don't know which they'll choose defaultValue={this.segments[0].category}
ref={this.categoryOptionRef}> ref={this.categoryOptionRef}>
{this.getCategoryOptions()} {this.getCategoryOptions()}
@@ -281,13 +330,12 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
{chrome.i18n.getMessage("submit")} {chrome.i18n.getMessage("submit")}
</button> </button>
} }
</td> </td>
</tr> </tr>
), ),
/* Segment Chooser Row */ /* Segment Chooser Row */
(this.state.actionState !== SkipNoticeAction.None && (this.state.actionState !== SkipNoticeAction.None && this.segments.length > 1 && !this.state.thanksForVotingText &&
<tr id={"sponsorSkipNoticeSubmissionOptionsRow" + this.idSuffix} <tr id={"sponsorSkipNoticeSubmissionOptionsRow" + this.idSuffix}
key={4}> key={4}>
<td id={"sponsorTimesSubmissionOptionsContainer" + this.idSuffix}> <td id={"sponsorTimesSubmissionOptionsContainer" + this.idSuffix}>
@@ -306,9 +354,10 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
<span className="sponsorSkipNoticeUnskipSection"> <span className="sponsorSkipNoticeUnskipSection">
<button id={"sponsorSkipUnskipButton" + this.idSuffix} <button id={"sponsorSkipUnskipButton" + this.idSuffix}
className="sponsorSkipObject sponsorSkipNoticeButton" className="sponsorSkipObject sponsorSkipNoticeButton"
style={{marginLeft: "4px"}} style={{marginLeft: "4px",
color: (this.state.actionState === SkipNoticeAction.Unskip) ? this.selectedColor : this.unselectedColor
}}
onClick={() => this.prepAction(SkipNoticeAction.Unskip)}> onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
{this.state.skipButtonText + (this.state.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "")} {this.state.skipButtonText + (this.state.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "")}
</button> </button>
</span> </span>
@@ -318,20 +367,40 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
getSubmissionChooser(): JSX.Element[] { getSubmissionChooser(): JSX.Element[] {
const elements: JSX.Element[] = []; const elements: JSX.Element[] = [];
for (let i = 0; i < this.segments.length; i++) { for (let i = 0; i < this.segments.length; i++) {
elements.push( elements.push(
<button className="sponsorSkipObject sponsorSkipNoticeButton" <button className="sponsorSkipObject sponsorSkipNoticeButton"
style={{opacity: this.getSubmissionChooserOpacity(i),
color: this.getSubmissionChooserColor(i)}}
onClick={() => this.performAction(i)} onClick={() => this.performAction(i)}
key={"submission" + i + this.segments[i].category + this.idSuffix}> key={"submission" + i + this.segments[i].category + this.idSuffix}>
{(i + 1) + ". " + chrome.i18n.getMessage("category_" + this.segments[i].category)} {(i + 1) + ". " + chrome.i18n.getMessage("category_" + this.segments[i].category)}
</button> </button>
); );
} }
return elements; return elements;
} }
getSubmissionChooserOpacity(index: number): number {
const isUpvote = this.state.actionState === SkipNoticeAction.Upvote;
const isDownvote = this.state.actionState == SkipNoticeAction.Downvote;
const isCopyDownvote = this.state.actionState == SkipNoticeAction.CopyDownvote;
const shouldBeGray: boolean = (isUpvote && this.state.voted[index] == SkipNoticeAction.Upvote) ||
(isDownvote && this.state.voted[index] == SkipNoticeAction.Downvote) ||
(isCopyDownvote && this.state.copied[index] == SkipNoticeAction.CopyDownvote);
return shouldBeGray ? 0.35 : 1;
}
getSubmissionChooserColor(index: number): string {
const isDownvote = this.state.actionState == SkipNoticeAction.Downvote;
const isCopyDownvote = this.state.actionState == SkipNoticeAction.CopyDownvote;
const shouldWarnUser = Config.config.isVip && (isDownvote || isCopyDownvote)
&& this.segments[index].locked === 1;
return shouldWarnUser ? this.lockedColor : this.unselectedColor;
}
onMouseEnter(): void { onMouseEnter(): void {
if (this.state.smaller) { if (this.state.smaller) {
this.setState({ this.setState({
@@ -340,16 +409,6 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
} }
} }
prepAction(action: SkipNoticeAction): void {
if (this.segments.length === 1) {
this.performAction(0, action);
} else {
this.setState({
actionState: action
});
}
}
getMessageBoxes(): JSX.Element[] { getMessageBoxes(): JSX.Element[] {
if (this.state.messages.length === 0) { if (this.state.messages.length === 0) {
// Add a spacer if there is no text // Add a spacer if there is no text
@@ -365,8 +424,8 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
for (let i = 0; i < this.state.messages.length; i++) { for (let i = 0; i < this.state.messages.length; i++) {
elements.push( elements.push(
<tr> <tr key={i + "_messageBox"}>
<td> <td key={i + "_messageBox"}>
<NoticeTextSelectionComponent idSuffix={this.idSuffix} <NoticeTextSelectionComponent idSuffix={this.idSuffix}
text={this.state.messages[i]} text={this.state.messages[i]}
onClick={this.state.messageOnClick} onClick={this.state.messageOnClick}
@@ -380,6 +439,33 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
return elements; return elements;
} }
prepAction(action: SkipNoticeAction): void {
if (this.segments.length === 1) {
this.performAction(0, action);
} else {
switch (action ?? this.state.actionState) {
case SkipNoticeAction.None:
this.resetStateToStart();
break;
case SkipNoticeAction.Upvote:
this.resetStateToStart(SkipNoticeAction.Upvote);
break;
case SkipNoticeAction.Downvote:
this.resetStateToStart(SkipNoticeAction.Downvote);
break;
case SkipNoticeAction.CategoryVote:
this.resetStateToStart(SkipNoticeAction.CategoryVote, true, true);
break;
case SkipNoticeAction.CopyDownvote:
this.resetStateToStart(SkipNoticeAction.CopyDownvote, true);
break;
case SkipNoticeAction.Unskip:
this.resetStateToStart(SkipNoticeAction.Unskip);
break;
}
}
}
/** /**
* Performs the action from the current state * Performs the action from the current state
* *
@@ -388,74 +474,110 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
performAction(index: number, action?: SkipNoticeAction): void { performAction(index: number, action?: SkipNoticeAction): void {
switch (action ?? this.state.actionState) { switch (action ?? this.state.actionState) {
case SkipNoticeAction.None: case SkipNoticeAction.None:
this.noAction(index);
break; break;
case SkipNoticeAction.Upvote: case SkipNoticeAction.Upvote:
this.contentContainer().vote(1, this.segments[index].UUID, undefined, this); this.upvote(index);
break; break;
case SkipNoticeAction.Downvote: case SkipNoticeAction.Downvote:
this.contentContainer().vote(0, this.segments[index].UUID, undefined, this); this.downvote(index);
break; break;
case SkipNoticeAction.CategoryVote: case SkipNoticeAction.CategoryVote:
this.contentContainer().vote(undefined, this.segments[index].UUID, this.categoryOptionRef.current.value as Category, this) this.categoryVote(index);
break;
case SkipNoticeAction.CopyDownvote:
this.copyDownvote(index);
break; break;
case SkipNoticeAction.Unskip: case SkipNoticeAction.Unskip:
this.state.skipButtonCallback(index); this.unskipAction(index);
break;
default:
this.resetStateToStart();
break; break;
} }
}
noAction(index: number): void {
const voted = this.state.voted;
voted[index] = SkipNoticeAction.None;
this.setState({ this.setState({
actionState: SkipNoticeAction.None voted
}); });
} }
adjustDownvotingState(value: boolean): void { upvote(index: number): void {
if (!value) this.clearConfigListener(); if (this.segments.length === 1) this.resetStateToStart();
this.contentContainer().vote(1, this.segments[index].UUID, undefined, this);
}
downvote(index: number): void {
if (this.segments.length === 1) this.resetStateToStart();
this.contentContainer().vote(0, this.segments[index].UUID, undefined, this);
}
categoryVote(index: number): void {
this.contentContainer().vote(undefined, this.segments[index].UUID, this.categoryOptionRef.current.value as Category, this)
}
copyDownvote(index: number): void {
const sponsorVideoID = this.props.contentContainer().sponsorVideoID;
const sponsorTimesSubmitting : SponsorTime = {
segment: this.segments[index].segment,
UUID: null,
category: this.segments[index].category,
actionType: this.segments[index].actionType,
source: 2
};
const segmentTimes = Config.config.segmentTimes.get(sponsorVideoID) || [];
segmentTimes.push(sponsorTimesSubmitting);
Config.config.segmentTimes.set(sponsorVideoID, segmentTimes);
this.props.contentContainer().sponsorTimesSubmitting.push(sponsorTimesSubmitting);
this.props.contentContainer().updatePreviewBar();
this.props.contentContainer().resetSponsorSubmissionNotice();
this.props.contentContainer().updateEditButtonsOnPlayer();
this.contentContainer().vote(0, this.segments[index].UUID, undefined, this);
const copied = this.state.copied;
copied[index] = SkipNoticeAction.CopyDownvote;
this.setState({ this.setState({
downvoting: value, copied
choosingCategory: false
}); });
} }
clearConfigListener(): void { unskipAction(index: number): void {
if (this.configListener) { this.state.skipButtonCallback(index);
Config.configListeners.splice(Config.configListeners.indexOf(this.configListener), 1);
this.configListener = null;
}
} }
openCategoryChooser(): void { openEditingOptions(): void {
// Add as a config listener this.resetStateToStart(undefined, true);
this.configListener = () => this.forceUpdate();
Config.configListeners.push(this.configListener);
this.setState({
choosingCategory: true,
downvoting: false
}, () => {
if (this.segments.length > 1) {
// Use the action selectors as a submit button
this.prepAction(SkipNoticeAction.CategoryVote);
}
});
} }
getCategoryOptions(): React.ReactElement[] { getCategoryOptions(): React.ReactElement[] {
const elements = []; const elements = [];
const categories = CompileConfig.categoryList.filter((cat => getCategoryActionType(cat as Category) === CategoryActionType.Skippable)); const categories = (CompileConfig.categoryList.filter((cat => getCategoryActionType(cat as Category) === CategoryActionType.Skippable))) as Category[];
for (const category of categories) { for (const category of categories) {
elements.push( elements.push(
<option value={category} <option value={category}
key={category}> key={category}
className={this.getCategoryNameClass(category)}>
{chrome.i18n.getMessage("category_" + category)} {chrome.i18n.getMessage("category_" + category)}
</option> </option>
); );
} }
return elements; return elements;
} }
getCategoryNameClass(category: string): string {
return this.props.contentContainer().lockedCategories.includes(category) ? "sponsorBlockLockedColor" : ""
}
unskip(index: number): void { unskip(index: number): void {
this.contentContainer().unskipSponsorTime(this.segments[index], this.props.unskipTime); this.contentContainer().unskipSponsorTime(this.segments[index], this.props.unskipTime);
@@ -512,19 +634,40 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
} }
afterVote(segment: SponsorTime, type: number, category: Category): void { afterVote(segment: SponsorTime, type: number, category: Category): void {
this.addVoteButtonInfo(chrome.i18n.getMessage("voted")); const index = utils.getSponsorIndexFromUUID(this.segments, segment.UUID);
const wikiLinkText = CompileConfig.wikiLinks[segment.category];
if (type === 0) { const voted = this.state.voted;
this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack")); switch (type) {
this.adjustDownvotingState(false); case 0:
this.clearConfigListener();
this.setNoticeInfoMessageWithOnClick(() => window.open(wikiLinkText), chrome.i18n.getMessage("OpenCategoryWikiPage"));
voted[index] = SkipNoticeAction.Downvote;
break;
case 1:
voted[index] = SkipNoticeAction.Upvote;
break;
case 20:
voted[index] = SkipNoticeAction.None;
break;
} }
this.setState({
voted
});
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
// Change the sponsor locally // Change the sponsor locally
if (segment) { if (segment) {
if (type === 0) { if (type === 0) {
segment.hidden = SponsorHideType.Downvoted; segment.hidden = SponsorHideType.Downvoted;
} else if (category) { } else if (category) {
segment.category = category; segment.category = category; // This is the actual segment on the video page
this.segments[index].category = category; //this is the segment inside the skip notice.
} else if (type === 1) {
segment.hidden = SponsorHideType.Visible;
} }
this.contentContainer().updatePreviewBar(); this.contentContainer().updatePreviewBar();
@@ -562,6 +705,13 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
this.props.closeListener(); this.props.closeListener();
} }
clearConfigListener(): void {
if (this.configListener) {
Config.configListeners.splice(Config.configListeners.indexOf(this.configListener), 1);
this.configListener = null;
}
}
unmutedListener(): void { unmutedListener(): void {
if (this.props.segments.length === 1 if (this.props.segments.length === 1
&& this.props.segments[0].actionType === ActionType.Mute && this.props.segments[0].actionType === ActionType.Mute
@@ -572,6 +722,26 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
} }
} }
resetStateToStart(actionState: SkipNoticeAction = SkipNoticeAction.None, editing = false, choosingCategory = false): void {
this.setState({
actionState: actionState,
editing: editing,
choosingCategory: choosingCategory,
thanksForVotingText: null,
messages: []
});
}
downvoteButtonColor(downvoteType: SkipNoticeAction): string {
// Also used for "Copy and Downvote"
if (this.segments.length > 1) {
return (this.state.actionState === downvoteType) ? this.selectedColor : this.unselectedColor;
} else {
// You dont have segment selectors so the lockbutton needs to be colored and cannot be selected.
return Config.config.isVip && this.segments[0].locked === 1 ? this.lockedColor : this.unselectedColor;
}
}
private getUnskipText(): string { private getUnskipText(): string {
switch (this.props.segments[0].actionType) { switch (this.props.segments[0].actionType) {
case ActionType.Mute: { case ActionType.Mute: {

View File

@@ -24,6 +24,7 @@ export interface SponsorTimeEditProps {
export interface SponsorTimeEditState { export interface SponsorTimeEditState {
editing: boolean; editing: boolean;
sponsorTimeEdits: [string, string]; sponsorTimeEdits: [string, string];
selectedCategory: Category;
} }
const DEFAULT_CATEGORY = "chooseACategory"; const DEFAULT_CATEGORY = "chooseACategory";
@@ -47,7 +48,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
this.state = { this.state = {
editing: false, editing: false,
sponsorTimeEdits: [null, null] sponsorTimeEdits: [null, null],
selectedCategory: DEFAULT_CATEGORY as Category
}; };
} }
@@ -306,7 +308,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
for (const category of (this.props.categoryList ?? CompileConfig.categoryList)) { for (const category of (this.props.categoryList ?? CompileConfig.categoryList)) {
elements.push( elements.push(
<option value={category} <option value={category}
key={category}> key={category}
className={this.getCategoryLockedClass(category)}>
{chrome.i18n.getMessage("category_" + category)} {chrome.i18n.getMessage("category_" + category)}
</option> </option>
); );
@@ -315,6 +318,10 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
return elements; return elements;
} }
getCategoryLockedClass(category: string): string {
return this.props.contentContainer().lockedCategories.includes(category) ? "sponsorBlockLockedColor" : "";
}
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void { categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void {
// See if show more categories was pressed // See if show more categories was pressed
if (event.target.value !== DEFAULT_CATEGORY && !Config.config.categorySelections.some((category) => category.name === event.target.value)) { if (event.target.value !== DEFAULT_CATEGORY && !Config.config.categorySelections.some((category) => category.name === event.target.value)) {

View File

@@ -3,7 +3,9 @@ import { Category, CategorySelection, CategorySkipOption, NoticeVisbilityMode, P
interface SBConfig { interface SBConfig {
userID: string, userID: string,
/** Contains unsubmitted segments that the user has created. */ isVip: boolean,
lastIsVipUpdate: number,
/* Contains unsubmitted segments that the user has created. */
segmentTimes: SBMap<string, SponsorTime[]>, segmentTimes: SBMap<string, SponsorTime[]>,
defaultCategory: Category, defaultCategory: Category,
whitelistedChannels: string[], whitelistedChannels: string[],
@@ -44,7 +46,12 @@ interface SBConfig {
autoHideInfoButton: boolean, autoHideInfoButton: boolean,
autoSkipOnMusicVideos: boolean, autoSkipOnMusicVideos: boolean,
highlightCategoryUpdate: boolean, highlightCategoryUpdate: boolean,
scrollToEditTimeUpdate: boolean colorPalette: {
red: string,
white: string,
locked: string
},
scrollToEditTimeUpdate: boolean,
// What categories should be skipped // What categories should be skipped
categorySelections: CategorySelection[], categorySelections: CategorySelection[],
@@ -152,6 +159,8 @@ const Config: SBObject = {
configListeners: [], configListeners: [],
defaults: { defaults: {
userID: null, userID: null,
isVip: false,
lastIsVipUpdate: 0,
segmentTimes: new SBMap("segmentTimes"), segmentTimes: new SBMap("segmentTimes"),
defaultCategory: "chooseACategory" as Category, defaultCategory: "chooseACategory" as Category,
whitelistedChannels: [], whitelistedChannels: [],
@@ -199,6 +208,12 @@ const Config: SBObject = {
option: CategorySkipOption.AutoSkip option: CategorySkipOption.AutoSkip
}], }],
colorPalette: {
red: "#780303",
white: "#ffffff",
locked: "#ffc83d"
},
// Preview bar // Preview bar
barTypes: { barTypes: {
"preview-chooseACategory": { "preview-chooseACategory": {

View File

@@ -34,8 +34,10 @@ let lastPOISkip = 0;
// JSON video info // JSON video info
let videoInfo: VideoInfo = null; let videoInfo: VideoInfo = null;
//the channel this video is about // The channel this video is about
let channelIDInfo: ChannelIDInfo; let channelIDInfo: ChannelIDInfo;
// Locked Categories in this tab, like: ["sponsor","intro","outro"]
let lockedCategories: Category[] = [];
// Skips are scheduled to ensure precision. // Skips are scheduled to ensure precision.
// Skips are rescheduled every seeking event. // Skips are rescheduled every seeking event.
@@ -121,7 +123,8 @@ const skipNoticeContentContainer: ContentContainer = () => ({
updateEditButtonsOnPlayer, updateEditButtonsOnPlayer,
previewTime, previewTime,
videoInfo, videoInfo,
getRealCurrentTime: getRealCurrentTime getRealCurrentTime: getRealCurrentTime,
lockedCategories
}); });
// value determining when to count segment as skipped and send telemetry to server (percent based) // value determining when to count segment as skipped and send telemetry to server (percent based)
@@ -231,6 +234,7 @@ function resetValues() {
status: ChannelIDStatus.Fetching, status: ChannelIDStatus.Fetching,
id: null id: null
}; };
lockedCategories = [];
//empty the preview bar //empty the preview bar
if (previewBar !== null) { if (previewBar !== null) {
@@ -757,6 +761,55 @@ async function sponsorsLookup(id: string, keepOldSubmissions = true) {
sponsorLookupRetries++; sponsorLookupRetries++;
} }
lookupVipInformation(id);
}
function lookupVipInformation(id: string): void {
updateVipInfo().then((isVip) => {
if (isVip) {
lockedCategoriesLookup(id);
}
});
}
async function updateVipInfo(): Promise<boolean> {
const currentTime = Date.now();
const lastUpdate = Config.config.lastIsVipUpdate;
if (currentTime - lastUpdate > 1000 * 60 * 60 * 72) { // 72 hours
Config.config.lastIsVipUpdate = currentTime;
const response = await utils.asyncRequestToServer("GET", "/api/isUserVIP", { userID: Config.config.userID});
if (response.ok) {
let isVip = false;
try {
const vipResponse = JSON.parse(response.responseText)?.vip;
if (typeof(vipResponse) === "boolean") {
isVip = vipResponse;
}
} catch (e) { } //eslint-disable-line no-empty
Config.config.isVip = isVip;
return isVip;
}
}
return Config.config.isVip;
}
async function lockedCategoriesLookup(id: string): Promise<void> {
const hashPrefix = (await utils.getHash(id, 1)).substr(0, 4);
const response = await utils.asyncRequestToServer("GET", "/api/lockCategories/" + hashPrefix);
if (response.ok) {
try {
const categoriesResponse = JSON.parse(response.responseText).filter((lockInfo) => lockInfo.videoID === id)[0]?.categories;
if (Array.isArray(categoriesResponse)) {
lockedCategories = categoriesResponse;
}
} catch (e) { } //eslint-disable-line no-empty
}
} }
function retryFetch(): void { function retryFetch(): void {
@@ -1688,7 +1741,11 @@ function resetSponsorSubmissionNotice() {
} }
function submitSponsorTimes() { function submitSponsorTimes() {
if (submissionNotice !== null) return; if (submissionNotice !== null){
submissionNotice.close();
submissionNotice = null;
return;
}
if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) { if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) {
submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage); submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage);

View File

@@ -379,8 +379,10 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
container.removeChild(container.firstChild); container.removeChild(container.firstChild);
} }
const isVip = Config.config.isVip;
for (let i = 0; i < segmentTimes.length; i++) { for (let i = 0; i < segmentTimes.length; i++) {
const UUID = segmentTimes[i].UUID; const UUID = segmentTimes[i].UUID;
const locked = segmentTimes[i].locked;
const sponsorTimeButton = document.createElement("button"); const sponsorTimeButton = document.createElement("button");
sponsorTimeButton.className = "segmentTimeButton popupElement"; sponsorTimeButton.className = "segmentTimeButton popupElement";
@@ -430,7 +432,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
const downvoteButton = document.createElement("img"); const downvoteButton = document.createElement("img");
downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + UUID; downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + UUID;
downvoteButton.className = "voteButton"; downvoteButton.className = "voteButton";
downvoteButton.src = chrome.runtime.getURL("icons/thumbs_down.svg"); downvoteButton.src = locked && isVip ? chrome.runtime.getURL("icons/thumbs_down_locked.svg") : chrome.runtime.getURL("icons/thumbs_down.svg");
downvoteButton.addEventListener("click", () => vote(0, UUID)); downvoteButton.addEventListener("click", () => vote(0, UUID));
//uuid button //uuid button

View File

@@ -0,0 +1,18 @@
import * as React from "react";
const pencilSvg = ({
fill = "#ffffff"
}): JSX.Element => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 24 24"
fill={fill}
>
<path
d="M14.1 7.1l2.9 2.9L6.1 20.7l-3.6.7.7-3.6L14.1 7.1zm0-2.8L1.4 16.9 0 24l7.1-1.4L19.8 9.9l-5.7-5.7zm7.1 4.3L24 5.7 18.3 0l-2.8 2.8 5.7 5.7z"></path>
</svg>
);
export default pencilSvg;

View File

@@ -0,0 +1,23 @@
import * as React from "react";
const thumbsDownSvg = ({
fill = "#ffffff"
}): JSX.Element => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
fill={fill}
viewBox="0 0 24 24"
>
<path
fill="none"
d="M0 0h24v24H0z">
</path>
<path
d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"
></path>
</svg>
);
export default thumbsDownSvg;

View File

@@ -0,0 +1,22 @@
import * as React from "react";
const thumbsUpSvg = ({
fill = "#ffffff"
}): JSX.Element => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
fill={fill}
viewBox="0 0 24 24"
>
<path
fill="none"
d="M0 0h24v24H0V0z"></path>
<path
d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"
></path>
</svg>
);
export default thumbsUpSvg;

View File

@@ -20,7 +20,8 @@ export interface ContentContainer {
updateEditButtonsOnPlayer: () => void, updateEditButtonsOnPlayer: () => void,
previewTime: (time: number, unpause?: boolean) => void, previewTime: (time: number, unpause?: boolean) => void,
videoInfo: VideoInfo, videoInfo: VideoInfo,
getRealCurrentTime: () => number getRealCurrentTime: () => number,
lockedCategories: string[]
} }
} }
@@ -75,6 +76,7 @@ export enum SponsorSourceType {
export interface SponsorTime { export interface SponsorTime {
segment: [number] | [number, number]; segment: [number] | [number, number];
UUID: SegmentUUID; UUID: SegmentUUID;
locked?: number;
category: Category; category: Category;
actionType: ActionType; actionType: ActionType;

View File

@@ -539,5 +539,4 @@ export default class Utils {
return hashHex; return hashHex;
} }
} }