mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-06 19:47:04 +03:00
Compare commits
211 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c9c9fe8a | ||
|
|
7f8badb34d | ||
|
|
f9d8daeca0 | ||
|
|
55070d5852 | ||
|
|
789bd5939b | ||
|
|
b591fbfc4b | ||
|
|
57eb122fce | ||
|
|
aec287f0cf | ||
|
|
c68aabaa40 | ||
|
|
167cff4693 | ||
|
|
99c343c2ce | ||
|
|
70239bc045 | ||
|
|
d1748f1758 | ||
|
|
ac3d27bf88 | ||
|
|
3fb5c1c14f | ||
|
|
b1d9cde715 | ||
|
|
aa8225c196 | ||
|
|
918adc7c28 | ||
|
|
ab84b9d2e0 | ||
|
|
9e0a9b4601 | ||
|
|
98fd841a54 | ||
|
|
3816313f1e | ||
|
|
a433dad080 | ||
|
|
dc04e045aa | ||
|
|
2f842a0455 | ||
|
|
7c38b1f8f2 | ||
|
|
6942bcb418 | ||
|
|
a335ae2b72 | ||
|
|
52020bcac6 | ||
|
|
5454861c78 | ||
|
|
1217b9ed0b | ||
|
|
e78a1b0fed | ||
|
|
a259949cd6 | ||
|
|
ebf333b8c6 | ||
|
|
9a5cb5ae0f | ||
|
|
20e1a96a84 | ||
|
|
822c7bda89 | ||
|
|
1526fbcbe8 | ||
|
|
b8f4f8bebc | ||
|
|
e3698dcdca | ||
|
|
fc3abc2b56 | ||
|
|
2a8a425627 | ||
|
|
9069f7cee6 | ||
|
|
a217831c22 | ||
|
|
44e8b316a5 | ||
|
|
885b38b682 | ||
|
|
938db4b8e0 | ||
|
|
ad361cdf28 | ||
|
|
fbafb723cb | ||
|
|
797fbf563b | ||
|
|
d23c8b0e1f | ||
|
|
18852d16ac | ||
|
|
6179278699 | ||
|
|
8a6488f082 | ||
|
|
89c4432b89 | ||
|
|
16896be97f | ||
|
|
8a9a19efeb | ||
|
|
f3c786eb57 | ||
|
|
19ab83fee9 | ||
|
|
0f9e794428 | ||
|
|
1b8af9da11 | ||
|
|
0b90539372 | ||
|
|
4131442066 | ||
|
|
e4f642e7d6 | ||
|
|
a65e40a87d | ||
|
|
edf467a6b9 | ||
|
|
3fbb11191e | ||
|
|
54a67e6aba | ||
|
|
8912f88131 | ||
|
|
c31d30821b | ||
|
|
7eb6f1c482 | ||
|
|
a7e2f83033 | ||
|
|
0cfe0dc90f | ||
|
|
8c1d837770 | ||
|
|
9a70599e60 | ||
|
|
89f72c185c | ||
|
|
2f5c239c82 | ||
|
|
31b76553dc | ||
|
|
eff73548e3 | ||
|
|
2ca98ad97b | ||
|
|
4e9b5ca0bc | ||
|
|
3d7d291d9a | ||
|
|
195ed1f5fc | ||
|
|
74f14b3bf8 | ||
|
|
290dff25f9 | ||
|
|
64ab6b5768 | ||
|
|
1b2bc6def4 | ||
|
|
18c7be8161 | ||
|
|
638439a671 | ||
|
|
9fafb9cf54 | ||
|
|
0223aa8307 | ||
|
|
07f1106579 | ||
|
|
2f78f31874 | ||
|
|
74a4ef0692 | ||
|
|
2d55ea0fc5 | ||
|
|
a50f030a3b | ||
|
|
ae690f0c65 | ||
|
|
e2128f7ae3 | ||
|
|
80fe28a952 | ||
|
|
be74ebe7bc | ||
|
|
e085163dfd | ||
|
|
adef65b878 | ||
|
|
b7870cbd74 | ||
|
|
cd03218940 | ||
|
|
6abf6a0044 | ||
|
|
6ef5dd4522 | ||
|
|
9f87c839b5 | ||
|
|
85c1a45c8b | ||
|
|
963fb58321 | ||
|
|
d1d4dcdc9c | ||
|
|
24dd98a98f | ||
|
|
5abc0bedd4 | ||
|
|
e1e570fb18 | ||
|
|
93c0a0c003 | ||
|
|
93f82de7fd | ||
|
|
f6945b56d8 | ||
|
|
55e17ceb60 | ||
|
|
2a432490bc | ||
|
|
0115a6df13 | ||
|
|
a5e9ceda60 | ||
|
|
09f53c80f0 | ||
|
|
8134b5a67e | ||
|
|
ebd6c9c952 | ||
|
|
37e2fb0972 | ||
|
|
7af44eae66 | ||
|
|
62c50d77c6 | ||
|
|
bac9029a28 | ||
|
|
48a614943d | ||
|
|
ec9f1efd55 | ||
|
|
59c6455298 | ||
|
|
d7a7476cd1 | ||
|
|
36981af95a | ||
|
|
d4d5e4743e | ||
|
|
3afde08a6e | ||
|
|
6ea87d7cd0 | ||
|
|
b6c243236b | ||
|
|
6fa67088bc | ||
|
|
d37abcfa9f | ||
|
|
5575eda7b1 | ||
|
|
e17eb60b4d | ||
|
|
e055a66342 | ||
|
|
72c98923f6 | ||
|
|
8ecea87c52 | ||
|
|
7727cd56db | ||
|
|
242fbf8009 | ||
|
|
24f2ce4a32 | ||
|
|
0d08e11b1d | ||
|
|
513a140754 | ||
|
|
88350e3421 | ||
|
|
36d79313de | ||
|
|
a9993d5d80 | ||
|
|
4a6ddf6774 | ||
|
|
b6172c6d9b | ||
|
|
b21a59f4e5 | ||
|
|
78dd44c502 | ||
|
|
f4a129b346 | ||
|
|
6d60a90533 | ||
|
|
0d33794636 | ||
|
|
e62d46f2dd | ||
|
|
7f36c7eec3 | ||
|
|
08d28798c6 | ||
|
|
fe33277d8f | ||
|
|
feec5b4e22 | ||
|
|
62b5e90d87 | ||
|
|
2c980a269d | ||
|
|
1da60e38a1 | ||
|
|
ed67cc52fe | ||
|
|
b614dce91a | ||
|
|
c013c7ef0f | ||
|
|
c78e2cd214 | ||
|
|
da5a3841bd | ||
|
|
e73d79071c | ||
|
|
f100ee4738 | ||
|
|
37662138df | ||
|
|
037d1089a3 | ||
|
|
0467dd5d21 | ||
|
|
1df123de6d | ||
|
|
3063591a4c | ||
|
|
a182354254 | ||
|
|
5f879bceab | ||
|
|
457bd15e17 | ||
|
|
cc1b8ee499 | ||
|
|
4a9ed1348e | ||
|
|
5595420be6 | ||
|
|
191e9ceb6f | ||
|
|
a02aef591e | ||
|
|
1e26faa57c | ||
|
|
1a92265e65 | ||
|
|
92a6065c98 | ||
|
|
d7ca56941a | ||
|
|
030256c9e1 | ||
|
|
77eff12d9b | ||
|
|
2967fce013 | ||
|
|
db1def623a | ||
|
|
140e324bf1 | ||
|
|
f0bf051259 | ||
|
|
2ec47d52cd | ||
|
|
50002cfbbd | ||
|
|
da6ccb561d | ||
|
|
c526a812e0 | ||
|
|
ccbc0456f9 | ||
|
|
0d9b624fd5 | ||
|
|
008c9380b1 | ||
|
|
8d82a6a3e6 | ||
|
|
88a8fda566 | ||
|
|
995fe072bd | ||
|
|
8cdbebd6de | ||
|
|
94af8ab301 | ||
|
|
be3a4a4e91 | ||
|
|
1c17464c94 | ||
|
|
8896c5707a |
61
.github/workflows/release.yml
vendored
61
.github/workflows/release.yml
vendored
@@ -26,9 +26,12 @@ jobs:
|
||||
name: ChromeExtension
|
||||
path: dist
|
||||
- run: mkdir ./builds
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtension.zip ./dist
|
||||
args: zip -r ../builds/ChromeExtension.zip *
|
||||
- run: cd ../
|
||||
|
||||
# Create Firefox artifacts
|
||||
- name: Create Firefox artifacts
|
||||
@@ -37,9 +40,12 @@ jobs:
|
||||
with:
|
||||
name: FirefoxExtension
|
||||
path: dist
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtension.zip ./dist
|
||||
args: zip -r ../builds/FirefoxExtension.zip *
|
||||
- run: cd ../
|
||||
|
||||
# Create Beta artifacts (Builds with the name changed to beta)
|
||||
- name: Create Chrome Beta artifacts
|
||||
@@ -48,9 +54,12 @@ jobs:
|
||||
with:
|
||||
name: ChromeExtensionBeta
|
||||
path: dist
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtensionBeta.zip ./dist
|
||||
args: zip -r ../builds/ChromeExtensionBeta.zip *
|
||||
- run: cd ../
|
||||
|
||||
- name: Create Firefox Beta artifacts
|
||||
run: npm run build:firefox -- --env.stream=beta
|
||||
@@ -58,21 +67,57 @@ jobs:
|
||||
with:
|
||||
name: FirefoxExtensionBeta
|
||||
path: dist
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtensionBeta.zip ./dist
|
||||
args: zip -r ../builds/FirefoxExtensionBeta.zip *
|
||||
- run: cd ../
|
||||
|
||||
# Create Firefox Signed Beta version
|
||||
- name: Create Firefox Signed Beta artifacts
|
||||
run: npm run web-sign
|
||||
env:
|
||||
WEB_EXT_API_KEY: ${{ secrets.WEB_EXT_API_KEY }}
|
||||
WEB_EXT_API_SECRET: ${{ secrets.WEB_EXT_API_SECRET }}
|
||||
- name: Install rename
|
||||
run: sudo apt-get install rename
|
||||
- name: Install signed file
|
||||
run: cd ./web-ext-artifacts
|
||||
- run: rename 's/.*/FirefoxSignedInstaller.xpi/' *
|
||||
- run: cd ..
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtensionSigned.xpi
|
||||
path: ./web-ext-artifacts/FirefoxSignedInstaller.xpi
|
||||
|
||||
# Upload each release asset
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtension.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: ChromeExtension.zip
|
||||
path: ./builds/ChromeExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtensionBeta.zip
|
||||
name: ChromeExtensionBeta.zip
|
||||
path: ./builds/ChromeExtensionBeta.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/FirefoxExtension.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: FirefoxExtension.zip
|
||||
path: ./builds/FirefoxExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: web-ext-artifacts/FirefoxSignedInstaller.xpi
|
||||
name: FirefoxSignedInstaller.xpi
|
||||
path: ./web-ext-artifacts/FirefoxSignedInstaller.xpi
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
36
README.md
36
README.md
@@ -34,41 +34,47 @@ SponsorBlock is an extension that will skip over sponsored segments of YouTube v
|
||||
|
||||
Also support Invidio.us.
|
||||
|
||||
**Translate:** [](https://crowdin.com/project/sponsorblock)
|
||||
|
||||
# Important Links
|
||||
|
||||
See the [Wiki](https://github.com/ajayyy/SponsorBlock/wiki) for important links.
|
||||
|
||||
# Server
|
||||
|
||||
The backend server code is available here: https://github.com/ajayyy/SponsorBlockServer
|
||||
|
||||
It is a simple Sqlite database that will hold all the timing data.
|
||||
It is a simple SQLite database that will hold all the timing data.
|
||||
|
||||
To make sure that this project doesn't die, I have made the database publicly downloadable at https://api.sponsor.ajay.app/database.db. So, you can download a backup or get archive.org to take a backup for you if you want.
|
||||
To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. If you are planning on using the database in another project, please read the [API Docs](https://github.com/ajayyy/SponsorBlock/wiki/API-Docs) page for more information.
|
||||
|
||||
Hopefully this project can be combined with projects like [this](https://github.com/Sponsoff/sponsorship_remover) and use this data to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea.
|
||||
The dataset and API are now being used in some [ports](https://github.com/ajayyy/SponsorBlock/wiki/Unofficial-Ports) as well as a [neural network](https://github.com/andrewzlee/NeuralBlock).
|
||||
|
||||
A [previous project](https://github.com/Sponsoff/sponsorship_remover) attempted to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea starting from a crowd-sourced system instead.
|
||||
|
||||
# API
|
||||
|
||||
You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs).
|
||||
|
||||
# Build Yourself
|
||||
# Building
|
||||
|
||||
You can load this project as an unpacked extension. Make sure to rename the `config.json.example` file to `config.json` before installing.
|
||||
Rename `config.json.example` to `config.json` and adjust configuration as desired.
|
||||
|
||||
There are also other build scripts available. Install `npm`, then run `npm install` in the repository.
|
||||
There are also other build scripts available. Install `npm`, then run `npm install` in the repository to install dependencies.
|
||||
|
||||
Run `npm run build` to generate a Chrome extension.
|
||||
|
||||
Use `npm run build:firefox` to generate a Firefox extension.
|
||||
|
||||
The result is in `dist`. This can be loaded as an unpacked extension
|
||||
|
||||
## Developing with a clean profile
|
||||
|
||||
Run `npm run dev` to run the extension using a clean browser profile with hot reloading. Use `npm run dev:firefox` for Firefox. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands).
|
||||
|
||||
## Packing
|
||||
|
||||
Run `npm run build` to generate a packed Chrome extension.
|
||||
|
||||
Use `npm run build:firefox` to generate a Firefox extension.
|
||||
|
||||
The result is in `dist`.
|
||||
|
||||
# Credit
|
||||
|
||||
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) previously was used.
|
||||
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) was previously used.
|
||||
|
||||
Originally forked from [YTSponsorSkip](https://github.com/OfficialNoob/YTSponsorSkip), but zero code remains.
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"serverAddress": "https://sponsor.ajay.app",
|
||||
"serverAddressComment": "This specifies the default SponsorBlock server to conect to"
|
||||
"testingServerAddress": "https://sponsor.ajay.app/test",
|
||||
"serverAddressComment": "This specifies the default SponsorBlock server to conect to",
|
||||
"categoryList": ["sponsor", "intro", "outro", "interaction", "selfpromo", "music_offtopic"]
|
||||
}
|
||||
11
crowdin.yml
11
crowdin.yml
@@ -1,10 +1,3 @@
|
||||
files:
|
||||
- source: /_locales/en/*
|
||||
translation: /_locales/%two_letters_code%/%original_file_name%
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
pl-PL: "pl_PL"
|
||||
pr-BR: "pt_BR"
|
||||
pr-PT: "pt_PT"
|
||||
zh-CN: "zh_CH"
|
||||
zh-TW: "zh_TW"
|
||||
- source: /public/_locales/en/*
|
||||
translation: /public/_locales/%two_letters_code%/%original_file_name%
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "__MSG_Name__",
|
||||
"version": "1.2.21",
|
||||
"version": "1.2.28.1",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"content_scripts": [{
|
||||
@@ -32,6 +32,7 @@
|
||||
"icons/downvote.png",
|
||||
"icons/report.png",
|
||||
"icons/close.png",
|
||||
"icons/beep.ogg",
|
||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||
"popup.html",
|
||||
|
||||
4094
package-lock.json
generated
4094
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@@ -4,10 +4,18 @@
|
||||
"description": "",
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"concurrently": "^5.1.0"
|
||||
"@types/react": "^16.9.22",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"babel": "^6.23.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"concurrently": "^5.1.0",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"web-ext": "^4.0.0",
|
||||
"web-ext": "^4.2.0",
|
||||
"@types/chrome": "0.0.91",
|
||||
"@types/firefox-webext-browser": "70.0.1",
|
||||
"@types/jest": "^24.0.23",
|
||||
@@ -24,6 +32,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"web-run": "npm run web-run:chrome",
|
||||
"web-sign": "web-ext sign -s dist",
|
||||
"web-run:firefox": "cd dist && web-ext run --start-url https://addons.mozilla.org/firefox/addon/ublock-origin/",
|
||||
"web-run:chrome": "cd dist && web-ext run --start-url https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm -t chromium",
|
||||
"build": "npm run build:chrome",
|
||||
|
||||
1
public/_locales/af/messages.json
Normal file
1
public/_locales/af/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/am/messages.json
Normal file
1
public/_locales/am/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/ar/messages.json
Normal file
1
public/_locales/ar/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/bg/messages.json
Normal file
1
public/_locales/bg/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/bn/messages.json
Normal file
1
public/_locales/bn/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/ca/messages.json
Normal file
1
public/_locales/ca/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
8
public/_locales/cs/messages.json
Normal file
8
public/_locales/cs/messages.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Sponsor": {
|
||||
"message": "sponzor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponzoři"
|
||||
}
|
||||
}
|
||||
1
public/_locales/da/messages.json
Normal file
1
public/_locales/da/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -4,17 +4,13 @@
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"message": "SponsorBlock für YouTube - Überspringe Sponsor Anzeigen",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Überspringe die gesponserten Inhalte in YouTube-Videos. Melde gesponsorte Inhalte in den von dir angesehenen Videos und erspare anderen die Zeit.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Ungültige Anforderung"
|
||||
},
|
||||
@@ -33,7 +29,7 @@
|
||||
"Sponsors": {
|
||||
"message": "Sponsoren"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "gesponsorter Inhalt"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -133,37 +129,37 @@
|
||||
"message": "Bist du sicher, dass die Auswahl abgeschickt werden soll?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Kanal auf Whitelist setzen "
|
||||
"message": "Kanal auf Whitelist setzen "
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Kanal von Whitelist entfernen"
|
||||
"message": "Kanal von Whitelist entfernen"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Stimme für Zeiten ab"
|
||||
"message": "Stimme für Zeiten ab"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Lege das Zeitfenster eines gesponsorten Inhalts fest"
|
||||
"message": "Lege das Zeitfenster eines gesponsorten Inhalts fest"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Gemeldet wurden von dir bisher"
|
||||
"message": "Gemeldet wurden von dir bisher"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Du hast andere Benutzer bewahrt vor"
|
||||
"message": "Du hast andere Benutzer bewahrt vor"
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Siehe Rangliste"
|
||||
"message": "Siehe Rangliste"
|
||||
},
|
||||
"here": {
|
||||
"message": "hier"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klicke den Knopf unten, wenn der gesponsorte Inhalt beginnt und endet, um aufzunehmen und\n einzusenden"
|
||||
"message": "Klicke den Knopf unten, wenn der gesponsorte Inhalt beginnt und endet, um aufzunehmen und\n einzusenden"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Hinweis: In den Optionen lässt sich eine Taste für das Festlegen von Anfang/Ende des gesponsorten Inhalts, sowie für das Einsenden festlegen"
|
||||
"message": "Hinweis: In den Optionen lässt sich eine Taste für das Festlegen von Anfang/Ende des gesponsorten Inhalts, sowie für das Einsenden festlegen"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Letzte ausgewählte Zeitabschnitte"
|
||||
"message": "Letzte ausgewählte Zeitabschnitte"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Zeiten löschen"
|
||||
@@ -291,6 +287,12 @@
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto-Überspringen überspringt gesponsorte Inhalte für dich. Wenn deaktiviert, fragt die Benachrichtigung, ob übersprungen werden soll."
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Audio-Benachrichtigung beim Überspringen"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Audio-Benachrichtigung beim Überspringen wird einen Ton abspielen, wenn ein Sponsor übersprungen wird. Wenn deaktiviert (oder wenn Automatisches-Überspringen deaktiviert ist), wird kein Ton abgespielt."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Du übersprangst "
|
||||
},
|
||||
@@ -314,5 +316,201 @@
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " ihrer Zeit."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Stellen Sie sicher, dass Ihr Segment nur kostenpflichtige Werbeaktionen enthält, nichts anderes.\n- Stellen Sie sicher, dass das Überspringen dieses Segments wertvolle Inhalte nicht abschneiden wird\n- Wenn das ganze Video ein Sponsor ist, bitte nicht melden. Ein vollständiges Video-Reporting-System wird bald herauskommen.\n- Bitte melde keine Haftungsausschlüsse, die Voreingenommenheit zeigen könnten (falls ein Bewertungsvideo gesponsert wird, überspringen Sie nicht, wenn sie dies erwähnen)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Überprüfen Sie status.sponsor.ajay.app für den Serverstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Benutzer ID importieren/exportieren"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Dies sollte privat gehalten werden. Dies ist wie ein Passwort und sollte nicht mit jemandem geteilt werden."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Benutzer ID festlegen"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Warnung: Das Ändern der Benutzer ID ist permanent. Sind Sie sicher, dass Sie dies tun möchten? Stellen Sie sicher, dass Sie von Ihren alten Benutzer ID eine Sicherheitskopie machen, nur für den Fall."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Erstellt von"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Automatisch überspringen"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Zeige Hinweis nach dem Übersprung eines Sponsors"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Es ist derzeit gesetzt auf:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Unterstütze Invidious"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Invidious Support aktivieren, Autoskip deaktivieren, Tasten ausblenden und vieles mehr."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Invidious-Instanzen hinzufügen"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Fügen Sie eine benutzerdefinierte Instanz von Invidious hinzu. Dies muss mit NUR der Domain formatiert werden. Beispiel: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Hinzufügen"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Dies ist eine ungültige Domain. Dies sollte NUR den Domain-Teil beinhalten. Beispiel: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Invidious Instanzliste zurücksetzen"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Du bist dabei, die Liste der \"Invidious\" Instanzen zurückzusetzen"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Aktuelle Instanzen:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Automatisches Liken"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Wenn dies aktiviert ist, wird die Erweiterung alle Beiträge hochladen, die Sie ansehen, wenn Sie sie nicht melden. Wenn die Benachrichtigung deaktiviert ist, wird dies nicht geschehen."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimale Dauer (Sekunden):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Sponsor Segmente, die kürzer als der festgelegte Wert sind, werden nicht übersprungen oder im Player angezeigt."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Die folgende Einreichung ist kürzer als Ihre Mindestdauer. Dies könnte bedeuten, dass dies bereits eingereicht wurde und aufgrund dieser Option einfach ignoriert wird. Sind Sie sicher, dass Sie einreichen möchten?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Upload-Button anzeigen"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Diese Schaltfläche erscheint auf dem YouTube-Player, nachdem Sie einen Zeitstempel ausgewählt haben und bereit sind zu senden."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlock Server-Adresse"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Die Ardesse die SponsorBlock verwendet um Anfragen an den Server zu senden. Solange sie keine eigene Serverinstanz haben sollte das nicht geändert werden."
|
||||
},
|
||||
"save": {
|
||||
"message": "Speichern"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Zurücksetzen"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Diese Adresse ist nicht in der richtigen Form. Stellen Sie sicher, dass Sie http:// oder https:// am Anfang haben und keine abschließenden Schrägstriche haben."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Sind sie sicher dass sie das zurücksetzen wollen?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Das Video wurde als ungelistet erkannt. Klicken Sie auf Abbrechen, wenn Sie nicht nach Sponsoren suchen möchten."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Nicht gelistete Videos ignorieren"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Diese Einstellung verlangsamt den Sponsor-Block erheblich. Sponsor-Suchvorgänge erfordern das Senden der Video-ID an den Server. Wenn Sie sich Sorgen darüber machen, dass nicht gelistete Video-IDs über das Internet gesendet werden, aktivieren Sie diese Option."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com wird jetzt unterstützt"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Import/Export aller Optionen"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Dies ist Ihre gesamte Konfiguration in JSON. Dies schließt Ihre Benutzer-ID ein, also sollten Sie diese klug teilen."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Optionen einstellen"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Warnung: Das Ändern der Benutzer ID ist permanent. Sind Sie sicher, dass Sie dies tun möchten? Stellen Sie sicher, dass Sie von Ihren alten Benutzer ID eine Sicherheitskopie machen, nur für den Fall."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "Dieses JSON ist nicht korrekt formatiert. Ihre Einstellungen wurden nicht geändert."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Segment absenden"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Senden"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Abbrechen"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Löschen"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Vorschau"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Bearbeiten"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Debug-Informationen in Zwischenablage kopieren"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Fehler beim Schreiben in die Zwischenablage"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Kopiert Informationen in die Zwischenablage einem Entwickler zur Verfügung gestellt werden, wenn ein Bug / wenn ein Entwickler es anfordert. Sensitive Informationen wie Ihre Benutzer-ID, Kanäle auf der Whitelist-Liste und benutzerdefinierte Server-Adresse wurden entfernt. Es enthält jedoch Informationen wie den Useragent, den Browser, das Betriebssystem und die Versionsnummer der Erweiterung. "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "Die Debug-Informationen wurden in das Clip-Board kopiert. Sie können alle Informationen entfernen, die Sie nicht teilen möchten. Speichern Sie diese in einer Textdatei oder fügen Sie sie in den Fehlerbericht ein."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "Die Taste"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "wird bereits von Youtube verwendet. Bitte wählen Sie eine andere Taste."
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "an eine andere Aktion gebunden. Bitte wählen Sie eine andere Taste."
|
||||
},
|
||||
"to": {
|
||||
"message": "bis",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Eigenwerbung und Merchandise"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Deaktivieren"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Manueller Überspringen"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Vor-/Rücklaufleiste anzeigen"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Beta Testing Server aktivieren"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Deine Einreichungen und Stimmen werden NICHT für den Hauptserver geltend. Benutze dies nur für Tests."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Alle Einreichungen und Stimmen werden NICHT ZÄHLEN gegenüber dem Hauptserver während der Verbindung zum Test-Server. Stellen Sie sicher, dass sie dies deaktivieren, wenn Sie echte Einreichungen machen möchten."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(jetzt)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Weitere Kategorien"
|
||||
}
|
||||
}
|
||||
|
||||
1
public/_locales/el/messages.json
Normal file
1
public/_locales/el/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -7,14 +7,10 @@
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Server said this request was invalid"
|
||||
},
|
||||
@@ -193,7 +189,7 @@
|
||||
"message": "Hide Buttons On YouTube Player"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "This hides the buttons that appear on the YouTube player to submit sponsors. I can see this being annoying for some\n people. Instead of using the button there, this popup can be used to submit sponsors. To hide the notice that appears, \n use the button that appears on the notice saying \"Don't show this again\". You can always enable these settings again later."
|
||||
"message": "This hides the buttons that appear on the YouTube player to submit skip segments."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Show Info Button On YouTube Player"
|
||||
@@ -211,7 +207,7 @@
|
||||
"message": "Show Delete Button On YouTube Player"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "This is the button that allows you to clear all sponsors on the YouTube player."
|
||||
"message": "This is the button on the YouTube player that will clear all your un-submitted segments for the current video."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Disable Sponsor Skip Count Tracking"
|
||||
@@ -291,6 +287,12 @@
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto skip will skip sponsors for you. If disabled, a notice will appear asking if you'd like to skip."
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Audio Notification On Skip"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Audio notification on skip will play a sound whenever a sponsor is skipped. If disabled (or auto skip is disabled), no sound will be played."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "You have skipped "
|
||||
},
|
||||
@@ -349,7 +351,7 @@
|
||||
"message": "Support Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) is a third party YouTube client. To enable support, you must accept the extra permissions. This does NOT work in incongnito on Chrome and other Chromium variants."
|
||||
"message": "Invidious (invidio.us) is a third party YouTube client. To enable support, you must accept the extra permissions. This does NOT work in incognito on Chrome and other Chromium variants."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Enable Invidious support, disable autoskip, hide buttons and more."
|
||||
@@ -418,12 +420,151 @@
|
||||
"message": "The video has been detected as unlisted. Click cancel if you do not want to check for sponsors."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignore Unlisted Videos"
|
||||
"message": "Ignore Unlisted/Private Videos"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "This setting will significantly slow down SponsorBlock. Sponsor lookups require sending the video ID to the server. If you are concerned about unlisted video IDs being sent over the internet, enable this option."
|
||||
"message": "This setting will slightly slow down SponsorBlock. Sponsor lookups require sending the video ID to the server. If you are concerned about unlisted video IDs being sent over the internet, enable this option."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com is now supported"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Import/Export All Options"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "This is your entire configuration in JSON. This includes your userID, so be sure to share this wisely."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Set Options"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Warning: Changing the options is permanent and can break your install. Are you sure you would like to do this? Make sure to backup your old one just in case."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "This JSON is not formatted correctly. Your options have not been changed."
|
||||
},
|
||||
"confirmNoticeTitle" : {
|
||||
"message": "Submit Segment"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Submit"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Cancel"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Delete"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Preview"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Edit"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Copy Debug Information To Clipboard"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Failed to write to clipboard"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Copies information to the clipboard to be provided to a developer when raising a bug / when a developer requests it. Sensitive information such as your user ID, whitelisted channels, and custom server address have been removed. However it does contain information such as your useragent, browser, operating system, and extension version number. "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "The debug information has been copied to the clip board. Feel free to remove any information you would rather not share. Save this in a text file or paste into the bug report."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "The key"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "is already used by youtube. Please select another key."
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "is bound to another action. Please select another key."
|
||||
},
|
||||
"to": {
|
||||
"message": "to",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Intro Animation"
|
||||
},
|
||||
"category_outro": {
|
||||
"message": "Endcards/Credits"
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Interaction Reminder (Subscribe)"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Self-Promotion and Merchandise"
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Music: Non-Music Section"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Livestream: Donation/Message Readings"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Disable"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Manual Skip"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Show In Seek Bar"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Enable Beta Testing Server"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Your submissions and votes WILL NOT COUNT towards the main server. Only use this for testing."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "All submissions and votes WILL NOT COUNT towards the main server while connecting to the test server. Make sure to disable this when you want to make real submissions."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Now)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "More Categories"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(End)"
|
||||
},
|
||||
"hiddenDueToDownvote": {
|
||||
"message": "hidden: downvote"
|
||||
},
|
||||
"hiddenDueToDuration": {
|
||||
"message": "hidden: too short"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "Channel ID not loaded yet."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "It seems that something is blocking SponsorBlock's ability to get video data. This is probably your ad blocker. Please check https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "If this keeps occuring, it could be caused by your ad blocker. Please check https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "Force Channel Check Before Skipping Sponsors"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "By default, it will skip sponsors right away before it even knows what the channel is. By default, some zero second sponsors might be skipped on whitelisted channels. Enabling this option will prevent this but making all skipping have a slight delay as getting the channelID can take some time. This delay might be unnoticeable if you have fast internet."
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Consider Enabling Force Channel Check Before Skipping Sponsors"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Incorrect"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "Wrong Category"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "This video is categorized as music. Are you sure you would like to submit segments with non-music categories? Unless this video is not actually music, you should not be submitting this segment. Please read the guidelines if you are confused."
|
||||
}
|
||||
}
|
||||
|
||||
1
public/_locales/es/messages.json
Normal file
1
public/_locales/es/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/et/messages.json
Normal file
1
public/_locales/et/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/fa/messages.json
Normal file
1
public/_locales/fa/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/fi/messages.json
Normal file
1
public/_locales/fi/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/fil/messages.json
Normal file
1
public/_locales/fil/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -7,14 +7,10 @@
|
||||
"message": "SponsorBlock pour YouTube - Supprime les messages commerciaux et publicités intégrées",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Passe automatiquement les messages commerciaux intégrés dans les vidéos YouTube. Soumettez les segments commerciaux dans les vidéos que vous regardez pour aidez les autres.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Soumission invalide"
|
||||
},
|
||||
@@ -25,7 +21,7 @@
|
||||
"message": "Déja soumis"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Cette chaîne est sur la liste blanche !"
|
||||
"message": "Chaîne mise sur liste blanche !"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "message commercial"
|
||||
@@ -43,16 +39,16 @@
|
||||
"message": "Message commercial passé"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Incorrect"
|
||||
"message": "Signaler"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Signaler que ce segment commercial est incorrect ou n'existe pas."
|
||||
"message": "Signaler que ce segment commercial est incorrect."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Fermer"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Chargement en cours..."
|
||||
"message": "Chargement..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
@@ -64,7 +60,7 @@
|
||||
"message": "Ne plus montrer"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Cliquez sur revenir en arrière pour revenir avant le saut du segment commercial"
|
||||
"message": "Cliquez sur revenir en arrière pour revenir avant le saut du segment commercial."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Revenir en arrière"
|
||||
@@ -76,7 +72,7 @@
|
||||
"message": "En pause"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nPour modifier ou supprimer des soumissions, cliquez sur le bouton d'info ou ouvrez la fenêtre de l'extension en cliquant sur son icône dans le coin en haut à droite."
|
||||
"message": "Pour modifier ou supprimer des soumissions, cliquez sur le bouton d'info ou ouvrez la fenêtre de l'extension en cliquant sur son icône dans le coin en haut à droite."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Êtes-vous certain(e) de vouloir supprimer vos soumissions ?\n\n"
|
||||
@@ -85,10 +81,10 @@
|
||||
"message": "Une erreur s'est produite lors de la soumission, veuillez ré-essayer plus tard."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Les messages commerciaux sont déjà dans notre base de donnée pour cette vidéo !"
|
||||
"message": "Les messages commerciaux pour cette vidéo sont déjà dans notre base de donnée !"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Pas de messages commerciaux trouvés"
|
||||
"message": "Pas de sponsors trouvés"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Début du message commercial"
|
||||
@@ -138,9 +134,6 @@
|
||||
"removeFromWhitelist": {
|
||||
"message": "Supprimer la chaîne de la liste blanche"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Ajouter à la liste blanche les chaînes qui publient des messages commerciaux de façon éthique pour encourager les bons comportements, ou qui publient des messages commerciaux divertissants ou drôles. Ou pas, c'est votre choix."
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Voter sur un segment commercial"
|
||||
},
|
||||
@@ -187,7 +180,7 @@
|
||||
"message": "Cacher"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Options"
|
||||
"message": "Paramètres"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Montrer les boutons sur le lecteur YouTube"
|
||||
@@ -245,7 +238,7 @@
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Si elle ne vous plaît pas, cliquez sur le bouton \"Ne plus montrer\"",
|
||||
"message": "Si elle ne vous plaît pas, cliquez sur le bouton \"Ne plus montrer\".",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
@@ -259,5 +252,199 @@
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Le raccourci choisi est : "
|
||||
},
|
||||
"0": {
|
||||
"message": "Délai de connexion dépassé. Vérifiez votre connexion internet. Si votre connexion internet fonctionne, le serveur est probablement surchargé ou hors service."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Désactiver SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Activer SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Votre travail",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Le serveur semble être surchargé. Réessayez dans quelques secondes."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Code d'erreur : "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Passer le sponsor ?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Passer"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Désactiver le passage automatique"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Activer le passage automatique"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Le passage automatique passera automatiquement les sponsors pour vous. Si désactivé, un avis apparaîtra vous demandant si vous souhaitez passer."
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Notification audio lors du passage"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "La notification audio lors du passage jouera un son à chaque fois qu'un sponsor est ignoré. Si désactivé (ou si le passage automatique est désactivé), aucun son ne sera joué."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Vous avez passé "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Vous avez économisé "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minute"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minutes"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "heure"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "heures"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Vous avez économisé"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " aux autres."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Assurez-vous que votre segment ne contient que des segments de promotion payante, rien d'autre.\n- Assurez-vous que passer ce segment ne sautera pas de contenu important\n- Si la vidéo entière est un sponsor, s'il vous plaît, ne le signalez pas. Un système complet de reportage vidéo sortira bientôt.\n- Veuillez ne pas signaler les avertissements qui pourraient montrer des biais (si une vidéo de revue est sponsorisée, ne sautez pas quand ils le mentionnent)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Vérifiez status.sponsor.ajay.app pour le status du serveur."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importer/Exporter votre ID d'utilisateur"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Gardez ça privé. C'est comme un mot de passe et ne devrait pas être partagé avec quiconque. Si quelqu'un l'obtiens, il peut vous usurper."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Définir \"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"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Passage automatique"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Afficher l'avis après le passage d'un sponsor"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Il est actuellement réglé sur :"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Soutenir Invidious"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Activer Invidious, désactiver le passage automatique, masquer les boutons et plus encore."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Ajouter une instance Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Ajouter une instance Invidious personnalisée. Doit être formaté avec SEULEMENT le domaine. Exemple: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Ajouter"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Ce domaine n'est pas valide. Il devrait JUSTE inclure le domaine. Exemple: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Réinitialiser la liste d'instances Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Vous êtes sur le point de réinitialiser la liste des instances Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Instances actuelles:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Vote automatique"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Si cette option est activée, l'extension votera en faveur de tous les segments que vous visualiserez si vous ne les signalez pas. Si l'avis est désactivé, cela ne se produira pas."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Durée minimale (en secondes):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Les segments sponsorisés plus courts que la valeur définie ne seront pas passé ni affichés dans le lecteur."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Le segment suivant est plus court que votre option de durée minimale. Cela pourrait signifier qu'il est déjà soumis, et just ignoré par cette option. Êtes-vous sûr de vouloir soumettre ?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Afficher le bouton de téléchargement"
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "Adresse du serveur SponsorBlock"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "L'adresse que SponsorBlock utilise pour passer des appels vers le serveur.\nSauf si vous avez votre propre instance de serveur, cela ne devrait pas être changé."
|
||||
},
|
||||
"save": {
|
||||
"message": "Sauvegarder"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Réinitialiser"
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignorer les vidéos non listées"
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com est maintenant pris en charge"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Importer/Exporter toutes les options"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Soumettre"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Annuler"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Supprimer"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Éditer"
|
||||
},
|
||||
"theKey": {
|
||||
"message": "La clé"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "est déjà utilisé par youtube. Veuillez sélectionner une autre clé."
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "est lié à une autre action. Veuillez sélectionner une autre clé."
|
||||
},
|
||||
"to": {
|
||||
"message": "à",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Activer le serveur de test bêta"
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Maintenant)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Autres catégories"
|
||||
}
|
||||
}
|
||||
|
||||
1
public/_locales/gu/messages.json
Normal file
1
public/_locales/gu/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/he/messages.json
Normal file
1
public/_locales/he/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/hi/messages.json
Normal file
1
public/_locales/hi/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/hr/messages.json
Normal file
1
public/_locales/hr/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
29
public/_locales/hu/messages.json
Normal file
29
public/_locales/hu/messages.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"Loading": {
|
||||
"message": "Betöltés..."
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Sose mutassa"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Szüneteltetve"
|
||||
},
|
||||
"save": {
|
||||
"message": "Mentés"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Visszaállítás"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Mégse"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Törlés"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Előnézet"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Szerkesztés"
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,12 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock per YouTube - Salta gli sponsor",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Salta i contenuti sponsorizzati nei video di YouTube. Segnala gli annunci incorporati nei video che guardi per far risparmiare tempo agli altri.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Richiesta non valida"
|
||||
},
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "sponsorizzazioni"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "spezzone sponsorizzato"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -84,7 +76,6 @@
|
||||
"Unknown": {
|
||||
"message": "Si è verificato un errore durante l'invio dello spezzone sponsorizzato, per favore riprova più tardi."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "I contenuti sponsorizzati di questo video sono nel database!"
|
||||
},
|
||||
@@ -134,40 +125,37 @@
|
||||
"message": "Sei sicuro di volerlo inviare?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Aggiungi Canale alla Whitelist"
|
||||
"message": "Aggiungi Canale alla Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Rimuovi Canale dalla Whitelist"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Aggiungi alla whitelist i canali che sponsorizzano eticamente per incoraggiare ad un comportamento corretto, oppure se sono semplicemente intrattenenti e divertenti. Oppure non farlo, decidi tu."
|
||||
"message": "Rimuovi Canale dalla Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vota uno Spezzone Sponsorizzato"
|
||||
"message": "Vota uno Spezzone Sponsorizzato"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registra uno Spezzone Sponsorizzato"
|
||||
"message": "Registra uno Spezzone Sponsorizzato"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Fino ad ora hai inviato"
|
||||
"message": "Fino ad ora hai inviato"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Hai salvato le persone da "
|
||||
"message": "Hai salvato le persone da "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Guarda la classifica"
|
||||
"message": "Guarda la classifica"
|
||||
},
|
||||
"here": {
|
||||
"message": "qui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Premi il pulsante qui sotto quando inizia e finisce la sponsorizzazione per registrarla e\ninviarla al database."
|
||||
"message": "Premi il pulsante qui sotto quando inizia e finisce la sponsorizzazione per registrarla e\ninviarla al database."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Suggerimento: Premi il tasto punto e virgola mentre il video è attivo per segnalare l'inizio/fine di una sponsorizzazione e virgolette per inviare."
|
||||
"message": "Suggerimento: Premi il tasto punto e virgola mentre il video è attivo per segnalare l'inizio/fine di una sponsorizzazione e virgolette per inviare."
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ultimi minutaggi sponsorizzati scelti"
|
||||
"message": "Ultimi minutaggi sponsorizzati scelti"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Cancella Minutaggi"
|
||||
@@ -197,7 +185,7 @@
|
||||
"message": "Nascondi i Pulsanti nel Lettore di YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Nasconde i pulsanti che appaiono nel lettore di YouTube per inviare spezzoni sponsorizzati. Capisco che può essere fastidioso per alcune\n persone. Invece di utilizzare quei pulsanti, è possibile utilizzare questo popup per inviare gli spezzoni sponsorizzati. Per nascondere l'avviso che appare, \nusa il bottone \"Non mostrare più\" nell'avviso. Potrai sempre abilitare nuovamente queste impostazioni in futuro."
|
||||
"message": "Nasconde i pulsanti che appaiono nel lettore di YouTube per inviare spezzoni sponsorizzati. Capisco che può essere fastidioso per alcune\n persone. Invece di utilizzare quei pulsanti, è possibile utilizzare questo popup per inviare gli spezzoni sponsorizzati. Per nascondere l'avviso che appare, \nusa il bottone \"Non mostrare più\" nell'avviso. Potrai sempre abilitare nuovamente queste impostazioni in futuro."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Mostra il Pulsante Informazioni nel Lettore di YouTube"
|
||||
|
||||
1
public/_locales/ja/messages.json
Normal file
1
public/_locales/ja/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/kn/messages.json
Normal file
1
public/_locales/kn/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/ko/messages.json
Normal file
1
public/_locales/ko/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/lt/messages.json
Normal file
1
public/_locales/lt/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/lv/messages.json
Normal file
1
public/_locales/lv/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/ml/messages.json
Normal file
1
public/_locales/ml/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/mr/messages.json
Normal file
1
public/_locales/mr/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/ms/messages.json
Normal file
1
public/_locales/ms/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
47
public/_locales/nl/messages.json
Normal file
47
public/_locales/nl/messages.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"paused": {
|
||||
"message": "Gepauzeerd"
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Weet je zeker dat je dit formulier wilt wissen?\n\n"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Geen sponsors gevonden"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Sponsorschap"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Sponshopschap eindigt nu"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Er is geen YouTube-video gevonden op dit tabblad. Als je weet dat dit een YouTube-tabblad is, sluit je deze pop-up en open het opnieuw. Als dat niet werkt, probeer het tabblad opnieuw te laden."
|
||||
},
|
||||
"success": {
|
||||
"message": "Succesvol!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Gestemd!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "U hebt al eerder op deze manier gestemd."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Het lijkt erop dat de server niet draait. Contacteer de ontwikkelaar onmiddellijk."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Er is een verbindingsfout opgetreden. Foutcode: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Wilt u de sponsor tijden indienen voor video id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Het lijkt erop dat sommige sponsortijden niet ingezonden zijn. Ga terug naar die pagina om ze in te dienen (deze zijn niet verwijderd)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Sponsortijden wissen"
|
||||
},
|
||||
"here": {
|
||||
"message": "hier"
|
||||
}
|
||||
}
|
||||
1
public/_locales/no/messages.json
Normal file
1
public/_locales/no/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -1,390 +1,370 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nazwa rozszerzenia."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
||||
"description": "Nazwa rozszerzenia."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
||||
"description": "Opis rozszerzenia."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||
},
|
||||
"429": {
|
||||
"message": "Zgłosiłeś bardzo dużo segmentów reklamowych dla tego jednego nagrania, jesteś pewien, że jest ich tak dużo?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Treść została już wcześniej zgłoszona"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanał dodany do wyjątków!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorzy"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmet sponsorowany"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty sponsorowane"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Segment przewinięty"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Zgłoś"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Zgłoś ten segment reklamowy jako nieprawidłowy."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Odrzuć"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Ładowanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nigdy nie pokazuj"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Kliknij cofnij aby przenieść się do miejsca przed przewinięciem."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Cofnij"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Zatrzymany"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Żeby zmienić lub usunąć wartości, kliknij na guzik informacji lub otwórz okienko rozszerzenia klikając w ikonę rozszerzenia znajdującą się w prawym górnym rogu."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Jesteś pewien, że chcesz to usunąć?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Wystąpił błąd podczas przesyłania twojego zgłoszenia, proszę spróbować ponownie później."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Segmenty reklamowe dla tego nagrania są już w bazie!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nie znaleziono segmentów reklamowych"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Reklama zaczyna się teraz"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Reklama kończy się teraz"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono nagrania wideo w tej karcie. Jeśli wiesz, że to karta YouTube'a, zamknij to okienko i otwórz je ponownie. Jeśli to nie zadziała spróbuj przeładować stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Zagłosowano!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Już na to głosowałeś."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Wygląda na to, że serwer nie działa. Skontaktuj się z dewloperem."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Chcesz zgłosić segment sponsorowany dla nagrania z id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że masz nie wysłane segmenty reklamowe. Cofnij się do tej strony i zgłoś je (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty reklamowe"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Otwórz okienko SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Zgłoś segmenty reklamowe"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Jesteś pewien, że chcesz to zgłosić?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanał do wyjątków"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Usuń kanał z listy wyjątków"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Głosuj na segment reklamowy"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Nagraj czasy segmentów reklamowych"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Jak na razie zgłosiłeś:"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij guzik poniżej kiedy segment reklamowy się zaczyna i kończy żeby go oznaczyć i wysłać do bazy danych."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Klikając średnik kiedy zaznaczone jest zgłaszanie wideo możesz oznaczyć początek reklamy, znakiem cytatu oznaczysz jej koniec. (Klawisze można zmienić w opcjach)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ostanie wybrane czasy reklam"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Usuń czasy"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Zgłoś czasy"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ustaw nazwę użytkownika"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Dołącz do oficjalnego serwera na discordzie i podziel się wrażeniami i sugestiami!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Ukryj to"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opcje"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Pokaż guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Ukryj guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ta opcja ukrywa guziki zgłaszania reklamy w odtwarzaczu. Wiem, że mogą one irytować niektórych. Zamiast zgłaszania bezpośrednio w odtwarzaczu możesz to zrobić w tym okienku. Zawsze możesz zmienić te opcje później."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Pokaż guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Ukryj guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Jest to guzik otwierający popup na stronie YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Ukryj guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Pokaż guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ten guzik pozwala ci wyczyścić wszystkie segmenty reklamowe w odtwarzaczu YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Wyłącz licznik przewinięć"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Włącz licznik przewinięć"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ta opcja śledzi które segmenty pominąłeś i informuje zgłaszających ile czasu Ci zaoszczędzili, też wraz systemem głosowania pomaga wykrywać spam w zgłoszeniach. Rozszerzenie wysyła zapytanie do serwera za każdym razem kiedy przewinąłeś segment reklamowy. Miejmy nadzieję, że większość ludzi tego nie wyłączy i licznik wyświetleń będzie rzetelny. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock jest rozszerzeniem które przewinie segmenty sponsorów w filmach na YouTube. SponsorBlock jest opartym na crowdsourcing rozszerzeniem które pozwala każdemu zgłaszać początek i koniec segmentu reklamowego w filmach na YouTube. Kiedy ktoś zgłosi taki fragment zostanie on pominięty przez innych użytkowników rozszerzenia.",
|
||||
"description": "Pełny opis rozszerzenia na stronie w sklepie."
|
||||
},
|
||||
"website": {
|
||||
"message": "Strona",
|
||||
"description": "Używane w sklepie Firefoxa"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Kod źródłowy",
|
||||
"description": "Używane w sklepie Firefoxa"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Informacje zostały zaktualizowane!",
|
||||
"description": "Pierwsza linia po aktualizacji informacji."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
||||
"description": "Druga linia po aktualizacji informacji."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Ustaw klawisz do wysyłania czasów"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Wybierz klawisz klikając go na klawiaturze"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Ustawiony klawisz to: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Połączenie przerwane z powodu braku odpowiedzi. Sprawdź swoje połączenie z internetem. Jeśli wszystko z nim w porządku oznacza to, że serwer jest prawdopodobnie przeciążony lub nie działa."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Wyłącz SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Włącz SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Twój wkład",
|
||||
"description": "Nagłowek sekcji ze statystykami użytkownika."
|
||||
},
|
||||
"502": {
|
||||
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Kod błędu: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Przewinąć reklamę?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Wyłącz auto przewijanie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Włącz auto przewijanie"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto przewijanie przewinie segment za ciebie, wyłączone wyświetli komunikat z pytaniem czy chcesz przewinąć reklamę."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Przewinąłeś "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Oszczędziłeś sobie "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuta"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minuty"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "godzina"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "godziny"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Oszczędziłeś ludziom"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " czasu."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Upewnij się, że zgłaszany fragment zawiera tylko reklamę i nic więcej.\n- Upewnij się, że nie zostanie przewinięta wartościowa treść\n- Jeśli całe nagranie to reklama, proszę nie zgłaszaj go. Blokowanie całych nagrań pojawi się wkrótce.\n- Nie ukrywaj treści które są istotne dla użytkownika (nie ukrywaj informacji, że recenzja produktu została opłacona przez producenta)"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Wejdź na status.sponsor.ajay.app żeby sprawdzić czy serwer działa."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Zaimportuj/Wyeksportuj swój UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ta informacja jest poufna i działa jak hasło, użytkownik który ma do niej dostęp może zgłaszać treści jako ty."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ustaw UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Ostrzeżenie: Zmiana UserID jest nieodwracalna. Jesteś pewien, że chcesz to zrobić? Skopiuj obecny UserID na wszelki wypadek."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto przewijanie"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Pokaż informację po przewiniętym fragmencie"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jest obecnie ustawione jako:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Wesprzyj Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) to nieoficjalny klient YouTube. Aby go wesprzeć musisz przyznać dodatkowe uprawnienia rozszerzeniowi. Ta opcja nie działa w incognito i innych wersjach Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Wesprzyj Invidious, wyłącz auto przewijanie, ukryj guziki i więcej."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Dodaj instancje Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Dodaj niestandardową instancje Invidious. W formie domeny. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Dodaj"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Ta domena jest nieprawidłowa. Wartość powinna zawierać TYLKO domenę. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Zresetuj listę instancji Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Zresetujesz listę instancji Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Obecne instancje:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto potwierdzanie"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "To ustawienie sprawia, że wszystkie przewinięte przez ciebie a nie zgłoszone jako błąd segmenty reklamowe zostaną potwierdzone jako prawidłowe. Ta opcja nie działa jeśli okienko z informacją o przewinięciu jest ukryte."
|
||||
},
|
||||
"invidiousInfo1": {
|
||||
"message": "Invidious (nieoficjalny klient YouTube) została dodana do wspieranych!"
|
||||
},
|
||||
"invidiousInfo2": {
|
||||
"message": "Musisz odblokować to w opcjach aby móc to zrobić."
|
||||
}
|
||||
"fullName": {
|
||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||
},
|
||||
"429": {
|
||||
"message": "Zgłosiłeś bardzo dużo segmentów reklamowych dla tego jednego nagrania, jesteś pewien, że jest ich tak dużo?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Treść została już wcześniej zgłoszona"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanał dodany do wyjątków!"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorzy"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmet sponsorowany"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty sponsorowane"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Segment przewinięty"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Zgłoś"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Zgłoś ten segment reklamowy jako nieprawidłowy."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Odrzuć"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Ładowanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nigdy nie pokazuj"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Kliknij cofnij aby przenieść się do miejsca przed przewinięciem."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Cofnij"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Zatrzymany"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Żeby zmienić lub usunąć wartości, kliknij na guzik informacji lub otwórz okienko rozszerzenia klikając w ikonę rozszerzenia znajdującą się w prawym górnym rogu."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Jesteś pewien, że chcesz to usunąć?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Wystąpił błąd podczas przesyłania twojego zgłoszenia, proszę spróbować ponownie później."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Segmenty reklamowe dla tego nagrania są już w bazie!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nie znaleziono segmentów reklamowych"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Reklama zaczyna się teraz"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Reklama kończy się teraz"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono nagrania wideo w tej karcie. Jeśli wiesz, że to karta YouTube'a, zamknij to okienko i otwórz je ponownie. Jeśli to nie zadziała spróbuj przeładować stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Zagłosowano!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Już na to głosowałeś."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Wygląda na to, że serwer nie działa. Skontaktuj się z dewloperem."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Chcesz zgłosić segment sponsorowany dla nagrania z id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że masz nie wysłane segmenty reklamowe. Cofnij się do tej strony i zgłoś je (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty reklamowe"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Otwórz okienko SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Zgłoś segmenty reklamowe"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Jesteś pewien, że chcesz to zgłosić?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanał do wyjątków"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Usuń kanał z listy wyjątków"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Głosuj na segment reklamowy"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Nagraj czasy segmentów reklamowych"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Jak na razie zgłosiłeś:"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij guzik poniżej kiedy segment reklamowy się zaczyna i kończy żeby go oznaczyć i wysłać do bazy danych."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Klikając średnik kiedy zaznaczone jest zgłaszanie wideo możesz oznaczyć początek reklamy, znakiem cytatu oznaczysz jej koniec. (Klawisze można zmienić w opcjach)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ostanie wybrane czasy reklam"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Usuń czasy"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Zgłoś czasy"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ustaw nazwę użytkownika"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Dołącz do oficjalnego serwera na discordzie i podziel się wrażeniami i sugestiami!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Ukryj to"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opcje"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Pokaż guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Ukryj guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ta opcja ukrywa guziki zgłaszania reklamy w odtwarzaczu. Wiem, że mogą one irytować niektórych. Zamiast zgłaszania bezpośrednio w odtwarzaczu możesz to zrobić w tym okienku. Zawsze możesz zmienić te opcje później."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Pokaż guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Ukryj guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Jest to guzik otwierający popup na stronie YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Ukryj guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Pokaż guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ten guzik pozwala ci wyczyścić wszystkie segmenty reklamowe w odtwarzaczu YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Wyłącz licznik przewinięć"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Włącz licznik przewinięć"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ta opcja śledzi które segmenty pominąłeś i informuje zgłaszających ile czasu Ci zaoszczędzili, też wraz systemem głosowania pomaga wykrywać spam w zgłoszeniach. Rozszerzenie wysyła zapytanie do serwera za każdym razem kiedy przewinąłeś segment reklamowy. Miejmy nadzieję, że większość ludzi tego nie wyłączy i licznik wyświetleń będzie rzetelny. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock jest rozszerzeniem które przewinie segmenty sponsorów w filmach na YouTube. SponsorBlock jest opartym na crowdsourcing rozszerzeniem które pozwala każdemu zgłaszać początek i koniec segmentu reklamowego w filmach na YouTube. Kiedy ktoś zgłosi taki fragment zostanie on pominięty przez innych użytkowników rozszerzenia.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Strona",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Kod źródłowy",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Informacje zostały zaktualizowane!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Ustaw klawisz do wysyłania czasów"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Wybierz klawisz klikając go na klawiaturze"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Ustawiony klawisz to: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Połączenie przerwane z powodu braku odpowiedzi. Sprawdź swoje połączenie z internetem. Jeśli wszystko z nim w porządku oznacza to, że serwer jest prawdopodobnie przeciążony lub nie działa."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Wyłącz SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Włącz SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Twój wkład",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Kod błędu: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Przewinąć reklamę?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Wyłącz auto przewijanie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Włącz auto przewijanie"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto przewijanie przewinie segment za ciebie, wyłączone wyświetli komunikat z pytaniem czy chcesz przewinąć reklamę."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Przewinąłeś "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Oszczędziłeś sobie "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuta"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minuty"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "godzina"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "godziny"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Oszczędziłeś ludziom"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " czasu."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Upewnij się, że zgłaszany fragment zawiera tylko reklamę i nic więcej.\n- Upewnij się, że nie zostanie przewinięta wartościowa treść\n- Jeśli całe nagranie to reklama, proszę nie zgłaszaj go. Blokowanie całych nagrań pojawi się wkrótce.\n- Nie ukrywaj treści które są istotne dla użytkownika (nie ukrywaj informacji, że recenzja produktu została opłacona przez producenta)"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Wejdź na status.sponsor.ajay.app żeby sprawdzić czy serwer działa."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Zaimportuj/Wyeksportuj swój UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ta informacja jest poufna i działa jak hasło, użytkownik który ma do niej dostęp może zgłaszać treści jako ty."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ustaw UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Ostrzeżenie: Zmiana UserID jest nieodwracalna. Jesteś pewien, że chcesz to zrobić? Skopiuj obecny UserID na wszelki wypadek."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto przewijanie"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Pokaż informację po przewiniętym fragmencie"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jest obecnie ustawione jako:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Wesprzyj Invidious"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Wesprzyj Invidious, wyłącz auto przewijanie, ukryj guziki i więcej."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Dodaj instancje Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Dodaj niestandardową instancje Invidious. W formie domeny. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Dodaj"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Ta domena jest nieprawidłowa. Wartość powinna zawierać TYLKO domenę. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Zresetuj listę instancji Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Zresetujesz listę instancji Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Obecne instancje:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto potwierdzanie"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "To ustawienie sprawia, że wszystkie przewinięte przez ciebie a nie zgłoszone jako błąd segmenty reklamowe zostaną potwierdzone jako prawidłowe. Ta opcja nie działa jeśli okienko z informacją o przewinięciu jest ukryte."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock para YouTube - Pule patrocínios",
|
||||
"description": "Nome da extensão."
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Pule patrocinadores em vídeos do YouTube. Reporte patrocinadores em videos que você assiste para salvar o tempo dos outros.",
|
||||
"description": "Descrição da extensão."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "O servidor disse que esse pedido foi inválido"
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "patrocinadores"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "segmento de patrocinador"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -84,7 +76,6 @@
|
||||
"Unknown": {
|
||||
"message": "Teve um erro ao enviar seus segmentos, tente novamente depois."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "Os patrocinadores desse vídeo estão no banco de dados!"
|
||||
},
|
||||
@@ -134,40 +125,37 @@
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Colocar na Whitelist canais com patrocínios éticos que encoragem boas atitude, ou simplesmente canais com patrocínios engraçados. Ou não, é consigo."
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
@@ -231,14 +219,14 @@
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Código fonte",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,11 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock para o YouTube - Salte patrocínios",
|
||||
"description": "Nome da extensão."
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Salte patrocinadores em vídeos do YouTube. Reporte patrocinadores em vídeos que assista para poupar tempo a outros.",
|
||||
"description": "Descrição da extensão."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "O servidor disse que este pedido foi inválido"
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "patrocinadores"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "segmento de patrocínio"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -133,40 +125,37 @@
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Colocar na Whitelist canais com patrocínios éticos que encoragem boas atitude, ou simplesmente canais com patrocínios engraçados. Ou não, é consigo."
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
@@ -230,14 +219,14 @@
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Código fonte",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
}
|
||||
}
|
||||
1
public/_locales/ro/messages.json
Normal file
1
public/_locales/ro/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -1,19 +1,11 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Название расширения, не переводится."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock для YouTube - Пропускайте спонсорские вставки",
|
||||
"description": "Название расширения."
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Пропускайте спонсорские вставки в видео на YouTube. Сообщайте о спонсорских вставках в видео, которые Вы смотрите, чтобы сэкономить время других пользователей.",
|
||||
"description": "Описание раширения."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Сервер отклонил этот запрос."
|
||||
@@ -33,7 +25,7 @@
|
||||
"Sponsors": {
|
||||
"message": "спонсоров"
|
||||
},
|
||||
"Segment": {
|
||||
"Segment": {
|
||||
"message": "спонсорская вставка"
|
||||
},
|
||||
"Segments": {
|
||||
@@ -84,7 +76,6 @@
|
||||
"Unknown": {
|
||||
"message": "При отправке отчета о спонсорском сегменте произошла ошибка. Попытайтесь отправить его позже."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "Спонсоры этого видео уже находятся в базе данных!"
|
||||
},
|
||||
@@ -125,37 +116,37 @@
|
||||
"message": "Вы уверены, что хотите отправить эту информацию?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Добавить канал в белый список"
|
||||
"message": "Добавить канал в белый список"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Удалить канал из белого списка"
|
||||
"message": "Удалить канал из белого списка"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Проголосовать за время спонсорской вставки"
|
||||
"message": "Проголосовать за время спонсорской вставки"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Записать время спонсорской вставки"
|
||||
"message": "Записать время спонсорской вставки"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "На данный момент Вы отправили"
|
||||
"message": "На данный момент Вы отправили"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Вы помогли людям сэкономить "
|
||||
"message": "Вы помогли людям сэкономить "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Посмотреть доску почёта"
|
||||
"message": "Посмотреть доску почёта"
|
||||
},
|
||||
"here": {
|
||||
"message": "здесь"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Нажмите кнопку ниже, когда спонсорская вставка начинается и заканчивается, чтобы записать\nи отправить её в базу данных."
|
||||
"message": "Нажмите кнопку ниже, когда спонсорская вставка начинается и заканчивается, чтобы записать\nи отправить её в базу данных."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Подсказка: нажмите ;, чтобы сообщить начало/конец спонсорской вставки, и \", чтобы отправить. (Это можно изменить в настройках)"
|
||||
"message": "Подсказка: нажмите ;, чтобы сообщить начало/конец спонсорской вставки, и \", чтобы отправить. (Это можно изменить в настройках)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Последнее выбранное время спонсорской вставки"
|
||||
"message": "Последнее выбранное время спонсорской вставки"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Очистить время"
|
||||
@@ -219,15 +210,15 @@
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock — это расширение, которое пропускает спонсорские вставки в видео на YouTube. SponsorBlock — это краудсорсинговое расширение, которое позволяет каждому отправить время начала и конца спонсорских сегментов в видео на YouTube. После того, как кто-нибудь отправляет эту информацию, все остальные пользователи расширения будут автоматически пропускать спонсорские сегменты.",
|
||||
"description": "Полное описание расширения на страницах магазинов."
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Сайт",
|
||||
"description": "Используется на странице магазина Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Исходный код",
|
||||
"description": "Используется на странице магазина Firefox"
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Уведомление было обновлено!",
|
||||
@@ -340,9 +331,6 @@
|
||||
"supportInvidious": {
|
||||
"message": "Поддержка Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) — это неофициальный клиент YouTube. Чтобы включить поддержку, Вам понадобится принять дополнительные разрешения. Это НЕ работает в приватном режиме в Chrome и других вариантах Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Включить поддержку Invidious, выключить автоматический пропуск, скрыть кнопки и не только."
|
||||
},
|
||||
@@ -378,7 +366,7 @@
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Спонсорские сегменты короче этого значения не будут пропускаться и не будут показаны в плеере."
|
||||
},
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Следующий диапазон времени короче, чем Ваша настройка минимальной длительности. Это может означать, что он уже был отправлен, и просто игнорируется из-за этой настройки. Вы действительно хотите отправить?"
|
||||
},
|
||||
|
||||
148
public/_locales/sk/messages.json
Normal file
148
public/_locales/sk/messages.json
Normal file
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponzor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponzori"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponzor bol Preskočený"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Nahlásiť"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Načitávanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minúty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nikdy nezobrazovať"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Pozastavené"
|
||||
},
|
||||
"here": {
|
||||
"message": "tu"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Skryť Toto"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Nastavenia"
|
||||
},
|
||||
"website": {
|
||||
"message": "Webstránka",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Zdrojový Kód",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Vaša Práca",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Kód chyby: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Preskočiť Sponzor?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Preskočiť"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Zakázať Automatické Preskočenie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Povoliť Automatické Preskočenie"
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minúta"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minúty"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "hodina"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "hodiny"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Nastaviť Používateľove ID"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Vytvoril"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Automatické Preskočenie"
|
||||
},
|
||||
"add": {
|
||||
"message": "Pridať"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Ukázať Nahrávacie Tlačidlo"
|
||||
},
|
||||
"save": {
|
||||
"message": "Uložiť"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Vynulovať"
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Nastaviť Nastavenia"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Poslať"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Zrušiť"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Odstrániť"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Ukážka"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Upraviť"
|
||||
},
|
||||
"theKey": {
|
||||
"message": "Kľúč"
|
||||
},
|
||||
"to": {
|
||||
"message": "pre",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponzor"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Zakázať"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Manuálne Preskočenie"
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Teraz)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Viac Kategórií"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Koniec)"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "ID kanála nie je zatiaľ načítané."
|
||||
}
|
||||
}
|
||||
1
public/_locales/sl/messages.json
Normal file
1
public/_locales/sl/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/sr/messages.json
Normal file
1
public/_locales/sr/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
518
public/_locales/sv/messages.json
Normal file
518
public/_locales/sv/messages.json
Normal file
@@ -0,0 +1,518 @@
|
||||
{
|
||||
"fullName": {
|
||||
"message": "SponsorBlock för YouTube - Hoppa över sponsring",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Hoppa över sponsormeddelanden på YouTube-videor. Rapportera sponsring på videor du ser på för att spara tid för andra.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Felaktigt anrop enligt servern"
|
||||
},
|
||||
"429": {
|
||||
"message": "Du har rapporterat för många sponsormeddelanden för den här videon, är du säker att det finns så många?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Den här har redan blivit rapporterad."
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanal vitlistad!"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorer"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "sponsorsegment"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "sponsorsegment"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsormeddelande undvikt"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Rapportera"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Rapportera det här sponsorsegmentet som inkorrekt."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Avfärda"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Laddar..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuter"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekunder"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "\"Visa aldrig\"-knappen. "
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Tryck på Tillbaka för att ångra åtgärden."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Tillbaka"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Frammåt"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Pausad"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Klicka på infoknappen eller öppna popup-rutan genom att klicka på tilläggets ikon i hörnet uppe till höger för att redigera eller ta bort inviduella värden."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Är du säker på att du vill rensa detta?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Ett fel uppstod vid rapportering av sponsorsegment, försök igen senare."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Den här videons sponsormeddelande finns i databasen!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Inga sponsormeddelanden hittades"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Sponsormeddelandet Börjar Nu"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Sponsormeddelandet Slutar Nu"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Kunde inte hitta någon YouTube-video i denna tab. Om du är säker på att detta är en Youtube-flik, stäng den här rutan och öppna den igen. Ladda om fliken om inte det funkar."
|
||||
},
|
||||
"success": {
|
||||
"message": "Lyckades!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Röstat!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Du har redan röstat."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Det ser ut som att servern är nere. Kontakta utvecklaren med en gång."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Anslutningsfel. Felkod: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Vill du rapportera sponsortiderna för video id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Du har lämnat några sponsortider orapporterade. Gå tillbaka till den sidan för att rapportera dem (de är inte borttagna)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Rensa Sponsortider"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Öppna SponsorBlock Popup"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Rapportera Sponsortider"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Är du säker på att du vill rapportera detta?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Vitlista Kanal"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Ta bort kanal från vitlistan"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Rösta på en sponsortid"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Spela in sponsortider"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Hitills har du rapporterat"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Du har sparat andra "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Se leaderboarden"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klicka på knappen nedan när sponsormeddelandet börjar och slutar för att spela in och rapportera till databasen."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Tips: Tryck på semikolon när fokus är på en video för att markera början/slutet av ett sponsormeddelande och citattecken för att rapportera till databasen. (Kan ändras under inställningar)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Senaste Sponsortiderna Valda."
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Rensa Tider"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Rapportera Tider"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Detta kommer att användas på den publika statistiksidan för att visa hur mycket du har bidragit. Spana in den"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ange Användarnamn"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Gå med i den officiella discordservern för att ge förslag och feedback!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Dölj detta"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Inställningar"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Visa Knappar På YouTube-spelaren"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Dölj Knappar På YouTube-spelaren"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Detta döljer knapparna på YouTube-spelaren som du kan rapportera sponsormeddelanden med. Jag förstår att det kan se störande ut för en del. Istället för att ha knappen där kan den här popup-rutan användas för att rapportera sponsormeddelanden. För att dölja notisen som dyker upp, tryck på knappen som syns på notisen som säger \"Visa inte det här igen\". Du kan alltid slå på dessa inställningar igen senare."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Visa Infoknapp På YouTube-spelaren"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Dölj Infoknapp På YouTube-spelaren"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Detta är knappen som öppnar popup-rutan på YouTube-sidan."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Dölj \"Ta Bort\"-knappen På YouTube-spelaren"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Visa \"Ta Bort\"-knappen På YouTube-spelaren"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Denna knappen tar bort alla sponsormeddelanden på YouTube-spelaren."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Avaktivera Räkning Av Undvikta Sponsormeddelanden"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Aktivera Räkning Av Undvikta Sponsormeddelanden"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Den här funktionen håller koll på vilka sponsormeddelanden du har hoppat över för att uppskatta hur mycket tid en användare har sparat andra och används tillsammans med röster för att se till att spam inte läggs i databasen. Detta tillägg skickar ett meddelande till servern varje gång du hoppar över ett sponsormeddelande. Förhoppningsvis ändrar inte folk den här inställningen så statistiken hålls tillförlitlig. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Visa Notisen Igen"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock är ett webbläsartillägg som hoppar över sponsormeddelanden på YouTube-videor. SponsorBlock är ett crowdsourcat webbläsartillägg som låter vem som hellst att rapportera start och sluttider för sponsorsegment på YouTube-videor. När informationen väl har rapporterats kommer alla andra med detta tillägg att hoppa över sponsorsegmentet.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Hemsida",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Källkod",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Den här notisen har förbättrats!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Om du ändå inte gillar det, tryck på \"Visa aldrig\"-knappen.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Välj knapp att koppla till start av sponsormeddelande"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Välj knapp att koppla till rapportering av sponsormeddelande"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Koppla knapp genom att trycka på den"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Kopplad till: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Anslutningsfel. Se över din internetanslutning. Om du kan komma åt internet så är servern förmodligen överbelastad eller nere."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Avaktivera SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Aktivera SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Ditt Bidrag",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Servern verkar vara överbelastad. Försök igen om några sekunder."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Felkod: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Hoppa över sponsormeddelande?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Hoppa över"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Avaktivera Hoppa Över Automatiskt"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Aktivera Hoppa Över Automatiskt"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Hoppa Över Automatiskt undviker att spela upp sponsormeddelanden för dig. Ifall det är avaktiverat dyker en notis upp som frågar om du vill hoppa över."
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Ljudeffekt vid hopp"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Ljudeffekt vid hopp spelar upp en ljudeffekt när du hoppar över ett sponsormeddelande. Ifall det är avaktiverat (eller hoppa över automatiskt är avaktiverat), kommer inget ljud att spelas upp."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Du har hoppat över "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Du har sparat "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuter"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minuter"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "timma"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "timmar"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Du har sparat andra"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " av deras liv."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Se till att ditt sponsorsegment bara innehåller betald marknadsföring, inget annat.\n- Se till att inget värdefullt innehåll missas genom att hoppa över ditt sponsorsegment\n- Rapportera inte en video ifall hela videon är ett sponsormeddelande. Ett rapporteringssystem för hela videor kommer snart.\n- Se till att inte hoppa över delar som uppmärksammar partiskhet (om en recensionsvideo är sponsrad, hoppa inte över delen av videon där det nämns)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Gå till status.sponsor.ajay.app för serverstatus."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importera/Exportera Ditt AnvändarID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Detta bör hållas hemligt. Det fungerar som ett lösenord och borde inte delas vidare med någon. Om någon kommer över detta kan den personen utge sig för att vara dig."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ange AnvändarID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Varning: Ändring av AnvändarID är permanent. Är du säker att du vill göra det? Se till att ta en backup av ditt gamla för säkerhets skull."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Skapad av"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Hoppa Över Automatiskt"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Visa Notis Efter Sponsormeddelande Har Hoppats Över"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Är just nu kopplat till:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Stöd Invidious"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Aktivera Invidious stöd, avaktivera hoppa över automatiskt, dölj knappar och mer."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Lägg Till Invidious Instans"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Lägg till en anpassad instans av Invidious. Denna måste vara formaterad med ENBART domänen. Exempelvis: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Lägg till"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Detta är en individuell domän. Den måste ENBART inkludera domändelen. Exempelvis: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Rensa Invidious instanslista"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Du kommer nu att rensa Invidious instanslista"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Nuvarande Instanser:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Rösta Upp Automatiskt"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Med detta aktiverat kommer tillägget att rösta upp alla rapporterade sponsormeddelanden om du inte rapporterar dem som felaktiga. Om notisen är avaktiverad så kommer det inte att ske."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minsta varaktighet (sekunder):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Sponsorsegment som är kortare än det satta minstavärdet kommer inte att hoppas över eller visas i spelaren."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Följande rapport är kortare än ditt minstavärde i inställningarna. Det skulle kunna betyda att det redan är rapporterat och bara ignorerat på grund av denna inställning. Är du säker på att du vill rapportera?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Visa Uppladdningsknapp"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Denna knapp visas på YouTube-spelaren efter att du har valt en tidpunkt och är redo att rapportera."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlock Serveradress"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Adressen SponsorBlock använder för att prata med servern.\nOm du inte har din egen serverinstans ska den här inställningen inte ändras."
|
||||
},
|
||||
"save": {
|
||||
"message": "Spara"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Rensa"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Denna adressen är inte korrekt formaterad. Se till att du har http:// eller https:// i början och inga snedstreck i slutet."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Är du säker på att du vill rensa?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Videon ser ut att vara olistad. Tryck på avbryt om du inte vill kolla efter sponsorer."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignorera Olistade Videor"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Denna inställning kommer göra SponsorBlock märkbart långsammare. Uppslag av sponsormeddelanden kräver att video-ID skickas till servern. Om du är bekymrad över att olistade video-IDn skickas över internet, aktivera denna inställning."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com stöds nu"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Importera/Exportera Alla Inställningar"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Detta är alla dina inställningar i JSON-format. Det inkluderar ditt AnvändarID, så var nog med hur du hanterar datan."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Ange Inställningar"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Varning: Att ändra inställningarna är permanent och kan förstöra din installation. Är du säker på att du vill göra detta? Se till att göra en backup för säkerhets skull."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "Denna JSON är inte korrekt formaterad. Dina inställningar har inte ändrats."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Rapportera Segment"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Skicka"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Avbryt"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Ta bort"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Förhandsgranska"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Redigera"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Kopiera Debuginformation Till Urklipp"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Misslyckades med att kopiera debuginformation till urklipp"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Kopierar information till urklipp för att dela med en utvecklare vid rapportering av en bugg / när en utvecklare ber om det. Känslig data som AnvändarID, vitlistade kanaler, och anpassad serveradress följer inte med. Däremot innehåller det information om useragent, webbläsare, operativsystem, och tilläggsversion."
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "Debuginformationen har kopierats till urklipp. Ta bort eventuell information du inte vill dela med dig av. Spara informationen i en textfil eller klistra in den i en buggrapport."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "Nyckeln"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "används redan av YouTube. Välj en annan nyckel."
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "är kopplad till en annan funktion. Välj en annan knapp."
|
||||
},
|
||||
"to": {
|
||||
"message": "till",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponsormeddelande"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Självreklam och egna produkter"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Avaktivera"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Hoppa Över Manuellt"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Visa Lager Ovanpå Spelare"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Aktivera Server För Betatestning"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Dina rapporter och röster KOMMER INTE RÄKNAS mot huvudservern. Använd endast detta för testning."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Alla rapporter och röster KOMMER INTE RÄKNAS mot huvudservern så länge du är ansluten mot testservern. Se till att avaktivera detta när du vill rapportera ett riktigt sponsormeddelande."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Nu)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Fler Kategorier"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Slut)"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "Kanal-ID är inte inladdat än."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "Det verkar som om något blockerar SponsorBlocks från att hämta videodata. Det beror förmodligen på din annonsblockerare. Vänligen kontrollera https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "Om detta fortsätter att inträffa, kan orsaken vara din annonsblockerare. Vänligen kontrollera https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
}
|
||||
}
|
||||
1
public/_locales/sw/messages.json
Normal file
1
public/_locales/sw/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/ta/messages.json
Normal file
1
public/_locales/ta/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/te/messages.json
Normal file
1
public/_locales/te/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
public/_locales/th/messages.json
Normal file
1
public/_locales/th/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
570
public/_locales/tr/messages.json
Normal file
570
public/_locales/tr/messages.json
Normal file
@@ -0,0 +1,570 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "Youtube için SponsorBlock - Sponsorlukları Atla",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "YouTube videolarındaki sponsorlukları atla. İzlediğin videolardaki sponsorları diğerlerine zaman kazandırmak için raporla.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Sunucu isteğin geçersiz olduğunu iletti"
|
||||
},
|
||||
"429": {
|
||||
"message": "Sadece bu video için çok fazla sponsor süresi belirtti, bu kadar fazla olduğuna emin misin?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Bu daha önce zaten gönderilmiş"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanal beyazlistede!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorlar"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "sponsor bölümü"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "sponsor bölümleri"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsor Geçildi"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Raporla"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Bu sponsor bölümünü hatalı olarak rapor et."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Yoksay"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Yükleniyor..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Dakika"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Saniye"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Asla Gösterme"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Geldiğiniz yere dönmek istiyorsanız atlama'ya basın."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Atlama"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Tekrar atla"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Duraklatıldı"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Değerleri tek başına düzenlemek ve silmek için, bilgi butonuna basın veya sağ yukarıdaki eklenti simgesine tıklayarak eklenti menüsünü açın."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Bunu silmek istediğinize emin misiniz?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Sponsor sürelerini yollarken bir sorun oluştur, lütfen tekrar deneyin."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Bu videonun sponsorları veritabanında mevcut!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Sponsor bulunamadı"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Sponsorluk Şimdi Başlıyor"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Sponsorluk Şimdi Bitiyor"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Bu sekmede YouTube videosu bulunamadı. Bu sekmenin bir YouTube sekmesi olduğundan eminseniz, bu pencereyi kapatıp, tekrar açın. Eğer o da işe yaramazsa, sekmeyi yenilemeyi deneyin."
|
||||
},
|
||||
"success": {
|
||||
"message": "Başarılı!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Oylandı!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Bu şekilde zaten oy kullanmıştın."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Sunucu çökmüş gibi duruyor. Derhal geliştiriciyle iletişime geçin."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Bağlantı hatası oluştu. Hata kodu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Bu video için sponsor sürelerini göndermek istiyor musunuz"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Bazı sponsor sürelerini göndermediğinizi görüyoruz. Göndermek için sayfaya geri dönebilirsiniz (hala mevcutlar)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Sponsor Sürelerini Temizle"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "SponsorBlock Penceresini Aç"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Sponsor Sürelerini Gönder"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Bunu göndermek istediğinize emin misiniz?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Kanalı Beyazlisteye Ekle"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Kanalı Beyazlisteden Kaldır"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Sponsor Süresi için Oy Kullan"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Sponsor Süresini Kaydet"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Şu an kadar yolladığınız"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "İnsanların şu kadar vaktini kurtardınız "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Liderlik tablosunu görüntüle"
|
||||
},
|
||||
"here": {
|
||||
"message": "burada"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kaydetmek ve veritabanına yollamak için sponsorluk başladığında ve bittiğinde aşağıdaki butona tıklayın."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "İpuçu: Sponsorluk süresinin başını ve sonunu raporlamak için video üzerindeyken noktalı virgül tuşuna, yollamak için tırnak tuşuna basınız. (Bu ayarlardan değiştirilebilir.)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Son Sponsor Mesajı Süresi Seçildi"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Süreleri Temizle"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Süreleri Gönder"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Bu, ne kadar katkı sağladığınızı göstermek için herkese açık istatistik sayfasında kullanılacaktır. Görün"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Kullanıcı Adı Belirle"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Öneri ve geri bildirimleriniz için resmi Discord serverımıza katılın!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Bunu sakla"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Ayarlar"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "YouTube oynatıcısında Butonları Göster"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "YouTube Oynatıcısındaki Butonları Gizle"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Bu YouTube oynatıcısındaki bölüm geçişlerini yolladığınız butonları saklayacaktır."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "YouTube Oynatıcısındaki Bilgi Butonunu Göster"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "YouTube Oynatıcısındaki Bilgi Butonunu Gizle"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Bu, YouTube sayfasında açılan pencereyi açan butondur."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "YouTube Oynatıcısında Silme Tuşunu Gizle"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "YouTube Oynatıcısında Silme Tuşunu Göster"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Bu, YouTube oynatıcısındaki mevcut video için gönderilmemiş bölümleri temizleyen butondur."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Sponsor Atlama Takip Sayacını Devredışı Bırak"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Sponsor Atlama Takip Sayacını Devreye Sok"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Bu özellik, önerinizin diğerlerine ne kadar işe yaradığını bildirmek için atladığınız sponsorları kaydeder ve istenmeyen önerilerin veritabanına girmesini engellemek adına bir ölçü olarak kullanılır. Her sponsor atladığınızda eklenti sunucuya bir mesaj yollar. Umarım bu ayarı birçok kişi değiştirmez ve böylece görüntülenme sayıları doğru kalır. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Uyarıyı Tekrar Göster"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock, YouTube'da sponsorlu bölümleri atlamanıza yardımcı olan bir eklentidir. SponsorBlock, herkesin YouTube videolarında bulunan sponsorlu bölümlerin başını ve sonunu göndermesine izin veren kitlekaynaklı bir tarayıcı eklentisidir. Bu bilgiyi biri yolladığında, bu sponsorlu bölüm herkeste atlanır.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Website",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Kaynak Kodu",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Uyarı güncellendi!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Eğer hala beğenmediyseniz, asla gösterme butonuna basın.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Sponsor bölümünün başlangıcı için bir tuş belirleyin"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Gönderim için bir tuş belirleyin"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Yazarak bir tuş seçin"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Tuş seçimi şu tuşa ayarlandı: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Bağlantı zaman aşımına uğradı. İnternet bağlantınızı kontrol ediniz. Eğer internetiniz çalışıyor ise, büyük ihtimalle sunucuya erişilemiyor veya sunucuya aşırı yüklenilmiş olabilir."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock'u Devredışı Bırak"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock'u Devreye Sok"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Çalışmalarınız",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Sunucuya aşırı yüklenilmiş gibi gözüküyor. Birazdan tekrar deneyin."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Hata Kodu: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Sponsoru Atla?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Atla"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Otomatik Atlamayı Devredışı Bırak"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Otomatik Atlamayı Devreye Sok"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Otomatik atlama sponsorları sizin için atlayacak. Kapalı olduğunda, atlamak istediğinizi soran bir uyarı ekranı belirecek."
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Atlamada Sesli Bildirim"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "Atlamada sesli bildirim, bir sponsor bölümü atlandığında bir ses çalar. Eğer devredışı bırakıldıysa (veya otomatik atlama devredışı bırakıldıysa), herhangi bir ses çalmayacak."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Bunu atladınız "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Şu kadar süre kazandınız "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "dakika"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "dakika"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "saat"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "saat"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "İnsanların"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " kadar vaktini kurtardınız."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Bölümünüzün sadece ücretli tanıtım bölümü olduğundan emin olun.\n- Bu bölümü atlamanın önemli içerik bölümlerini de atlamayacağından emin olun. \n- Eğer tüm bölüm sponsor ise, lütfen raporlamayın. Tüm video rapor sistemimiz yakında gelecek.\n- Eğer videoda taraflılık içeren bir uyarı var raporlamayın (Eğer bir inceleme videosu sponsorluysa, bundan bahsettikleri kısmı atlatmayın)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Sunucu durumu için status.sponsor.ajay.app kontrol edin."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Kullanıcı kimliğini Dışarı/İçeri Aktar"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Bu gizli tutulmalıdır. Bu bir şifreye benzer ve diğerleriyle paylaşılmaması gerekir. Birinin eline geçerse, sizi taklit edebilir."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Kullanıcı kimliği Belirle"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Oluşturan"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Otomatik Atla"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Sponsor Atladıktan Sonra Uyarı Göster"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Şu an buna ayarlı:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Invidious'a Destek Ver"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) üçüncü parti YouTube istemcisidir. Desteği etkinleştirmek için fazladan izinlere onay vermelisiniz. Bu Chrome ve Chromium bazlı tarayıcılarda gizli pencere modunda ÇALIŞMAZ."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Invidious desteğini, otomatik atlamayı, butonları saklamayı ve daha fazlasını etkinleştir."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Invidious Oluşumu Ekle"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Özel Indivious oluşumu ekle. Bu SADECE alan adıyla düzenlenmelidir. Örnek: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Ekle"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Bu geçersiz bir alan adı. Bu SADECE alan adı kısmını içermelidir. Örnek: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Invidious Oluşum Listesini Sıfırla"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Invidious Oluşum listesini sıfırlamak üzeresiniz"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Mevcut Oluşumlar:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Otomatik Oy Ver"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Eğer bu ayar açıksa, eklenti eğer rapor etmediyseniz gördüğünüz tüm önerileri oylayacaktır. Eğer bildirim kapalıysa, bu gerçekleşmeyecektir."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimum süre (saniye):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Belirlenen değerden kısa olan sponsor bölümleri atlanmayacak veya oynatıcıda gözükmeyecektir."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Sıradaki öneri belirlediğiniz minimum süre ayarından daha kısa. Bu zaten yollandığı ve bu ayardan dolayı yok sayıldığı anlamına gelebilir. Göndermek istediğinizden emin misiniz?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Karşıya Yükleme Butonunu Göster"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Bu buton, YouTube oynatıcısında bir zaman seçtiğiniz ve göndermeye hazır olduğunuzda gözükür."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlock Sunucu Adresi"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "SponsorBlock'un sunucu ile iletişimi sağlamak için kullandığı adres.\nKendi sunucu kopyanız olmadığı sürece bu değiştirilmemelidir."
|
||||
},
|
||||
"save": {
|
||||
"message": "Kaydet"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Sıfırla"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Bu adres doğru formatta değil. Başında http:// veya https:// olduğundan ve sonda / işareti olmadığından emin olun."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Bunu sıfırlamak istediğinize emin misiniz?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Bu videonun listede olmadığı belirlendi. Bu videoyu sponsorlar için kontrol etmek istemiyorsanız iptale basınız."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Listedışı/Özel Videoları Görmezden Gel"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Bu ayar SponsorBlock eklentisini az miktarda yavaşlatacaktır. Sponsor kontrolleri, sunucuya video kimlik numarası göndermeyi gerektirir. Eğer listedışı videoların, video kimlik numaralarının internet üzerinden gönderilmesini istemiyorsanız bu seçeneği aktive edin."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com şu an desteklenmektedir"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Bütün Ayarlarını İçe/Dışa Aktar"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Bu, JSON formatında bütün kurulumunuzu gösterir. Kullanıcı kimliğinizi içerir, bu sebeple paylaşırken dikkatli olun."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Seçenekleri Ayarla"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Uyarı: Ayarları değiştirmek kalıcıdır ve yüklemenizi bozabilir. Bunu yapmak istediğinizden emin misiniz? Eskisini yenilediğinizden emin olun."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "Bu JSON doğru formatlanmamış. Ayarlarınız değiştirilmedi."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Bölüm Gönder"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Gönder"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "İptal"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Sil"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Önizle"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Düzenle"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Onarım Bilgisini Panoya Kopyala"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Panoya kopyalanamadı"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Panoya, geliştiricinin hata gideriminde veya ulaşmak istediğinde geliştiriciye sağlamak üzerine bilgileri kaydeder. Kullanıcı kimliği, beyaz listenizdeki kanallar ve düzenlenmiş sunucu adresleri gibi hassas bilgiler silinmiştir. Ancak tarayıcı bilgileri, işletim sisteminiz ve eklenti numaranız gibi bilgileri içerebilir. "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "Bu çözüm bilgisi panoya kopyalandı. Paylaşmak istemediğiniz herhangi bir bilgiyi silmekte özgürsünüz. Bir yazı dosyası olarak kaydedin veya hata raporuna kopyalayın."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "Anahtar"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "YouTube tarafından zaten kullanımda. Lütfen başka bir anahtar seçin."
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "başka bir eyleme bağlı. Lütfen başka bir anahtar seçin."
|
||||
},
|
||||
"to": {
|
||||
"message": "'e",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Giriş Animasyonu"
|
||||
},
|
||||
"category_outro": {
|
||||
"message": "Bitiş Ekranı/Jenerik"
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Etkileşim Hatırlatıcısı (Abonelik)"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Kendi Reklamını Yapma ve Ürün"
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Müzik: Müzik Olmayan Bölüm"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Canlı Yayın: Bağış/Mesaj Okuma"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Devredışı"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Elle Atla"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Arama Çubuğunda Göster"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Beta Deneme Sunucusunu Devreye Sok"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Önerileriniz ve oylarınız ana sunucuya GÖNDERİLMEYECEKTİR. Bunu sadece deneme amacıyla kullanın."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Tüm öneriler ve oylar, test sunucusuna bağlandığınız sürece ana sunucuya iletilmeyecektir. Gerçek öneriler yapmak istediğinizde bu ayarı kapatmayı unutmayın."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Şimdi)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Daha Fazla Kategori"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Son)"
|
||||
},
|
||||
"hiddenDueToDownvote": {
|
||||
"message": "gizlendi: eksile"
|
||||
},
|
||||
"hiddenDueToDuration": {
|
||||
"message": "gizlendi: çok kısa"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "Kanal kimliği henüz yüklenmedi."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "Bir şeyin SponsorBlock'un video bilgisi almasını engelliyor gibi görünüyor. Bu reklam engelleyiciniz olabilir. Lütfen şu adresi kontrol edin https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "Bunu sürekli yaşıyorsanız, reklam engelleyiciniz tarafından gerçekleşiyor olabilir. https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests adresini kontrol edin."
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "Sponsorları Atlamadan Önce Kanal Kontrolünü Zorla"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "Varsayılan olarak, eklenti kanalın ne olduğunu bilmeden önce sponsorları atlayacaktır. Varsayılan olarak, beyaz listede olan kanallarda sıfır saniyelik sponsor bölümleri atlanacaktır. Bu ayarı aktifleştirmek bunu engelleyecektir ancak kanal kimlik bilgisini almak biraz vakit alacağından atlamalarda gecikmeler yaratabilir. Eğer hızlı bir internetiniz varsa bu gecikmeler farkedilmeyebilir."
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Sponsorları Atlamadan Önce Kanal Kontrolünü Zorlamayı Gözden Geçir"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Hatalı"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "Yanlış Kategori"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "Bu videonun kategorisi müzik olarak belirlenmiş. Müzik içermeyen bölümleri göndermek istediğinize emin misiniz? Eğer bu bir müzik videosu değilse, bu bölümleri göndermemelisiniz. Eğer ayırt edemiyorsanız, lütfen rehberi okuyunuz."
|
||||
}
|
||||
}
|
||||
449
public/_locales/uk/messages.json
Normal file
449
public/_locales/uk/messages.json
Normal file
@@ -0,0 +1,449 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock для YouTube - Пропускайте спонсорські вставки",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "Пропускайте спонсорські вставки в відео на YouTube. Повідомляйте про спонсорські вставки в відео, які Ви дивіться, щоб заощадити час інших користувачів.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "Сервер відхилив цей запит"
|
||||
},
|
||||
"429": {
|
||||
"message": "Ви відправили занадто багато спонсорів для цього відео. Ви впевнені, що їх так багато?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Цей запит був відправлений раніше"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Канал доданий у білий список!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "спонсори"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "спонсорів"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "спонсорська вставка"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "спонсорські вставки"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Спонсор пропущений"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Помилка"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Повідомити, що інформація про це спонсорський сегменті є хибною."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Закрити"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Завантаження..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "хв"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "сек"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Не відображати"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Натисніть «Назад», щоб повернутися назад."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Назад"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Пропустити"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Пауза"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Щоб змінити або видалити окремі значення, натисніть кнопку «Інформація» або відкрийте спливаюче вікно розширення, клацнувши значок розширення в правому верхньому куті."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Ви впевнені, що хочете видалити цю інформацію?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "При надсиланні звіту про спонсорський сегмент сталася помилка. Спробуйте надіслати його пізніше."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Спонсори цього відео вже знаходяться в базі даних!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Спонсорські вставки не знайдені"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Спонсорська вставка починається зараз"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Спонсорська вставка закінчується зараз"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Можливо, це не вкладка YouTube, або Ви натиснули занадто рано.\n Якщо це вкладка YouTube,\n закрийте це спливаюче вікно і відкрийте його знову."
|
||||
},
|
||||
"success": {
|
||||
"message": "Успіх!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Голос зарахований!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Ви вже проголосували таким чином раніше."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Здається, сервер не працює. Зв'яжіться з розробником."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Помилка з'єднання. Код помилки: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Ви точно хочете надіслати звіт про спонсорські вставки у відео з ідентифікатором"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Ви ще не надіслали звіти про деякі спонсорські вставки. Хочете повернутися на цю сторінку, щоб надіслати їх (вони не видаляються)."
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Ви впевнені, що хочете надіслати цю інформацію?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Додати канал в білий список"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Видалити канал з білого списку"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Проголосувати за час спонсорської вставки"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Записати час спонсорської вставки"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "На даний момент Ви надіслали"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ви допомогли людям заощадити "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Подивитися дошку пошани"
|
||||
},
|
||||
"here": {
|
||||
"message": "тут"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Натисніть кнопку нижче, коли спонсорська вставка починається і закінчується, щоб записати\nі надіслати її в базу даних."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Підказка: Натисніть клавішу крапки з комою, щоб повідомити початок/кінець спонсорської вставки і пропозицію для надсилання. (Це можна змінити в налаштуваннях)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Останній обраний час спонсорської вставки"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Очистити час"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Надіслати час"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Воно використовується на публічній сторінці статистики, щоб показати Ваш внесок. Її можна подивитися"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Встановити ім'я користувача"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Приєднуйтесь до офіційного сервера Discord, щоб залишити пропозиції і зворотний зв'язок!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Приховати це"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Налаштування"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Показувати кнопки в плеєрі YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Приховати кнопки в плеєрі YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Це налаштування приховує кнопки для надсилання спонсорських вставок, які з'являються в плеєрі YouTube."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Показувати кнопку інформації в плеєрі YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Приховати кнопку інформації в плеєрі YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Ця кнопка відкриває спливаюче вікно на сторінці YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Приховати кнопку видалення в плеєрі YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Показувати кнопку видалення в плеєрі YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ця кнопка дозволяє очистити всі спонсорські вставки в плеєрі YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Вимкнути відстеження кількості пропусків спонсорських вставок"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Увімкнути відстеження кількості пропусків спонсорських вставок"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ця можливість відстежує, які спонсорські вставки Ви пропустили, щоб допомогти користувачам дізнатися, наскільки їхвнесок допоміг іншим, і використовується як метрика, щоб переконатися, що спам не потрапляє у базу даних. Розширення відправляє повідомлення на сервер кожен раз, коли Ви пропускаєте спонсорську вставку. Сподіваємося, велика частина користувачів не поміняє це налаштування, так що у нас буде точна статистика переглядів :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Показувати сповіщення знову"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock - це розширення, яке пропускає спонсорські вставки в відео на YouTube. SponsorBlock - це краудсорсінгове розширення, яке дозволяє кожному надіслати час початку і кінця спонсорських сегментів в відео на YouTube. Після того, як хто-небудь надсилає цю інформацію, всі інші користувачі розширення будуть автоматично пропускати спонсорські сегменти.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Сайт",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Вихідний код",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Повідомлення було оновлено!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Якщо воно Вам все одно не подобається, натисніть «не показувати\".",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Призначити гарячу клавішу для початку спонсорської вставки"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Призначити гарячу клавішу для надсилання"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Натисніть, щоб вибрати її"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Кнопка призначена на: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Таймаут підключення. Перевірте ваше з'єднання з інтернетом. Якщо ваш інтернет працює, сервер, швидше за все, перевантажений або лежить."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Відключити SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Увімкнути SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Ваша робота",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Схоже, він перевантажений. Спробуйте ще раз через кілька секунд."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Код помилки: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Пропустити спонсорську вставку?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Пропустити"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Вимкнути автоматичний пропуск"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Увімкнути автоматичний пропуск"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Автоматичний пропуск буде пропускати спонсорські вставки за Вас. Якщо вимкнено, буде показуватися повідомлення з пропозицією пропустити."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Ви пропустили "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Ви заощадили "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "хвилину"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "хвилин"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "година"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "годин"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Ви заощадили людям"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " їх життя."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Переконайтеся, що Ваш сегмент містить тільки платну інтеграцію, і більше нічого.\n- Переконайтеся, що пропуск цього сегмента не пропустить жодного цінного контенту\n- Якщо все відео цілком спонсорське, будь ласка, не повідомляйте про нього. Система для повідомлення про цілі відео скоро вийде.\n- Будь ласка, не повідомляйте про відмови від відповідальності, які можуть показати упередженість (якщо відео з оглядом проплачено, не пропускайте, коли вони це згадують)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Дивіться стан сервера на status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Імпортувати/Експортувати Ваш ідентифікатор користувача"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Це потрібно тримати в секреті. Це як пароль, не варто ним ні з ким ділитися. Якщо він у кого-то є, він зможе видати себе за Вас."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Встановити ідентифікатор користувача"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Увага: зміна ідентифікатора користувача є незворотнім. Ви дійсно хочете це зробити? Зробіть резервну копію вашого старого про всяк випадок."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Створено"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Автоматичний пропуск"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Показувати сповіщення після пропуску спонсорської вставки"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Він зараз призначений на:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Підтримка Invidious"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Увімкнути підтримку Invidious, вимкнути автоматичний пропуск, приховати кнопки і не тільки."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Додати інстанси Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Додати свій інстанси Invidious. Формат: ТІЛЬКИ домен. Наприклад: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Додати"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Це неправильний домен. Введіть ТІЛЬКИ домен. Наприклад: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Скинути список інстанси Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Ви збираєтеся скинути список інстанси Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Поточні інстанси:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Автоматично голосувати \"за\""
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Якщо це увімкнено, розширення буде голосувати \"за\" всі пропозиції інших користувачів, якщо Ви на них не поскаржитеся. Якщо повідомлення вимкнуто, це не буде відбуватися."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Мінімальна тривалість (секунд):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Спонсорські сегменти коротше цього значення не будуть пропускатися і не будуть показані в плеєрі."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Наступний діапазон часу коротше, ніж Ваше налаштування мінімальної тривалості. Це може означати, що він вже був надісланий, і просто ігнорується через це налаштування. Ви дійсно хочете надіслати?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Показувати кнопку надсилання"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Ця кнопка з'являється в плеєрі YouTube після того, як Ви вибрали позначку часу і готові до надсилання."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "Адреса сервера SponsorBlock"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Адреса, за якою SponsorBlock звертається до сервера.\nМіняйте тільки якщо Ви підняли свій сервер."
|
||||
},
|
||||
"save": {
|
||||
"message": "Зберегти"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Скинути"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Ця адреса неправильного формату. Переконайтеся, що він починається з http: // або https: //, і що на кінці немає слеша."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Ви дійсно хочете це скинути?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Було виявлено, що це відео непублічна. Натисніть \"скасування\", якщо не хочете перевіряти його на спонсорів."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ігнорувати непублічні відео"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Це налаштування значно сповільнить SponsorBlock. Пошук спонсорів вимагає надсилання ідентифікатора відео на сервер. Якщо Вас турбує відправка ідентифікаторів непублічних відео по інтернету, увімкніть це налаштування."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com тепер підтримується"
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Надіслати сегмент"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Надіслати"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Скасувати"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Видалити"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Попередній перегляд"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Редагувати"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Спонсор"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Вимкнути"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Пропуск вручну"
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(Зараз)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Більше категорій"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Кінець)"
|
||||
}
|
||||
}
|
||||
1
public/_locales/vi/messages.json
Normal file
1
public/_locales/vi/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
567
public/_locales/zh_CN/messages.json
Normal file
567
public/_locales/zh_CN/messages.json
Normal file
@@ -0,0 +1,567 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - 跳过赞助商广告",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"Description": {
|
||||
"message": "跳过 YouTube 视频的赞助商广告。报告您观看的视频的赞助商广告以节省他人的时间。",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"400": {
|
||||
"message": "服务器说此请求无效"
|
||||
},
|
||||
"429": {
|
||||
"message": "您为这个视频提交了太长的赞助商广告时间,您确定有这么多吗?"
|
||||
},
|
||||
"409": {
|
||||
"message": "它之前已经被提交过了"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "频道已加入白名单!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "赞助商广告"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "赞助商广告"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "赞助商广告片段"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "赞助商广告片段"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "已跳过赞助商广告"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "报告"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "报告这个被提交的赞助商广告不正确。"
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "忽略"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "加载中..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "分钟"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "秒"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "不再显示"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "点击取消跳过以回到您原来的样子。"
|
||||
},
|
||||
"unskip": {
|
||||
"message": "取消跳过"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "继续跳过"
|
||||
},
|
||||
"paused": {
|
||||
"message": "已暂停"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "要编辑或删除个别值,请点击信息按钮或通过点击右上角的扩展图标打开扩展弹窗。"
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "您确定要清空它吗?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "提交您的赞助商广告时间时出错。请稍后再试。"
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "此视频的赞助商广告在数据库中!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "未找到赞助商广告"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "赞助商广告现在开始"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "赞助商广告现在结束"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "在此标签页未找到 Youtube 视频。如果您确定这是一个 Youtube 页面,请关闭此弹窗并重新打开。如果那没用,请尝试重新加载页面。"
|
||||
},
|
||||
"success": {
|
||||
"message": "成功 !"
|
||||
},
|
||||
"voted": {
|
||||
"message": "已投票!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "您之前已经这样投过了。"
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "服务器似乎已宕机。请立即联系开发者。"
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "连接错误。错误代码: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "您想要为此视频提交赞助商广告时间吗"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "您似乎还有一些赞助商广告时间未提交。请回到那个页面提交它们(它们未被删除)。"
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "清除赞助商广告时间"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "打开 SponsorBlock 弹窗"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "提交赞助商广告时间"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "您确定要提交它吗?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "白名单频道"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "将频道移出白名单"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "为赞助商广告时间投票"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "记录赞助商广告次数"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "您目前已提交"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "您已为人们节省了 "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "查看排行榜"
|
||||
},
|
||||
"here": {
|
||||
"message": "这里"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "当赞助商广告开始和结束时,请点击下面的按钮记录并将其提交到数据库。"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "提示:在观看视频时,按下分号键(;)以报告赞助商广告的开始/结束时间,按下引号键(’)提交。(可以在选项中更改)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "选择的最新的赞助商广告信息时间"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "清除时间"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "提交时间"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "这被用于在公开统计页面上展示您的贡献。查看它"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "设定用户名"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "快加入官方 Discord 服务器来提供建议与反馈!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "隐藏它"
|
||||
},
|
||||
"Options": {
|
||||
"message": "选项"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "在 Youtube 播放器上显示按钮"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "在 Youtube 播放器上隐藏按钮"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "这将隐藏在 YouTube 播放器上提交赞助商广告的按钮。我了解这个东西打扰到了某些人。除了使用那个按钮,这个弹窗也可以用来提交赞助商广告。 要隐藏出现的通知,请使用通知中显示的写着 ”不再显示“ 的按钮。您可以在以后再次启用这些设置。"
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "在 Youtube 播放器上显示信息按钮"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "在 Youtube 播放器上隐藏信息按钮"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "此按钮用于在 Youtube 页面中打开弹窗。"
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "在 Youtube 播放器上隐藏删除按钮"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "在 Youtube 播放器上显示删除按钮"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "此按钮用于在 Youtube 播放器中清除所有赞助商广告。"
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "禁用赞助商广告跳过统计跟踪"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "启用赞助商广告跳过统计跟踪"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "此功能追踪您跳过了哪些赞助商广告,以让用户知道他们提交的信息帮助了多少人,并与点赞一同作为依据,来确保垃圾信息不会进入数据库。在您每次跳过赞助商广告时,扩展都会向服务器发送一条消息。希望大部分人不要改变此设置,以使观看数字准确。:)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "重新显示通知"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock 是一个用于跳过 YouTube 视频的赞助商广告片段的扩展。SponsorBlock 是一个众包的浏览器扩展,可以让任何人提交 Youtube 视频的赞助商广告片段的开始和结束时间。一旦有人提交了信息,其他所有使用此扩展的人都能直接跳过赞助商广告片段。",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "网站",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "源代码",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "通知已升级!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "如果您依然不喜欢它,请按下不再显示按钮。",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "设定赞助商广告开始的绑定按键"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "设定提交的绑定按键"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "点击您想选择的按键"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "绑定按键已被设定为: "
|
||||
},
|
||||
"0": {
|
||||
"message": "连接超时。请检查您的网络连接。如果您的网络运行正常,则可能是服务器过载或宕机。"
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "禁用 SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "启用 SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "您的成果",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "服务器似乎已过载。请稍后再试。"
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "错误代码: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "跳过赞助商广告?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "跳过"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "禁用自动跳过"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "启用自动跳过"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "自动跳过将会为您跳过赞助商广告。如果被禁用,将会显示一个通知询问您是否要跳过。"
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "跳过时音频通知"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "跳过时音频通知会在跳过赞助商广告时播放声音。如果被禁用(或自动跳过被禁用),则不会播放声音。"
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "您已跳过 "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "您为自己节省了 "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "分钟"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "分钟"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "小时"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "小时"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "您为人们节省了"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " 的生命。"
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- 请确保您的片段只包含付费推广片段,没有其他的东西。\n- 请确保跳过此片段不会跳过重要的内容\n- 如果整个视频本身就是赞助商广告,请不要报告它。完整视频报告系统将在不久后推出。\n- 请不要报告可能产生偏见的免责声明(如果评测视频有赞助商,请不要在他们提到这一点时跳过)。"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "在 status.sponsor.ajay.app 检查服务器状态。"
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "导入/导出您的用户 ID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "这应该被保密。这就像一个密码,且不应该告诉任何人。如果有人拥有它,他就可以冒充您。"
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "设定用户 ID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "警告:更改用户 ID 是永久性的。您确定要这么做吗?请务必备份您的旧用户 ID 以防万一。"
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "创建者"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "自动跳过"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "跳过赞助商广告后显示通知"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": "。目前被设定为:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "支持 Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) 是一个第三方 Youtube 客户端。要启用支持,您必须允许额外的权限。在 Chrome 及其他 Chromium 变种的匿名模式中无法工作。"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "启用 Invidious 支持,禁用自动跳过,隐藏按钮等等。"
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "添加 Invidious 实例"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "添加一个 Invidious 自定义实例。它必须是只有域名的格式。例如:invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "添加"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "这是一个无效的域名。它应该只包括域名部分。例如:invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "重置 Invidious 实例列表"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "您将会重置 Invidious 实例列表"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "当前实例:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "自动点赞"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "启用此选项后,扩展将会为所有您观看过的提交点赞,如果您没有报告它们的话。如果通知被禁用,那就不会出现。"
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "最小持续时间(秒):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "短于设定值的赞助商广告片段将不会被跳过或显示在播放器中。"
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "以下的提交短于您的最小持续时间选项。这代表它们可能已经被提交,只是由于该选项被忽略了。您确定要提交吗?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "显示上传按钮"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "在您选择了时间并准备提交后,此按钮会出现在 Youtube 播放器中。"
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlock 服务器地址"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "SponsorBlock 用于联系服务器的地址。\n除非您有自己的服务器实例,否则这不应该更改。"
|
||||
},
|
||||
"save": {
|
||||
"message": "保存"
|
||||
},
|
||||
"reset": {
|
||||
"message": "重置"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "此地址格式不正确。请确保开头有 http:// 或 https:// ,结尾没有斜杠 / 。"
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "您确定要重置它吗?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "未检测到视频的记录。如果您不想检查赞助商广告,请点击取消。"
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "忽略未找到记录的视频"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "此设置将显著的减慢 SponsorBlock 。赞助商广告查找器需要向服务器发送未找到记录的视频 ID 。如果您对通过互联网发送视频 ID 有疑虑,请启用此选项。"
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "现已支持 m.youtube.com"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "导入/导出所有选项"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "这是您全部配置的 JSON 格式。它包含了您的用户 ID ,所以您一定要谨慎的保管它。"
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "设定选项"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "警告:更改选项是永久性的且可能破坏您安装的东西。您确定要这么做吗?请确保已备份旧文件以防万一。"
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "此 JSON 格式不正确。您的选项尚未更改。"
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "提交片段"
|
||||
},
|
||||
"submit": {
|
||||
"message": "提交"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "取消"
|
||||
},
|
||||
"delete": {
|
||||
"message": "删除"
|
||||
},
|
||||
"preview": {
|
||||
"message": "预览"
|
||||
},
|
||||
"edit": {
|
||||
"message": "编辑"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "复制调试信息到剪贴板"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "复制到剪贴板失败"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "复制信息到剪贴板,在提交错误或开发者需要时提供给他。 敏感信息如:您的用户ID,白名单频道和自定义服务器地址等已被删除。然而,它仍然包含诸如您的 useragent ,浏览器,操作系统和扩展版本号等信息。 "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "调试信息已复制到剪切板中。 您可以随意移除任何您不想分享的信息。请将其另存为 .txt 文件或粘贴到错误报告中。"
|
||||
},
|
||||
"theKey": {
|
||||
"message": "按键"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "已被 Youtube 使用。请选择其他按键。"
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "已绑定其他操作。请选择其他按键。"
|
||||
},
|
||||
"to": {
|
||||
"message": "到",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "赞助商广告"
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "介绍动画"
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "互动提醒(订阅)"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "自我推销和商品"
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "音乐:非音乐部分"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "直播:捐赠/消息阅读"
|
||||
},
|
||||
"disable": {
|
||||
"message": "禁用"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "手动跳过"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "在搜索栏中显示"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "启用 Beta 测试服务器"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "您的提交和投票将不会计入主服务器。它只被用于测试。"
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "当连接到测试服务器时,所有的提交和投票将不会计入主服务器。当您想要进行真实提交时,请确保禁用了此选项。"
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(现在)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "更多类别"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(结束)"
|
||||
},
|
||||
"hiddenDueToDownvote": {
|
||||
"message": "隐藏:差评"
|
||||
},
|
||||
"hiddenDueToDuration": {
|
||||
"message": "隐藏:过短"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "频道 ID 尚未加载。"
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "似乎某些东西正在阻止 SponsorBlock 获取视频数据的功能。它很可能是您的广告拦截器。请查看 https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "如果这种情况不断发生,它可能是由您的广告拦截器引起的。请查看 https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "跳过赞助商广告前强制进行频道检查"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "默认情况下,即使还未检测出当前是什么频道,也会立即跳过赞助商广告。默认情况下,即使在白名单中的频道,一些在开头的赞助商广告也可能被跳过。启用此选项将防止这种情况,但所有的跳过将会产生轻微的延迟,因为获取频道 ID 需要一点时间。如果您的网速很快,那延迟可能非常短。"
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "请考虑启用跳过赞助商广告前强制进行频道检查"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "不正确"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "错误的类别"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "此视频被归类为音乐。您确定要提交带有非音乐类别的片段吗?除非此视频实际上不是音乐,否则您不应提交此片段。如果您感到困惑,请阅读指南。"
|
||||
}
|
||||
}
|
||||
1
public/_locales/zh_TW/messages.json
Normal file
1
public/_locales/zh_TW/messages.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -11,11 +11,28 @@
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.sbHidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
.previewbar {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Preview Bar page hacks */
|
||||
|
||||
.sbTooltipTwoTitleThumbnailOffset {
|
||||
bottom: -5px !important;
|
||||
}
|
||||
|
||||
.sbTooltipOneTitleThumbnailOffset {
|
||||
bottom: 10px !important;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
.popup {
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
@@ -80,11 +97,15 @@
|
||||
|
||||
border-radius: 5px;
|
||||
|
||||
animation: fadeIn 0.5s;
|
||||
|
||||
border-spacing: 5px 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
|
||||
border-collapse: unset;
|
||||
}
|
||||
|
||||
.sponsorSkipNoticeFadeIn {
|
||||
animation: fadeIn 0.5s;
|
||||
}
|
||||
|
||||
.sponsorSkipNoticeFadeOut {
|
||||
@@ -312,3 +333,65 @@
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
/* Submission Notice */
|
||||
|
||||
.sponsorTimeDisplay {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.sponsorTimeEditButton {
|
||||
text-decoration: underline;
|
||||
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
|
||||
font-size: 13px;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sponsorTimeEdit > input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sponsorTimeMessagesRow {
|
||||
max-height: 300px;
|
||||
display: flex;
|
||||
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.sponsorTimeEdit {
|
||||
font-size: 14px;
|
||||
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.sponsorTimeEditMinutes {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.sponsorTimeEditSeconds {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.sponsorNowButton {
|
||||
font-size: 11px;
|
||||
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sponsorTimeCategories {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
background-color: rgba(28, 28, 28, 0.9);
|
||||
border-color: rgb(130,0,0,0.9);
|
||||
color: white;
|
||||
border-width: 3px;
|
||||
padding: 3px;
|
||||
}
|
||||
BIN
public/icons/beep.ogg
Normal file
BIN
public/icons/beep.ogg
Normal file
Binary file not shown.
@@ -324,3 +324,26 @@ svg {
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* React styles */
|
||||
|
||||
.categoryTableElement {
|
||||
font-size: 16px;
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
.categoryTableElement > * {
|
||||
padding-right: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.categoryOptionsSelector {
|
||||
background-color: #c00000;
|
||||
color: white;
|
||||
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
@@ -24,6 +24,13 @@
|
||||
|
||||
<div id="options" class="hidden">
|
||||
|
||||
<div id="category-type" option-type="react-CategoryChooserComponent">
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div id="support-invidious" option-type="toggle" sync-option="supportInvidious">
|
||||
<label class="switch-container" label-name="__MSG_supportInvidious__">
|
||||
<label class="switch">
|
||||
@@ -77,24 +84,6 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="disableAutoSkip">
|
||||
<label class="switch-container" label-name="__MSG_autoSkip__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_autoSkipDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<div option-type="keybind-change" sync-option="startSponsorKeybind">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_setStartSponsorShortcut__
|
||||
@@ -231,6 +220,23 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="audioNotificationOnSkip">
|
||||
<label class="switch-container" label-name="__MSG_audioNotification__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_audioNotificationDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="autoUpvote">
|
||||
<label class="switch-container" label-name="__MSG_enableAutoUpvote__">
|
||||
<label class="switch">
|
||||
@@ -308,6 +314,62 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="private-text-change" sync-option="*" confirm-message="exportOptionsWarning">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_exportOptions__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatExportOptions__</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<input class="option-text-box" type="text">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="option-button text-change-set">
|
||||
__MSG_setOptions__
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="button-press" sync-option="copyDebugInformation" confirm-message="copyDebugInformation">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_copyDebugInformation__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_copyDebugInformationOptions__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="testingServer" confirm-message="testingServerWarning">
|
||||
<label class="switch-container" label-name="__MSG_enableTestingServer__">
|
||||
<label class="switch">
|
||||
<input type="checkbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatEnableTestingServer__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="text-change" sync-option="serverAddress">
|
||||
<label class="text-label-container">
|
||||
<div>__MSG_customServerAddress__</div>
|
||||
|
||||
@@ -39,10 +39,8 @@ sub.popupElement {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.popupElement {
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
|
||||
color: black;
|
||||
.logoText {
|
||||
color: white;
|
||||
}
|
||||
|
||||
h1.popupElement {
|
||||
@@ -52,12 +50,21 @@ h1.popupElement {
|
||||
|
||||
.popupBody {
|
||||
font-size: 14px;
|
||||
background-color: #ffd9d9;
|
||||
background-color: #333;
|
||||
padding: 0px 5px;
|
||||
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
.outerPopupBody {
|
||||
background-color: #222626;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.discreteLink.popupElement {
|
||||
color: black;
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
.recordingSubtitle.popupElement {
|
||||
@@ -102,7 +109,7 @@ h1.popupElement {
|
||||
}
|
||||
|
||||
.whitelistButton.popupElement {
|
||||
background-color:#3acc3a;
|
||||
background-color:#27a52d;
|
||||
-moz-border-radius:28px;
|
||||
-webkit-border-radius:28px;
|
||||
border-radius:28px;
|
||||
@@ -114,13 +121,15 @@ h1.popupElement {
|
||||
padding:8px 37px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 0px 0px #27663c;
|
||||
}
|
||||
|
||||
transition: 0.01s background-color;
|
||||
}
|
||||
.whitelistButton:hover.popupElement {
|
||||
background-color:#218b26;
|
||||
background-color:#3acc3a;
|
||||
}
|
||||
.whitelistButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#218b26;
|
||||
background-color:#3acc3a;
|
||||
}
|
||||
.whitelistButton:active.popupElement {
|
||||
position:relative;
|
||||
@@ -128,25 +137,27 @@ h1.popupElement {
|
||||
}
|
||||
|
||||
.greenButton.popupElement {
|
||||
background-color:#ec1c1c;
|
||||
background-color:#cc1717;
|
||||
-moz-border-radius:28px;
|
||||
-webkit-border-radius:28px;
|
||||
border-radius:28px;
|
||||
border:1px solid #d31919;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
font-size:16px;
|
||||
padding:8px 37px;
|
||||
text-decoration:none;
|
||||
text-shadow:0px 0px 0px #662727;
|
||||
text-shadow:0px 0px 0px #662727;
|
||||
|
||||
transition: 0.01s background-color;
|
||||
}
|
||||
.greenButton:hover.popupElement {
|
||||
background-color:#bf2a2a;
|
||||
background-color:#ec1c1c;
|
||||
}
|
||||
.greenButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#bf2a2a;
|
||||
background-color:#ec1c1c;
|
||||
}
|
||||
.greenButton:active.popupElement {
|
||||
position:relative;
|
||||
@@ -154,14 +165,11 @@ h1.popupElement {
|
||||
}
|
||||
|
||||
.dangerButton.popupElement {
|
||||
-moz-box-shadow:inset 0px 1px 0px 0px #cf866c;
|
||||
-webkit-box-shadow:inset 0px 1px 0px 0px #cf866c;
|
||||
box-shadow:inset 0px 1px 0px 0px #cf866c;
|
||||
background-color:#d0451b;
|
||||
background-color:#bc3315;
|
||||
-moz-border-radius:3px;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
border:1px solid #942911;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
@@ -171,11 +179,11 @@ h1.popupElement {
|
||||
text-shadow:0px 1px 0px #854629;
|
||||
}
|
||||
.dangerButton:hover.popupElement {
|
||||
background-color:#bc3315;
|
||||
background-color:#d0451b;
|
||||
}
|
||||
.dangerButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#bc3315;
|
||||
background-color:#d0451b;
|
||||
}
|
||||
.dangerButton:active.popupElement {
|
||||
position:relative;
|
||||
@@ -183,14 +191,11 @@ h1.popupElement {
|
||||
}
|
||||
|
||||
.warningButton.popupElement {
|
||||
-moz-box-shadow:inset 0px 1px 0px 0px #cfbd6c;
|
||||
-webkit-box-shadow:inset 0px 1px 0px 0px #cfbd6c;
|
||||
box-shadow:inset 0px 1px 0px 0px #cfbd6c;
|
||||
background-color:#d0821b;
|
||||
background-color:#bc8215;
|
||||
-moz-border-radius:3px;
|
||||
-webkit-border-radius:3px;
|
||||
border-radius:3px;
|
||||
border:1px solid #948b11;
|
||||
border: none;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
color:#ffffff;
|
||||
@@ -200,11 +205,11 @@ h1.popupElement {
|
||||
text-shadow:0px 1px 0px #856829;
|
||||
}
|
||||
.warningButton:hover.popupElement {
|
||||
background-color:#bc8215;
|
||||
background-color:#d0821b;
|
||||
}
|
||||
.warningButton:focus.popupElement {
|
||||
outline: none;
|
||||
background-color:#bc8215;
|
||||
background-color:#d0821b;
|
||||
}
|
||||
.warningButton:active.popupElement {
|
||||
position:relative;
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<link id="sponsorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/>
|
||||
</head>
|
||||
|
||||
<body class="popupBody">
|
||||
<body class="outerPopupBody">
|
||||
<center>
|
||||
<div id="app" class="popupBody sponsorBlockPageBody">
|
||||
<h1 class="popupElement">
|
||||
<h1 class="popupElement logoText">
|
||||
<img src="icons/IconSponsorBlocker256px.png" height="32px" id="sponsorBlockPopupLogo"/>
|
||||
__MSG_Name__
|
||||
</h1>
|
||||
@@ -39,29 +39,15 @@
|
||||
|
||||
<div id="submissionSection" class="popupElement" style="display: none">
|
||||
<h3 class="popupElement">__MSG_lastTimes__</h3>
|
||||
<b>
|
||||
<div id="sponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
</b>
|
||||
<b>Sponsor Editing has been moved and will appear after you click submit</b>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="clearTimes" class="smallButton popupElement">__MSG_clearTimesButton__</button>
|
||||
|
||||
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="submitTimes" class="smallButton popupElement">__MSG_submitTimesButton__</button>
|
||||
|
||||
<div id="submitTimesInfoMessageContainer" class="popupElement" style="display: none">
|
||||
<h3 id="submitTimesInfoMessage" class="popupElement">
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -85,6 +71,10 @@
|
||||
|
||||
<button id="whitelistChannel" class="whitelistButton popupElement">__MSG_whitelistChannel__</button>
|
||||
<button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">__MSG_removeFromWhitelist__</button>
|
||||
|
||||
<div id="whitelistForceCheck" style="text-decoration: underline; cursor: pointer;display: none">
|
||||
__MSG_forceChannelCheckPopup__
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
@@ -145,7 +135,7 @@
|
||||
<span id="sponsorTimesSkipsDoneDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesSkipsDoneEndWord" class="popupElement">__MSG_Segments__</span> (since February).
|
||||
<span id="sponsorTimesSkipsDoneEndWord" class="popupElement">__MSG_Segments__</span>
|
||||
</div>
|
||||
|
||||
<div id="sponsorTimeSavedContainer" class="popupElement" style="display: none">
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as Types from "./types";
|
||||
|
||||
import Config from "./config";
|
||||
// Make the config public for debugging purposes
|
||||
(<any> window).SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
var utils = new Utils({
|
||||
@@ -28,11 +31,6 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
case "openConfig":
|
||||
chrome.runtime.openOptionsPage();
|
||||
return
|
||||
case "submitTimes":
|
||||
submitTimes(request.videoID, callback);
|
||||
|
||||
//this allows the callback to be called later by the submitTimes function
|
||||
return true;
|
||||
case "addSponsorTime":
|
||||
addSponsorTime(request.time, request.videoID, callback);
|
||||
|
||||
@@ -49,7 +47,7 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "submitVote":
|
||||
submitVote(request.type, request.UUID, callback);
|
||||
submitVote(request.type, request.UUID, request.category, callback);
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
@@ -85,10 +83,6 @@ chrome.runtime.onInstalled.addListener(function (object) {
|
||||
const newUserID = utils.generateUserID();
|
||||
//save this UUID
|
||||
Config.config.userID = newUserID;
|
||||
|
||||
//TODO: Remove when mobile support is old
|
||||
// Don't show this to new users
|
||||
// Config.config.mobileUpdateShowCount = 1;
|
||||
}
|
||||
}, 1500);
|
||||
});
|
||||
@@ -153,7 +147,7 @@ function addSponsorTime(time, videoID, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function submitVote(type, UUID, callback) {
|
||||
function submitVote(type, UUID, category, callback) {
|
||||
let userID = Config.config.userID;
|
||||
|
||||
if (userID == undefined || userID === "undefined") {
|
||||
@@ -162,8 +156,10 @@ function submitVote(type, UUID, callback) {
|
||||
Config.config.userID = userID;
|
||||
}
|
||||
|
||||
let typeSection = (type !== undefined) ? "&type=" + type : "&category=" + category;
|
||||
|
||||
//publish this vote
|
||||
utils.sendRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
|
||||
utils.sendRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + typeSection, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
callback({
|
||||
successType: 1
|
||||
@@ -184,57 +180,3 @@ function submitVote(type, UUID, callback) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function submitTimes(videoID, callback) {
|
||||
//get the video times from storage
|
||||
let sponsorTimes = Config.config.sponsorTimes.get(videoID);
|
||||
let userID = Config.config.userID;
|
||||
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||
let durationResult = <Types.videoDurationResponse> await new Promise((resolve, reject) => {
|
||||
chrome.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, function(tabs) {
|
||||
chrome.tabs.sendMessage(tabs[0].id, {
|
||||
message: "getVideoDuration"
|
||||
}, (response) => resolve(response));
|
||||
});
|
||||
});
|
||||
|
||||
//check if a sponsor exceeds the duration of the video
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i][1] > durationResult.duration) {
|
||||
sponsorTimes[i][1] = durationResult.duration;
|
||||
}
|
||||
}
|
||||
|
||||
//submit these times
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
//to prevent it from happeneing twice
|
||||
let increasedContributionAmount = false;
|
||||
|
||||
//submit the sponsorTime
|
||||
utils.sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
|
||||
+ "&userID=" + userID, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && !error) {
|
||||
callback({
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
|
||||
if (xmlhttp.status == 200) {
|
||||
//save the amount contributed
|
||||
if (!increasedContributionAmount) {
|
||||
increasedContributionAmount = true;
|
||||
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimes.length;
|
||||
}
|
||||
} else if (error) {
|
||||
callback({
|
||||
statusCode: -1
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/components/CategoryChooserComponent.tsx
Normal file
53
src/components/CategoryChooserComponent.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import * as React from "react";
|
||||
|
||||
import Config from "../config"
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import CategorySkipOptionsComponent from "./CategorySkipOptionsComponent";
|
||||
|
||||
export interface CategoryChooserProps {
|
||||
|
||||
}
|
||||
|
||||
export interface CategoryChooserState {
|
||||
|
||||
}
|
||||
|
||||
class CategoryChooserComponent extends React.Component<CategoryChooserProps, CategoryChooserState> {
|
||||
|
||||
constructor(props: CategoryChooserProps) {
|
||||
super(props);
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<table id="categoryChooserTable"
|
||||
className="categoryChooserTable">
|
||||
<tbody>
|
||||
{this.getCategorySkipOptions()}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
getCategorySkipOptions(): JSX.Element[] {
|
||||
let elements: JSX.Element[] = [];
|
||||
|
||||
for (const category of CompileConfig.categoryList) {
|
||||
elements.push(
|
||||
<CategorySkipOptionsComponent category={category}
|
||||
defaultColor={"00d400"}
|
||||
key={category}>
|
||||
</CategorySkipOptionsComponent>
|
||||
);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
||||
export default CategoryChooserComponent;
|
||||
130
src/components/CategorySkipOptionsComponent.tsx
Normal file
130
src/components/CategorySkipOptionsComponent.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import * as React from "react";
|
||||
|
||||
import Config from "../config"
|
||||
import { CategorySkipOption } from "../types";
|
||||
|
||||
export interface CategorySkipOptionsProps {
|
||||
category: string;
|
||||
defaultColor: string;
|
||||
}
|
||||
|
||||
export interface CategorySkipOptionsState {
|
||||
color: string;
|
||||
}
|
||||
|
||||
class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsProps, CategorySkipOptionsState> {
|
||||
|
||||
constructor(props: CategorySkipOptionsProps) {
|
||||
super(props);
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
color: props.defaultColor
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let defaultOption = "disable";
|
||||
// Set the default opton properly
|
||||
for (const categorySelection of Config.config.categorySelections) {
|
||||
if (categorySelection.name === this.props.category) {
|
||||
switch (categorySelection.option) {
|
||||
case CategorySkipOption.ShowOverlay:
|
||||
defaultOption = "showOverlay";
|
||||
break;
|
||||
case CategorySkipOption.ManualSkip:
|
||||
defaultOption = "manualSkip";
|
||||
break;
|
||||
case CategorySkipOption.AutoSkip:
|
||||
defaultOption = "autoSkip";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<tr id={this.props.category + "OptionsRow"}
|
||||
className="categoryTableElement">
|
||||
<td id={this.props.category + "OptionName"}
|
||||
className="categoryTableLabel">
|
||||
{chrome.i18n.getMessage("category_" + this.props.category)}
|
||||
</td>
|
||||
|
||||
<td id={this.props.category + "SkipOption"}>
|
||||
<select
|
||||
className="categoryOptionsSelector"
|
||||
defaultValue={defaultOption}
|
||||
onChange={this.skipOptionSelected.bind(this)}>
|
||||
{this.getCategorySkipOptions()}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
{/* TODO: Add colour chooser */}
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
skipOptionSelected(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
let option: CategorySkipOption;
|
||||
|
||||
this.removeCurrentCategorySelection();
|
||||
|
||||
switch (event.target.value) {
|
||||
case "disable":
|
||||
return;
|
||||
case "showOverlay":
|
||||
option = CategorySkipOption.ShowOverlay;
|
||||
|
||||
break;
|
||||
case "manualSkip":
|
||||
option = CategorySkipOption.ManualSkip;
|
||||
|
||||
break;
|
||||
case "autoSkip":
|
||||
option = CategorySkipOption.AutoSkip;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Config.config.categorySelections.push({
|
||||
name: this.props.category,
|
||||
option: option
|
||||
});
|
||||
|
||||
// Forces the Proxy to send this to the chrome storage API
|
||||
Config.config.categorySelections = Config.config.categorySelections;
|
||||
}
|
||||
|
||||
/** Removes this category from the config list of category selections */
|
||||
removeCurrentCategorySelection(): void {
|
||||
// Remove it if it exists
|
||||
for (let i = 0; i < Config.config.categorySelections.length; i++) {
|
||||
if (Config.config.categorySelections[i].name === this.props.category) {
|
||||
Config.config.categorySelections.splice(i, 1);
|
||||
|
||||
// Forces the Proxy to send this to the chrome storage API
|
||||
Config.config.categorySelections = Config.config.categorySelections;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getCategorySkipOptions(): JSX.Element[] {
|
||||
let elements: JSX.Element[] = [];
|
||||
""
|
||||
let optionNames = ["disable", "showOverlay", "manualSkip", "autoSkip"];
|
||||
|
||||
for (const optionName of optionNames) {
|
||||
elements.push(
|
||||
<option key={optionName} value={optionName}>
|
||||
{chrome.i18n.getMessage(optionName)}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
||||
export default CategorySkipOptionsComponent;
|
||||
246
src/components/NoticeComponent.tsx
Normal file
246
src/components/NoticeComponent.tsx
Normal file
@@ -0,0 +1,246 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface NoticeProps {
|
||||
noticeTitle: string,
|
||||
|
||||
maxCountdownTime?: () => number,
|
||||
amountOfPreviousNotices?: number,
|
||||
timed?: boolean,
|
||||
idSuffix?: string,
|
||||
|
||||
fadeIn?: boolean,
|
||||
|
||||
// Callback for when this is closed
|
||||
closeListener: () => void,
|
||||
|
||||
zIndex?: number
|
||||
}
|
||||
|
||||
export interface NoticeState {
|
||||
noticeTitle: string,
|
||||
|
||||
maxCountdownTime?: () => number,
|
||||
|
||||
countdownTime: number,
|
||||
countdownText: string,
|
||||
}
|
||||
|
||||
class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
countdownInterval: NodeJS.Timeout;
|
||||
idSuffix: any;
|
||||
|
||||
amountOfPreviousNotices: number;
|
||||
|
||||
constructor(props: NoticeProps) {
|
||||
super(props);
|
||||
|
||||
let maxCountdownTime = () => {
|
||||
if (this.props.maxCountdownTime) return this.props.maxCountdownTime();
|
||||
else return 4;
|
||||
};
|
||||
|
||||
//the id for the setInterval running the countdown
|
||||
this.countdownInterval = null;
|
||||
|
||||
this.amountOfPreviousNotices = props.amountOfPreviousNotices || 0;
|
||||
|
||||
this.idSuffix = props.idSuffix || "";
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
noticeTitle: props.noticeTitle,
|
||||
|
||||
maxCountdownTime,
|
||||
|
||||
//the countdown until this notice closes
|
||||
countdownTime: maxCountdownTime(),
|
||||
countdownText: null,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.startCountdown();
|
||||
}
|
||||
|
||||
render() {
|
||||
let noticeStyle: React.CSSProperties = {
|
||||
zIndex: this.props.zIndex || (50 + this.amountOfPreviousNotices)
|
||||
}
|
||||
|
||||
return (
|
||||
<table id={"sponsorSkipNotice" + this.idSuffix}
|
||||
className={"sponsorSkipObject sponsorSkipNotice" + (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")}
|
||||
style={noticeStyle}
|
||||
onMouseEnter={this.pauseCountdown.bind(this)}
|
||||
onMouseLeave={this.startCountdown.bind(this)}>
|
||||
<tbody>
|
||||
|
||||
{/* First row */}
|
||||
<tr id={"sponsorSkipNoticeFirstRow" + this.idSuffix}>
|
||||
{/* Left column */}
|
||||
<td>
|
||||
{/* Logo */}
|
||||
<img id={"sponsorSkipLogo" + this.idSuffix}
|
||||
className="sponsorSkipLogo sponsorSkipObject"
|
||||
src={chrome.extension.getURL("icons/IconSponsorBlocker256px.png")}>
|
||||
</img>
|
||||
|
||||
<span id={"sponsorSkipMessage" + this.idSuffix}
|
||||
className="sponsorSkipMessage sponsorSkipObject">
|
||||
|
||||
{this.state.noticeTitle}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
{/* Right column */}
|
||||
<td className="sponsorSkipNoticeRightSection"
|
||||
style={{top: "11px"}}>
|
||||
|
||||
{/* Time left */}
|
||||
{this.props.timed ? (
|
||||
<span id={"sponsorSkipNoticeTimeLeft" + this.idSuffix}
|
||||
className="sponsorSkipObject sponsorSkipNoticeTimeLeft">
|
||||
|
||||
{this.state.countdownText || (this.state.countdownTime + "s")}
|
||||
</span>
|
||||
) : ""}
|
||||
|
||||
|
||||
{/* Close button */}
|
||||
<img src={chrome.extension.getURL("icons/close.png")}
|
||||
className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton sponsorSkipNoticeRightButton"
|
||||
onClick={() => this.close()}>
|
||||
</img>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{this.props.children}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
//called every second to lower the countdown before hiding the notice
|
||||
countdown() {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
let countdownTime = this.state.countdownTime - 1;
|
||||
|
||||
if (countdownTime <= 0) {
|
||||
//remove this from setInterval
|
||||
clearInterval(this.countdownInterval);
|
||||
|
||||
//time to close this notice
|
||||
this.close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (countdownTime == 3) {
|
||||
//start fade out animation
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.style.removeProperty("animation");
|
||||
notice.classList.add("sponsorSkipNoticeFadeOut");
|
||||
}
|
||||
|
||||
this.setState({
|
||||
countdownTime
|
||||
})
|
||||
}
|
||||
|
||||
pauseCountdown() {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
//remove setInterval
|
||||
clearInterval(this.countdownInterval);
|
||||
this.countdownInterval = null;
|
||||
|
||||
//reset countdown and inform the user
|
||||
this.setState({
|
||||
countdownTime: this.state.maxCountdownTime(),
|
||||
countdownText: chrome.i18n.getMessage("paused")
|
||||
});
|
||||
|
||||
//remove the fade out class if it exists
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
||||
notice.style.animation = "none";
|
||||
}
|
||||
|
||||
startCountdown() {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
//if it has already started, don't start it again
|
||||
if (this.countdownInterval !== null) return;
|
||||
|
||||
this.setState({
|
||||
countdownTime: this.state.maxCountdownTime(),
|
||||
countdownText: null
|
||||
});
|
||||
|
||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
||||
}
|
||||
|
||||
resetCountdown() {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
this.setState({
|
||||
countdownTime: this.state.maxCountdownTime(),
|
||||
countdownText: null
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param silent If true, the close listener will not be called
|
||||
*/
|
||||
close(silent?: boolean) {
|
||||
//remove setInterval
|
||||
if (this.countdownInterval !== null) clearInterval(this.countdownInterval);
|
||||
|
||||
if (!silent) this.props.closeListener();
|
||||
}
|
||||
|
||||
changeNoticeTitle(title) {
|
||||
this.setState({
|
||||
noticeTitle: title
|
||||
});
|
||||
}
|
||||
|
||||
addNoticeInfoMessage(message: string, message2: string = "") {
|
||||
//TODO: Replace
|
||||
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2");
|
||||
if (previousInfoMessage2 != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2);
|
||||
}
|
||||
|
||||
//add info
|
||||
let thanksForVotingText = document.createElement("p");
|
||||
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
//add element to div
|
||||
document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
|
||||
if (message2 !== undefined) {
|
||||
let thanksForVotingText2 = document.createElement("p");
|
||||
thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2";
|
||||
thanksForVotingText2.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText2.innerText = message2;
|
||||
|
||||
//add element to div
|
||||
document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default NoticeComponent;
|
||||
28
src/components/NoticeTextSectionComponent.tsx
Normal file
28
src/components/NoticeTextSectionComponent.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface NoticeTextSelectionProps {
|
||||
text: string,
|
||||
idSuffix: string
|
||||
}
|
||||
|
||||
export interface NoticeTextSelectionState {
|
||||
|
||||
}
|
||||
|
||||
class NoticeTextSelectionComponent extends React.Component<NoticeTextSelectionProps, NoticeTextSelectionState> {
|
||||
|
||||
constructor(props: NoticeTextSelectionProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<p id={"sponsorTimesInfoMessage" + this.props.idSuffix}
|
||||
className="sponsorTimesInfoMessage">
|
||||
{this.props.text}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NoticeTextSelectionComponent;
|
||||
451
src/components/SkipNoticeComponent.tsx
Normal file
451
src/components/SkipNoticeComponent.tsx
Normal file
@@ -0,0 +1,451 @@
|
||||
import * as React from "react";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import Config from "../config"
|
||||
import { ContentContainer, SponsorHideType } from "../types";
|
||||
|
||||
import Utils from "../utils";
|
||||
var utils = new Utils();
|
||||
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
|
||||
|
||||
export interface SkipNoticeProps {
|
||||
UUID: string;
|
||||
autoSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
closeListener: () => void
|
||||
}
|
||||
|
||||
export interface SkipNoticeState {
|
||||
noticeTitle: string;
|
||||
|
||||
messages: string[];
|
||||
|
||||
countdownTime: number;
|
||||
maxCountdownTime: () => number;
|
||||
countdownText: string;
|
||||
|
||||
unskipText: string;
|
||||
unskipCallback: () => void;
|
||||
|
||||
downvoting: boolean;
|
||||
choosingCategory: boolean;
|
||||
}
|
||||
|
||||
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
|
||||
UUID: string;
|
||||
autoSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
amountOfPreviousNotices: number;
|
||||
audio: HTMLAudioElement;
|
||||
|
||||
idSuffix: any;
|
||||
|
||||
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||
categoryOptionRef: React.RefObject<HTMLSelectElement>;
|
||||
|
||||
// Used to update on config change
|
||||
configListener: () => void;
|
||||
|
||||
constructor(props: SkipNoticeProps) {
|
||||
super(props);
|
||||
this.noticeRef = React.createRef();
|
||||
this.categoryOptionRef = React.createRef();
|
||||
|
||||
this.UUID = props.UUID;
|
||||
this.autoSkip = props.autoSkip;
|
||||
this.contentContainer = props.contentContainer;
|
||||
this.audio = null;
|
||||
|
||||
let noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||
|
||||
if (!this.autoSkip) {
|
||||
noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped");
|
||||
}
|
||||
|
||||
//add notice
|
||||
this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
|
||||
//this is the suffix added at the end of every id
|
||||
this.idSuffix = this.UUID + this.amountOfPreviousNotices;
|
||||
|
||||
if (this.amountOfPreviousNotices > 0) {
|
||||
//another notice exists
|
||||
|
||||
let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
||||
previousNotice.classList.add("secondSkipNotice")
|
||||
}
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
noticeTitle,
|
||||
messages: [],
|
||||
|
||||
//the countdown until this notice closes
|
||||
maxCountdownTime: () => 4,
|
||||
countdownTime: 4,
|
||||
countdownText: null,
|
||||
|
||||
unskipText: chrome.i18n.getMessage("unskip"),
|
||||
unskipCallback: this.unskip.bind(this),
|
||||
|
||||
downvoting: false,
|
||||
choosingCategory: false
|
||||
}
|
||||
|
||||
if (!this.autoSkip) {
|
||||
Object.assign(this.state, this.getUnskippedModeInfo(chrome.i18n.getMessage("skip")));
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (Config.config.audioNotificationOnSkip && this.audio) {
|
||||
this.audio.volume = this.contentContainer().v.volume * 0.1;
|
||||
this.audio.play();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let noticeStyle: React.CSSProperties = {
|
||||
zIndex: 50 + this.amountOfPreviousNotices
|
||||
}
|
||||
if (this.contentContainer().onMobileYouTube) {
|
||||
noticeStyle.bottom = "4em";
|
||||
noticeStyle.transform = "scale(0.8) translate(10%, 10%)";
|
||||
}
|
||||
|
||||
return (
|
||||
<NoticeComponent noticeTitle={this.state.noticeTitle}
|
||||
amountOfPreviousNotices={this.amountOfPreviousNotices}
|
||||
idSuffix={this.idSuffix}
|
||||
fadeIn={true}
|
||||
timed={true}
|
||||
maxCountdownTime={this.state.maxCountdownTime}
|
||||
ref={this.noticeRef}
|
||||
closeListener={() => this.closeListener()}>
|
||||
|
||||
{(Config.config.audioNotificationOnSkip) && <audio ref={(source) => { this.audio = source; }}>
|
||||
<source src={chrome.extension.getURL("icons/beep.ogg")} type="audio/ogg"></source>
|
||||
</audio>}
|
||||
|
||||
{/* Text Boxes */}
|
||||
{this.getMessageBoxes()}
|
||||
|
||||
{/* Bottom Row */}
|
||||
<tr id={"sponsorSkipNoticeSecondRow" + this.idSuffix}>
|
||||
|
||||
{/* Vote Button Container */}
|
||||
<td id={"sponsorTimesVoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorTimesVoteButtonsContainer">
|
||||
|
||||
{/* Report Text */}
|
||||
<span id={"sponsorTimesReportText" + this.idSuffix}
|
||||
className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
|
||||
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||
style={{marginRight: "5px"}}>
|
||||
|
||||
{chrome.i18n.getMessage("reportButtonTitle")}
|
||||
</span>
|
||||
|
||||
{/* Report Button */}
|
||||
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorSkipObject voteButton"
|
||||
src={chrome.extension.getURL("icons/report.png")}
|
||||
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||
onClick={() => this.adjustDownvotingState(true)}>
|
||||
|
||||
</img>
|
||||
|
||||
</td>
|
||||
|
||||
{/* Unskip Button */}
|
||||
<td className="sponsorSkipNoticeUnskipSection">
|
||||
<button id={"sponsorSkipUnskipButton" + this.idSuffix}
|
||||
className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
style={{marginLeft: "4px"}}
|
||||
onClick={this.state.unskipCallback}>
|
||||
|
||||
{this.state.unskipText}
|
||||
</button>
|
||||
</td>
|
||||
|
||||
{/* Never show button if autoSkip is enabled */}
|
||||
{!this.autoSkip ? "" :
|
||||
<td className="sponsorSkipNoticeRightSection">
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"
|
||||
onClick={this.contentContainer().dontShowNoticeAgain}>
|
||||
|
||||
{chrome.i18n.getMessage("Hide")}
|
||||
</button>
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
|
||||
{/* Downvote Options Row */}
|
||||
{this.state.downvoting &&
|
||||
<tr id={"sponsorSkipNoticeDownvoteOptionsRow" + this.idSuffix}>
|
||||
<td id={"sponsorTimesDownvoteOptionsContainer" + this.idSuffix}>
|
||||
|
||||
{/* Normal downvote */}
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.contentContainer().vote(0, this.UUID, undefined, this)}>
|
||||
{chrome.i18n.getMessage("downvoteDescription")}
|
||||
</button>
|
||||
|
||||
{/* Category vote */}
|
||||
{Config.config.testingServer &&
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.openCategoryChooser()}>
|
||||
|
||||
{chrome.i18n.getMessage("incorrectCategory")}
|
||||
</button>
|
||||
}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
}
|
||||
|
||||
{/* Category Chooser Row */}
|
||||
{this.state.choosingCategory &&
|
||||
<tr id={"sponsorSkipNoticeCategoryChooserRow" + this.idSuffix}>
|
||||
<td>
|
||||
{/* Category Selector */}
|
||||
<select id={"sponsorTimeCategories" + this.idSuffix}
|
||||
className="sponsorTimeCategories"
|
||||
defaultValue={utils.getSponsorTimeFromUUID(this.props.contentContainer().sponsorTimes, this.props.UUID).category}
|
||||
ref={this.categoryOptionRef}
|
||||
onChange={this.categorySelectionChange.bind(this)}>
|
||||
|
||||
{this.getCategoryOptions()}
|
||||
</select>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.contentContainer().vote(undefined, this.UUID, this.categoryOptionRef.current.value, this)}>
|
||||
|
||||
{chrome.i18n.getMessage("submit")}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
</NoticeComponent>
|
||||
);
|
||||
}
|
||||
|
||||
getMessageBoxes(): JSX.Element[] | JSX.Element {
|
||||
if (this.state.messages.length === 0) {
|
||||
// Add a spacer if there is no text
|
||||
return (
|
||||
<tr id={"sponsorSkipNoticeSpacer" + this.idSuffix}
|
||||
className="sponsorBlockSpacer">
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
let elements: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < this.state.messages.length; i++) {
|
||||
elements.push(
|
||||
<NoticeTextSelectionComponent idSuffix={this.idSuffix}
|
||||
text={this.state.messages[i]}
|
||||
key={i}>
|
||||
</NoticeTextSelectionComponent>
|
||||
)
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
adjustDownvotingState(value: boolean) {
|
||||
if (!value) this.clearConfigListener();
|
||||
|
||||
this.setState({
|
||||
downvoting: value,
|
||||
choosingCategory: false
|
||||
});
|
||||
}
|
||||
|
||||
clearConfigListener() {
|
||||
if (this.configListener) {
|
||||
Config.configListeners.splice(Config.configListeners.indexOf(this.configListener), 1);
|
||||
this.configListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
openCategoryChooser() {
|
||||
// Add as a config listener
|
||||
this.configListener = () => this.forceUpdate();
|
||||
Config.configListeners.push(this.configListener);
|
||||
|
||||
this.setState({
|
||||
choosingCategory: true,
|
||||
downvoting: false
|
||||
});
|
||||
}
|
||||
|
||||
getCategoryOptions() {
|
||||
let elements = [];
|
||||
|
||||
for (const category of Config.config.categorySelections) {
|
||||
elements.push(
|
||||
<option value={category.name}
|
||||
key={category.name}>
|
||||
{chrome.i18n.getMessage("category_" + category.name)}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
if (elements.length < CompileConfig.categoryList.length) {
|
||||
// Add show more button
|
||||
elements.push(
|
||||
<option value={"moreCategories"}
|
||||
key={"moreCategories"}>
|
||||
{chrome.i18n.getMessage("moreCategories")}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||
// See if show more categories was pressed
|
||||
if (event.target.value === "moreCategories") {
|
||||
// Open options page
|
||||
chrome.runtime.sendMessage({"message": "openConfig"});
|
||||
|
||||
// Reset option to original
|
||||
event.target.value = utils.getSponsorTimeFromUUID(this.props.contentContainer().sponsorTimes, this.props.UUID).category;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unskip() {
|
||||
this.contentContainer().unskipSponsorTime(this.UUID);
|
||||
|
||||
this.unskippedMode(chrome.i18n.getMessage("reskip"));
|
||||
}
|
||||
|
||||
/** Sets up notice to be not skipped yet */
|
||||
unskippedMode(buttonText: string) {
|
||||
//setup new callback and reset countdown
|
||||
this.setState(this.getUnskippedModeInfo(buttonText), () => {
|
||||
this.noticeRef.current.resetCountdown();
|
||||
});
|
||||
}
|
||||
|
||||
getUnskippedModeInfo(buttonText: string) {
|
||||
let maxCountdownTime = function() {
|
||||
let sponsorTime = utils.getSponsorTimeFromUUID(this.contentContainer().sponsorTimes, this.UUID);
|
||||
let duration = Math.round((sponsorTime.segment[1] - this.contentContainer().v.currentTime) * (1 / this.contentContainer().v.playbackRate));
|
||||
|
||||
return Math.max(duration, 4);
|
||||
}.bind(this);
|
||||
|
||||
return {
|
||||
unskipText: buttonText,
|
||||
|
||||
unskipCallback: this.reskip.bind(this),
|
||||
|
||||
//change max duration to however much of the sponsor is left
|
||||
maxCountdownTime: maxCountdownTime,
|
||||
|
||||
countdownTime: maxCountdownTime()
|
||||
}
|
||||
}
|
||||
|
||||
reskip() {
|
||||
this.contentContainer().reskipSponsorTime(this.UUID);
|
||||
|
||||
//reset countdown
|
||||
this.setState({
|
||||
unskipText: chrome.i18n.getMessage("unskip"),
|
||||
unskipCallback: this.unskip.bind(this),
|
||||
|
||||
maxCountdownTime: () => 4,
|
||||
countdownTime: 4
|
||||
});
|
||||
|
||||
// See if the title should be changed
|
||||
if (!this.autoSkip) {
|
||||
this.setState({
|
||||
noticeTitle: chrome.i18n.getMessage("noticeTitle")
|
||||
});
|
||||
|
||||
if(Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
afterDownvote(type: number, category: string) {
|
||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||
this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
|
||||
|
||||
this.adjustDownvotingState(false);
|
||||
|
||||
// Change the sponsor locally
|
||||
let sponsorTime = utils.getSponsorTimeFromUUID(this.contentContainer().sponsorTimes, this.UUID);
|
||||
if (sponsorTime) {
|
||||
if (type === 0) {
|
||||
sponsorTime.hidden = SponsorHideType.Downvoted;
|
||||
} else if (category) {
|
||||
sponsorTime.category = category;
|
||||
}
|
||||
|
||||
this.contentContainer().updatePreviewBar();
|
||||
}
|
||||
}
|
||||
|
||||
setNoticeInfoMessage(...messages: string[]) {
|
||||
this.setState({
|
||||
messages
|
||||
})
|
||||
}
|
||||
|
||||
addVoteButtonInfo(message) {
|
||||
this.resetVoteButtonInfo();
|
||||
|
||||
//hide report button and text for it
|
||||
let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
|
||||
if (downvoteButton != null) {
|
||||
downvoteButton.style.display = "none";
|
||||
}
|
||||
let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
|
||||
if (downvoteButtonText != null) {
|
||||
downvoteButtonText.style.display = "none";
|
||||
}
|
||||
|
||||
//add info
|
||||
let thanksForVotingText = document.createElement("td");
|
||||
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
|
||||
}
|
||||
|
||||
resetVoteButtonInfo() {
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
//show button again
|
||||
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
|
||||
}
|
||||
|
||||
closeListener() {
|
||||
this.clearConfigListener();
|
||||
|
||||
this.props.closeListener();
|
||||
}
|
||||
}
|
||||
|
||||
export default SkipNoticeComponent;
|
||||
369
src/components/SponsorTimeEditComponent.tsx
Normal file
369
src/components/SponsorTimeEditComponent.tsx
Normal file
@@ -0,0 +1,369 @@
|
||||
import * as React from "react";
|
||||
|
||||
import Config from "../config";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
|
||||
import Utils from "../utils";
|
||||
import { ContentContainer, SponsorTime } from "../types";
|
||||
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||
var utils = new Utils();
|
||||
|
||||
export interface SponsorTimeEditProps {
|
||||
index: number,
|
||||
|
||||
idSuffix: string,
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer,
|
||||
|
||||
submissionNotice: SubmissionNoticeComponent;
|
||||
}
|
||||
|
||||
export interface SponsorTimeEditState {
|
||||
editing: boolean;
|
||||
sponsorTimeEdits: string[][];
|
||||
}
|
||||
|
||||
class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, SponsorTimeEditState> {
|
||||
|
||||
idSuffix: string;
|
||||
|
||||
categoryOptionRef: React.RefObject<HTMLSelectElement>;
|
||||
|
||||
configUpdateListener: () => void;
|
||||
|
||||
constructor(props: SponsorTimeEditProps) {
|
||||
super(props);
|
||||
|
||||
this.categoryOptionRef = React.createRef();
|
||||
|
||||
this.idSuffix = this.props.idSuffix;
|
||||
|
||||
this.state = {
|
||||
editing: false,
|
||||
sponsorTimeEdits: [[null, null], [null, null]]
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Prevent inputs from triggering key events
|
||||
document.getElementById("sponsorTimesContainer" + this.idSuffix).addEventListener('keydown', function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Add as a config listener
|
||||
if (!this.configUpdateListener) {
|
||||
this.configUpdateListener = () => this.configUpdate();
|
||||
Config.configListeners.push(this.configUpdate.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.configUpdateListener) {
|
||||
Config.configListeners.splice(Config.configListeners.indexOf(this.configUpdate.bind(this)), 1);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let style: React.CSSProperties = {
|
||||
textAlign: "center"
|
||||
};
|
||||
|
||||
if (this.props.index != 0) {
|
||||
style.marginTop = "15px";
|
||||
}
|
||||
|
||||
// This method is required to get !important
|
||||
// https://stackoverflow.com/a/45669262/1985387
|
||||
let oldYouTubeDarkStyles = (node) => {
|
||||
if (node) {
|
||||
node.style.setProperty("color", "black", "important");
|
||||
node.style.setProperty("text-shadow", "none", "important");
|
||||
}
|
||||
};
|
||||
|
||||
// Create time display
|
||||
let timeDisplay: JSX.Element;
|
||||
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
let segment = sponsorTime.segment;
|
||||
if (this.state.editing) {
|
||||
timeDisplay = (
|
||||
<div id={"sponsorTimesContainer" + this.idSuffix}
|
||||
className="sponsorTimeDisplay">
|
||||
|
||||
<span id={"nowButton0" + this.idSuffix}
|
||||
className="sponsorNowButton"
|
||||
onClick={() => this.setTimeToNow(0)}>
|
||||
{chrome.i18n.getMessage("bracketNow")}
|
||||
</span>
|
||||
|
||||
<input id={"submittingTimeMinutes0" + this.idSuffix}
|
||||
className="sponsorTimeEdit sponsorTimeEditMinutes"
|
||||
ref={oldYouTubeDarkStyles}
|
||||
type="number"
|
||||
value={this.state.sponsorTimeEdits[0][0]}
|
||||
onChange={(e) => {
|
||||
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[0][0] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
}}>
|
||||
</input>
|
||||
|
||||
<input id={"submittingTimeSeconds0" + this.idSuffix}
|
||||
className="sponsorTimeEdit sponsorTimeEditSeconds"
|
||||
ref={oldYouTubeDarkStyles}
|
||||
type="number"
|
||||
value={this.state.sponsorTimeEdits[0][1]}
|
||||
onChange={(e) => {
|
||||
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[0][1] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
}}>
|
||||
</input>
|
||||
|
||||
<span>
|
||||
{" " + chrome.i18n.getMessage("to") + " "}
|
||||
</span>
|
||||
|
||||
<input id={"submittingTimeMinutes1" + this.idSuffix}
|
||||
className="sponsorTimeEdit sponsorTimeEditMinutes"
|
||||
ref={oldYouTubeDarkStyles}
|
||||
type="text"
|
||||
value={this.state.sponsorTimeEdits[1][0]}
|
||||
onChange={(e) => {
|
||||
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[1][0] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
}}>
|
||||
</input>
|
||||
|
||||
<input id={"submittingTimeSeconds1" + this.idSuffix}
|
||||
className="sponsorTimeEdit sponsorTimeEditSeconds"
|
||||
ref={oldYouTubeDarkStyles}
|
||||
type="text"
|
||||
value={this.state.sponsorTimeEdits[1][1]}
|
||||
onChange={(e) => {
|
||||
let sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[1][1] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
}}>
|
||||
</input>
|
||||
|
||||
<span id={"nowButton1" + this.idSuffix}
|
||||
className="sponsorNowButton"
|
||||
onClick={() => this.setTimeToNow(1)}>
|
||||
{chrome.i18n.getMessage("bracketNow")}
|
||||
</span>
|
||||
|
||||
<span id={"endButton" + this.idSuffix}
|
||||
className="sponsorNowButton"
|
||||
onClick={() => this.setTimeToEnd()}>
|
||||
{chrome.i18n.getMessage("bracketEnd")}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
timeDisplay = (
|
||||
<div id={"sponsorTimesContainer" + this.idSuffix}
|
||||
className="sponsorTimeDisplay"
|
||||
onClick={this.toggleEditTime.bind(this)}>
|
||||
{utils.getFormattedTime(segment[0], true) +
|
||||
((!isNaN(segment[1])) ? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segment[1], true) : "")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
|
||||
{timeDisplay}
|
||||
|
||||
{/* Category */}
|
||||
|
||||
<select id={"sponsorTimeCategories" + this.idSuffix}
|
||||
className="sponsorTimeCategories"
|
||||
defaultValue={sponsorTime.category}
|
||||
ref={this.categoryOptionRef}
|
||||
onChange={this.categorySelectionChange.bind(this)}>
|
||||
{this.getCategoryOptions()}
|
||||
</select>
|
||||
|
||||
<br/>
|
||||
|
||||
{/* Editing Tools */}
|
||||
|
||||
<span id={"sponsorTimeDeleteButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={this.deleteTime.bind(this)}>
|
||||
{chrome.i18n.getMessage("delete")}
|
||||
</span>
|
||||
|
||||
{(!isNaN(segment[1])) ? (
|
||||
<span id={"sponsorTimePreviewButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={this.previewTime.bind(this)}>
|
||||
{chrome.i18n.getMessage("preview")}
|
||||
</span>
|
||||
): ""}
|
||||
|
||||
{(!isNaN(segment[1])) ? (
|
||||
<span id={"sponsorTimeEditButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={this.toggleEditTime.bind(this)}>
|
||||
{this.state.editing ? chrome.i18n.getMessage("save") : chrome.i18n.getMessage("edit")}
|
||||
</span>
|
||||
): ""}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getCategoryOptions() {
|
||||
let elements = [];
|
||||
|
||||
for (const category of Config.config.categorySelections) {
|
||||
elements.push(
|
||||
<option value={category.name}
|
||||
key={category.name}>
|
||||
{chrome.i18n.getMessage("category_" + category.name)}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
if (elements.length < CompileConfig.categoryList.length) {
|
||||
// Add show more button
|
||||
elements.push(
|
||||
<option value={"moreCategories"}
|
||||
key={"moreCategories"}>
|
||||
{chrome.i18n.getMessage("moreCategories")}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||
// See if show more categories was pressed
|
||||
if (event.target.value === "moreCategories") {
|
||||
// Open options page
|
||||
chrome.runtime.sendMessage({"message": "openConfig"});
|
||||
|
||||
// Reset option to previous
|
||||
event.target.value = this.props.contentContainer().sponsorTimesSubmitting[this.props.index].category;
|
||||
return;
|
||||
}
|
||||
|
||||
this.saveEditTimes();
|
||||
}
|
||||
|
||||
setTimeToNow(index: number) {
|
||||
this.setTimeTo(index, this.props.contentContainer().getRealCurrentTime());
|
||||
}
|
||||
|
||||
setTimeToEnd() {
|
||||
this.setTimeTo(1, this.props.contentContainer().v.duration);
|
||||
}
|
||||
|
||||
setTimeTo(index: number, time: number) {
|
||||
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
|
||||
sponsorTime.segment[index] =
|
||||
time;
|
||||
|
||||
this.setState({
|
||||
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||
}, this.saveEditTimes);
|
||||
}
|
||||
|
||||
toggleEditTime(): void {
|
||||
if (this.state.editing) {
|
||||
|
||||
this.setState({
|
||||
editing: false
|
||||
});
|
||||
|
||||
this.saveEditTimes();
|
||||
} else {
|
||||
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
|
||||
this.setState({
|
||||
editing: true,
|
||||
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns an array in the sponsorTimeEdits form (minutes and seconds) from a normal seconds sponsor time */
|
||||
getFormattedSponsorTimesEdits(sponsorTime: SponsorTime): string[][] {
|
||||
return [[String(utils.getFormattedMinutes(sponsorTime.segment[0])), String(utils.getFormattedSeconds(sponsorTime.segment[0]))],
|
||||
[String(utils.getFormattedMinutes(sponsorTime.segment[1])), String(utils.getFormattedSeconds(sponsorTime.segment[1]))]];
|
||||
}
|
||||
|
||||
saveEditTimes() {
|
||||
let sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
|
||||
if (this.state.editing) {
|
||||
sponsorTimesSubmitting[this.props.index].segment =
|
||||
[utils.getRawSeconds(parseFloat(this.state.sponsorTimeEdits[0][0]), parseFloat(this.state.sponsorTimeEdits[0][1])),
|
||||
utils.getRawSeconds(parseFloat(this.state.sponsorTimeEdits[1][0]), parseFloat(this.state.sponsorTimeEdits[1][1]))];
|
||||
}
|
||||
|
||||
sponsorTimesSubmitting[this.props.index].category = this.categoryOptionRef.current.value;
|
||||
|
||||
Config.config.sponsorTimes.set(this.props.contentContainer().sponsorVideoID, utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting));
|
||||
|
||||
this.props.contentContainer().updatePreviewBar();
|
||||
}
|
||||
|
||||
previewTime(): void {
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
let index = this.props.index;
|
||||
|
||||
let skipTime = sponsorTimes[index].segment[0];
|
||||
|
||||
if (this.state.editing) {
|
||||
// Save edits before previewing
|
||||
this.saveEditTimes();
|
||||
}
|
||||
|
||||
this.props.contentContainer().previewTime(skipTime - 2);
|
||||
}
|
||||
|
||||
deleteTime(): void {
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
let index = this.props.index;
|
||||
|
||||
//if it is not a complete sponsor time
|
||||
if (sponsorTimes[index].segment.length < 2) {
|
||||
//update video player
|
||||
this.props.contentContainer().changeStartSponsorButton(true, false);
|
||||
}
|
||||
|
||||
sponsorTimes.splice(index, 1);
|
||||
|
||||
//save this
|
||||
Config.config.sponsorTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimes);
|
||||
|
||||
this.props.contentContainer().updatePreviewBar();
|
||||
|
||||
//if they are all removed
|
||||
if (sponsorTimes.length == 0) {
|
||||
this.props.submissionNotice.cancel();
|
||||
|
||||
//update video player
|
||||
this.props.contentContainer().changeStartSponsorButton(true, false);
|
||||
} else {
|
||||
//update display
|
||||
this.props.submissionNotice.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
configUpdate() {
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
export default SponsorTimeEditComponent;
|
||||
181
src/components/SubmissionNoticeComponent.tsx
Normal file
181
src/components/SubmissionNoticeComponent.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
import * as React from "react";
|
||||
import Config from "../config"
|
||||
import { ContentContainer } from "../types";
|
||||
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
import SponsorTimeEditComponent from "./SponsorTimeEditComponent";
|
||||
|
||||
export interface SubmissionNoticeProps {
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
callback: () => any;
|
||||
|
||||
closeListener: () => void
|
||||
}
|
||||
|
||||
export interface SubmissionNoticeeState {
|
||||
noticeTitle: string,
|
||||
messages: string[],
|
||||
idSuffix: string;
|
||||
}
|
||||
|
||||
class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, SubmissionNoticeeState> {
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
|
||||
callback: () => any;
|
||||
|
||||
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||
timeEditRefs: React.RefObject<SponsorTimeEditComponent>[];
|
||||
|
||||
videoObserver: MutationObserver;
|
||||
|
||||
constructor(props: SubmissionNoticeProps) {
|
||||
super(props);
|
||||
this.noticeRef = React.createRef();
|
||||
|
||||
this.contentContainer = props.contentContainer;
|
||||
this.callback = props.callback;
|
||||
|
||||
let noticeTitle = chrome.i18n.getMessage("confirmNoticeTitle");
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
noticeTitle,
|
||||
messages: [],
|
||||
idSuffix: "SubmissionNotice"
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Catch and rerender when the video size changes
|
||||
//TODO: Use ResizeObserver when it is supported in TypeScript
|
||||
this.videoObserver = new MutationObserver(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
|
||||
this.videoObserver.observe(this.contentContainer().v, {
|
||||
attributes: true
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.videoObserver) {
|
||||
this.videoObserver.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<NoticeComponent noticeTitle={this.state.noticeTitle}
|
||||
idSuffix={this.state.idSuffix}
|
||||
ref={this.noticeRef}
|
||||
closeListener={this.cancel.bind(this)}
|
||||
zIndex={50000}>
|
||||
|
||||
{/* Text Boxes */}
|
||||
{this.getMessageBoxes()}
|
||||
|
||||
{/* Sponsor Time List */}
|
||||
<tr id={"sponsorSkipNoticeMiddleRow" + this.state.idSuffix}
|
||||
className="sponsorTimeMessagesRow"
|
||||
style={{maxHeight: (this.contentContainer().v.offsetHeight - 200) + "px"}}>
|
||||
<td style={{width: "100%"}}>
|
||||
{this.getSponsorTimeMessages()}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* Last Row */}
|
||||
<tr id={"sponsorSkipNoticeSecondRow" + this.state.idSuffix}>
|
||||
|
||||
<td className="sponsorSkipNoticeRightSection"
|
||||
style={{position: "relative"}}>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"
|
||||
onClick={this.submit.bind(this)}>
|
||||
|
||||
{chrome.i18n.getMessage("submit")}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</NoticeComponent>
|
||||
);
|
||||
}
|
||||
|
||||
getSponsorTimeMessages(): JSX.Element[] | JSX.Element {
|
||||
let elements: JSX.Element[] = [];
|
||||
this.timeEditRefs = [];
|
||||
|
||||
let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
let timeRef = React.createRef<SponsorTimeEditComponent>();
|
||||
|
||||
elements.push(
|
||||
<SponsorTimeEditComponent key={i}
|
||||
idSuffix={this.state.idSuffix + i}
|
||||
index={i}
|
||||
contentContainer={this.props.contentContainer}
|
||||
submissionNotice={this}
|
||||
ref={timeRef}>
|
||||
</SponsorTimeEditComponent>
|
||||
);
|
||||
|
||||
this.timeEditRefs.push(timeRef);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
getMessageBoxes(): JSX.Element[] | JSX.Element {
|
||||
let elements: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < this.state.messages.length; i++) {
|
||||
elements.push(
|
||||
<NoticeTextSelectionComponent idSuffix={this.state.idSuffix + i}
|
||||
text={this.state.messages[i]}
|
||||
key={i}>
|
||||
</NoticeTextSelectionComponent>
|
||||
);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.noticeRef.current.close(true);
|
||||
|
||||
this.contentContainer().resetSponsorSubmissionNotice();
|
||||
|
||||
this.props.closeListener();
|
||||
}
|
||||
|
||||
submit() {
|
||||
// save all items
|
||||
for (const ref of this.timeEditRefs) {
|
||||
ref.current.saveEditTimes();
|
||||
}
|
||||
|
||||
// Check if any non music categories are being used on a music video
|
||||
if (this.contentContainer().videoInfo?.microformat?.playerMicroformatRenderer?.category === "Music") {
|
||||
let sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
for (const sponsorTime of sponsorTimesSubmitting) {
|
||||
if (!sponsorTime.category.startsWith("music_")) {
|
||||
if (!confirm(chrome.i18n.getMessage("nonMusicCategoryOnMusic"))) return;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.props.callback();
|
||||
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
export default SubmissionNoticeComponent;
|
||||
134
src/config.ts
134
src/config.ts
@@ -1,16 +1,20 @@
|
||||
import * as CompileConfig from "../config.json";
|
||||
import { CategorySelection, CategorySkipOption } from "./types";
|
||||
|
||||
import Utils from "./utils";
|
||||
const utils = new Utils();
|
||||
|
||||
interface SBConfig {
|
||||
userID: string,
|
||||
sponsorTimes: SBMap<string, any>,
|
||||
whitelistedChannels: Array<any>,
|
||||
whitelistedChannels: string[],
|
||||
forceChannelCheck: boolean,
|
||||
startSponsorKeybind: string,
|
||||
submitKeybind: string,
|
||||
minutesSaved: number,
|
||||
skipCount: number,
|
||||
sponsorTimesContributed: number,
|
||||
disableSkipping: boolean,
|
||||
disableAutoSkip: boolean,
|
||||
trackViewCount: boolean,
|
||||
dontShowNotice: boolean,
|
||||
hideVideoPlayerControls: boolean,
|
||||
@@ -24,8 +28,13 @@ interface SBConfig {
|
||||
supportInvidious: boolean,
|
||||
serverAddress: string,
|
||||
minDuration: number,
|
||||
audioNotificationOnSkip,
|
||||
checkForUnlistedVideos: boolean,
|
||||
mobileUpdateShowCount: number
|
||||
mobileUpdateShowCount: number,
|
||||
testingServer: boolean,
|
||||
|
||||
// What categories should be skipped
|
||||
categorySelections: CategorySelection[]
|
||||
}
|
||||
|
||||
interface SBObject {
|
||||
@@ -33,6 +42,10 @@ interface SBObject {
|
||||
defaults: SBConfig;
|
||||
localConfig: SBConfig;
|
||||
config: SBConfig;
|
||||
|
||||
// Functions
|
||||
encodeStoredItem<T>(data: T): T | Array<any>;
|
||||
convertJSON(): void;
|
||||
}
|
||||
|
||||
// Allows a SBMap to be conveted into json form
|
||||
@@ -84,13 +97,8 @@ class SBMap<T, U> extends Map {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return Array.from(this.entries());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var Config: SBObject = {
|
||||
/**
|
||||
* Callback function when an option is updated
|
||||
@@ -100,13 +108,13 @@ var Config: SBObject = {
|
||||
userID: null,
|
||||
sponsorTimes: new SBMap("sponsorTimes"),
|
||||
whitelistedChannels: [],
|
||||
forceChannelCheck: false,
|
||||
startSponsorKeybind: ";",
|
||||
submitKeybind: "'",
|
||||
minutesSaved: 0,
|
||||
skipCount: 0,
|
||||
sponsorTimesContributed: 0,
|
||||
disableSkipping: false,
|
||||
disableAutoSkip: false,
|
||||
trackViewCount: true,
|
||||
dontShowNotice: false,
|
||||
hideVideoPlayerControls: false,
|
||||
@@ -115,30 +123,41 @@ var Config: SBObject = {
|
||||
hideUploadButtonPlayerControls: false,
|
||||
hideDiscordLaunches: 0,
|
||||
hideDiscordLink: false,
|
||||
invidiousInstances: ["invidio.us", "invidiou.sh", "invidious.snopyta.org"],
|
||||
invidiousInstances: ["invidio.us", "invidious.snopyta.org"],
|
||||
autoUpvote: true,
|
||||
supportInvidious: false,
|
||||
serverAddress: CompileConfig.serverAddress,
|
||||
minDuration: 0,
|
||||
audioNotificationOnSkip: false,
|
||||
checkForUnlistedVideos: false,
|
||||
mobileUpdateShowCount: 0
|
||||
mobileUpdateShowCount: 0,
|
||||
testingServer: false,
|
||||
|
||||
categorySelections: [{
|
||||
name: "sponsor",
|
||||
option: CategorySkipOption.AutoSkip
|
||||
}]
|
||||
},
|
||||
localConfig: null,
|
||||
config: null
|
||||
config: null,
|
||||
|
||||
// Functions
|
||||
encodeStoredItem,
|
||||
convertJSON
|
||||
};
|
||||
|
||||
// Function setup
|
||||
|
||||
/**
|
||||
* A SBMap cannot be stored in the chrome storage.
|
||||
* This data will be encoded into an array instead as specified by the toJSON function.
|
||||
* This data will be encoded into an array instead
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
function encodeStoredItem(data) {
|
||||
function encodeStoredItem<T>(data: T): T | Array<any> {
|
||||
// if data is SBMap convert to json for storing
|
||||
if(!(data instanceof SBMap)) return data;
|
||||
return JSON.stringify(data);
|
||||
return Array.from(data.entries());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,19 +166,31 @@ function encodeStoredItem(data) {
|
||||
*
|
||||
* @param {*} data
|
||||
*/
|
||||
function decodeStoredItem(id: string, data) {
|
||||
if(typeof data !== "string") return data;
|
||||
function decodeStoredItem<T>(id: string, data: T): T | SBMap<string, any> {
|
||||
if (!Config.defaults[id]) return data;
|
||||
|
||||
try {
|
||||
let str = JSON.parse(data);
|
||||
if (Config.defaults[id] instanceof SBMap) {
|
||||
try {
|
||||
let jsonData: any = data;
|
||||
|
||||
if(!Array.isArray(str)) return data;
|
||||
return new SBMap(id, str);
|
||||
} catch(e) {
|
||||
// Check if data is stored in the old format for SBMap (a JSON string)
|
||||
if (typeof data === "string") {
|
||||
try {
|
||||
jsonData = JSON.parse(data);
|
||||
} catch(e) {
|
||||
// Continue normally (out of this if statement)
|
||||
}
|
||||
}
|
||||
|
||||
// If all else fails, return the data
|
||||
return data;
|
||||
if (!Array.isArray(jsonData)) return data;
|
||||
return new SBMap(id, jsonData);
|
||||
} catch(e) {
|
||||
console.error("Failed to parse SBMap: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
// If all else fails, return the data
|
||||
return data;
|
||||
}
|
||||
|
||||
function configProxy(): any {
|
||||
@@ -210,11 +241,54 @@ function fetchConfig() {
|
||||
});
|
||||
}
|
||||
|
||||
function migrateOldFormats() { // Convert sponsorTimes format
|
||||
for (const key in Config.localConfig) {
|
||||
if (key.startsWith("sponsorTimes") && key !== "sponsorTimes" && key !== "sponsorTimesContributed") {
|
||||
Config.config.sponsorTimes.set(key.substr(12), Config.config[key]);
|
||||
delete Config.config[key];
|
||||
async function migrateOldFormats() {
|
||||
if (Config.config["disableAutoSkip"]) {
|
||||
for (const selection of Config.config.categorySelections) {
|
||||
if (selection.name === "sponsor") {
|
||||
selection.option = CategorySkipOption.ManualSkip;
|
||||
|
||||
chrome.storage.sync.remove("disableAutoSkip");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Channel URLS
|
||||
if (Config.config.whitelistedChannels.length > 0 &&
|
||||
(Config.config.whitelistedChannels[0] == null || Config.config.whitelistedChannels[0].includes("/"))) {
|
||||
let newChannelList: string[] = [];
|
||||
for (const item of Config.config.whitelistedChannels) {
|
||||
if (item != null) {
|
||||
if (item.includes("/channel/")) {
|
||||
newChannelList.push(item.split("/")[2]);
|
||||
} else if (item.includes("/user/") && utils.isContentScript()) {
|
||||
// Replace channel URL with channelID
|
||||
let response = await utils.asyncRequestToCustomServer("GET", "https://sponsor.ajay.app/invidious/api/v1/channels/" + item.split("/")[2] + "?fields=authorId");
|
||||
|
||||
if (response.ok) {
|
||||
newChannelList.push((await response.json()).authorId);
|
||||
} else {
|
||||
// Add it at the beginning so it gets converted later
|
||||
newChannelList.unshift(item);
|
||||
}
|
||||
} else if (item.includes("/user/")) {
|
||||
// Add it at the beginning so it gets converted later (The API can only be called in the content script due to CORS issues)
|
||||
newChannelList.unshift(item);
|
||||
} else {
|
||||
newChannelList.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Config.config.whitelistedChannels = newChannelList;
|
||||
}
|
||||
|
||||
// Check if off-topic category needs to be removed
|
||||
for (let i = 0; i < Config.config.categorySelections.length; i++) {
|
||||
if (Config.config.categorySelections[i].name === "offtopic") {
|
||||
Config.config.categorySelections.splice(i, 1);
|
||||
// Call set listener
|
||||
Config.config.categorySelections = Config.config.categorySelections;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +306,7 @@ function resetConfig() {
|
||||
Config.config = Config.defaults;
|
||||
};
|
||||
|
||||
function convertJSON() {
|
||||
function convertJSON(): void {
|
||||
Object.keys(Config.localConfig).forEach(key => {
|
||||
Config.localConfig[key] = decodeStoredItem(key, Config.localConfig[key]);
|
||||
});
|
||||
|
||||
942
src/content.ts
942
src/content.ts
File diff suppressed because it is too large
Load Diff
@@ -8,15 +8,55 @@
|
||||
let barTypes = {
|
||||
"undefined": {
|
||||
color: "#00d400",
|
||||
opacity: "0.5"
|
||||
opacity: "0.7"
|
||||
},
|
||||
"sponsor": {
|
||||
color: "#00d400",
|
||||
opacity: "0.5"
|
||||
opacity: "0.7"
|
||||
},
|
||||
"previewSponsor": {
|
||||
color: "#0000d4",
|
||||
opacity: "0.5"
|
||||
"preview-sponsor": {
|
||||
color: "#007800",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"intro": {
|
||||
color: "#00ffff",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"preview-intro": {
|
||||
color: "#008080",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"outro": {
|
||||
color: "#0202ed",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"preview-outro": {
|
||||
color: "#000070",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"interaction": {
|
||||
color: "#cc00ff",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"preview-interaction": {
|
||||
color: "#6c0087",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"selfpromo": {
|
||||
color: "#ffff00",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"preview-selfpromo": {
|
||||
color: "#bfbf35",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"music_offtopic": {
|
||||
color: "#ff9900",
|
||||
opacity: "0.7"
|
||||
},
|
||||
"preview-music_offtopic": {
|
||||
color: "#a6634a",
|
||||
opacity: "0.7"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,6 +65,9 @@ class PreviewBar {
|
||||
parent: any;
|
||||
onMobileYouTube: boolean;
|
||||
|
||||
timestamps: number[][];
|
||||
types: string;
|
||||
|
||||
constructor(parent, onMobileYouTube) {
|
||||
this.container = document.createElement('ul');
|
||||
this.container.id = 'previewbar';
|
||||
@@ -33,6 +76,87 @@ class PreviewBar {
|
||||
this.onMobileYouTube = onMobileYouTube;
|
||||
|
||||
this.updatePosition(parent);
|
||||
|
||||
this.setupHoverText();
|
||||
}
|
||||
|
||||
setupHoverText() {
|
||||
let seekBar = document.querySelector(".ytp-progress-bar-container");
|
||||
|
||||
// Create label placeholder
|
||||
let tooltipTextWrapper = document.querySelector(".ytp-tooltip-text-wrapper");
|
||||
let titleTooltip = document.querySelector(".ytp-tooltip-title");
|
||||
let categoryTooltip = document.createElement("div");
|
||||
categoryTooltip.className = "sbHidden ytp-tooltip-title";
|
||||
categoryTooltip.id = "sponsor-block-category-tooltip"
|
||||
|
||||
tooltipTextWrapper.insertBefore(categoryTooltip, titleTooltip.nextSibling);
|
||||
|
||||
let mouseOnSeekBar = false;
|
||||
|
||||
seekBar.addEventListener("mouseenter", (event) => {
|
||||
mouseOnSeekBar = true;
|
||||
});
|
||||
|
||||
seekBar.addEventListener("mouseleave", (event) => {
|
||||
mouseOnSeekBar = false;
|
||||
categoryTooltip.classList.add("sbHidden");
|
||||
});
|
||||
|
||||
const observer = new MutationObserver((mutations, observer) => {
|
||||
if (!mouseOnSeekBar) return;
|
||||
|
||||
// See if mutation observed is only this ID (if so, ignore)
|
||||
if (mutations.length == 1 && (mutations[0].target as HTMLElement).id === "sponsor-block-category-tooltip") {
|
||||
return;
|
||||
}
|
||||
|
||||
let tooltips = document.querySelectorAll(".ytp-tooltip-text");
|
||||
for (const tooltip of tooltips) {
|
||||
let splitData = tooltip.textContent.split(":");
|
||||
if (splitData.length === 2 && !isNaN(parseInt(splitData[0])) && !isNaN(parseInt(splitData[1]))) {
|
||||
// Add label
|
||||
let timeInSeconds = parseInt(splitData[0]) * 60 + parseInt(splitData[1]);
|
||||
|
||||
// Find category at that location
|
||||
let category = null;
|
||||
for (let i = 0; i < this.timestamps?.length; i++) {
|
||||
if (this.timestamps[i][0] < timeInSeconds && this.timestamps[i][1] > timeInSeconds){
|
||||
category = this.types[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (category === null && !categoryTooltip.classList.contains("sbHidden")) {
|
||||
categoryTooltip.classList.add("sbHidden");
|
||||
tooltipTextWrapper.classList.remove("sbTooltipTwoTitleThumbnailOffset");
|
||||
tooltipTextWrapper.classList.remove("sbTooltipOneTitleThumbnailOffset");
|
||||
} else if (category !== null) {
|
||||
categoryTooltip.classList.remove("sbHidden");
|
||||
categoryTooltip.textContent = chrome.i18n.getMessage("category_" + category)
|
||||
|| (chrome.i18n.getMessage("preview") + " " + chrome.i18n.getMessage("category_" + category.split("preview-")[1]));
|
||||
|
||||
// There is a title now
|
||||
tooltip.classList.remove("ytp-tooltip-text-no-title");
|
||||
|
||||
// Add the correct offset for the number of titles there are
|
||||
if (titleTooltip.textContent !== "") {
|
||||
if (!tooltipTextWrapper.classList.contains("sbTooltipTwoTitleThumbnailOffset")) {
|
||||
tooltipTextWrapper.classList.add("sbTooltipTwoTitleThumbnailOffset");
|
||||
}
|
||||
} else if (!tooltipTextWrapper.classList.contains("sbTooltipOneTitleThumbnailOffset")) {
|
||||
tooltipTextWrapper.classList.add("sbTooltipOneTitleThumbnailOffset");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(tooltipTextWrapper, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
|
||||
updatePosition(parent) {
|
||||
@@ -69,6 +193,9 @@ class PreviewBar {
|
||||
return;
|
||||
}
|
||||
|
||||
this.timestamps = timestamps;
|
||||
this.types = types;
|
||||
|
||||
// to avoid rounding error resulting in width more than 100%
|
||||
duration = Math.floor(duration * 100) / 100;
|
||||
let width;
|
||||
|
||||
@@ -1,444 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import Config from "../config";
|
||||
|
||||
/**
|
||||
* The notice that tells the user that a sponsor was just skipped
|
||||
*/
|
||||
class SkipNotice {
|
||||
parent: HTMLElement;
|
||||
UUID: string;
|
||||
manualSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: () => any;
|
||||
|
||||
maxCountdownTime: () => number;
|
||||
countdownTime: any;
|
||||
countdownInterval: NodeJS.Timeout;
|
||||
unskipCallback: any;
|
||||
idSuffix: any;
|
||||
|
||||
constructor(parent: HTMLElement, UUID: string, manualSkip: boolean = false, contentContainer) {
|
||||
this.parent = parent;
|
||||
this.UUID = UUID;
|
||||
this.manualSkip = manualSkip;
|
||||
this.contentContainer = contentContainer;
|
||||
|
||||
let noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||
|
||||
if (manualSkip) {
|
||||
noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped");
|
||||
}
|
||||
|
||||
this.maxCountdownTime = () => 4;
|
||||
//the countdown until this notice closes
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
//the id for the setInterval running the countdown
|
||||
this.countdownInterval = null;
|
||||
|
||||
//the unskip button's callback
|
||||
this.unskipCallback = this.unskip.bind(this);
|
||||
|
||||
//add notice
|
||||
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
|
||||
//this is the suffix added at the end of every id
|
||||
this.idSuffix = this.UUID + amountOfPreviousNotices;
|
||||
|
||||
if (amountOfPreviousNotices > 0) {
|
||||
//already exists
|
||||
|
||||
let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
||||
previousNotice.classList.add("secondSkipNotice")
|
||||
}
|
||||
|
||||
let noticeElement = document.createElement("div");
|
||||
//what sponsor time this is about
|
||||
noticeElement.id = "sponsorSkipNotice" + this.idSuffix;
|
||||
noticeElement.classList.add("sponsorSkipObject");
|
||||
noticeElement.classList.add("sponsorSkipNotice");
|
||||
noticeElement.style.zIndex = String(50 + amountOfPreviousNotices);
|
||||
if (contentContainer().onMobileYouTube) {
|
||||
noticeElement.style.bottom = "4em";
|
||||
noticeElement.style.transform = "scale(0.8) translate(10%, 10%)";
|
||||
}
|
||||
|
||||
//add mouse enter and leave listeners
|
||||
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
|
||||
noticeElement.addEventListener("mouseleave", this.startCountdown.bind(this));
|
||||
|
||||
//the row that will contain the info
|
||||
let firstRow = document.createElement("tr");
|
||||
firstRow.id = "sponsorSkipNoticeFirstRow" + this.idSuffix;
|
||||
|
||||
let logoColumn = document.createElement("td");
|
||||
|
||||
let logoElement = document.createElement("img");
|
||||
logoElement.id = "sponsorSkipLogo" + this.idSuffix;
|
||||
logoElement.className = "sponsorSkipLogo sponsorSkipObject";
|
||||
logoElement.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png");
|
||||
|
||||
let noticeMessage = document.createElement("span");
|
||||
noticeMessage.id = "sponsorSkipMessage" + this.idSuffix;
|
||||
noticeMessage.classList.add("sponsorSkipMessage");
|
||||
noticeMessage.classList.add("sponsorSkipObject");
|
||||
noticeMessage.innerText = noticeTitle;
|
||||
|
||||
//create the first column
|
||||
logoColumn.appendChild(logoElement);
|
||||
logoColumn.appendChild(noticeMessage);
|
||||
|
||||
//add the x button
|
||||
let closeButtonContainer = document.createElement("td");
|
||||
closeButtonContainer.className = "sponsorSkipNoticeRightSection";
|
||||
closeButtonContainer.style.top = "11px";
|
||||
|
||||
let timeLeft = document.createElement("span");
|
||||
timeLeft.id = "sponsorSkipNoticeTimeLeft" + this.idSuffix;
|
||||
timeLeft.innerText = this.countdownTime + "s";
|
||||
timeLeft.className = "sponsorSkipObject sponsorSkipNoticeTimeLeft";
|
||||
|
||||
let hideButton = document.createElement("img");
|
||||
hideButton.src = chrome.extension.getURL("icons/close.png");
|
||||
hideButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton sponsorSkipNoticeRightButton";
|
||||
hideButton.addEventListener("click", this.close.bind(this));
|
||||
|
||||
closeButtonContainer.appendChild(timeLeft);
|
||||
closeButtonContainer.appendChild(hideButton);
|
||||
|
||||
//add all objects to first row
|
||||
firstRow.appendChild(logoColumn);
|
||||
firstRow.appendChild(closeButtonContainer);
|
||||
|
||||
let spacer = document.createElement("hr");
|
||||
spacer.id = "sponsorSkipNoticeSpacer" + this.idSuffix;
|
||||
spacer.className = "sponsorBlockSpacer";
|
||||
|
||||
//the row that will contain the buttons
|
||||
let secondRow = document.createElement("tr");
|
||||
secondRow.id = "sponsorSkipNoticeSecondRow" + this.idSuffix;
|
||||
|
||||
//thumbs up and down buttons
|
||||
let voteButtonsContainer = document.createElement("td");
|
||||
voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer" + this.idSuffix;
|
||||
voteButtonsContainer.className = "sponsorTimesVoteButtonsContainer"
|
||||
|
||||
let reportText = document.createElement("span");
|
||||
reportText.id = "sponsorTimesReportText" + this.idSuffix;
|
||||
reportText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
||||
reportText.innerText = chrome.i18n.getMessage("reportButtonTitle");
|
||||
reportText.style.marginRight = "5px";
|
||||
reportText.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
|
||||
|
||||
let downvoteButton = document.createElement("img");
|
||||
downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + this.idSuffix;
|
||||
downvoteButton.className = "sponsorSkipObject voteButton";
|
||||
downvoteButton.src = chrome.extension.getURL("icons/report.png");
|
||||
downvoteButton.addEventListener("click", () => this.contentContainer().vote(0, this.UUID, this));
|
||||
downvoteButton.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
|
||||
|
||||
//add downvote and report text to container
|
||||
voteButtonsContainer.appendChild(reportText);
|
||||
voteButtonsContainer.appendChild(downvoteButton);
|
||||
|
||||
//add unskip button
|
||||
let unskipContainer = document.createElement("td");
|
||||
unskipContainer.className = "sponsorSkipNoticeUnskipSection";
|
||||
|
||||
let unskipButton = document.createElement("button");
|
||||
unskipButton.id = "sponsorSkipUnskipButton" + this.idSuffix;
|
||||
unskipButton.innerText = chrome.i18n.getMessage("unskip");
|
||||
unskipButton.className = "sponsorSkipObject sponsorSkipNoticeButton";
|
||||
unskipButton.addEventListener("click", this.unskipCallback);
|
||||
|
||||
unskipButton.style.marginLeft = "4px";
|
||||
|
||||
unskipContainer.appendChild(unskipButton);
|
||||
|
||||
//add don't show again button
|
||||
let dontshowContainer = document.createElement("td");
|
||||
dontshowContainer.className = "sponsorSkipNoticeRightSection";
|
||||
|
||||
let dontShowAgainButton = document.createElement("button");
|
||||
dontShowAgainButton.innerText = chrome.i18n.getMessage("Hide");
|
||||
dontShowAgainButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton";
|
||||
dontShowAgainButton.addEventListener("click", this.contentContainer().dontShowNoticeAgain);
|
||||
|
||||
// Don't let them hide it if manually skipping
|
||||
if (!this.manualSkip) {
|
||||
dontshowContainer.appendChild(dontShowAgainButton);
|
||||
}
|
||||
|
||||
//add to row
|
||||
secondRow.appendChild(voteButtonsContainer);
|
||||
secondRow.appendChild(unskipContainer);
|
||||
secondRow.appendChild(dontshowContainer);
|
||||
|
||||
noticeElement.appendChild(firstRow);
|
||||
noticeElement.appendChild(spacer);
|
||||
noticeElement.appendChild(secondRow);
|
||||
|
||||
//get reference node
|
||||
let referenceNode = document.getElementById("player-container-id")
|
||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||
if (referenceNode == null) {
|
||||
//for embeds
|
||||
let player = document.getElementById("player");
|
||||
referenceNode = <HTMLElement> player.firstChild;
|
||||
let index = 1;
|
||||
|
||||
//find the child that is the video player (sometimes it is not the first)
|
||||
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
||||
referenceNode = <HTMLElement> player.children[index];
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
referenceNode.prepend(noticeElement);
|
||||
|
||||
if (manualSkip) {
|
||||
this.unskippedMode(chrome.i18n.getMessage("skip"));
|
||||
}
|
||||
|
||||
this.startCountdown();
|
||||
}
|
||||
|
||||
//called every second to lower the countdown before hiding the notice
|
||||
countdown() {
|
||||
this.countdownTime--;
|
||||
|
||||
if (this.countdownTime <= 0) {
|
||||
//remove this from setInterval
|
||||
clearInterval(this.countdownInterval);
|
||||
|
||||
//time to close this notice
|
||||
this.close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.countdownTime == 3) {
|
||||
//start fade out animation
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.style.removeProperty("animation");
|
||||
notice.classList.add("sponsorSkipNoticeFadeOut");
|
||||
}
|
||||
|
||||
this.updateTimerDisplay();
|
||||
}
|
||||
|
||||
pauseCountdown() {
|
||||
//remove setInterval
|
||||
clearInterval(this.countdownInterval);
|
||||
this.countdownInterval = null;
|
||||
|
||||
//reset countdown
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
|
||||
//inform the user
|
||||
let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix);
|
||||
timeLeft.innerText = chrome.i18n.getMessage("paused");
|
||||
|
||||
//remove the fade out class if it exists
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
||||
notice.style.animation = "none";
|
||||
}
|
||||
|
||||
startCountdown() {
|
||||
//if it has already started, don't start it again
|
||||
if (this.countdownInterval !== null) return;
|
||||
|
||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
||||
|
||||
this.updateTimerDisplay();
|
||||
}
|
||||
|
||||
updateTimerDisplay() {
|
||||
//update the timer display
|
||||
let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix);
|
||||
timeLeft.innerText = this.countdownTime + "s";
|
||||
}
|
||||
|
||||
unskip() {
|
||||
this.contentContainer().unskipSponsorTime(this.UUID);
|
||||
|
||||
this.unskippedMode(chrome.i18n.getMessage("reskip"));
|
||||
}
|
||||
|
||||
/** Sets up notice to be not skipped yet */
|
||||
unskippedMode(buttonText) {
|
||||
//change unskip button to a reskip button
|
||||
let unskipButton = this.changeUnskipButton(buttonText);
|
||||
|
||||
//setup new callback
|
||||
this.unskipCallback = this.reskip.bind(this);
|
||||
unskipButton.addEventListener("click", this.unskipCallback);
|
||||
|
||||
//change max duration to however much of the sponsor is left
|
||||
this.maxCountdownTime = function() {
|
||||
let sponsorTime = this.contentContainer().sponsorTimes[this.contentContainer().UUIDs.indexOf(this.UUID)];
|
||||
let duration = Math.round(sponsorTime[1] - this.contentContainer().v.currentTime);
|
||||
|
||||
return Math.max(duration, 4);
|
||||
};
|
||||
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
this.updateTimerDisplay();
|
||||
}
|
||||
|
||||
reskip() {
|
||||
this.contentContainer().reskipSponsorTime(this.UUID);
|
||||
|
||||
//change reskip button to a unskip button
|
||||
let unskipButton = this.changeUnskipButton(chrome.i18n.getMessage("unskip"));
|
||||
|
||||
//setup new callback
|
||||
this.unskipCallback = this.unskip.bind(this);
|
||||
unskipButton.addEventListener("click", this.unskipCallback);
|
||||
|
||||
//reset duration
|
||||
this.maxCountdownTime = () => 4;
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
this.updateTimerDisplay();
|
||||
|
||||
// See if the title should be changed
|
||||
if (this.manualSkip) {
|
||||
this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle"));
|
||||
|
||||
if (Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the text on the reskip button
|
||||
*
|
||||
* @param {string} text
|
||||
* @returns {HTMLElement} unskipButton
|
||||
*/
|
||||
changeUnskipButton(text) {
|
||||
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
|
||||
unskipButton.innerText = text;
|
||||
unskipButton.removeEventListener("click", this.unskipCallback);
|
||||
|
||||
return unskipButton;
|
||||
}
|
||||
|
||||
afterDownvote() {
|
||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||
this.addNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
|
||||
|
||||
//remove this sponsor from the sponsors looked up
|
||||
//find which one it is
|
||||
for (let i = 0; i < this.contentContainer().sponsorTimes.length; i++) {
|
||||
if (this.contentContainer().UUIDs[i] == this.UUID) {
|
||||
//this one is the one to hide
|
||||
|
||||
//add this as a hidden sponsorTime
|
||||
this.contentContainer().hiddenSponsorTimes.push(i);
|
||||
|
||||
this.contentContainer().updatePreviewBar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeNoticeTitle(title) {
|
||||
let noticeElement = document.getElementById("sponsorSkipMessage" + this.idSuffix);
|
||||
|
||||
noticeElement.innerText = title;
|
||||
}
|
||||
|
||||
addNoticeInfoMessage(message: string, message2: string = "") {
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2");
|
||||
if (previousInfoMessage2 != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2);
|
||||
}
|
||||
|
||||
//add info
|
||||
let thanksForVotingText = document.createElement("p");
|
||||
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
|
||||
if (message2 !== undefined) {
|
||||
let thanksForVotingText2 = document.createElement("p");
|
||||
thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2";
|
||||
thanksForVotingText2.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText2.innerText = message2;
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
}
|
||||
}
|
||||
|
||||
resetNoticeInfoMessage() {
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
}
|
||||
|
||||
addVoteButtonInfo(message) {
|
||||
this.resetVoteButtonInfo();
|
||||
|
||||
//hide report button and text for it
|
||||
let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
|
||||
if (downvoteButton != null) {
|
||||
downvoteButton.style.display = "none";
|
||||
}
|
||||
let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
|
||||
if (downvoteButtonText != null) {
|
||||
downvoteButtonText.style.display = "none";
|
||||
}
|
||||
|
||||
//add info
|
||||
let thanksForVotingText = document.createElement("td");
|
||||
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
|
||||
}
|
||||
|
||||
resetVoteButtonInfo() {
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
//show button again
|
||||
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
|
||||
}
|
||||
|
||||
//close this notice
|
||||
close() {
|
||||
//reset message
|
||||
this.resetNoticeInfoMessage();
|
||||
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
if (notice != null) {
|
||||
notice.remove();
|
||||
}
|
||||
|
||||
//remove setInterval
|
||||
if (this.countdownInterval !== null) clearInterval(this.countdownInterval);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SkipNotice;
|
||||
185
src/options.ts
185
src/options.ts
@@ -1,6 +1,11 @@
|
||||
import Config from "./config";
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
// Make the config public for debugging purposes
|
||||
(<any> window).SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
import CategoryChooser from "./render/CategoryChooser";
|
||||
var utils = new Utils();
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
@@ -27,6 +32,8 @@ async function init() {
|
||||
let checkbox = optionsElements[i].querySelector("input");
|
||||
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
||||
|
||||
let confirmMessage = optionsElements[i].getAttribute("confirm-message");
|
||||
|
||||
if (optionResult != undefined) {
|
||||
checkbox.checked = optionResult;
|
||||
|
||||
@@ -44,6 +51,12 @@ async function init() {
|
||||
|
||||
// Add click listener
|
||||
checkbox.addEventListener("click", () => {
|
||||
// Confirm if required
|
||||
if (checkbox.checked && confirmMessage && !confirm(chrome.i18n.getMessage(confirmMessage))){
|
||||
checkbox.checked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Config.config[option] = reverse ? !checkbox.checked : checkbox.checked;
|
||||
|
||||
// See if anything extra must be run
|
||||
@@ -72,7 +85,7 @@ async function init() {
|
||||
|
||||
textChangeInput.value = Config.config[textChangeOption];
|
||||
|
||||
textChangeSetButton.addEventListener("click", () => {
|
||||
textChangeSetButton.addEventListener("click", async () => {
|
||||
// See if anything extra must be done
|
||||
switch (textChangeOption) {
|
||||
case "serverAddress":
|
||||
@@ -84,6 +97,18 @@ async function init() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permission needed on Firefox
|
||||
if (utils.isFirefox()) {
|
||||
let permissionSuccess = await new Promise((resolve, reject) => {
|
||||
chrome.permissions.request({
|
||||
origins: [textChangeInput.value + "/"],
|
||||
permissions: []
|
||||
}, resolve);
|
||||
});
|
||||
|
||||
if (!permissionSuccess) return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -112,6 +137,16 @@ async function init() {
|
||||
invidiousInstanceAddInit(<HTMLElement> optionsElements[i], privateTextChangeOption);
|
||||
}
|
||||
|
||||
break;
|
||||
case "button-press":
|
||||
let actionButton = optionsElements[i].querySelector(".trigger-button");
|
||||
|
||||
switch(optionsElements[i].getAttribute("sync-option")) {
|
||||
case "copyDebugInformation":
|
||||
actionButton.addEventListener("click", copyDebugOutputToClipboard);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case "keybind-change":
|
||||
let keybindButton = optionsElements[i].querySelector(".trigger-button");
|
||||
@@ -138,6 +173,9 @@ async function init() {
|
||||
});
|
||||
|
||||
break;
|
||||
case "react-CategoryChooserComponent":
|
||||
new CategoryChooser(optionsElements[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +297,8 @@ function invidiousOnClick(checkbox: HTMLInputElement, option: string) {
|
||||
if (!granted) {
|
||||
Config.config[option] = false;
|
||||
checkbox.checked = false;
|
||||
} else {
|
||||
checkbox.checked = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -303,25 +343,60 @@ function activateKeybindChange(element: HTMLElement) {
|
||||
function keybindKeyPressed(element: HTMLElement, e: KeyboardEvent) {
|
||||
var key = e.key;
|
||||
|
||||
let button = element.querySelector(".trigger-button");
|
||||
if (["Shift", "Control", "Meta", "Alt", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Tab"].indexOf(key) !== -1) {
|
||||
|
||||
// Wait for more
|
||||
document.addEventListener("keydown", (e) => keybindKeyPressed(element, e), {once: true});
|
||||
} else {
|
||||
let button: HTMLElement = element.querySelector(".trigger-button");
|
||||
let option = element.getAttribute("sync-option");
|
||||
|
||||
// Don't allow keys which are already listened for by youtube
|
||||
let restrictedKeys = "1234567890,.jklftcibmJKLFTCIBMNP/<> -+";
|
||||
if (restrictedKeys.indexOf(key) !== -1 ) {
|
||||
closeKeybindOption(element, button);
|
||||
|
||||
alert(chrome.i18n.getMessage("theKey") + " " + key + " " + chrome.i18n.getMessage("keyAlreadyUsedByYouTube"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure keybind isn't used by the other listener
|
||||
// TODO: If other keybindings are going to be added, we need a better way to find the other keys used.
|
||||
let otherKeybind = (option === "startSponsorKeybind") ? Config.config['submitKeybind'] : Config.config['startSponsorKeybind'];
|
||||
if (key === otherKeybind) {
|
||||
closeKeybindOption(element, button);
|
||||
|
||||
alert(chrome.i18n.getMessage("theKey") + " " + key + " " + chrome.i18n.getMessage("keyAlreadyUsed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// cancel setting a keybind
|
||||
if (key === "Escape") {
|
||||
closeKeybindOption(element, button);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Config.config[option] = key;
|
||||
|
||||
let status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
status.innerText = chrome.i18n.getMessage("keybindDescriptionComplete");
|
||||
|
||||
let statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
statusKey.innerText = key;
|
||||
|
||||
// cancel setting a keybind
|
||||
if (key === "Escape") {
|
||||
element.querySelector(".option-hidden-section").classList.add("hidden");
|
||||
button.classList.remove("disabled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let option = element.getAttribute("sync-option");
|
||||
|
||||
Config.config[option] = key;
|
||||
|
||||
let status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
status.innerText = chrome.i18n.getMessage("keybindDescriptionComplete");
|
||||
|
||||
let statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
statusKey.innerText = key;
|
||||
|
||||
/**
|
||||
* Closes the menu for editing the keybind
|
||||
*
|
||||
* @param element
|
||||
* @param button
|
||||
*/
|
||||
function closeKeybindOption(element: HTMLElement, button: HTMLElement) {
|
||||
element.querySelector(".option-hidden-section").classList.add("hidden");
|
||||
button.classList.remove("disabled");
|
||||
}
|
||||
|
||||
@@ -346,14 +421,56 @@ function activatePrivateTextChange(element: HTMLElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
textBox.value = Config.config[option];
|
||||
let result = Config.config[option];
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
case "*":
|
||||
let jsonData = JSON.parse(JSON.stringify(Config.localConfig));
|
||||
|
||||
// Fix sponsorTimes data as it is destroyed from the JSON stringify
|
||||
jsonData.sponsorTimes = Config.encodeStoredItem(Config.localConfig.sponsorTimes);
|
||||
|
||||
result = JSON.stringify(jsonData);
|
||||
break;
|
||||
}
|
||||
|
||||
textBox.value = result;
|
||||
|
||||
let setButton = element.querySelector(".text-change-set");
|
||||
setButton.addEventListener("click", () => {
|
||||
let confirmMessage = element.getAttribute("confirm-message");
|
||||
|
||||
if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) {
|
||||
Config.config[option] = textBox.value;
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
case "*":
|
||||
try {
|
||||
let newConfig = JSON.parse(textBox.value);
|
||||
for (const key in newConfig) {
|
||||
Config.config[key] = newConfig[key];
|
||||
}
|
||||
Config.convertJSON();
|
||||
|
||||
// Reload options on page
|
||||
init();
|
||||
|
||||
if (newConfig.supportInvidious) {
|
||||
let checkbox = <HTMLInputElement> document.querySelector("#support-invidious > label > label > input");
|
||||
|
||||
checkbox.checked = true;
|
||||
invidiousOnClick(checkbox, "supportInvidious");
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
alert(chrome.i18n.getMessage("incorrectlyFormattedOptions"));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
Config.config[option] = textBox.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -382,3 +499,35 @@ function validateServerAddress(input: string): string {
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
function copyDebugOutputToClipboard() {
|
||||
// Build output debug information object
|
||||
let output = {
|
||||
debug: {
|
||||
userAgent: navigator.userAgent,
|
||||
platform: navigator.platform,
|
||||
language: navigator.language,
|
||||
extensionVersion: chrome.runtime.getManifest().version
|
||||
},
|
||||
config: JSON.parse(JSON.stringify(Config.localConfig)) // Deep clone config object
|
||||
};
|
||||
|
||||
// Fix sponsorTimes data as it is destroyed from the JSON stringify
|
||||
output.config.sponsorTimes = Config.encodeStoredItem(Config.localConfig.sponsorTimes);
|
||||
|
||||
// Sanitise sensitive user config values
|
||||
delete output.config.userID;
|
||||
output.config.serverAddress = (output.config.serverAddress === CompileConfig.serverAddress)
|
||||
? "Default server address" : "Custom server address";
|
||||
output.config.invidiousInstances = output.config.invidiousInstances.length;
|
||||
output.config.whitelistedChannels = output.config.whitelistedChannels.length;
|
||||
|
||||
// Copy object to clipboard
|
||||
navigator.clipboard.writeText(JSON.stringify(output, null, 4))
|
||||
.then(() => {
|
||||
alert(chrome.i18n.getMessage("copyDebugInformationComplete"));
|
||||
})
|
||||
.catch(err => {
|
||||
alert(chrome.i18n.getMessage("copyDebugInformationFailed"));
|
||||
});;
|
||||
}
|
||||
185
src/popup.ts
185
src/popup.ts
@@ -1,6 +1,7 @@
|
||||
import Config from "./config";
|
||||
|
||||
import Utils from "./utils";
|
||||
import { SponsorTime, SponsorHideType } from "./types";
|
||||
var utils = new Utils();
|
||||
|
||||
interface MessageListener {
|
||||
@@ -50,13 +51,13 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
// Top toggles
|
||||
"whitelistChannel",
|
||||
"unwhitelistChannel",
|
||||
"whitelistForceCheck",
|
||||
"disableSkipping",
|
||||
"enableSkipping",
|
||||
// Options
|
||||
"showNoticeAgain",
|
||||
"optionsButton",
|
||||
// More controls
|
||||
"clearTimes",
|
||||
"submitTimes",
|
||||
"reportAnIssue",
|
||||
// sponsorTimesContributions
|
||||
@@ -82,9 +83,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
// discordButtons
|
||||
"discordButtonContainer",
|
||||
"hideDiscordButton",
|
||||
// submitTimesInfoMessage
|
||||
"submitTimesInfoMessageContainer",
|
||||
"submitTimesInfoMessage",
|
||||
// Username
|
||||
"setUsernameContainer",
|
||||
"setUsernameButton",
|
||||
@@ -105,10 +103,10 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
//setup click listeners
|
||||
PageElements.sponsorStart.addEventListener("click", sendSponsorStartMessage);
|
||||
PageElements.whitelistChannel.addEventListener("click", whitelistChannel);
|
||||
PageElements.whitelistForceCheck.addEventListener("click", openOptions);
|
||||
PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel);
|
||||
PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true));
|
||||
PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false));
|
||||
PageElements.clearTimes.addEventListener("click", clearTimes);
|
||||
PageElements.submitTimes.addEventListener("click", submitTimes);
|
||||
PageElements.showNoticeAgain.addEventListener("click", showNoticeAgain);
|
||||
PageElements.setUsernameButton.addEventListener("click", setUsernameButton);
|
||||
@@ -263,8 +261,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
|
||||
sponsorTimes = sponsorTimesStorage;
|
||||
|
||||
displaySponsorTimes();
|
||||
|
||||
//show submission section
|
||||
PageElements.submissionSection.style.display = "unset";
|
||||
|
||||
@@ -279,7 +275,7 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
);
|
||||
}
|
||||
|
||||
function infoFound(request) {
|
||||
function infoFound(request: {found: boolean, sponsorTimes: SponsorTime[]}) {
|
||||
if(chrome.runtime.lastError) {
|
||||
//This page doesn't have the injected content script, or at least not yet
|
||||
displayNoVideo();
|
||||
@@ -363,28 +359,14 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
|
||||
updateStartTimeChosen();
|
||||
|
||||
//display video times on screen
|
||||
displaySponsorTimes();
|
||||
|
||||
//show submission section
|
||||
PageElements.submissionSection.style.display = "unset";
|
||||
|
||||
showSubmitTimesIfNecessary();
|
||||
}
|
||||
|
||||
//display the video times from the array
|
||||
function displaySponsorTimes() {
|
||||
//remove all children
|
||||
while (PageElements.sponsorMessageTimes.firstChild) {
|
||||
PageElements.sponsorMessageTimes.removeChild(PageElements.sponsorMessageTimes.firstChild);
|
||||
}
|
||||
|
||||
//add sponsor times
|
||||
PageElements.sponsorMessageTimes.appendChild(getSponsorTimesMessageDiv(sponsorTimes));
|
||||
}
|
||||
|
||||
//display the video times from the array at the top, in a different section
|
||||
function displayDownloadedSponsorTimes(request) {
|
||||
function displayDownloadedSponsorTimes(request: {found: boolean, sponsorTimes: SponsorTime[]}) {
|
||||
if (request.sponsorTimes != undefined) {
|
||||
//set it to the message
|
||||
if (PageElements.downloadedSponsorMessageTimes.innerText != chrome.i18n.getMessage("channelWhitelisted")) {
|
||||
@@ -398,16 +380,19 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
sponsorTimeButton.className = "warningButton popupElement";
|
||||
|
||||
let extraInfo = "";
|
||||
if (request.hiddenSponsorTimes.includes(i)) {
|
||||
//this one is hidden
|
||||
extraInfo = " (hidden)";
|
||||
if (request.sponsorTimes[i].hidden === SponsorHideType.Downvoted) {
|
||||
//this one is downvoted
|
||||
extraInfo = " (" + chrome.i18n.getMessage("hiddenDueToDownvote") + ")";
|
||||
} else if (request.sponsorTimes[i].hidden === SponsorHideType.MinimumDuration) {
|
||||
//this one is too short
|
||||
extraInfo = " (" + chrome.i18n.getMessage("hiddenDueToDuration") + ")";
|
||||
}
|
||||
|
||||
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i][0]) + " to " + getFormattedTime(request.sponsorTimes[i][1]) + extraInfo;
|
||||
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i].segment[0]) + " to " + getFormattedTime(request.sponsorTimes[i].segment[1]) + extraInfo;
|
||||
|
||||
let votingButtons = document.createElement("div");
|
||||
|
||||
let UUID = request.UUIDs[i];
|
||||
let UUID = request.sponsorTimes[i].UUID;
|
||||
|
||||
//thumbs up and down buttons
|
||||
let voteButtonsContainer = document.createElement("div");
|
||||
@@ -451,12 +436,12 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
}
|
||||
|
||||
//get the message that visually displays the video times
|
||||
function getSponsorTimesMessage(sponsorTimes) {
|
||||
function getSponsorTimesMessage(sponsorTimes: SponsorTime[]) {
|
||||
let sponsorTimesMessage = "";
|
||||
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
for (let s = 0; s < sponsorTimes[i].length; s++) {
|
||||
let timeMessage = getFormattedTime(sponsorTimes[i][s]);
|
||||
for (let s = 0; s < sponsorTimes[i].segment.length; s++) {
|
||||
let timeMessage = getFormattedTime(sponsorTimes[i].segment[s]);
|
||||
//if this is an end time
|
||||
if (s == 1) {
|
||||
timeMessage = " to " + timeMessage;
|
||||
@@ -465,6 +450,14 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
timeMessage = ", " + timeMessage;
|
||||
}
|
||||
|
||||
if (sponsorTimes[i].hidden === SponsorHideType.Downvoted) {
|
||||
//this one is downvoted
|
||||
timeMessage += " (" + chrome.i18n.getMessage("hiddenDueToDownvote") + ")";
|
||||
} else if (sponsorTimes[i].hidden === SponsorHideType.MinimumDuration) {
|
||||
//this one is too short
|
||||
timeMessage += " (" + chrome.i18n.getMessage("hiddenDueToDuration") + ")";
|
||||
}
|
||||
|
||||
sponsorTimesMessage += timeMessage;
|
||||
}
|
||||
}
|
||||
@@ -692,8 +685,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
});
|
||||
|
||||
if (closeEditMode) {
|
||||
displaySponsorTimes();
|
||||
|
||||
showSubmitTimesIfNecessary();
|
||||
}
|
||||
}
|
||||
@@ -721,9 +712,6 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
//save this
|
||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
||||
|
||||
//update display
|
||||
displaySponsorTimes();
|
||||
|
||||
//if they are all removed
|
||||
if (sponsorTimes.length == 0) {
|
||||
//update chrome tab
|
||||
@@ -753,67 +741,17 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
});
|
||||
}
|
||||
|
||||
function clearTimes() {
|
||||
//send new sponsor time state to tab
|
||||
function submitTimes() {
|
||||
if (sponsorTimes.length > 0) {
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, function(tabs) {
|
||||
messageHandler.sendMessage(tabs[0].id, {
|
||||
message: "changeStartSponsorButton",
|
||||
showStartSponsor: true,
|
||||
uploadButtonVisible: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//reset sponsorTimes
|
||||
sponsorTimes = [];
|
||||
|
||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{message: "sponsorDataChanged"}
|
||||
{message: 'submitTimes'},
|
||||
);
|
||||
});
|
||||
|
||||
displaySponsorTimes();
|
||||
|
||||
//hide submission section
|
||||
document.getElementById("submissionSection").style.display = "none";
|
||||
|
||||
resetStartTimeChosen();
|
||||
}
|
||||
|
||||
function submitTimes() {
|
||||
//make info message say loading
|
||||
PageElements.submitTimesInfoMessage.innerText = chrome.i18n.getMessage("Loading");
|
||||
PageElements.submitTimesInfoMessageContainer.style.display = "unset";
|
||||
|
||||
if (sponsorTimes.length > 0) {
|
||||
chrome.runtime.sendMessage({
|
||||
message: "submitTimes",
|
||||
videoID: currentVideoID
|
||||
}, function(response) {
|
||||
if (response != undefined) {
|
||||
if (response.statusCode == 200) {
|
||||
//hide loading message
|
||||
PageElements.submitTimesInfoMessageContainer.style.display = "none";
|
||||
|
||||
clearTimes();
|
||||
} else {
|
||||
document.getElementById("submitTimesInfoMessage").innerText = utils.getErrorMessage(response.statusCode);
|
||||
document.getElementById("submitTimesInfoMessageContainer").style.display = "unset";
|
||||
|
||||
PageElements.submitTimesInfoMessageContainer.style.display = "unset";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,39 +921,46 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{message: 'getChannelURL'},
|
||||
{message: 'getChannelID'},
|
||||
function(response) {
|
||||
if (!response.channelID) {
|
||||
alert(chrome.i18n.getMessage("channelDataNotFound") + "\n\n" +
|
||||
chrome.i18n.getMessage("itCouldBeAdblockerIssue"));
|
||||
return;
|
||||
}
|
||||
|
||||
//get whitelisted channels
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
if (whitelistedChannels == undefined) {
|
||||
whitelistedChannels = [];
|
||||
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";
|
||||
if (!Config.config.forceChannelCheck) PageElements.whitelistForceCheck.style.display = "unset";
|
||||
|
||||
PageElements.downloadedSponsorMessageTimes.innerText = chrome.i18n.getMessage("channelWhitelisted");
|
||||
PageElements.downloadedSponsorMessageTimes.style.fontWeight = "bold";
|
||||
|
||||
//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
|
||||
});
|
||||
}
|
||||
|
||||
//add on this channel
|
||||
whitelistedChannels.push(response.channelURL);
|
||||
|
||||
//change button
|
||||
PageElements.whitelistChannel.style.display = "none";
|
||||
PageElements.unwhitelistChannel.style.display = "unset";
|
||||
|
||||
PageElements.downloadedSponsorMessageTimes.innerText = chrome.i18n.getMessage("channelWhitelisted");
|
||||
PageElements.downloadedSponsorMessageTimes.style.fontWeight = "bold";
|
||||
|
||||
//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
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -1029,7 +974,7 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
{message: 'getChannelURL'},
|
||||
{message: 'getChannelID'},
|
||||
function(response) {
|
||||
//get whitelisted channels
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
@@ -1038,7 +983,7 @@ async function runThePopup(messageListener?: MessageListener) {
|
||||
}
|
||||
|
||||
//remove this channel
|
||||
let index = whitelistedChannels.indexOf(response.channelURL);
|
||||
let index = whitelistedChannels.indexOf(response.channelID);
|
||||
whitelistedChannels.splice(index, 1);
|
||||
|
||||
//change button
|
||||
|
||||
15
src/render/CategoryChooser.tsx
Normal file
15
src/render/CategoryChooser.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import CategoryChooserComponent from "../components/CategoryChooserComponent";
|
||||
|
||||
class CategoryChooser {
|
||||
|
||||
constructor(element: Element) {
|
||||
ReactDOM.render(
|
||||
<CategoryChooserComponent/>,
|
||||
element
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CategoryChooser;
|
||||
61
src/render/SkipNotice.tsx
Normal file
61
src/render/SkipNotice.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import SkipNoticeComponent from "../components/SkipNoticeComponent";
|
||||
|
||||
class SkipNotice {
|
||||
UUID: string;
|
||||
autoSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: () => any;
|
||||
|
||||
noticeElement: HTMLDivElement;
|
||||
|
||||
constructor(UUID: string, autoSkip: boolean = false, contentContainer) {
|
||||
this.UUID = UUID;
|
||||
this.autoSkip = autoSkip;
|
||||
this.contentContainer = contentContainer;
|
||||
|
||||
//get reference node
|
||||
let referenceNode = document.getElementById("player-container-id")
|
||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||
if (referenceNode == null) {
|
||||
//for embeds
|
||||
let player = document.getElementById("player");
|
||||
referenceNode = player.firstChild as HTMLElement;
|
||||
let index = 1;
|
||||
|
||||
//find the child that is the video player (sometimes it is not the first)
|
||||
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
||||
referenceNode = player.children[index] as HTMLElement;
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
//this is the suffix added at the end of every id
|
||||
let idSuffix = this.UUID + amountOfPreviousNotices;
|
||||
|
||||
this.noticeElement = document.createElement("div");
|
||||
this.noticeElement.id = "sponsorSkipNoticeContainer" + idSuffix;
|
||||
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
ReactDOM.render(
|
||||
<SkipNoticeComponent UUID={UUID}
|
||||
autoSkip={autoSkip}
|
||||
contentContainer={contentContainer}
|
||||
closeListener={() => this.close()} />,
|
||||
this.noticeElement
|
||||
);
|
||||
}
|
||||
|
||||
close() {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
|
||||
this.noticeElement.remove();
|
||||
}
|
||||
}
|
||||
|
||||
export default SkipNotice;
|
||||
65
src/render/SubmissionNotice.tsx
Normal file
65
src/render/SubmissionNotice.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import SubmissionNoticeComponent from "../components/SubmissionNoticeComponent";
|
||||
|
||||
class SubmissionNotice {
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: () => any;
|
||||
|
||||
callback: () => any;
|
||||
|
||||
noticeRef: React.MutableRefObject<SubmissionNoticeComponent>;
|
||||
|
||||
noticeElement: HTMLDivElement;
|
||||
|
||||
constructor(contentContainer: () => any, callback: () => any) {
|
||||
this.noticeRef = React.createRef();
|
||||
|
||||
this.contentContainer = contentContainer;
|
||||
this.callback = callback;
|
||||
|
||||
//get reference node
|
||||
let referenceNode = document.getElementById("player-container-id")
|
||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||
if (referenceNode == null) {
|
||||
//for embeds
|
||||
let player = document.getElementById("player");
|
||||
referenceNode = player.firstChild as HTMLElement;
|
||||
let index = 1;
|
||||
|
||||
//find the child that is the video player (sometimes it is not the first)
|
||||
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
||||
referenceNode = player.children[index] as HTMLElement;
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
this.noticeElement = document.createElement("div");
|
||||
this.noticeElement.id = "submissionNoticeContainer";
|
||||
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
ReactDOM.render(
|
||||
<SubmissionNoticeComponent
|
||||
contentContainer={contentContainer}
|
||||
callback={callback}
|
||||
ref={this.noticeRef}
|
||||
closeListener={() => this.close()} />,
|
||||
this.noticeElement
|
||||
);
|
||||
}
|
||||
|
||||
update() {
|
||||
this.noticeRef.current.forceUpdate();
|
||||
}
|
||||
|
||||
close() {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
|
||||
this.noticeElement.remove();
|
||||
}
|
||||
}
|
||||
|
||||
export default SubmissionNotice;
|
||||
62
src/types.ts
62
src/types.ts
@@ -1,7 +1,65 @@
|
||||
interface videoDurationResponse {
|
||||
import SubmissionNotice from "./render/SubmissionNotice";
|
||||
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
|
||||
interface ContentContainer {
|
||||
(): {
|
||||
vote: (type: any, UUID: any, category?: string, skipNotice?: SkipNoticeComponent) => void,
|
||||
dontShowNoticeAgain: () => void,
|
||||
unskipSponsorTime: (UUID: any) => void,
|
||||
sponsorTimes: SponsorTime[],
|
||||
sponsorTimesSubmitting: SponsorTime[],
|
||||
v: HTMLVideoElement,
|
||||
sponsorVideoID,
|
||||
reskipSponsorTime: (UUID: any) => void,
|
||||
updatePreviewBar: () => void,
|
||||
onMobileYouTube: boolean,
|
||||
sponsorSubmissionNotice: SubmissionNotice,
|
||||
resetSponsorSubmissionNotice: () => void,
|
||||
changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise<boolean>,
|
||||
previewTime: (time: number) => void,
|
||||
videoInfo: any,
|
||||
getRealCurrentTime: () => number
|
||||
}
|
||||
}
|
||||
|
||||
interface VideoDurationResponse {
|
||||
duration: number;
|
||||
}
|
||||
|
||||
enum CategorySkipOption {
|
||||
ShowOverlay,
|
||||
ManualSkip,
|
||||
AutoSkip
|
||||
}
|
||||
|
||||
interface CategorySelection {
|
||||
name: string;
|
||||
option: CategorySkipOption
|
||||
}
|
||||
|
||||
enum SponsorHideType {
|
||||
Visible = undefined,
|
||||
Downvoted = 1,
|
||||
MinimumDuration
|
||||
}
|
||||
|
||||
interface SponsorTime {
|
||||
segment: number[];
|
||||
UUID: string;
|
||||
|
||||
category: string;
|
||||
|
||||
hidden?: SponsorHideType;
|
||||
}
|
||||
|
||||
type VideoID = string;
|
||||
|
||||
export {
|
||||
videoDurationResponse
|
||||
VideoDurationResponse,
|
||||
ContentContainer,
|
||||
CategorySelection,
|
||||
CategorySkipOption,
|
||||
SponsorTime,
|
||||
VideoID,
|
||||
SponsorHideType
|
||||
};
|
||||
125
src/utils.ts
125
src/utils.ts
@@ -1,4 +1,7 @@
|
||||
import Config from "./config";
|
||||
import { CategorySelection, SponsorTime } from "./types";
|
||||
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
class Utils {
|
||||
|
||||
@@ -154,6 +157,42 @@ class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets just the timestamps from a sponsorTimes array
|
||||
*
|
||||
* @param sponsorTimes
|
||||
*/
|
||||
getSegmentsFromSponsorTimes(sponsorTimes: SponsorTime[]): number[][] {
|
||||
let segments: number[][] = [];
|
||||
for (const sponsorTime of sponsorTimes) {
|
||||
segments.push(sponsorTime.segment);
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
getSponsorIndexFromUUID(sponsorTimes: SponsorTime[], UUID: string): number {
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i].UUID === UUID) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
getSponsorTimeFromUUID(sponsorTimes: SponsorTime[], UUID: string): SponsorTime {
|
||||
return sponsorTimes[this.getSponsorIndexFromUUID(sponsorTimes, UUID)];
|
||||
}
|
||||
|
||||
getCategorySelection(category: string): CategorySelection {
|
||||
for (const selection of Config.config.categorySelections) {
|
||||
if (selection.name === category) {
|
||||
return selection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localizeHtmlPage() {
|
||||
//Localize by replacing __MSG_***__ meta tags
|
||||
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
@@ -230,6 +269,51 @@ class Utils {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to a custom server
|
||||
*
|
||||
* @param type The request type. "GET", "POST", etc.
|
||||
* @param address The address to add to the SponsorBlock server address
|
||||
* @param callback
|
||||
*/
|
||||
async asyncRequestToCustomServer(type: string, url: string, data = {}) {
|
||||
|
||||
// If GET, convert JSON to parameters
|
||||
if (type.toLowerCase() === "get") {
|
||||
for (const key in data) {
|
||||
let seperator = url.includes("?") ? "&" : "?";
|
||||
let value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]);
|
||||
url += seperator + key + "=" + value;
|
||||
}
|
||||
|
||||
data = null;
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: type,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
redirect: 'follow',
|
||||
body: data ? JSON.stringify(data) : null
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the SponsorBlock server with address added as a query
|
||||
*
|
||||
* @param type The request type. "GET", "POST", etc.
|
||||
* @param address The address to add to the SponsorBlock server address
|
||||
* @param callback
|
||||
*/
|
||||
async asyncRequestToServer(type: string, address: string, data = {}) {
|
||||
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
|
||||
return await (this.asyncRequestToCustomServer(type, serverAddress + address, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the SponsorBlock server with address added as a query
|
||||
*
|
||||
@@ -240,7 +324,9 @@ class Utils {
|
||||
sendRequestToServer(type: string, address: string, callback?: (xmlhttp: XMLHttpRequest, err: boolean) => any) {
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
|
||||
xmlhttp.open(type, Config.config.serverAddress + address, true);
|
||||
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
|
||||
|
||||
xmlhttp.open(type, serverAddress + address, true);
|
||||
|
||||
if (callback != undefined) {
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
@@ -256,10 +342,45 @@ class Utils {
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
getFormattedMinutes(seconds: number) {
|
||||
return Math.floor(seconds / 60);
|
||||
}
|
||||
|
||||
getFormattedSeconds(seconds: number) {
|
||||
return seconds % 60;
|
||||
}
|
||||
|
||||
getFormattedTime(seconds: number, precise?: boolean) {
|
||||
let minutes = Math.floor(seconds / 60);
|
||||
let secondsNum: number = seconds - minutes * 60;
|
||||
if (!precise) {
|
||||
secondsNum = Math.floor(secondsNum);
|
||||
}
|
||||
|
||||
let secondsDisplay: string = String(secondsNum.toFixed(3));
|
||||
|
||||
if (secondsNum < 10) {
|
||||
//add a zero
|
||||
secondsDisplay = "0" + secondsDisplay;
|
||||
}
|
||||
|
||||
let formatted = minutes + ":" + secondsDisplay;
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
getRawSeconds(minutes: number, seconds: number): number {
|
||||
return minutes * 60 + seconds;
|
||||
}
|
||||
|
||||
isContentScript(): boolean {
|
||||
return window.location.protocol === "http:" || window.location.protocol === "https:";
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this Firefox (web-extensions)
|
||||
*/
|
||||
isFirefox() {
|
||||
isFirefox(): boolean {
|
||||
return typeof(browser) !== "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"outDir": "dist/js",
|
||||
"noEmitOnError": true,
|
||||
"typeRoots": [ "node_modules/@types" ],
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user