Compare commits

...

68 Commits

Author SHA1 Message Date
Ajay
afe8d2a20c bump version 2023-03-07 21:31:04 -05:00
github-actions[bot]
bc038c3eb3 Update OSS Attribution (#1678)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-07 21:30:30 -05:00
Ajay Ramachandran
729c816f6e Update translations (#1690) 2023-03-07 21:29:59 -05:00
github-actions[bot]
d6541945ef Update Invidious List (#1686)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-07 21:27:35 -05:00
Ajay
369d241874 bump maze utils 2023-03-07 21:27:13 -05:00
Ajay
66f3d34942 Fix chapter imports when not in focus 2023-03-03 19:47:08 -05:00
Ajay
419f0e0907 Fix duplicate code 2023-02-28 00:14:37 -05:00
Ajay
c0954b2819 Add new skip workaround for Firefox
Wait until next animation frame before starting the skipping timer
2023-02-28 00:10:54 -05:00
Ajay
290c910a1b rename submission button to "Open Submission Menu" 2023-02-26 22:12:05 -05:00
Ajay
1ffe42771f Fix unhiding one segment unhiding all 2023-02-26 20:15:33 -05:00
Ajay
b25a0a4db1 Lower case and trim invidious instances 2023-02-24 14:21:17 -05:00
Ajay
21f1e52571 Only update invidious instances if there are more, and don't remove old ones 2023-02-24 14:19:27 -05:00
Ajay
11f6fc9a31 Don't reset custom invidious instances on safari 2023-02-24 14:17:02 -05:00
Ajay
4af318403a Update channel id regex 2023-02-22 00:28:46 -05:00
Ajay
c14b33283d Switch headless mode to new due to chrome update
https://bugs.chromium.org/p/chromium/issues/detail?id=706008#c42
2023-02-22 00:22:20 -05:00
Ajay
069b1c1681 Fix odd skipping behavior sometimes with auto skip on music videos
Fix #1682
2023-02-22 00:16:51 -05:00
Ajay
dfbe036119 Fix skipping not working 2023-02-22 00:11:56 -05:00
Ajay
00c09052dc update chrome driver 2023-02-22 00:06:35 -05:00
Ajay
4095ca8642 Fix missing userid generation call swaps 2023-02-18 22:44:34 -05:00
Ajay
4ca6a331f1 Move generate userID to shared lib 2023-02-18 02:54:42 -05:00
Ajay
1d05c2b3df Convert dots to colons when importing existing chapters 2023-02-14 18:38:47 -05:00
Ajay
1d0ac86e5a Move get hash to shared lib 2023-02-14 01:42:25 -05:00
Ajay
12c63b4ff9 Fix setup tab updates missing 2023-02-14 01:24:25 -05:00
Ajay
8c994f362d Move requesting logic to shared lib 2023-02-14 01:20:46 -05:00
Ajay
5ecb809c73 Remove unused interface 2023-02-13 13:14:23 -05:00
github-actions[bot]
6ee58167d8 Update OSS Attribution (#1676)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-13 03:26:09 -05:00
Ajay
c4619aee51 Fix category pill disappearing on mobile youtube 2023-02-13 03:22:55 -05:00
Ajay
d3117d603f Fix mobile and invidious 2023-02-13 02:43:43 -05:00
Ajay
5859c33ce8 Move video handing and config to shared library 2023-02-13 02:31:25 -05:00
Ajay Ramachandran
f4d80d8843 Merge pull request #1671 from ajayyy/ci/oss_attribution
Update OSS Attribution
2023-02-07 17:51:34 -05:00
Ajay
0cdfd68239 bump version 2023-02-07 17:42:38 -05:00
Ajay
bbb234e498 Make invidious instances work on safari 2023-02-07 17:42:22 -05:00
Ajay Ramachandran
3716c8aa80 chrome limitation gone 2023-02-07 02:54:06 -05:00
github-actions[bot]
57fe4d7d65 Update OSS Attribution 2023-02-07 02:23:30 +00:00
Ajay
92e156834b Use pollyfill for invidious registration
Fix #798
2023-02-06 21:22:34 -05:00
Ajay
b2e6e4f076 Fix tests 2023-02-01 19:55:01 -05:00
Ajay
6348bdccde bump version 2023-02-01 19:51:50 -05:00
Ajay
c3213eb040 Add invidious instances by default for safari
https://github.com/ajayyy/SponsorBlock/issues/798
2023-02-01 19:48:24 -05:00
Ajay
78a006544a Fix icon not square 2023-01-31 01:07:00 -05:00
Ajay
3ab2361f45 bump version 2023-01-31 00:58:40 -05:00
Ajay
6068276644 Fix icon on firefox being wrong 2023-01-31 00:58:31 -05:00
Ajay
e3bedbf5f2 Fix chapter importing and lock fetching after 404 2023-01-29 17:53:37 -05:00
Ajay Ramachandran
c9fc22e51e Merge pull request #1654 from mchangrh/fix-large-img
load shared.css on third party sites
2023-01-28 16:42:52 -05:00
Michael C
146c1fc889 load shared.css on third party sites 2023-01-26 03:07:43 -05:00
Ajay
63a5b6fb6f Store fonts locally 2023-01-23 01:05:33 -05:00
Ajay
254261b83a Don't hide chevron if segments are null 2023-01-21 17:37:12 -05:00
Ajay
9301a0914d Add info that piped is supported 2023-01-21 17:26:43 -05:00
Ajay Ramachandran
8e3bae6396 bump version 2023-01-21 17:24:55 -05:00
Ajay Ramachandran
1a4d48503a Merge pull request #1560 from mchangrh/piped-support
add selector for piped
2023-01-21 17:23:45 -05:00
Ajay Ramachandran
508d51d582 New Crowdin updates (#1619) 2023-01-21 17:23:10 -05:00
Ajay
8f91b83195 Remove next chapter from youtube hotkeys warning 2023-01-21 17:17:05 -05:00
Ajay
6adac26a3d Fix keybinds from popup 2023-01-21 17:13:48 -05:00
Ajay
140e816979 Change next chapter keybind to be same as YouTube and disable YouTube's one
Fix #1508
2023-01-21 17:11:08 -05:00
Ajay
f89682c2d6 give more time for chapters to load 2023-01-21 16:59:36 -05:00
Ajay
35e0f7ede9 Fix warnings 2023-01-21 16:20:18 -05:00
Ajay
8383699a68 Fix chapter name sometimes disappearing 2023-01-21 16:18:25 -05:00
dependabot[bot]
76aa472745 Bump json5 from 2.2.1 to 2.2.3 (#1640)
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-08 15:41:36 -05:00
Michael C
6959bdbee1 Add piped support
- add playerInit listener
- made popup container generic for possible piped support
- explicitly add css files to web_accessible_resources
2023-01-03 17:10:51 -05:00
Michael C
c3d4914f57 add selector for piped 2023-01-02 18:28:37 -05:00
github-actions[bot]
55b6b74590 Update Invidious List (#1631)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-01 19:44:34 -05:00
Ajay
4a4b281495 Remove log 2022-12-30 23:13:39 -05:00
Ajay Ramachandran
b9b43513b4 Merge pull request #1627 from mchangrh/partialRequredSegment
highlight partial required segments
2022-12-27 12:42:06 -05:00
Michael C
f68429487e add brackets for operator precedence 2022-12-27 00:24:46 -05:00
Michael C
c5178b4c99 highlight partial required segments 2022-12-26 20:18:51 -05:00
Ajay
27f3ced338 Remove lookbehind because safari
Resolves https://github.com/ajayyy/SponsorBlock/issues/1626
2022-12-26 16:28:17 -05:00
Ajay
06a112a030 Fix category pill disappearing on mobile 2022-12-25 00:38:49 -05:00
github-actions[bot]
89b210ffd5 Update OSS Attribution (#1624)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-24 00:56:55 -05:00
Ajay
7dd2c9eb3e Move some generic functions to a new package 2022-12-24 00:54:56 -05:00
83 changed files with 2463 additions and 2099 deletions

View File

@@ -1 +1 @@
["inv.bp.projectsegfau.lt","inv.odyssey346.dev","inv.riverside.rocks","inv.vern.cc","invidio.xamh.de","invidious.baczek.me","invidious.esmailelbob.xyz","invidious.flokinet.to","invidious.namazso.eu","invidious.nerdvpn.de","invidious.rhyshl.live","invidious.sethforprivacy.com","invidious.slipfox.xyz","invidious.snopyta.org","invidious.tiekoetter.com","invidious.weblibre.org","vid.puffyan.us","y.com.sb","yewtu.be","yt.artemislena.eu"]
["inv.bp.projectsegfau.lt","inv.odyssey346.dev","inv.riverside.rocks","inv.vern.cc","invidious.baczek.me","invidious.epicsite.xyz","invidious.esmailelbob.xyz","invidious.flokinet.to","invidious.lidarshield.cloud","invidious.nerdvpn.de","invidious.privacydev.net","invidious.snopyta.org","invidious.tiekoetter.com","invidious.weblibre.org","iv.melmac.space","vid.puffyan.us","watch.thekitty.zone","y.com.sb","yewtu.be","yt.artemislena.eu","yt.funami.tech","yt.oelrichsgarcia.de"]

View File

@@ -1,7 +1,7 @@
{
"name": "__MSG_fullName__",
"short_name": "SponsorBlock",
"version": "5.1.11",
"version": "5.3.0",
"default_locale": "en",
"description": "__MSG_Description__",
"homepage_url": "https://sponsor.ajay.app",
@@ -69,15 +69,23 @@
"icons/PlayerInfoIconSponsorBlocker.svg",
"icons/PlayerDeleteIconSponsorBlocker.svg",
"popup.html",
"popup.css",
"content.css",
"js/document.js"
"shared.css",
"js/document.js",
"libs/Source+Sans+Pro.css",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2"
],
"permissions": [
"storage",
"https://sponsor.ajay.app/*"
],
"optional_permissions": [
"*://*/*"
"*://*/*",
"webNavigation"
],
"browser_action": {
"default_title": "SponsorBlock",
@@ -85,8 +93,8 @@
"default_icon": {
"16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png",
"64": "icons/LogoSponsorBlocker64px.png",
"128": "icons/LogoSponsorBlocker128px.png"
"64": "icons/IconSponsorBlocker64px.png",
"128": "icons/IconSponsorBlocker128px.png"
},
"theme_icons": [
{
@@ -100,13 +108,13 @@
"size": 32
},
{
"light": "icons/LogoSponsorBlocker64px.png",
"dark": "icons/LogoSponsorBlocker64px.png",
"light": "icons/IconSponsorBlocker64px.png",
"dark": "icons/IconSponsorBlocker64px.png",
"size": 64
},
{
"light": "icons/LogoSponsorBlocker128px.png",
"dark": "icons/LogoSponsorBlocker128px.png",
"light": "icons/IconSponsorBlocker128px.png",
"dark": "icons/IconSponsorBlocker128px.png",
"size": 128
}
]
@@ -120,11 +128,11 @@
"icons": {
"16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png",
"64": "icons/LogoSponsorBlocker64px.png",
"128": "icons/LogoSponsorBlocker128px.png",
"256": "icons/LogoSponsorBlocker256px.png",
"512": "icons/LogoSponsorBlocker512px.png",
"1024": "icons/LogoSponsorBlocker1024px.png"
"64": "icons/IconSponsorBlocker64px.png",
"128": "icons/IconSponsorBlocker128px.png",
"256": "icons/IconSponsorBlocker256px.png",
"512": "icons/IconSponsorBlocker512px.png",
"1024": "icons/IconSponsorBlocker1024px.png"
},
"options_ui": {
"page": "options/options.html",

File diff suppressed because one or more lines are too long

325
package-lock.json generated
View File

@@ -27,6 +27,8 @@
],
"license": "LGPL-3.0-or-later",
"dependencies": {
"@ajayyy/maze-utils": "^1.1.7",
"content-scripts-register-polyfill": "^4.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
@@ -40,7 +42,7 @@
"@types/wicg-mediasession": "^1.1.4",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1",
"chromedriver": "^106.0.1",
"chromedriver": "^110.0.0",
"concurrently": "^7.4.0",
"copy-webpack-plugin": "^11.0.0",
"eslint": "^8.25.0",
@@ -65,6 +67,32 @@
"node": ">=16"
}
},
"node_modules/@ajayyy/maze-utils": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@ajayyy/maze-utils/-/maze-utils-1.1.7.tgz",
"integrity": "sha512-qmakLnRnNJ/CAyDO9ey0ihn71YWoyZfRFxF78ylofA5A+ghBXg4cVVY92iKDN3pivtT2kouLiKDRWgazYKqrOQ==",
"funding": [
{
"type": "individual",
"url": "https://sponsor.ajay.app/donate"
},
{
"type": "github",
"url": "https://github.com/sponsors/ajayyy-org"
},
{
"type": "patreon",
"url": "https://www.patreon.com/ajayyy"
},
{
"type": "individual",
"url": "https://paypal.me/ajayyy"
}
],
"engines": {
"node": ">=16"
}
},
"node_modules/@ampproject/remapping": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
@@ -2880,19 +2908,6 @@
"node": ">= 6.0.0"
}
},
"node_modules/aggregate-error": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
"dev": true,
"dependencies": {
"clean-stack": "^2.0.0",
"indent-string": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
@@ -3145,13 +3160,14 @@
"dev": true
},
"node_modules/axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.3.tgz",
"integrity": "sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios/node_modules/form-data": {
@@ -3906,16 +3922,15 @@
}
},
"node_modules/chromedriver": {
"version": "106.0.1",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-106.0.1.tgz",
"integrity": "sha512-thaBvbDEPgGocSp4/SBIajQz3G7UQfUqCOHZBp9TVhRJv7c91eZrUGcjeJUaNF4p9CfSjCYNYzs4EVVryqmddA==",
"version": "110.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-110.0.0.tgz",
"integrity": "sha512-Le6q8xrA/3fAt+g8qiN0YjsYxINIhQMC6wj9X3W5L77uN4NspEzklDrqYNwBcEVn7PcAEJ73nLlS7mTyZRspHA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"@testim/chrome-version": "^1.1.3",
"axios": "^0.27.2",
"axios": "^1.2.1",
"compare-versions": "^5.0.1",
"del": "^6.1.1",
"extract-zip": "^2.0.1",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^1.1.0",
@@ -3925,7 +3940,7 @@
"chromedriver": "bin/chromedriver"
},
"engines": {
"node": ">=10"
"node": ">=14"
}
},
"node_modules/ci-info": {
@@ -3940,15 +3955,6 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
"dev": true
},
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/cli-boxes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
@@ -4259,6 +4265,19 @@
"url": "https://github.com/yeoman/configstore?sponsor=1"
}
},
"node_modules/content-scripts-register-polyfill": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/content-scripts-register-polyfill/-/content-scripts-register-polyfill-4.0.2.tgz",
"integrity": "sha512-8hDm+tu3BkxHZP7EUIIIo/495F6QNXF7cI9Lwr4PQaiohw2wWmi9k2SE4W4kNrAaLnFw6RZ2ev8EmrQb+sCoGQ==",
"dependencies": {
"webext-content-scripts": "^2.5.2",
"webext-patterns": "^1.3.0",
"webext-polyfill-kinda": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/fregante"
}
},
"node_modules/convert-source-map": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@@ -4674,28 +4693,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/del": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz",
"integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==",
"dev": true,
"dependencies": {
"globby": "^11.0.1",
"graceful-fs": "^4.2.4",
"is-glob": "^4.0.1",
"is-path-cwd": "^2.2.0",
"is-path-inside": "^3.0.2",
"p-map": "^4.0.0",
"rimraf": "^3.0.2",
"slash": "^3.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
@@ -5961,9 +5958,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true,
"funding": [
{
@@ -6820,15 +6817,6 @@
"node": ">=0.8.19"
}
},
"node_modules/indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
@@ -7114,15 +7102,6 @@
"node": ">=8"
}
},
"node_modules/is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
"integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/is-path-inside": {
"version": "3.0.3",
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
@@ -9266,9 +9245,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -10357,21 +10336,6 @@
"node": ">=8"
}
},
"node_modules/p-map": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
"dev": true,
"dependencies": {
"aggregate-error": "^3.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -12784,6 +12748,48 @@
"node": ">= 8"
}
},
"node_modules/webext-content-scripts": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/webext-content-scripts/-/webext-content-scripts-2.5.2.tgz",
"integrity": "sha512-N1Xq/E8dx0lVAOyPquuo+2Vj9Fx1GoqCFo79lWeJHbemaBJ53N3BHBmbJJYsQ8FOP1xiwN4bPRQY2dpSjHAD3Q==",
"dependencies": {
"webext-patterns": "^1.3.0",
"webext-polyfill-kinda": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/fregante"
}
},
"node_modules/webext-patterns": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/webext-patterns/-/webext-patterns-1.3.0.tgz",
"integrity": "sha512-X9HMnic9ZtvSFKi2cdh0l+sxyj7f9oLedaa2JfxjnyEqGBz8OJjaHQ40jmraX1DJLTHOpqr+rCz1r3MW2+doUg==",
"dependencies": {
"escape-string-regexp": "^5.0.0"
},
"funding": {
"url": "https://github.com/sponsors/fregante"
}
},
"node_modules/webext-patterns/node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/webext-polyfill-kinda": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/webext-polyfill-kinda/-/webext-polyfill-kinda-1.0.0.tgz",
"integrity": "sha512-Py/d3w/bC0KntuO60ePSWHsdrebZ3uYBLeFUjyPkDV3yTEQib0MRFvPh57t8XjImu4ylBoEAsFjzh/r22UtxMw==",
"funding": {
"url": "https://github.com/sponsors/fregante"
}
},
"node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -13336,6 +13342,11 @@
}
},
"dependencies": {
"@ajayyy/maze-utils": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@ajayyy/maze-utils/-/maze-utils-1.1.7.tgz",
"integrity": "sha512-qmakLnRnNJ/CAyDO9ey0ihn71YWoyZfRFxF78ylofA5A+ghBXg4cVVY92iKDN3pivtT2kouLiKDRWgazYKqrOQ=="
},
"@ampproject/remapping": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
@@ -15517,16 +15528,6 @@
"debug": "4"
}
},
"aggregate-error": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
"dev": true,
"requires": {
"clean-stack": "^2.0.0",
"indent-string": "^4.0.0"
}
},
"ajv": {
"version": "6.12.6",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
@@ -15715,13 +15716,14 @@
"dev": true
},
"axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.3.tgz",
"integrity": "sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==",
"dev": true,
"requires": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
},
"dependencies": {
"form-data": {
@@ -16246,15 +16248,14 @@
}
},
"chromedriver": {
"version": "106.0.1",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-106.0.1.tgz",
"integrity": "sha512-thaBvbDEPgGocSp4/SBIajQz3G7UQfUqCOHZBp9TVhRJv7c91eZrUGcjeJUaNF4p9CfSjCYNYzs4EVVryqmddA==",
"version": "110.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-110.0.0.tgz",
"integrity": "sha512-Le6q8xrA/3fAt+g8qiN0YjsYxINIhQMC6wj9X3W5L77uN4NspEzklDrqYNwBcEVn7PcAEJ73nLlS7mTyZRspHA==",
"dev": true,
"requires": {
"@testim/chrome-version": "^1.1.3",
"axios": "^0.27.2",
"axios": "^1.2.1",
"compare-versions": "^5.0.1",
"del": "^6.1.1",
"extract-zip": "^2.0.1",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^1.1.0",
@@ -16273,12 +16274,6 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
"dev": true
},
"clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"dev": true
},
"cli-boxes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
@@ -16518,6 +16513,16 @@
"xdg-basedir": "^5.0.1"
}
},
"content-scripts-register-polyfill": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/content-scripts-register-polyfill/-/content-scripts-register-polyfill-4.0.2.tgz",
"integrity": "sha512-8hDm+tu3BkxHZP7EUIIIo/495F6QNXF7cI9Lwr4PQaiohw2wWmi9k2SE4W4kNrAaLnFw6RZ2ev8EmrQb+sCoGQ==",
"requires": {
"webext-content-scripts": "^2.5.2",
"webext-patterns": "^1.3.0",
"webext-polyfill-kinda": "^1.0.0"
}
},
"convert-source-map": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@@ -16820,22 +16825,6 @@
"object-keys": "^1.1.1"
}
},
"del": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz",
"integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==",
"dev": true,
"requires": {
"globby": "^11.0.1",
"graceful-fs": "^4.2.4",
"is-glob": "^4.0.1",
"is-path-cwd": "^2.2.0",
"is-path-inside": "^3.0.2",
"p-map": "^4.0.0",
"rimraf": "^3.0.2",
"slash": "^3.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
@@ -17756,9 +17745,9 @@
"dev": true
},
"follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true
},
"forever-agent": {
@@ -18354,12 +18343,6 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
@@ -18546,12 +18529,6 @@
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"dev": true
},
"is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
"integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
"dev": true
},
"is-path-inside": {
"version": "3.0.3",
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
@@ -20151,9 +20128,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonfile": {
@@ -20985,15 +20962,6 @@
"p-limit": "^2.2.0"
}
},
"p-map": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
"dev": true,
"requires": {
"aggregate-error": "^3.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -22788,6 +22756,35 @@
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
"dev": true
},
"webext-content-scripts": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/webext-content-scripts/-/webext-content-scripts-2.5.2.tgz",
"integrity": "sha512-N1Xq/E8dx0lVAOyPquuo+2Vj9Fx1GoqCFo79lWeJHbemaBJ53N3BHBmbJJYsQ8FOP1xiwN4bPRQY2dpSjHAD3Q==",
"requires": {
"webext-patterns": "^1.3.0",
"webext-polyfill-kinda": "^1.0.0"
}
},
"webext-patterns": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/webext-patterns/-/webext-patterns-1.3.0.tgz",
"integrity": "sha512-X9HMnic9ZtvSFKi2cdh0l+sxyj7f9oLedaa2JfxjnyEqGBz8OJjaHQ40jmraX1DJLTHOpqr+rCz1r3MW2+doUg==",
"requires": {
"escape-string-regexp": "^5.0.0"
},
"dependencies": {
"escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="
}
}
},
"webext-polyfill-kinda": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/webext-polyfill-kinda/-/webext-polyfill-kinda-1.0.0.tgz",
"integrity": "sha512-Py/d3w/bC0KntuO60ePSWHsdrebZ3uYBLeFUjyPkDV3yTEQib0MRFvPh57t8XjImu4ylBoEAsFjzh/r22UtxMw=="
},
"webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",

View File

@@ -4,6 +4,8 @@
"description": "",
"main": "background.js",
"dependencies": {
"@ajayyy/maze-utils": "^1.1.7",
"content-scripts-register-polyfill": "^4.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
@@ -17,7 +19,7 @@
"@types/wicg-mediasession": "^1.1.4",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1",
"chromedriver": "^106.0.1",
"chromedriver": "^110.0.0",
"concurrently": "^7.4.0",
"copy-webpack-plugin": "^11.0.0",
"eslint": "^8.25.0",

View File

@@ -25,6 +25,9 @@
"Segments": {
"message": "أجزاء"
},
"SegmentsCap": {
"message": "أجزاء من المقطع"
},
"Chapters": {
"message": "الفصول"
},
@@ -115,8 +118,11 @@
"closePopup": {
"message": "إغلاق النافذة المنبثقة"
},
"SubmitTimes": {
"message": "إرسال الأجزاء"
"closeIcon": {
"message": "أيقونة الإغلاق"
},
"sortSegments": {
"message": "ترتيب الأجزاء"
},
"submitCheck": {
"message": "هل أنت متأكد أنك تريد إرسال هذا؟"
@@ -152,9 +158,6 @@
"clearTimesButton": {
"message": "مسح الأوقات"
},
"submitTimesButton": {
"message": "إرسال الأوقات"
},
"publicStats": {
"message": "يستخدم هذا في صفحة الإحصائيات العامة لإظهار مقدار مساهمتك. قم برؤيتها"
},
@@ -321,12 +324,24 @@
"add": {
"message": "أضِف"
},
"showUploadButton": {
"message": "إظهار زر الرفع"
},
"save": {
"message": "حفظ"
},
"reset": {
"message": "إعادة تعيين"
},
"areYouSureReset": {
"message": "هل أنت متيقِّن من رغبتك في إعادة تعيين هذا؟"
},
"mobileUpdateInfo": {
"message": "m.youtube.com مدعوم الآن"
},
"exportOptions": {
"message": "إستيراد/تصدير جميع الإعدادات"
},
"exportOptionsCopy": {
"message": "تعديل/نسخ"
},
@@ -394,6 +409,9 @@
"category_preview": {
"message": "معاينة/خلاصة"
},
"category_preview_guideline2": {
"message": "موجز الفيديو السابق"
},
"category_filler_short": {
"message": "حشو"
},
@@ -406,6 +424,15 @@
"category_poi_highlight": {
"message": "ابراز"
},
"category_poi_highlight_guideline3": {
"message": "يمكن التخطي إلى عنوان المقطع أو الصورة المصغرة"
},
"category_chapter": {
"message": "فصل"
},
"category_chapter_guideline1": {
"message": "لا تذكر أسماء العلامة التجارية الراعية"
},
"category_livestream_messages_short": {
"message": "قراءة الرسالة"
},
@@ -462,6 +489,10 @@
"bracketEnd": {
"message": "(النهاية)"
},
"End": {
"message": "النهاية",
"description": "Button that skips to the end of a segment"
},
"hiddenDueToDownvote": {
"message": "مخفي: تصويت سلبي"
},
@@ -471,15 +502,31 @@
"manuallyHidden": {
"message": "مخفي يدوياً"
},
"acceptPermission": {
"message": "قَبُول الإذن"
},
"permissionRequestSuccess": {
"message": "نجح طلب الإذن!"
},
"permissionRequestFailed": {
"message": "فشل طلب الإذن ، هل نقرت على رفض؟"
},
"adblockerIssueWhitelist": {
"message": "إذا كنت غير قادر على حل هذا، عطل إعداد \"فرض قناة التحقق قبل التخطي\"، لأن SponsorBlock غير قادر على استرداد معلومات القناة لهذا المقطع"
},
"forceChannelCheck": {
"message": "إجبار القناة على التحقق قبل التخطي"
},
"downvoteDescription": {
"message": "خاطئ/التوقيت غير صحيح"
},
"incorrectVote": {
"message": "غير صحيح"
},
"harmfulVote": {
"message": "ضار",
"description": "Used for chapter segments when the text is harmful/offensive to remove it faster"
},
"incorrectCategory": {
"message": "تغيير الفئة"
},
@@ -533,6 +580,9 @@
"helpPageReviewOptions": {
"message": "يرجى مراجعة الخيارات أدناه"
},
"helpPageFeatureDisclaimer": {
"message": "العديد من الميزات معطلة بشكل تلقائي. إذا كنت ترغب في تخطي المقدمة و الخاتمة و استخدام الدعوات و إلخ. يمكنك تمكين هذه الميزات بالأسفل. يمكنك أيضًا إخفاء و إظهار عناصر واجهة المستخدم."
},
"helpPageHowSkippingWorks": {
"message": "كيف يعمل التخطي"
},
@@ -557,6 +607,9 @@
"helpPageSourceCode": {
"message": "أين يمكنني الحصول على شفرة المصدر؟"
},
"Credits": {
"message": "المساهمون في العمل"
},
"LearnMore": {
"message": "معرفة المزيد"
},
@@ -581,6 +634,9 @@
"hideSegment": {
"message": "إخفاء المقطع"
},
"playChapter": {
"message": "شغل الفصل"
},
"SponsorTimeEditScrollNewFeature": {
"message": "استخدم عجلة الماوس أثناء التمرير فوق مربع التعديل لضبط الوقت بسرعة. يمكن استخدام مجموعات مفتاح ctrl أو Shift لضبط التغييرات."
},
@@ -640,5 +696,55 @@
},
"confirmResetToDefault": {
"message": "هل أنت متأكد من أنك تريد إعادة تعيين كافة الإعدادات إلى حالتها الافتراضية؟ لا يمكنك التراجع عن ذلك."
},
"Import": {
"message": "استورد",
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
},
"chooseACountry": {
"message": "اختر البلد"
},
"noDiscount": {
"message": "أنت لست مؤهلاً للحصول على خصم"
},
"discountLink": {
"message": "رابط الخصم (انظر إلى السعر الوردي)"
},
"selectYourCountry": {
"message": "اختر بلدك"
},
"alreadyDonated": {
"message": "إذا تبرعت بأي مبلغ قبل الآن، يمكنك الحصول على إمكانية الوصول عبر التواصل مع البريد الإلكتروني:",
"description": "After the colon is an email address"
},
"patreonSignIn": {
"message": "سجل مع بيتريون (Patreon)"
},
"unsubmittedSegmentCounts": {
"message": "لديك حاليا {0} على {1}",
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
},
"videosSingular": {
"message": "مقطع",
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"
},
"videosPlural": {
"message": "مقاطع",
"description": "Example: You currently have 12 unsubmitted segments on 5 *videos*"
},
"showUnsubmittedSegments": {
"message": "أظهر الأجزاء",
"description": "Show/hide button for the unsubmitted segments list"
},
"videoID": {
"message": "معرف المقطع",
"description": "Header of the unsubmitted segments list"
},
"actions": {
"message": "قائمة الأوامر",
"description": "Header of the unsubmitted segments list"
},
"exportSegmentsAsURL": {
"message": "شارك كرابط"
}
}

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Икона - затваряне"
},
"SubmitTimes": {
"message": "Изпращане на сегментите"
"OpenSubmissionMenu": {
"message": "Отваряне на менюто за изпращане"
},
"sortSegments": {
"message": "Сортиране на сегментите"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Изчистване на времената"
},
"submitTimesButton": {
"message": "Изпращане на времената"
},
"publicStats": {
"message": "Това се използва на страницата с публичната статистика, за да покаже колко сте допринесли. Вижте го"
},
@@ -442,7 +439,7 @@
"message": "Поддръжка на YouTube-сайтове на трети страни"
},
"supportOtherSitesDescription": {
"message": "Поддръжка на клиенти за YouTube на трети страни. За да активирате поддръжката, трябва да приемете допълнителните разрешения. Това НЕ работи в режим инкогнито в Chrome и други варианти на Chromium.",
"message": "Поддръжка на клиенти на трети страни за YouTube. За да активирате поддръжката, трябва да приемете допълнителните разрешения.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Скриване завинаги"
},
"warningChatInfo": {
"message": "Забелязахме, че правите някои често срещани грешки, които не са злонамерени"
"message": "Забелязахме, че допускате някои често срещани грешки. Оценяваме високо досегашната ви работа, но тук се стремим към съвършенство, така че дори и много малките грешки са от значение :)"
},
"warningTitle": {
"message": "Имате предупреждение"

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "বন্ধ করার চিহ্ন"
},
"SubmitTimes": {
"message": "সেগমেন্ট জমা দিন"
"OpenSubmissionMenu": {
"message": "সাবমিশন মেন্যু খুলুন"
},
"sortSegments": {
"message": "সংক্ষিপ্ত অংশ"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "সময় মুছুন"
},
"submitTimesButton": {
"message": "সময় জমা দিন"
},
"publicStats": {
"message": "আপনি কতটা অবদান রেখেছেন তা দেখানোর জন্য এটি সর্বজনীন পরিসংখ্যান পৃষ্ঠায় ব্যবহার করা হয়। এটা দেখ"
},
@@ -442,7 +439,7 @@
"message": "এটি ৩য় পক্ষের ইউটইউব সাইট সাপোর্ট করে"
},
"supportOtherSitesDescription": {
"message": "তৃতীয় পক্ষের ইউটিউব ক্লায়েন্টদের সমর্থন করুন। সমর্থন সক্ষম করতে, আপনাকে অবশ্যই অতিরিক্ত অনুমতিগুলি গ্রহণ করতে হবে। এটি ক্রোম এবং অন্যান্য ক্রোমিয়াম ভেরিয়েন্টগুলিতে ছদ্মবেশে কাজ করে না।",
"message": "তৃতী পক্ষ YouTube ক্লােন্ট সমর্থন করে। এটি চালু করার জন্য আপনাকে কিছু অতিরিক্ত পারমিশনে সম্মতি দিতে হবে।",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -1026,9 +1023,18 @@
"message": "আমদানী",
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
},
"redeemFailed": {
"message": "লাইসেন্স কী অবৈধ"
},
"chooseACountry": {
"message": "দেশ নির্বাচন করুন"
},
"discountLink": {
"message": "মূল্যছাড় লিঙ্ক (পিংক মূল্য দেখুন)"
},
"selectYourCountry": {
"message": "আপনার দেশ নির্বাচন করুন"
},
"videosSingular": {
"message": "ভিডিও",
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"

View File

@@ -112,9 +112,6 @@
"closePopup": {
"message": "Tanca la finestra"
},
"SubmitTimes": {
"message": "Envia els segments"
},
"submitCheck": {
"message": "Segur que voleu enviar això?"
},
@@ -149,9 +146,6 @@
"clearTimesButton": {
"message": "Esborra temps"
},
"submitTimesButton": {
"message": "Envia temps"
},
"publicStats": {
"message": "Això s'utilitza a la pàgina d'estadístiques pública per fatxendejar de quant heu contribuït. Vegeu"
},

View File

@@ -4,7 +4,7 @@
"description": "Name of the extension."
},
"Description": {
"message": "Přeskoč sponzorství, žadonění o odběr a další v YouTube videích. Nahlaš sponzorované segmenty na videích co sleduješ a ušetři ostatním čas.",
"message": "Přeskočte sponzorství, žádosti o odběr a další ve videích na YouTube. Nahlaste sponzorované segmenty ve videích, která sledujete a ušetřete ostatním čas.",
"description": "Description of the extension."
},
"400": {
@@ -99,7 +99,7 @@
"message": "Zrušit vytváření segmentu"
},
"noVideoID": {
"message": "Nebylo nalezeno žádné YouTube video.\nPokud je to špatně, obnovte záložku."
"message": "Nebylo nalezeno žádné YouTube video.\nPokud je to špatně, obnovte kartu."
},
"refreshSegments": {
"message": "Aktualizovat segmenty"
@@ -111,7 +111,7 @@
"message": "Hlasováno!"
},
"serverDown": {
"message": "Zdá se, že server nefunguje. Obraťte se okamžitě na vývojáře."
"message": "Zdá se, že server je offline. Okamžitě kontaktujte vývojáře."
},
"connectionError": {
"message": "Došlo k chybě připojení. Kód chyby: "
@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Ikona pro zavření"
},
"SubmitTimes": {
"message": "Odeslat segmenty"
"OpenSubmissionMenu": {
"message": "Otevřít nabídku příspěvků"
},
"sortSegments": {
"message": "Seřadit segmenty"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Vymazat časy"
},
"submitTimesButton": {
"message": "Odeslat časy"
},
"publicStats": {
"message": "Toto se používá ve veřejném žebříčku k ukázání jak moc jste přispěli. Podívejte se na něj"
},
@@ -250,7 +247,7 @@
"message": "Místo žádání o segmenty ze serveru pomocí videoID jsou poslány první 4 charaktery hashe ve videoID. Tento server odešle zpět data pro všechna videa s podobnými hashy."
},
"enableRefetchWhenNotFound": {
"message": "Refetovat segmenty na nových videích"
"message": "Automaticky znovu načítat segmenty na nových videích"
},
"whatRefetchWhenNotFound": {
"message": "Pokud je video nové a nejsou nalezeny žádné segmenty, bude rozšíření každých několik minut refetchovat data, zatímco sledujete video."
@@ -442,7 +439,7 @@
"message": "Podpora pro weby YouTube třetích stran"
},
"supportOtherSitesDescription": {
"message": "Podpora pro YouTube klienty třetích stran. Chcete-li povolit podporu, musíte přijmout další oprávnění. Toto NEFUNGUJE v anonymním režimu v Chromu a dalších Chromium prohlížečích.",
"message": "Podporovat klienty YouTube třetích stran. Pro povolení podpory musíte přijmout dodatečná oprávnění.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Skrýt napořád"
},
"warningChatInfo": {
"message": "Všimli jsme si, že děláte některé běžné chyby, které nejsou úmyslně zlé"
"message": "Všimli jsme si, že děláte některé běžné chyby. Velmi si vážíme vaší dosavadní práce, ale snažíme se zde o dokonalost, takže i na velmi malých chybách záleží :)"
},
"warningTitle": {
"message": "Dostali jste varování"

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Luk ikon"
},
"SubmitTimes": {
"message": "Indsend Segmenter"
},
"sortSegments": {
"message": "Sortér Segmenter"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Ryd Tider"
},
"submitTimesButton": {
"message": "Indsend Tider"
},
"publicStats": {
"message": "Dette bruges på siden med offentlige statistikker til at vise, hvor meget du har bidraget. Se det"
},
@@ -441,10 +435,6 @@
"supportOtherSites": {
"message": "Understøtter tredjeparts YouTube sider"
},
"supportOtherSitesDescription": {
"message": "Understøt tredjeparts YouTube klienter. For at aktivere understøttelse, skal du acceptere de ekstra tilladelser. Dette virker IKKE i inkognito på Chrome og andre Chromium varianter.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Understøttede Sider: "
},
@@ -941,9 +931,6 @@
"hideForever": {
"message": "Skjul for evigt"
},
"warningChatInfo": {
"message": "Vi bemærkede, at du lavede nogle almindelige fejl, som ikke er ondsindede"
},
"warningTitle": {
"message": "Du fik en advarsel"
},

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Symbol schließen"
},
"SubmitTimes": {
"message": "Senden"
"OpenSubmissionMenu": {
"message": "Einreichungsmenü öffnen"
},
"sortSegments": {
"message": "Segmente sortieren"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Zeiten löschen"
},
"submitTimesButton": {
"message": "Zeiten übermitteln"
},
"publicStats": {
"message": "So wirst du in der öffentlichen Rangliste angezeigt. Siehe"
},
@@ -372,7 +369,7 @@
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} stummgeschalten",
"message": "{0} stummgeschaltet",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
@@ -442,7 +439,7 @@
"message": "Unterstütze Drittanbieter YouTube-Seiten"
},
"supportOtherSitesDescription": {
"message": "Unterstütze Drittanbieter YouTube Clients. Zum unterstützen müssen zusätzlichliche Berechtigungen akzeptiert werden. Dies funktioniert NICHT im Incognitomodus auf Chrome oder anderen Chromium Varianten.",
"message": "Unterstütze YouTube-Clients von Drittanbietern. Um die Unterstützung zu aktivieren, müssen Sie die zusätzlichen Berechtigungen akzeptieren.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Dauerhaft verbergen"
},
"warningChatInfo": {
"message": "Wir haben bemerkt, dass du einige häufige Fehler machst welche nicht bösartig sind"
"message": "Wir haben festgestellt, dass du einige häufig gemacht Fehler machst. Wir schätzen deine bisherige Arbeit sehr, streben aber hier aber auch nach Perfektion, sodass es auch wichtig ist kleine Fehler zu korrigieren :)"
},
"warningTitle": {
"message": "Du hast eine Verwarnung erhalten"

View File

@@ -122,9 +122,6 @@
"closePopup": {
"message": "Κλείσιμο αναδυόμενου παραθύρου"
},
"SubmitTimes": {
"message": "Υποβολή Τμημάτων"
},
"sortSegments": {
"message": "Ταξινόμηση Τμημάτων"
},
@@ -162,9 +159,6 @@
"clearTimesButton": {
"message": "Σβήσιμο τμημάτων"
},
"submitTimesButton": {
"message": "Υποβολή τμημάτων"
},
"publicStats": {
"message": "Χρησιμοποιείται στη δημόσια σελίδα στατιστικών για να αναδειχθεί πόσο έχετε συμβάλει. Δείτε το"
},
@@ -409,10 +403,6 @@
"supportOtherSites": {
"message": "Υποστήριξη 3των ιστοσελίδων τύπου YouTube"
},
"supportOtherSitesDescription": {
"message": "Υποστήριξη 3των πελατών διακομιστή YouTube. Για να ενεργοποιήσετε την υποστήριξη πρέπει να αποδεχτείτε επιπλέον άδειες. Αυτό ΔΕ λειτουργεί σε καρτέλες ανώνυμης περιήγησης του Chrome ή άλλων Chromium εκδοχών.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Υποστηριζόμενες Ιστοσελίδες: "
},
@@ -855,9 +845,6 @@
"hideForever": {
"message": "Απόκρυψη για πάντα"
},
"warningChatInfo": {
"message": "Παρατηρήσαμε ότι κάνατε συνηθισμένα μη κακόβουλα λάθη"
},
"warningTitle": {
"message": "Λάβατε προειδοποίηση"
},

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Close Icon"
},
"SubmitTimes": {
"message": "Submit Segments"
"OpenSubmissionMenu": {
"message": "Open Submission Menu"
},
"sortSegments": {
"message": "Sort Segments"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Clear Times"
},
"submitTimesButton": {
"message": "Submit Times"
},
"publicStats": {
"message": "This is used on the public stats page to show off how much you've contributed. See it"
},
@@ -442,7 +439,7 @@
"message": "Support 3rd Party YouTube-Sites"
},
"supportOtherSitesDescription": {
"message": "Support third party YouTube clients. To enable support, you must accept the extra permissions. This does NOT work in incognito on Chrome and other Chromium variants.",
"message": "Support third party YouTube clients. To enable support, you must accept the extra permissions.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Icono de cerrar"
},
"SubmitTimes": {
"message": "Enviar Segmentos"
},
"sortSegments": {
"message": "Ordenar Segmentos"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Eliminar Tiempos"
},
"submitTimesButton": {
"message": "Enviar Tiempos"
},
"publicStats": {
"message": "Esto se utiliza en la página de estadísticas públicas para mostrar cuánto has contribuido. Véala"
},
@@ -424,16 +418,16 @@
"message": "Comprueba status.sponsor.ajay.app para ver el estado del servidor."
},
"changeUserID": {
"message": "Importar/Exportar su ID de usuario Privado"
"message": "Importar/Exportar su ID de usuario privado"
},
"whatChangeUserID": {
"message": "Esto se debería mantener privado. Esto es como una contraseña y no debe ser compartido con nadie. Si alguien tiene esto, puede suplantarte. Si estás buscando tu ID de usuario Público, haz clic en el icono de portapapeles en la ventana emergente."
},
"setUserID": {
"message": "Establecer ID de usuario Privado"
"message": "Establecer ID de usuario privado"
},
"userIDChangeWarning": {
"message": "Advertencia: El cambio del ID de usuario Privado es permanente. ¿Está seguro/a de que desea hacer esto? Asegúrese de respaldar el antiguo por si acaso."
"message": "Advertencia: El cambio del ID de usuario privado es permanente. ¿Está seguro/a de que desea hacer esto? Asegúrese de respaldar el antiguo por si acaso."
},
"createdBy": {
"message": "Creado Por"
@@ -442,7 +436,7 @@
"message": "Soportar sitios de YouTube de terceros"
},
"supportOtherSitesDescription": {
"message": "Soportar clientes de YouTube de terceros. Para habilitar el soporte, debes aceptar los permisos extra. Esto NO funciona en incógnito en Chrome y otras variantes de Chromium.",
"message": "Admite clientes de YouTube de terceros. Para activar la compatibilidad, debes aceptar los permisos adicionales.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -595,7 +589,7 @@
"message": "Incluye transiciones entre segmentos"
},
"generic_guideline2": {
"message": "Se reproduce como si no se hubiera omitido nada"
"message": "Reproduce como si nada se omitiera"
},
"category_sponsor": {
"message": "Sponsor"
@@ -607,7 +601,7 @@
"message": "Promociones pagadas"
},
"category_sponsor_guideline2": {
"message": "No para donaciones o mercancía personalizada"
"message": "No para donaciones o merchandising"
},
"category_selfpromo": {
"message": "Promoción Propia/No Remunerada"
@@ -616,13 +610,13 @@
"message": "Similar a \"sponsor\", excepto que para la promoción propia o no remunerada. Esto incluye secciones sobre mercancía, donaciones o información sobre con quiénes colaboraron."
},
"category_selfpromo_guideline1": {
"message": "Donaciones, membresías y mercancía personalizada"
"message": "Donaciones, afiliaciones y merchandising"
},
"category_selfpromo_guideline2": {
"message": "Agradecimientos gratuitos que no contribuyen al video"
"message": "Comentarios inútiles que no aportan nada al vídeo"
},
"category_selfpromo_guideline3": {
"message": "No para productos ni mercancía diseñados por empresas"
"message": "No para productos y merchandising de empresas"
},
"category_exclusive_access": {
"message": "Acceso Exclusivo"
@@ -644,13 +638,13 @@
"message": "Cuando hay un breve recordatorio para dar me gusta, suscribirse o seguirlos en medio del contenido. Si es largo o sobre algo específico, debería estar bajo promoción propia en su lugar."
},
"category_interaction_guideline1": {
"message": "Breve recordatorio para dar me gusta, suscribirse o seguir"
"message": "Recordatorios breves para darle a me gusta, suscribirse o seguir"
},
"category_interaction_guideline2": {
"message": "Incluye recordatorios indirectos para comentar"
},
"category_interaction_guideline3": {
"message": "No para promoción general, solo llamadas a la acción"
"message": "No para promoción general, solo peticiones de actuación"
},
"category_interaction_short": {
"message": "Recordatorio de Interacción"
@@ -677,19 +671,19 @@
"message": "Créditos o cuando aparecen las tarjetas finales de YouTube. No para conclusiones con información."
},
"category_outro_guideline1": {
"message": "No incluyas contenido, aun si las tarjetas finales están en pantalla"
"message": "No incluyas contenido, aunque se estén mostrando las tarjetas finales"
},
"category_preview": {
"message": "Vista previa/Recapitulación"
},
"category_preview_description": {
"message": "Colección de clips que muestran lo que vendrá en este video u otros videos en una serie en la cual toda la información es repetida en el video."
"message": "Colección de vídeos que muestran lo que se verá en este vídeo o en otros vídeos de una serie en la que toda esta información se repite más adelante en el vídeo."
},
"category_preview_guideline1": {
"message": "Clips que aparecen más tarde o en un video futuro"
"message": "Vídeos que aparecen más tarde, o en un vídeo futuro"
},
"category_preview_guideline2": {
"message": "Recapitulación de un video anterior"
"message": "Recopilación de un vídeo anterior"
},
"category_preview_guideline3": {
"message": "No para secciones que añaden contenido adicional"
@@ -698,7 +692,7 @@
"message": "Tangentes de Relleno/Chistes"
},
"category_filler_description": {
"message": "Escenas tangenciales añadidas solo de relleno o humor que no son necesarias para entender el contenido principal del video. Esto no debe incluir segmentos que proporcionen contexto o detalles de fondo. Esta es una categoría muy agresiva para cuando no está de humor para la \"diversión\"."
"message": "Escenas tangenciales añadidas solo como relleno o humor que no son necesarias para entender el contenido principal del vídeo. Esto no debería incluir segmentos que proporcionen contexto o detalles de fondo. Es una categoría muy agresiva pensada para cuando no se está de humor para «divertirse»."
},
"category_filler_short": {
"message": "Relleno"
@@ -707,7 +701,7 @@
"message": "Escenas tangenciales solo de relleno o humor"
},
"category_filler_guideline2": {
"message": "Distracciones, bloopers, repeticiones"
"message": "Distracciones, meteduras de pata, repeticiones"
},
"category_filler_guideline3": {
"message": "No para escenas requeridas para entender el tema"
@@ -725,7 +719,7 @@
"message": "Secciones que no están en versiones oficiales"
},
"category_music_offtopic_guideline2": {
"message": "Secciones sin música en un espectáculo en vivo"
"message": "Sin música en un espectáculo en directo"
},
"category_poi_highlight": {
"message": "Destacado"
@@ -734,7 +728,7 @@
"message": "La parte del video que la mayoría de gente está buscando. Similar a los comentarios que dicen \"El video comienza en x\"."
},
"category_poi_highlight_guideline1": {
"message": "La sección que la mayoría de personas están buscando"
"message": "Sección que busca la mayoría"
},
"category_poi_highlight_guideline2": {
"message": "Puede omitir contexto"
@@ -942,7 +936,7 @@
"message": "Ocultar para siempre"
},
"warningChatInfo": {
"message": "Hemos notado que has estado cometiendo algunos errores comunes que no son maliciosos"
"message": "Nos hemos dado cuenta de que cometías algunos errores comunes. Apreciamos mucho tu trabajo hasta ahora, pero aquí nos esforzamos por alcanzar la perfección, así que incluso los errores más pequeños importan :)"
},
"warningTitle": {
"message": "Tienes una advertencia"
@@ -1170,7 +1164,7 @@
"message": "Canjear"
},
"joinOnPatreon": {
"message": "Danos tu apoyo en Patreon"
"message": "Suscríbete en Patreon"
},
"oneTimePurchase": {
"message": "Compra única"
@@ -1179,25 +1173,25 @@
"message": "Ingresar clave de licencia"
},
"chaptersPage1": {
"message": "La característica de los capítulos de origen de SponsorBlock sólo está disponible para personas que compran una licencia, o para las personas a las que se les concede acceso gratis debido a sus contribuciones anteriores"
"message": "La función de capítulos colaborativos de SponsorBlock solo está disponible para las personas que adquieran una licencia o para aquellas a las que se les conceda acceso gratuito debido a sus contribuciones anteriores"
},
"chaptersPage2": {
"message": "Nota: El permiso para enviar capítulos todavía está basado en la reputación calculada. Comprar una licencia solo le permite ver los capítulos enviados por otros",
"message": "Nota: el permiso para enviar capítulos sigue basándose en la reputación calculada. La compra de una licencia solo te permite ver los capítulos enviados por otros usuarios",
"description": "On the chapters page for getting access to the paid chapters feature"
},
"chapterNewFeature": {
"message": "Nueva Función: Capítulos personalizados marcados por la comunidad. Estos son secciones con nombres personalizados en los videos que pueden ser acumulados para ser cada vez más precisos. Compre una licencia para ver los capítulos enviados en este video, como: ",
"message": "Nueva función: capítulos personalizados creados por la comunidad. Se trata de secciones con nombres personalizados que se pueden superponer en los vídeos para obtener una mayor precisión. Adquiere una licencia para ver los capítulos presentados en este vídeo como: ",
"description": "After the comma, a list of chapters for this video will appear"
},
"chapterNewFeature2": {
"message": "Nueva Función: Capítulos personalizados marcados por la comunidad. Estos son secciones con nombres personalizados en los videos que pueden ser acumulados para ser cada vez más precisos. Tiene acceso gratuito, habilítelo en opciones."
"message": "Nueva función: capítulos personalizados creados por la comunidad. Se trata de secciones con nombres personalizados que se pueden superponer en los vídeos para obtener una mayor precisión. Tienes acceso de forma gratuita, se activa en las opciones."
},
"unsubmittedSegmentCounts": {
"message": "Actualmente tienes {0} en {1}",
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
},
"unsubmittedSegmentCountsZero": {
"message": "Actualmente no tiene segmentos sin enviar",
"message": "Actualmente, no tiene segmentos sin enviar",
"description": "Replaces 'unsubmittedSegmentCounts' string when there are no unsubmitted segments"
},
"unsubmittedSegmentsSingular": {

View File

@@ -36,7 +36,7 @@
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
},
"showSegmentNameInChapterBar": {
"message": "Kuva praegune segment video kõrval"
"message": "Kuva praegune segment video aja kõrval"
},
"upvoteButtonInfo": {
"message": "Anna segmendile poolthääl"
@@ -117,7 +117,7 @@
"message": "Ühendusega esines tõrge. Veakood: "
},
"segmentsStillLoading": {
"message": "Segmendid on veel laadimas..."
"message": "Segmente veel laetakse..."
},
"clearTimes": {
"message": "Tühjenda segmendid"
@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Sulgemisikoon"
},
"SubmitTimes": {
"message": "Esita segmendid"
},
"sortSegments": {
"message": "Sorteeri segmendid"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Tühjenda ajad"
},
"submitTimesButton": {
"message": "Saada ajad"
},
"publicStats": {
"message": "Seda kasutatakse avaliku statistika lehel, et näidata välja, kui palju oled panustanud. Vaata seda"
},
@@ -255,6 +249,12 @@
"whatRefetchWhenNotFound": {
"message": "Kui video on uus ning segmente ei leitud, proovitakse vaatamise ajal iga paari minuti tagant uuesti segmente tuua."
},
"enableShowCategoryWithoutPermission": {
"message": "Näita kategooriaid segmentide menüüs isegi ilma segmendi esitamise loata"
},
"whatShowCategoryWithoutPermission": {
"message": "Osade kategooriate esitamiseks on minimaalse reputatsiooni nõuete tõttu vajalik luba"
},
"showNotice": {
"message": "Kuva märkus uuesti"
},
@@ -319,6 +319,9 @@
"message": "Eelmine peatükk",
"description": "Keybind label"
},
"keybindDescription": {
"message": "Valige klahv vajutades sellele, seejärel valige need teisendklahvid, mida soovite kasutada."
},
"0": {
"message": "Ühenduse ajalõpp. Kontrolli oma võrguühendust. Kui internet töötab, on ilmselt server ülekoormatud või maas."
},
@@ -414,9 +417,18 @@
"statusReminder": {
"message": "Serveri oleku saamiseks vaata status.sponsor.ajay.app"
},
"changeUserID": {
"message": "Impordi/ekspordi oma privaatne UserID"
},
"whatChangeUserID": {
"message": "Seda tuleks privaatsena hoida. See on nagu parool ning seda ei tohiks kellegagi jagada. Kui kellelgi see on, saavad nad sinuna esineda.\nKui otsid avalikku UserID'd, klõpsa hüpikus olevat lõikelaua ikooni."
},
"setUserID": {
"message": "Määra privaatne UserID"
},
"userIDChangeWarning": {
"message": "Tähelepanu: privaatse UserID muutmine on lõplik. Kas soovid kindlasti seda teha? Igaks juhuks soovitame eelmise UserID varundada."
},
"createdBy": {
"message": "Autor"
},
@@ -424,7 +436,7 @@
"message": "Toeta 3. osapoole YouTube-saite"
},
"supportOtherSitesDescription": {
"message": "Kolmanda osapoole YouTube'i klientide tugi. Selle toe lubamiseks pead nõustuma lisalubadega. See EI tööta inkognito-režiimis nii Chromes kui ka teistes Chromiumi brauserites.",
"message": "Kolmanda osapoole YouTube'i klientide tugi. Selle toe lubamiseks pead nõustuma lisalubadega.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -460,6 +472,12 @@
"minDurationDescription": {
"message": "Segmendid, mis on lühemad kui määratud väärtus ei jäeta vahele või ei kuvata mängijal."
},
"enableManualSkipOnFullVideo": {
"message": "Jäta käsitsi vahele, kui täis video pealkiri on saadaval"
},
"whatManualSkipOnFullVideo": {
"message": "Inimestele, kes soovivad vaadata (enese-)reklaami sisaldavat videot segamatult."
},
"skipNoticeDuration": {
"message": "Vahelejätmise teavituse kestus (sekundites):"
},
@@ -469,6 +487,9 @@
"shortCheck": {
"message": "See saadetav segment on lühem, kui sinu lühima pikkuse valik. See võib tähendada, et see on juba saadetud ning on selle valiku tõttu lihtsalt ignoreeritud. Kas soovid kindlasti seda saata?"
},
"liveOrPremiere": {
"message": "Käimasolevale otseülekandele segmentide esitamine pole lubatud. Palun oodake kuni otseülekanne lõpeb, värskendage lehte ja kontrollige siis, kas segmendid on jätkuvalt kehtivad."
},
"showUploadButton": {
"message": "Kuva üleslaadimisnupp"
},
@@ -505,6 +526,9 @@
"exportOptionsUpload": {
"message": "Laadi failist"
},
"whatExportOptions": {
"message": "See on sinu terve seadistus JSON-formaadis. See sisaldab sinu privaatset UserID-d, seega ole tähelepanelik, kellega seda jagad."
},
"setOptions": {
"message": "Määra valikud"
},
@@ -550,6 +574,9 @@
"copyDebugInformationComplete": {
"message": "Silumisinfo on lõikelauale kopeeritud. Võid sellelt vabalt eemaldada mistahes info, mida ei soovi jagada. Salvesta see tekstifaili või kleebi vearaportisse."
},
"keyAlreadyUsed": {
"message": "See kiirkombinatsioon on juba kasutuses teise toimingu poolt. Palun valige teine kiirkombinatsioon."
},
"to": {
"message": "kuni",
"description": "Used between segments. Example: 1:20 to 1:30"
@@ -664,6 +691,9 @@
"category_filler": {
"message": "Täitesisu/naljad"
},
"category_filler_description": {
"message": "Video täiteks või huumori eesmärgil lisatud sisu, mis ei ole vajalik video põhieesmärgi mõistmiseks. Selle alla ei kuulu segmendid, mis annavad kontekstiteavet või taustainfot. See on väga agressiivne kategooria, mis on mõeldud olukorraks, kui te pole \"parimas tujus\"."
},
"category_filler_short": {
"message": "Täide"
},
@@ -709,9 +739,18 @@
"category_chapter": {
"message": "Peatükk"
},
"category_chapter_description": {
"message": "Isikupärastatava pealkirjaga peatükid, mis kirjeldavad tähtsamaid video osi."
},
"category_chapter_guideline1": {
"message": "Ära maini sponsorite brändi nimesid"
},
"category_chapter_guideline2": {
"message": "Kasutage suuri peatükke peamiste osade jaoks"
},
"category_chapter_guideline3": {
"message": "Lühikesemaid peatükke saab paigutada suurtemate peatükkide sisse"
},
"category_livestream_messages": {
"message": "Otseülekanne: annetuste ja sõnumite lugemine"
},
@@ -817,6 +856,9 @@
"description": "This error appears in an alert when they try to whitelist a channel and the extension is unable to determine what channel they are looking at.",
"message": "Kanali ID pole veel laaditud. Kui vaatad manustatud videot, proovi seda vaadata YouTube'i kodulehelt. See võib olla põhjustatud ka YouTube'i paigutuse muudatustest - kui arvad et see nii on, kommenteeri siin:"
},
"invidiousPermissionRefresh": {
"message": "Teie veebilehitseja on eemaldanud loa, mis on vajalik korrektseks tööks Invidious platformil ja muudel kolmandate osapoolte lehtedel. Vajutage allolevat nuppu, et taaskäivitada see luba."
},
"acceptPermission": {
"message": "Nõustu loaga"
},
@@ -877,9 +919,15 @@
"message": "Sain aru",
"description": "Used as the button to dismiss a tooltip"
},
"fullVideoTooltipWarning": {
"message": "See segment on üsna suur. Kui kogu video vältel käsitletakse üht teemat, muutke seade \"jäta vahele\" seadeks \"Täis video\". Vaadake juhiseid rohkema info jaoks."
},
"categoryPillTitleText": {
"message": "See terve video on selle kategooriaga sildistatud ning on liiga tihedalt integreeritud, et eraldada saaks"
},
"chapterNameTooltipWarning": {
"message": "Üks teie peatükkidest sarnaneb kategooriaga. Kui võimalik, kasutage kategooriaid."
},
"experiementOptOut": {
"message": "Keeldu kõigist tulevikus tehtavatatest eksperimentidest",
"description": "This is used in a popup about a new experiment to get a list of unlisted videos to back up since all unlisted videos uploaded before 2017 will be set to private."
@@ -888,7 +936,7 @@
"message": "Peida igaveseks"
},
"warningChatInfo": {
"message": "Panime tähele, et tegid teatud sagedasi vigu, mis ei olnud pahatahtlikud"
"message": "Märkasime, et olete teinud paar üsna tavalist viga. Oleme teie töö eest väga tänulikud, aga me püüdleme täiuslikkuse poole, seega iga väike viga loeb :)"
},
"warningTitle": {
"message": "Sa said hoiatuse"
@@ -921,20 +969,38 @@
"message": "Palun vaata allolevad valikud üle"
},
"helpPageFeatureDisclaimer": {
"message": "Paljud funktsioonid on vaikimisi välja lülitatud. Kui sa soovid jätta vahele vaheaejad, kasutada Invidioust jms, lülita need allpool sisse. Sa saad ka peita/kuvada kasutajaliidese elemente."
"message": "Paljud funktsioonid on vaikimisi välja lülitatud. Kui te soovite jätta vahele sissejutatused, kokkuvõtted, kasutada Invidioust jms, lülitage need allpool sisse. Te saate ka peita/kuvada kasutajaliidese elemente."
},
"helpPageHowSkippingWorks": {
"message": "Kuidas vahelejätmine töötab"
},
"helpPageHowSkippingWorks1": {
"message": "Video segmendid jäetakse automaatselt vahele, kui nendele vastavad segmendid leitakse andmebaasist. Saate avada hüpikakna vajutades SponsorBlock-i logo peale - nii saate näha eelvaadet nendest segmentidest."
},
"helpPageHowSkippingWorks2": {
"message": "Iga kord, kui jätate segmendi vahele, saadetakse teie teavitus. Kui segmendi ajastus tundub vale või ebatäpsena - hääletage see valeks vajutades vastuhäälele. Hääletamine on võimalik ka hüpikakna abil."
},
"Submitting": {
"message": "Saatmine"
},
"helpPageSubmitting1": {
"message": "Segmentide esitamine on võimalik kas käsitsi hüpikakna abil, vajutades \"Segment algab siit\" või läbi videopleieri kasutades pleieriribas olevaid kahte nuppu."
},
"helpPageSubmitting2": {
"message": "Vajutades play-nuppu märgite segmendi alguse ning stop-nuppu vajutades märgite segmendi lõpu. Võite märkida mitu sponsorit enne \"saada\" vajutamist. Vajutades üleslaadimisnupule laetakse teie loodud segmendid andmebaasi. Vajutades prügikastile kustutatakse teie märgitud segmendid."
},
"Editing": {
"message": "Redigeerimine"
},
"helpPageEditing1": {
"message": "Juhul, kui tegite vea, saate muuta või kustutada oma segmente vajutades üles näitavat noolt."
},
"helpPageTooSlow": {
"message": "See on liiga aeglane"
},
"helpPageTooSlow1": {
"message": "Kiirklahvid on saadaval, kui soovite neid kasutada. Vajutage semikooloniga klahvi, et märkida segmendi algus või lõpp ning vajutage ülakomaga klahvi, et oma segmendid esitada. Need kiirklahvid on muudetavad seadetest. Kui te ei kasuta QWERTY-klaviatuuri, tuleb teil tõenäoliselt muuta klahviseoseid."
},
"helpPageCopyOfDatabase": {
"message": "Kas ma saaksin andmebaasist koopia? Mis juhtub, kui sa kaod?"
},
@@ -1068,15 +1134,29 @@
"redeemFailed": {
"message": "Litsentsivõti on sobimatu"
},
"hideUpsells": {
"message": "Peida valikud, mis on saadaval vaid lisatasu eest"
},
"chooseACountry": {
"message": "Vali riik"
},
"noDiscount": {
"message": "Te ei kvalifitseeru allahindluse saamiseks"
},
"discountLink": {
"message": "Soodushinna link (vaata roosat hinda)"
},
"selectYourCountry": {
"message": "Vali oma riik"
},
"alreadyDonated": {
"message": "Kui olete annetanud ükskõik millise summa, saate lunastada oma tasuta ligipääsu saates kirja e-postile:",
"description": "After the colon is an email address"
},
"cantAfford": {
"message": "Kui te ei saa lubada endale litsensi soetamist, vajutage {here}, et uurida, kas kvalifitseerute allahindluse saamisele",
"description": "Keep the curly braces. The word 'here' should be translated as well."
},
"patreonSignIn": {
"message": "Logi Patreoniga sisse"
},
@@ -1095,6 +1175,17 @@
"chaptersPage1": {
"message": "SponsorBlocki kogukonna-loodud peatükkide funktsioon on saadaval vaid inimestele, kes ostavad litsentsi või neile, kes saavad tasuta ligipääsu varasemate panuste tõttu"
},
"chaptersPage2": {
"message": "NB: Teie luba peatükke esitada on jätkuvalt põhinev reputatsiooni arvutustel. Litsensi soetamine lubab vaid teiste inimeste peatükke näha",
"description": "On the chapters page for getting access to the paid chapters feature"
},
"chapterNewFeature": {
"message": "Uus Funktsioon: Rahva poolt rahastatavad isikupärased peatükid. Need on isikupärastatava pealikirjaga peatükid videos, mis on samuti ühildatavad, et näidata täpsemat segmendi pikkust. Soetage litsents, et näha selle video jaoks esitatud peatükke, nt: ",
"description": "After the comma, a list of chapters for this video will appear"
},
"chapterNewFeature2": {
"message": "Uus Funktsioon: Rahva poolt rahastatavad isikupärased peatükid. Need on isikupärastatava pealikirjaga peatükid videos, mis on samuti ühildatavad, et näidata täpsemat segmendi pikkust. Teil on tasuta ligipääs, lülitage see seadetest sisse."
},
"unsubmittedSegmentCounts": {
"message": "Sul on hetkel {0} {1}",
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
@@ -1151,7 +1242,7 @@
"message": "Jaga URLina"
},
"segmentFetchFailureWarning": {
"message": "Hoiatus: Server ei ole veel segmentidega vastanud. Sellel videol võivad juba olla saadetud segmendid, aga sa ei ole veel neid serveri vea tõttu saanud."
"message": "Tähelepanu: Server ei ole veel segmente edastanud. Sellel videol võivad olla esitatud segmendid, aga te pole neid serveri tõrke tõttu kätte saanud."
},
"allowScrollingToEdit": {
"message": "Luba aegade muutmiseks kerimine"

View File

@@ -109,9 +109,6 @@
"closePopup": {
"message": "بستن پنجره"
},
"SubmitTimes": {
"message": "ثبت بخش‌ها"
},
"submitCheck": {
"message": "مطمئن هستید که میخواهید این را ثبت کنید؟"
},
@@ -139,9 +136,6 @@
"clearTimesButton": {
"message": "حذف دفعات"
},
"submitTimesButton": {
"message": "ثبت دفعات"
},
"Username": {
"message": "نام‌کاربری"
},

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Sulkukuvake"
},
"SubmitTimes": {
"message": "Lähetä osiot"
"OpenSubmissionMenu": {
"message": "Avaa Lähetykset-valikko"
},
"sortSegments": {
"message": "Järjestä osiot"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Tyhjennä ajat"
},
"submitTimesButton": {
"message": "Lähetä ajat"
},
"publicStats": {
"message": "Tätä käytetään julkisella tilastosivulla näyttääksesi kuinka paljon olet osallistunut. Näytä"
},
@@ -442,7 +439,7 @@
"message": "Tue kolmansien osapuolien YouTube-sivustoja"
},
"supportOtherSitesDescription": {
"message": "Tue kolmannen osapuolen YouTube-asiakasohjelmia. Jotta voit ottaa käyttöön tuen, sinun täytyy hyväksyä lisäkäyttöoikeudet. Tämä EI toimi incognitossa Chromessa ja muissa Chromium varianteissa.",
"message": "Tue kolmannen osapuolen YouTube-sovelluksia. Ottaaksesi tuen käyttöön, sinun on hyväksyttävä tarvittavat käyttöoikeudet.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Piilota ikuisesti"
},
"warningChatInfo": {
"message": "Huomasimme, että teit joitakin yleisiä virheitä, jotka eivät ole haitallisia"
"message": "Huomasimme, että teit joitakin yleisiä virheitä. Arvostamme työtäsi erittäin paljon, mutta pyrimme täydellisyyteen, joten pienilläkin virheillä on väliä :)"
},
"warningTitle": {
"message": "Sait varoituksen"

View File

@@ -106,9 +106,6 @@
"closePopup": {
"message": "Isara ang Popup"
},
"SubmitTimes": {
"message": "I-submit ang mga segments"
},
"submitCheck": {
"message": "Sigurado ka bang gusto mong isumite ito?"
},

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Icône \"Fermer\""
},
"SubmitTimes": {
"message": "Soumettre des segments"
"OpenSubmissionMenu": {
"message": "Ouvrir le menu Contribution"
},
"sortSegments": {
"message": "Trier les segments"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Supprimer les temps"
},
"submitTimesButton": {
"message": "Soumettre les temps"
},
"publicStats": {
"message": "Votre pseudo est inscrit dans le classement public pour afficher vos contributions. Le consulter"
},
@@ -235,7 +232,7 @@
"message": "Activer le suivi du nombre de sauts dans les onglets privés/incognito"
},
"enableTrackDownvotes": {
"message": "Enregistrer les segments contre lesquels vous avez voté"
"message": "Enregistrer les segments votés négativement"
},
"whatTrackDownvotes": {
"message": "Tous les segments votés négativement resteront cachés même après rafraîchissement de la page"
@@ -442,7 +439,7 @@
"message": "Support de sites tiers YouTube"
},
"supportOtherSitesDescription": {
"message": "Support de clients YouTube tierces. Pour habiliter le support, vous devez accepter les autorisations supplémentaires. Cela ne fonctionne PAS en incognito sur Chrome et d'autres variantes de Chromium.",
"message": "Soutenez les clients tiers pour YouTube. Pour activer le soutien, vous devez accepter les autorisations supplémentaires.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Cacher pour toujours"
},
"warningChatInfo": {
"message": "Nous avons remarqué que vous faisiez des erreurs courantes qui ne sont pas intentionnelles"
"message": "Nous avons remarqué que vous commettiez des erreurs courantes. Nous apprécions votre travail jusqu'à présent, mais nous recherchons la perfection, donc même de petites erreurs comptent :)"
},
"warningTitle": {
"message": "Vous avez reçu un avertissement"
@@ -1249,5 +1246,8 @@
},
"segmentFetchFailureWarning": {
"message": "Attention : Le serveur n'a pas encore répondu avec les segments. Il se peut qu'il y ait des segments sur cette vidéo déjà soumise, mais vous ne les avez tout simplement pas reçus en raison de problèmes avec le serveur."
},
"allowScrollingToEdit": {
"message": "Autoriser l'utilisation de la molette pour modifier les temps"
}
}

View File

@@ -26,17 +26,17 @@
"message": "מקטעים"
},
"SegmentsCap": {
"message": "מקטעים"
"message": "קטעים"
},
"Chapters": {
"message": "פרקים"
},
"renderAsChapters": {
"message": "עיבוד מקטעים כפרקים",
"message": "עיבוד קטעים כפרקים",
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
},
"showSegmentNameInChapterBar": {
"message": "הצגת מקטע נוכחי לצד זמן וידאו"
"message": "הצגת קטע נוכחי לצד זמן וידאו"
},
"upvoteButtonInfo": {
"message": "הצבע לדיווח הזה"
@@ -96,13 +96,13 @@
"message": "מקטע נגמר עכשיו"
},
"sponsorCancel": {
"message": "ביטול יצירת מקטע"
"message": "ביטול יצירת קטע"
},
"noVideoID": {
"message": "לא נמצא סרטון יוטיוב.\nאם זה לא נכון, רענן את הכרטיסייה."
},
"refreshSegments": {
"message": "ריענון מקטעים"
"message": "ריענון קטעים"
},
"success": {
"message": "הצלחה!"
@@ -117,7 +117,7 @@
"message": "התקבלה שגיאת חיבור. קוד השגיאה: "
},
"segmentsStillLoading": {
"message": "מקטע עדיין נטען..."
"message": "קטעים עדיין נטענים..."
},
"clearTimes": {
"message": "נקה מקטעים"
@@ -131,8 +131,8 @@
"closeIcon": {
"message": "סגירת סמליל"
},
"SubmitTimes": {
"message": "הגש מקטעים"
"OpenSubmissionMenu": {
"message": "פתיחת תפריט הגשה"
},
"sortSegments": {
"message": "מיון מקטעים"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "ניקוי זמנים"
},
"submitTimesButton": {
"message": "הגשת זמנים"
},
"publicStats": {
"message": "זה משמש בדף הסטטיסטיקה הציבורי כדי להראות כמה תרמת. ניתן לצפות בזה"
},
@@ -225,9 +222,48 @@
"showDeleteButton": {
"message": "הצגת כפתור מחיקה על הנגן של יוטיוב"
},
"enableViewTracking": {
"message": "אפשר מעקב ספירת דילוגים"
},
"whatViewTracking": {
"message": "תכונה זו עוקבת אחר אילו מקטעים דילגת כדי לאפשר למשתמשים לדעת עד כמה ההגשה שלהם עזרה לאחרים והשתמשה כמדד יחד עם הצבעות בעד כדי להבטיח שספאם לא ייכנס למסד הנתונים. התוסף שולח הודעה לשרת בכל פעם שאתה מדלג על קטע. אני מקווה שרוב האנשים לא ישנו את ההגדרה הזו כדי שמספרי התצוגה יהיו מדויקים. :)"
},
"enableViewTrackingInPrivate": {
"message": "אפשר מעקב ספירת דילוגים בכרטיסיות גלישה פרטית/גלישה בסתר"
},
"enableTrackDownvotes": {
"message": "שמור דירוג קטעים"
},
"whatTrackDownvotes": {
"message": "כל קטע שידורג על ידך יישאר חבוי, גם לאחר רענון"
},
"trackDownvotesWarning": {
"message": "אזהרה: ביטול השמירה ימחק את הדירוגים שנשמרו"
},
"whatQueryByHashPrefix": {
"message": "במקום לבקש מקטעים מהשרת לפי מזהה סרטון, נשלחים ארבעת התווים הראשונים של ה-hash של מזהה הסרטון. שרת זה ישלח בחזרה נתונים לכל הסרטונים עם hash מתאים."
},
"enableRefetchWhenNotFound": {
"message": "השג מקטעים של סרטונים חדשים"
},
"whatRefetchWhenNotFound": {
"message": "אם הסרטון חדש, ואין בו אף מקטע, הוא יחפש מחדש מקטעים כל כמה דקות בהן תצפה/י בסרטון."
},
"enableShowCategoryWithoutPermission": {
"message": "הצג קטגוריה בתפריט ההגשה גם ללא הרשאת הגשה"
},
"whatShowCategoryWithoutPermission": {
"message": "ישנן קטגוריות שדורשות הרשאת הגשה בגלל דרישות מינימום נקודות רפוטציה"
},
"showNotice": {
"message": "הראה הודעה שוב"
},
"showSkipNotice": {
"message": "הצג הודעה לאחר דילוג על מקטע"
},
"showCategoryGuidelines": {
"message": "הצג עזרה לקטגוריה"
},
"website": {
"message": "אתר",
"description": "Used on Firefox Store Page"

View File

@@ -128,9 +128,6 @@
"closeIcon": {
"message": "आइकॉन बंद करें"
},
"SubmitTimes": {
"message": "खंड दर्ज करें"
},
"sortSegments": {
"message": "खंड छांटें"
},

View File

@@ -113,6 +113,9 @@
"connectionError": {
"message": "Dogodija se greška u povezivanju. Kod pogreške: "
},
"segmentsStillLoading": {
"message": "Segmenti se učitavaju..."
},
"clearTimes": {
"message": "Očisti isječke"
},
@@ -122,8 +125,8 @@
"closePopup": {
"message": "Zatvori izbornik"
},
"SubmitTimes": {
"message": "Podnesi isječke"
"closeIcon": {
"message": "Ikona za zatvaranje"
},
"sortSegments": {
"message": "Razvrstaj isječke"
@@ -162,9 +165,6 @@
"clearTimesButton": {
"message": "Očisti vremena"
},
"submitTimesButton": {
"message": "Unesi vremena"
},
"publicStats": {
"message": "Ovo se koristi na stranici sa javnim statistikama da se pokaže koliko se pridonijeli. Pogledajte"
},
@@ -383,6 +383,12 @@
"statusReminder": {
"message": "Provjerite status.sponsor.ajay.app za status poslužitelja."
},
"changeUserID": {
"message": "Uvezi/Izvezi svoj privatni UserID"
},
"setUserID": {
"message": "Postavi Privatni UserID"
},
"createdBy": {
"message": "Izradio"
},
@@ -482,6 +488,12 @@
"edit": {
"message": "Uredi"
},
"copyDebugInformation": {
"message": "Kopiraj Informaciju Za Otklanjanje Pogrešaka U Međuspremnik"
},
"copyDebugInformationFailed": {
"message": "Pisanje u međuspremnik nije uspjelo"
},
"copyDebugInformationOptions": {
"message": "Kopira informacije u međuspremnik koje treba dati razvojnom programeru kada otkrije grešku / kada to programer zatraži. Osjetljive informacije kao što su vaš korisnički ID, kanali s popisa dopuštenih i prilagođena adresa poslužitelja uklonjeni su. Međutim, sadrži informacije kao što su vaš korisnički agent, preglednik, operativni sustav i broj verzije proširenja. "
},
@@ -517,6 +529,9 @@
"category_selfpromo_description": {
"message": "Slično kao „sponzor”, osim za neplaćenu promociju i samopromociju. To uključuje odlomke marketinga, donacija ili informacija o tome, s kim su surađivali."
},
"category_selfpromo_guideline1": {
"message": "Donacije, članarine i roba"
},
"category_exclusive_access": {
"message": "Eksluzivni pristup"
},
@@ -538,6 +553,9 @@
"category_intro_short": {
"message": "Stanka"
},
"category_intro_guideline1": {
"message": "Interval bez stvarnog sadržaja"
},
"category_outro": {
"message": "Završni kadrovi/Zasluge"
},
@@ -547,6 +565,9 @@
"category_preview_description": {
"message": "Zbirka isječaka koji pokazuju što dolazi u ovom videu ili drugim videima u nizu gdje se sve informacije kasnije ponavljaju u videu."
},
"category_filler": {
"message": "Nepotrebna Popuna/Šale"
},
"category_filler_short": {
"message": "Popuna"
},
@@ -647,6 +668,9 @@
"message": "Kraj",
"description": "Button that skips to the end of a segment"
},
"hiddenDueToDuration": {
"message": "sakriveno: redak je prekratak"
},
"manuallyHidden": {
"message": "ručno skriveno"
},
@@ -701,15 +725,33 @@
"hideForever": {
"message": "Sakrij zauvijek"
},
"warningChatInfo": {
"message": "Primjetili smo da ste radili neke uobičajene pogreške. Mi cijenimo vaš trud, ali ovdje težimo perfekciji, pa i jako male pogreške su važne :)"
},
"warningTitle": {
"message": "Dobili ste upozorenje"
},
"questionButton": {
"message": "Imam pitanje"
},
"warningConfirmButton": {
"message": "Razumijem razlog"
},
"Donate": {
"message": "Doniraj"
},
"darkModeOptionsPage": {
"message": "Tamni Način Na Stranici Opcija"
},
"helpPageThanksForInstalling": {
"message": "Hvala na instaliranju SponsorBlocka."
},
"helpPageFeatureDisclaimer": {
"message": "Mnoge funkcije su standardno deaktivirane. Ako želiš preskočiti uvode, završne dijelove, koristiti Invidious, itd., aktiviraj ih niže dolje. Također možeš sakriti/prikazati elemente korisničkog sučelja."
},
"helpPageHowSkippingWorks": {
"message": "Kako preskakanje radi"
},
"Submitting": {
"message": "Slanje"
},
@@ -743,9 +785,18 @@
"ChangeCategoryTooltip": {
"message": "Ovo će se odmah primijeniti na vaše isječke"
},
"downvote": {
"message": "Glasaj protiv"
},
"upvote": {
"message": "Glasaj za"
},
"hideSegment": {
"message": "Sakri odsječak"
},
"skipSegment": {
"message": "Preskoči odsječak"
},
"dayAbbreviation": {
"message": "d",
"description": "100d"
@@ -852,5 +903,28 @@
},
"enterLicenseKey": {
"message": "Upiši licencni ključ"
},
"videosSingular": {
"message": "video",
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"
},
"videosPlural": {
"message": "videa",
"description": "Example: You currently have 12 unsubmitted segments on 5 *videos*"
},
"videoID": {
"message": "ID videa",
"description": "Header of the unsubmitted segments list"
},
"segmentCount": {
"message": "Broj segmenata",
"description": "Header of the unsubmitted segments list"
},
"actions": {
"message": "Radnje",
"description": "Header of the unsubmitted segments list"
},
"exportSegmentsAsURL": {
"message": "Dijeli kao URL"
}
}

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Bezárás ikon"
},
"SubmitTimes": {
"message": "Szegmensek beküldése"
"OpenSubmissionMenu": {
"message": "Beküldés menü megnyitása"
},
"sortSegments": {
"message": "Szegmensek rendezése"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Időpontok törlése"
},
"submitTimesButton": {
"message": "Időpontok beküldése"
},
"publicStats": {
"message": "Ez a nyilvános ranglistán használatos, ami mutatja, mennyit segítettél. Nézd meg"
},
@@ -442,7 +439,7 @@
"message": "Harmadik fél Youtube oldalainak támogatása"
},
"supportOtherSitesDescription": {
"message": "Harmadik fél YouTube oldalainak támogatása. A támogatás bekapcsolásához el kell fogadnod az extra engedélyeket. NEM működik inkognitó módban Chrome-ban és egyéb Chromium változatokban.",
"message": "Harmadik fél YouTube klienseineik támogatása. A támogatáshoz el kell fogadni az extra engedélyeket.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Eltüntetés örökre"
},
"warningChatInfo": {
"message": "Észrevettük, hogy néhány nem rossz szándékú, gyakran előforduló hibát ejtettél"
"message": "Észrevettük, hogy néhány gyakran előforduló hibát vétettél. Nagyra értékeljük az eddigi munkádat, de a tökéletességre törekszünk, úgyhogy a legkisebb hibák is számítanak :)"
},
"warningTitle": {
"message": "Figyelmeztetést kaptál"
@@ -1249,5 +1246,8 @@
},
"segmentFetchFailureWarning": {
"message": "Figyelem: A szerver még nem válaszolt szegmensekkel. Elképzelhető, hogy már vannak beküldött szegmensek ezen a videón, csak még nem töltődtek be szerver-problémák miatt."
},
"allowScrollingToEdit": {
"message": "Görgő használatának engedélyezése az idők szerkesztéséhez"
}
}

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Tutup Ikon"
},
"SubmitTimes": {
"message": "Kirim Segmen"
},
"sortSegments": {
"message": "Urutkan Segmen"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Hapus Waktu"
},
"submitTimesButton": {
"message": "Kirim Waktu"
},
"publicStats": {
"message": "Ini digunakan di halaman statistik publik untuk menampilkan berapa banyak anda berkontribusi. Lihat disini"
},
@@ -208,7 +202,7 @@
"message": "Ini akan menyembunyikan tombol yang muncul di pemutar YouTube untuk mengirimkan segmen yang dilewati."
},
"showSkipButton": {
"message": "Tetap lewati ke tombol Highlight di Pemutar"
"message": "Biarkan Tombol Lewati ke Sorotan Tetap Tampil di Pemutar"
},
"showInfoButton": {
"message": "Tampilkan Tombol Info Di Pemutar Video YouTube"
@@ -441,10 +435,6 @@
"supportOtherSites": {
"message": "Dukung Situs Youtube Pihak Ketiga"
},
"supportOtherSitesDescription": {
"message": "Dukung klien YouTube pihak ketiga. Untuk mengaktifkan dukungan, Anda harus menerima izin tambahan. Ini tidak akan bekerja di Mode Samaran di Chrome dan varian Chromium lainnya.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Situs yang didukung: "
},
@@ -682,6 +672,9 @@
"category_preview": {
"message": "Pratinjau/Rekap"
},
"category_preview_description": {
"message": "Koleksi klip yang menampilkan hal yang akan hadir di video ini atau video lain dalam suatu seri, di mana segala informasinya diulang dalam video tersebut."
},
"category_preview_guideline1": {
"message": "Klip yang ditampilkan nanti, atau di video di masa mendatang"
},
@@ -694,6 +687,9 @@
"category_filler": {
"message": "Pengisi Tak berkaitan/Lawakan"
},
"category_filler_description": {
"message": "Adegan tangensial ditambahkan hanya untuk pengisi atau humor yang tidak diperlukan untuk memahami isi utama video. Ini tidak boleh mencakup segmen yang memberikan detail konteks atau latar belakang. Ini adalah kategori sangat agresif yang ditujukan saat Anda tidak sedang ingin \"bersenang-senang\"."
},
"category_filler_short": {
"message": "Isian"
},
@@ -936,7 +932,7 @@
"message": "Sembunyikan selamanya"
},
"warningChatInfo": {
"message": "Kami melihat Anda membuat beberapa kesalahan umum yang tidak tersengaja"
"message": "Kami perhatikan Anda membuat beberapa kesalahan umum. Kami hargai sekali yang Anda kerjakan sejauh ini, tapi di sini kami berjuang mencapai sempurna, sehingga kesalahan sangat kecil pun berarti :)"
},
"warningTitle": {
"message": "Anda mendapatkan peringatan"
@@ -1172,10 +1168,20 @@
"enterLicenseKey": {
"message": "Masukkan Kode Lisensi"
},
"chaptersPage1": {
"message": "Fitur bab yang diurun-dayakan SponsorBlock hanya tersedia bagi pembeli lisensi, atau penerima akses gratis berkat kontribusinya di masa lalu"
},
"chaptersPage2": {
"message": "Catatan: Izin untuk mengirim bab tetap bedasarkan reputasi yang diperhitungkan. Membeli lisensi hanya memperbolehkan Anda untuk melihat bab yang dikirim oleh orang lain",
"description": "On the chapters page for getting access to the paid chapters feature"
},
"chapterNewFeature": {
"message": "Fitur Baru: Bab ubah suai yang diurun daya. Ini adalah beberapa bagian video yang secara khusus diberi nama dan dapat ditumpuk untuk mendapat ketepatan yang lebih. Beli lisensi untuk menampilkan bab yang dikirimkan untuk video ini seperti: ",
"description": "After the comma, a list of chapters for this video will appear"
},
"chapterNewFeature2": {
"message": "Fitur Baru: Bab ubah suai yang diurun daya. Ini adalah beberapa bagian video yang secara khusus diberi nama dan dapat ditumpuk untuk mendapat ketepatan yang lebih. Anda memiliki akses gratis yang aktif di opsi."
},
"unsubmittedSegmentCounts": {
"message": "Kamu mempunyai {0} dalam {1}",
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Icona Chiudi"
},
"SubmitTimes": {
"message": "Invia i segmenti"
},
"sortSegments": {
"message": "Ordina Segmenti"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Cancella minutaggio"
},
"submitTimesButton": {
"message": "Invia minutaggio"
},
"publicStats": {
"message": "Questo è usato nelle pagine pubbliche delle statistiche per mostrare quanto hai contribuito. Vedilo"
},
@@ -442,7 +436,7 @@
"message": "Supporta siti di YouTube di terze parti"
},
"supportOtherSitesDescription": {
"message": "Supporta client YouTube di terze parti. Per abilitare il supporto, devi accettare i permessi aggiuntivi. Questo NON funziona in incognito su Chrome e altre varianti di Chromium.",
"message": "Supporta client YouTube di terze parti. Per abilitare il supporto, devi accettare i permessi aggiuntivi.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +936,7 @@
"message": "Nascondi per sempre"
},
"warningChatInfo": {
"message": "Abbiamo notato che stavi facendo alcuni errori comuni che non sono intenzionali"
"message": "Abbiamo notato che hai fatto qualche errore comune. Noi apprezziamo molto il tuo lavoro fin'ora, ma qui puntiamo alla perfezione, quindi ogni errore, anche molto piccolo, conta :)"
},
"warningTitle": {
"message": "Hai ricevuto un avvertimento"

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "閉じるアイコン"
},
"SubmitTimes": {
"message": "セグメントを送信"
},
"sortSegments": {
"message": "セグメントを並び替え"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "時間を消去"
},
"submitTimesButton": {
"message": "時間を提出"
},
"publicStats": {
"message": "これは公開の統計ページであなたがどれだけ貢献したかを示すために使用され、ここで確認することができます: "
},
@@ -441,10 +435,6 @@
"supportOtherSites": {
"message": "第三者製のYouTube関連サイトに対応"
},
"supportOtherSitesDescription": {
"message": "第三者製のYouTubeクライアントに対応しました。有効にするには追加の権限を受け入れる必要があります。これはChromeやその他のChromium系列の匿名閲覧状態では動作しません。",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "対応サイト: "
},
@@ -942,7 +932,7 @@
"message": "二度と表示しない"
},
"warningChatInfo": {
"message": "悪意によるものではないよくある間違いを犯してたようです"
"message": "どうやらあなたはよくある間違いを犯してしまったようです。これまでのあなたの協力には大きく感謝しています。ですが、私たちは完璧さを追求しており、小さなミスでも重要であることをご理解ください :)"
},
"warningTitle": {
"message": "警告を付与されました"

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "닫기 아이콘"
},
"SubmitTimes": {
"message": "구간 제출"
"OpenSubmissionMenu": {
"message": "제출 메뉴 열기"
},
"sortSegments": {
"message": "구간 정렬"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "구간 초기화"
},
"submitTimesButton": {
"message": "구간 제출"
},
"publicStats": {
"message": "얼마나 기여했는지 확인할 수 있는 공개 통계 페이지로 다음에서 확인하실 수 있어요."
},
@@ -442,7 +439,7 @@
"message": "제3자 YouTube 사이트 지원"
},
"supportOtherSitesDescription": {
"message": "제3자 YouTube 클라이언트에서도 기능을 지원하도록 해요. 이 기능을 사용하려면 추가 권한을 허용해야 해요. Chrome 및 다른 Chromium 계열 브라우저의 시크릿 모드에서는 작동하지 않아요. ",
"message": "제자 YouTube 클라이언트에서도 기능을 지원하도록 해요. 이 기능을 사용하려면 추가 권한을 허용해야 해요.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "다시 보지 않음"
},
"warningChatInfo": {
"message": "악의적인 의도는 없었던 듯 보이지만 제출하신 구간 중에 일부 문제가 있는 것 같아요."
"message": "현재 일반적인 실수들을 저지르고 계셔서 알려드려요. 지금까지 작업해주신 것은 감사드리지만, 저희는 완벽을 추구하고 있기 때문에 아주 작은 실수라도 문제가 될 수 있어요 :)"
},
"warningTitle": {
"message": "경고를 받으셨어요"
@@ -1248,9 +1245,9 @@
"message": "URL로 공유"
},
"segmentFetchFailureWarning": {
"message": "경고: 아직 서버로부터 구간 정보를 지 못했습니다. 동영상에 이미 제출된 구간이 있지만 서버의 문제로 수신못했을 수 있습니다."
"message": "경고: 서버에서 구간 정보를 불러오지 못했어요. 동영상에 이미 제출된 구간이 있을 수 있지만 서버의 문제로 인해 수신않았을 수어요."
},
"allowScrollingToEdit": {
"message": "스크롤하여 수정"
"message": "스크롤하여 편집 허용"
}
}

View File

@@ -103,9 +103,6 @@
"closePopup": {
"message": "പോപ്പ്അപ്പ് അടയ്‌ക്കുക"
},
"SubmitTimes": {
"message": "സെഗ്‌മെന്റുകൾ സമർപ്പിക്കുക"
},
"submitCheck": {
"message": "ഇത് സമർപ്പിക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ?"
},
@@ -140,9 +137,6 @@
"clearTimesButton": {
"message": "ടൈംസ് മായ്‌ക്കുക"
},
"submitTimesButton": {
"message": "സമയം സമർപ്പിക്കുക"
},
"publicStats": {
"message": "നിങ്ങൾ എത്രമാത്രം സംഭാവന നൽകി എന്ന് കാണിക്കുന്നതിന് ഇത് പൊതു സ്ഥിതിവിവരക്കണക്ക് പേജിൽ ഉപയോഗിക്കുന്നു. അത് കാണുക"
},

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Tutup Ikon"
},
"SubmitTimes": {
"message": "Hantar Segmen"
},
"sortSegments": {
"message": "Susun Segmen"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Jelas Masa"
},
"submitTimesButton": {
"message": "Hantar Masa"
},
"publicStats": {
"message": "Ini digunakan di halaman statistik awam untuk menunjukkan berapa banyak yang anda sumbangkan. Lihatlah"
},
@@ -441,10 +435,6 @@
"supportOtherSites": {
"message": "Sokong Pihak Ke-3 Laman YouTube"
},
"supportOtherSitesDescription": {
"message": "Sokong klien pihak ketiga YouTube. Untuk membolehkan sokong, anda perlu menerima kebenaran tambahan. Ini TIDAK berfungsi dalam inkognito pada Chrome dan varian Chromium lain.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Laman Disokong: "
},
@@ -941,9 +931,6 @@
"hideForever": {
"message": "Sembunyikan selamanya"
},
"warningChatInfo": {
"message": "Kami perasaan yang anda telah membuat beberapa kesilapan biasa yang tidak berniat jahat"
},
"warningTitle": {
"message": "Anda mendapat amaran"
},

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Pictogram voor sluiten"
},
"SubmitTimes": {
"message": "Segmenten indienen"
"OpenSubmissionMenu": {
"message": "Inzending-menu openen"
},
"sortSegments": {
"message": "Segmenten sorteren"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Tijdstippen wissen"
},
"submitTimesButton": {
"message": "Tijdstippen indienen"
},
"publicStats": {
"message": "Dit wordt gebruikt op de publieke statistiekenpagina om te laten zien hoeveel u heeft bijgedragen. Bekijk het"
},
@@ -442,7 +439,7 @@
"message": "Ondersteuning voor YouTube-sites van derden"
},
"supportOtherSitesDescription": {
"message": "Ondersteuning voor YouTube-clients van derden. Om ondersteuning in te schakelen moet u de extra machtigingen accepteren. Dit werkt NIET in incognito in Chrome en andere Chromium-varianten.",
"message": "YouTube-clients van derden ondersteunen. Om ondersteuning in te schakelen, moet u de extra machtigingen accepteren.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Voor altijd verbergen"
},
"warningChatInfo": {
"message": "We hebben gemerkt dat u een aantal veelvoorkomende fouten maakte zonder slechte bedoelingen"
"message": "Het viel ons op dat u enkele veel voorkomende fouten maakte. We waarderen uw werk tot nu toe zeer, maar we streven hier naar perfectie, dus zelfs heel kleine foutjes zijn belangrijk :)"
},
"warningTitle": {
"message": "U heeft een waarschuwing gekregen"

View File

@@ -112,9 +112,6 @@
"closePopup": {
"message": "Lukk oppsprett"
},
"SubmitTimes": {
"message": "Send inn segmenter"
},
"submitCheck": {
"message": "Er du sikker på at du vil sende inn dette?"
},
@@ -149,9 +146,6 @@
"clearTimesButton": {
"message": "Tøm tidspunkter"
},
"submitTimesButton": {
"message": "Send inn tidspunkter"
},
"publicStats": {
"message": "Dette brukes på den offentlige statistikksiden for å vise hvor mye du har bidratt med. Se den"
},
@@ -381,10 +375,6 @@
"supportOtherSites": {
"message": "Støtt tredjeparts YouTube-nettsteder"
},
"supportOtherSitesDescription": {
"message": "Støtt tredjeparts YouTube-klienter. For å aktivere støtte må du akseptere ytterlige vilkår. Dette fungerer IKKE i inkognitomodus i Chrome og andre Chromium-varianter.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Støttede nettsteder: "
},

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Wyłącz ikonę"
},
"SubmitTimes": {
"message": "Prześlij segmenty"
},
"sortSegments": {
"message": "Sortuj segmenty"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Usuń czasy"
},
"submitTimesButton": {
"message": "Wyślij czasy"
},
"publicStats": {
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
},
@@ -442,7 +436,7 @@
"message": "Obsługa stron YouTube firm trzecich"
},
"supportOtherSitesDescription": {
"message": "Wspieraj nieoficjalne klienty YouTube'a. Aby włączyć dla nich wsparcie, musisz przyznać dodatkowe uprawnienia. Ta opcja nie działa w trybie incognito w Chrome i innych przeglądarkach bazujących na Chromium.",
"message": "Obsługa zewnętrznych klientów YouTube. Aby włączyć obsługę, należy zaakceptować dodatkowe uprawnienia.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +936,7 @@
"message": "Schowaj na zawsze"
},
"warningChatInfo": {
"message": "Zauważyliśmy, że popełniałeś pewne powszechne błędy, które nie są złośliwe"
"message": "Zauważyliśmy, że popełniłeś pewne powszechne błędy. Bardzo doceniamy dotychczasową pracę, ale dążymy tutaj do doskonałości, więc nawet bardzo małe błędy mają znaczenie :)"
},
"warningTitle": {
"message": "Otrzymałeś ostrzeżenie"
@@ -1249,5 +1243,8 @@
},
"segmentFetchFailureWarning": {
"message": "Ostrzeżenie: Serwer nie odpowiedział jeszcze na segmenty. Być może segmenty na tym filmie są już wysłane, ale po prostu nie otrzymałeś ich z powodu problemów z serwerem."
},
"allowScrollingToEdit": {
"message": "Zezwalaj na scroll'owanie do edycji czasów"
}
}

View File

@@ -116,6 +116,9 @@
"connectionError": {
"message": "Ocorreu um erro de conexão. Código de erro: "
},
"segmentsStillLoading": {
"message": "Segmentos ainda carregando..."
},
"clearTimes": {
"message": "Limpar Segmentos"
},
@@ -128,9 +131,6 @@
"closeIcon": {
"message": "Ícone de Fechar"
},
"SubmitTimes": {
"message": "Enviar Segmentos"
},
"sortSegments": {
"message": "Organizar Segmentos"
},
@@ -168,9 +168,6 @@
"clearTimesButton": {
"message": "Limpar Intervalos"
},
"submitTimesButton": {
"message": "Enviar Intervalos"
},
"publicStats": {
"message": "Isso é usado na página pública de estatísticas que mostra o quanto você já contribuiu. Veja-a"
},
@@ -438,10 +435,6 @@
"supportOtherSites": {
"message": "Suporte a Sites do YouTube de Terceiros"
},
"supportOtherSitesDescription": {
"message": "Suporte a clientes de terceiros do YouTube. Para habilitar o suporte, você deve aceitar as permissões extras. Isso NÃO funciona em incógnito no Chrome e outras variantes do Chromium.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Sites Suportados: "
},
@@ -912,9 +905,6 @@
"hideForever": {
"message": "Ocultar para sempre"
},
"warningChatInfo": {
"message": "Percebemos que você estava cometendo alguns erros comuns que não são prejudiciais"
},
"Donate": {
"message": "Doar"
},
@@ -1000,7 +990,7 @@
"message": "Copiar e dar voto negativo"
},
"ContinueVoting": {
"message": "Continuar Votando"
"message": "Continuar votando"
},
"ChangeCategoryTooltip": {
"message": "Isto irá aplicar instantaneamente seus segmentos"

View File

@@ -128,9 +128,6 @@
"closePopup": {
"message": "Fechar Popup"
},
"SubmitTimes": {
"message": "Submeter Segmentos"
},
"sortSegments": {
"message": "Ordenar Segmentos"
},
@@ -168,9 +165,6 @@
"clearTimesButton": {
"message": "Limpar Intervalos"
},
"submitTimesButton": {
"message": "Submeter Intervalos"
},
"publicStats": {
"message": "Isto é usado na página pública de estatísticas que mostra o quanto já contríbuíu. Veje-a"
},
@@ -252,12 +246,18 @@
"whatRefetchWhenNotFound": {
"message": "Se o vídeo for novo e nenhum segmento for encontrado, continuaremos a monitorizar enquanto assiste."
},
"whatShowCategoryWithoutPermission": {
"message": "Algumas categorias requerem permissão para submeter devido aos requisitos mínimos de reputação"
},
"showNotice": {
"message": "Mostrar notificação outra vez"
},
"showSkipNotice": {
"message": "Mostrar aviso após um segmento ser ignorado"
},
"showCategoryGuidelines": {
"message": "Mostrar Categoria de Ajuda"
},
"noticeVisibilityMode0": {
"message": "Avisos de ignorar em tamanho inteiro"
},
@@ -279,6 +279,10 @@
"message": "Iniciar/parar segmento",
"description": "Keybind label"
},
"setSubmitKeybind": {
"message": "Enviar segmentos",
"description": "Keybind label"
},
"nextChapterKeybind": {
"message": "Próximo capítulo",
"description": "Keybind label"
@@ -347,6 +351,10 @@
"createdBy": {
"message": "Criado por"
},
"supportOtherSitesDescription": {
"message": "Apoie clientes de terceiros do YouTube. Para ativar o suporte, deve aceitar as permissões adicionais.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Sites suportados: "
},

View File

@@ -116,6 +116,9 @@
"connectionError": {
"message": "A apărut o eroare de conexiune. Cod de eroare: "
},
"segmentsStillLoading": {
"message": "Încă se încarcă segmentele..."
},
"clearTimes": {
"message": "Curăță segmentele"
},
@@ -128,9 +131,6 @@
"closeIcon": {
"message": "Închide pictograma"
},
"SubmitTimes": {
"message": "Trimite segmente"
},
"sortSegments": {
"message": "Sortare Segmente"
},
@@ -168,9 +168,6 @@
"clearTimesButton": {
"message": "Șterge Timpii"
},
"submitTimesButton": {
"message": "Trimite Timpii"
},
"publicStats": {
"message": "Acest lucru este folosit pe pagina publică de statistici pentru a arăta cât de mult ai contribuit. Vezi pagina"
},
@@ -438,10 +435,6 @@
"supportOtherSites": {
"message": "Sprijină Site-uri YouTube 3rd Party"
},
"supportOtherSitesDescription": {
"message": "Sprijină Clienți YouTube 3rd party. Pentru a activa setarea, trebuie să acceptați permisiunile suprimentare. Această funcție NU funcționează în incognito pe Chrome sau în alte variante Chromium.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Site-uri cu Sprijin: "
},
@@ -939,7 +932,7 @@
"message": "Ascunde pentru totdeauna"
},
"warningChatInfo": {
"message": "Am observat că făceați niște greșeli comune care nu sunt răuvoitoare"
"message": "Am observat că faci niște greșeli comune. Apreciem foarte mult munca ta de până acum, însă noi tindem spre perfecțiune aici, așa că fiecare mică greșeală contează :)"
},
"warningTitle": {
"message": "Ai primit o avertizare"
@@ -1243,5 +1236,11 @@
},
"exportSegmentsAsURL": {
"message": "Distribuie ca URL"
},
"segmentFetchFailureWarning": {
"message": "Atenție: Serverul nu a răspuns încă cu segmente. Ar putea fi segmente în acest videoclip deja trimise, dar pur și simplu nu le-ai primit din cauza problemelor cu serverul."
},
"allowScrollingToEdit": {
"message": "Permite derularea la Editarea Timpilor"
}
}

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Кнопка закрытия"
},
"SubmitTimes": {
"message": "Отправить сегменты"
"OpenSubmissionMenu": {
"message": "Открыть меню отправки"
},
"sortSegments": {
"message": "Сортировать сегменты"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Очистить время"
},
"submitTimesButton": {
"message": "Отправить сегменты"
},
"publicStats": {
"message": "Оно используется на публичной странице статистики, чтобы показать Ваш вклад. Её можно посмотреть "
},
@@ -442,7 +439,7 @@
"message": "Поддерживать сторонние YouTube-сайты"
},
"supportOtherSitesDescription": {
"message": "Поддерживать сторонние клиенты для YouTube. Чтобы включить поддержку, Вам понадобится принять дополнительные разрешения. Эта функция НЕ работает в режиме \"инкогнито\" в Chrome и браузерах, основанных на Chromium.",
"message": "Поддержка сторонних клиентов YouTube. Чтобы включить поддержку, вы должны принять дополнительные разрешения.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Скрыть навсегда"
},
"warningChatInfo": {
"message": "Мы заметили, что вы совершаете распространённые и не злонамеренные ошибки"
"message": "Мы заметили, что вы совершаете распространенные ошибки. Мы очень ценим вашу работу, но мы стремимся делать всё идеально, так что даже очень маленькие ошибки имеют большое значение :)"
},
"warningTitle": {
"message": "Вы получили предупреждение"
@@ -1141,7 +1138,7 @@
"message": "Ключ лицензии недействителен"
},
"hideUpsells": {
"message": "Скрыть опции, не доступные без дополнительной платы"
"message": "Скрыть опции, недоступные без дополнительной платы"
},
"chooseACountry": {
"message": "Выберите страну"

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Ikona pre zatvorenie"
},
"SubmitTimes": {
"message": "Odoslať segmenty"
},
"sortSegments": {
"message": "Triedenie segmentov"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Vymazať časy"
},
"submitTimesButton": {
"message": "Odoslať časy"
},
"publicStats": {
"message": "Toto sa používa vo verejnom rebríčku pre zobrazenie vášho príspevku. Pozrite si ho"
},
@@ -442,7 +436,7 @@
"message": "Podpora alternatívnych Youtube webov"
},
"supportOtherSitesDescription": {
"message": "Podpora alternatívnych Youtube klientov. Pre zapnutie podpory musíte povoliť zvláštne oprávnenia. Nefunguje v anonymnom režime v prehliadači Chrome ani v Chromium variantoch.",
"message": "Podpora Youtube aplikácií tretích strán. Pre jej zapnutie musíte odsúhlasiť zvláštne oprávnenia.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +936,7 @@
"message": "Navždy skryť"
},
"warningChatInfo": {
"message": "Zaznamenali sme, že robíte omylom chyby"
"message": "Zaznamenali sme, že ste urobili obvyklú chybu. Vážime si vašej práce, ale ide nám o presnosť, takže aj na malých chybách záleží."
},
"warningTitle": {
"message": "Dostali ste varovanie"
@@ -954,7 +948,7 @@
"message": "Rozumiem dôvodu"
},
"warningError": {
"message": "Chyb a pri pokuse o súhlas s upozornením:"
"message": "Chyba pri pokuse o súhlas s upozornením:"
},
"Donate": {
"message": "Prispieť"

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Stäng ikon"
},
"SubmitTimes": {
"message": "Skicka in segment"
"OpenSubmissionMenu": {
"message": "Öppna inlämningsmenyn"
},
"sortSegments": {
"message": "Sortera segment"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "Rensa tider"
},
"submitTimesButton": {
"message": "Skicka in tider"
},
"publicStats": {
"message": "Detta används på den offentliga statistiksidan för att visa hur mycket du har bidragit. Ta en titt"
},
@@ -442,7 +439,7 @@
"message": "Stöd för tredjeparts YouTube-webbplatser"
},
"supportOtherSitesDescription": {
"message": "Stöd tredjeparts YouTube-klienter. För att aktivera support måste du acceptera de extra behörigheterna. Detta fungerar INTE i inkognito på Chrome och andra Chromium-varianter.",
"message": "Stöd tredjeparts YouTube-klienter. För att aktivera support måste du acceptera de extra behörigheterna.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -942,7 +939,7 @@
"message": "Dölj för alltid"
},
"warningChatInfo": {
"message": "Vi märkte att du gjorde några vanliga misstag som inte var uppsåtligt"
"message": "Vi märkte att du gjorde några vanliga misstag. Vi uppskattar verkligen ditt arbete hittills, men vi strävar mot perfektion här, så även mycket små misstag spelar roll :)"
},
"warningTitle": {
"message": "Du har fått en varning"

View File

@@ -112,9 +112,6 @@
"closePopup": {
"message": "பாப்அப்பை மூடு"
},
"SubmitTimes": {
"message": "பிரிவுகளைச் சமர்ப்பிக்கவும்"
},
"submitCheck": {
"message": "இதை நிச்சயமாக சமர்ப்பிக்க விரும்புகிறீர்களா?"
},
@@ -149,9 +146,6 @@
"clearTimesButton": {
"message": "நேரங்களை அழி"
},
"submitTimesButton": {
"message": "நேரங்களைச் சமர்ப்பிக்கவும்"
},
"publicStats": {
"message": "நீங்கள் எவ்வளவு பங்களித்தீர்கள் என்பதைக் காட்ட இது பொது புள்ளிவிவரங்கள் பக்கத்தில் பயன்படுத்தப்படுகிறது. அதை பார்"
},
@@ -390,10 +384,6 @@
"supportOtherSites": {
"message": "3 வது தரப்பு YouTube-தளங்களை ஆதரிக்கவும்"
},
"supportOtherSitesDescription": {
"message": "மூன்றாம் தரப்பு YouTube தளங்களை ஆதரிக்கவும். ஆதரவை இயக்க, நீங்கள் கூடுதல் அனுமதிகளை ஏற்க வேண்டும். இது Chrome மற்றும் பிற Chromium வகைகளில் தனிப்பட்ட தாவல்களில் வேலை செய்யாது.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "ஆதரிக்கப்படும் தளங்கள்: "
},

View File

@@ -103,9 +103,6 @@
"closePopup": {
"message": "పాపప్ మూసివేయండి"
},
"SubmitTimes": {
"message": "విభాగాలను సమర్పించండి"
},
"submitCheck": {
"message": "మీరు దీన్ని ఖచ్చితంగా సమర్పించాలనుకుంటున్నారా?"
},
@@ -140,9 +137,6 @@
"clearTimesButton": {
"message": "టైమ్స్ క్లియర్"
},
"submitTimesButton": {
"message": "టైమ్స్ సమర్పించండి"
},
"publicStats": {
"message": "మీరు ఎంత సహకరించారో చూపించడానికి ఇది పబ్లిక్ గణాంకాల పేజీలో ఉపయోగించబడుతుంది. ఇది చూడు"
},

View File

@@ -25,6 +25,9 @@
"Segments": {
"message": "ส่วน"
},
"SegmentsCap": {
"message": "ส่วน"
},
"upvoteButtonInfo": {
"message": "เห็นด้วยกับรายงานนี้"
},
@@ -69,5 +72,9 @@
},
"clearTimesButton": {
"message": "ล้างเวลา"
},
"supportOtherSitesDescription": {
"message": "สนับสนุนลูกค้า YouTube บุคคลที่สาม.\nในการเปิดใช้งานการสนับสนุน คุณต้องยอมรับการอนุญาตพิเศษ!",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
}
}

View File

@@ -131,8 +131,8 @@
"closeIcon": {
"message": "Kapat Simgesi"
},
"SubmitTimes": {
"message": "Kısımları gönder"
"OpenSubmissionMenu": {
"message": "Gönderiler Menüsünü Aç"
},
"sortSegments": {
"message": "Kısımları Sırala"
@@ -171,9 +171,6 @@
"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"
},
@@ -442,7 +439,7 @@
"message": "3. Taraf Youtube Sitelerini Destekle"
},
"supportOtherSitesDescription": {
"message": "Üçüncü taraf YouTube istemci desteği. Desteği etkinleştirmek için özel izinleri kabul etmelisiniz. Bu özellik Chrome ve diğer Chromium tarayıcılarda gizli modda çalışmaz.",
"message": "3. taraflarca yazılmış YouTube istemcileri desteği. Kullanabilmek için ilave izinler vermelisiniz.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
@@ -479,7 +476,7 @@
"message": "Ayarlanan değerden daha kısa kısımlar atlanmayacak veya oynatıcıda gösterilmeyecektir."
},
"enableManualSkipOnFullVideo": {
"message": "Tam bir video etiketi mevcut olduğunda manuel atlama özelliğini kullanın"
"message": "Bütün video etiketi mevcut olduğunda manuel atlama özelliğini kullanın"
},
"whatManualSkipOnFullVideo": {
"message": "Video boyunca sponsorlu veya kendi reklamını yapıyorsa videoyu kesintisiz izlemek isteyenler için."
@@ -942,7 +939,7 @@
"message": "Asla gösterme"
},
"warningChatInfo": {
"message": "Kötü amaçlı olmayan bazı yaygın hatalar yaptığınızı fark ettik"
"message": "Yaygın hataları sıkça yaptığınız anlaşılıyor. Çabalarınız için sağolun fakat burada mükemmel bir sonuç istiyoruz, küçük hatalar bile fark ediyor :)"
},
"warningTitle": {
"message": "Bir uyarı aldın"

View File

@@ -131,9 +131,6 @@
"closeIcon": {
"message": "Закрити іконку"
},
"SubmitTimes": {
"message": "Надіслати сегменти"
},
"sortSegments": {
"message": "Сортувати сегменти"
},
@@ -171,9 +168,6 @@
"clearTimesButton": {
"message": "Очистити час"
},
"submitTimesButton": {
"message": "Надіслати час"
},
"publicStats": {
"message": "Воно використовується на публічній сторінці статистики, щоб показати Ваш внесок. Її можна подивитися"
},
@@ -441,10 +435,6 @@
"supportOtherSites": {
"message": "Підтримувати сторонні YouTube-сайти"
},
"supportOtherSitesDescription": {
"message": "Підтримувати сторонні клієнти для YouTube. Щоб включити підтримку, Вам знадобиться прийняти додаткові дозволи. Ця функція НЕ працює в режимі \"інкогніто\" в Chrome і браузерах, заснованих на Chromium.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Підтримувані сайти: "
},
@@ -942,7 +932,7 @@
"message": "Сховати назавжди"
},
"warningChatInfo": {
"message": "Ми помітили, що ви не зловмисно робили деякі поширені помилки"
"message": "Ми помітили, що ви робите деякі типові помилки. Ми дуже цінуємо вашу роботу, але ми прагнемо до досконалості, тому навіть дуже маленькі помилки мають значення :)"
},
"warningTitle": {
"message": "Ви отримали попередження"
@@ -1249,5 +1239,8 @@
},
"segmentFetchFailureWarning": {
"message": "Попередження: сервер ще не завантажив сегменти. Можливо, у цьому відео вже є сегменти, але ви просто не отримали їх через проблеми з сервером."
},
"allowScrollingToEdit": {
"message": "Дозволити прокручування для редагування часу"
}
}

View File

@@ -25,6 +25,16 @@
"Segments": {
"message": "phân đoạn"
},
"SegmentsCap": {
"message": "Phân đoạn"
},
"Chapters": {
"message": "Chương"
},
"renderAsChapters": {
"message": "Coi phân đoạn như chương",
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
},
"upvoteButtonInfo": {
"message": "Tán thành phân đoạn này"
},
@@ -103,6 +113,9 @@
"connectionError": {
"message": "Đã xảy ra lỗi kết nối. Mã lỗi: "
},
"segmentsStillLoading": {
"message": "Phân đoạn vẫn đang tải..."
},
"clearTimes": {
"message": "Xóa các phân đoạn"
},
@@ -112,8 +125,8 @@
"closePopup": {
"message": "Đóng bảng popup"
},
"SubmitTimes": {
"message": "Gửi phân đoạn"
"sortSegments": {
"message": "Sắp xếp phân đoạn"
},
"submitCheck": {
"message": "Bạn có chắc chắn muốn gửi không?"
@@ -149,9 +162,6 @@
"clearTimesButton": {
"message": "Xóa thời gian"
},
"submitTimesButton": {
"message": "Gửi thời gian"
},
"publicStats": {
"message": "Tên này được dùng tại trang thông tin công khai để thể hiện lượng đóng góp của bạn. Xem"
},
@@ -289,6 +299,14 @@
"message": "Gửi phân đoạn",
"description": "Keybind label"
},
"nextChapterKeybind": {
"message": "Chương tiếp",
"description": "Keybind label"
},
"previousChapterKeybind": {
"message": "Chương trước",
"description": "Keybind label"
},
"keybindDescription": {
"message": "Chọn một phím bằng cách nhập nó và chọn bất kỳ phím bổ trợ nào bạn muốn sử dụng."
},
@@ -396,10 +414,6 @@
"supportOtherSites": {
"message": "Hỗ trợ các trang web Youtube thuộc bên thứ 3"
},
"supportOtherSitesDescription": {
"message": "Bật hỗ trợ các ứng dụng/trang web Youtube của bên thứ ba. Để bật hỗ trợ cho ứng dụng này, bạn phải chấp nhận các yêu cầu cho phép bổ sung. Nó KHÔNG CÓ tác dụng trong chế độ ẩn danh của Chrome và các trình duyệt có nền tảng Chromium.",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "Các trang web được hỗ trợ: "
},
@@ -533,6 +547,10 @@
"message": "đến",
"description": "Used between segments. Example: 1:20 to 1:30"
},
"CopiedExclamation": {
"message": "Đã sao chép!",
"description": "Used after something has been copied to the clipboard. Example: 'Copied!'"
},
"generic_guideline2": {
"message": "Chơi như thể không có gì bị bỏ qua"
},
@@ -669,6 +687,9 @@
"category_poi_highlight_guideline3": {
"message": "Có thể bỏ qua để đến tiêu đề hoặc hình thu nhỏ"
},
"category_chapter": {
"message": "Chương"
},
"category_livestream_messages": {
"message": "Luồng phát trực tiếp: Đọc Quyên góp/Tin nhắn"
},
@@ -754,6 +775,10 @@
"bracketEnd": {
"message": "(Kết thúc)"
},
"End": {
"message": "Kết thúc",
"description": "Button that skips to the end of a segment"
},
"hiddenDueToDownvote": {
"message": "đã ẩn: hạ bình chọn"
},
@@ -791,6 +816,9 @@
"downvoteDescription": {
"message": "Chỉnh thời gian sai/không đúng"
},
"incorrectVote": {
"message": "Sai"
},
"incorrectCategory": {
"message": "Đổi danh mục"
},
@@ -941,6 +969,9 @@
"hideSegment": {
"message": "Ẩn phân đoạn"
},
"skipSegment": {
"message": "Bỏ qua phân đoạn"
},
"SponsorTimeEditScrollNewFeature": {
"message": "Sử dụng con lăn chuột của bạn khi di chuột qua hộp chỉnh sửa để nhanh chóng điều chỉnh thời gian. Kết hợp phím ctrl hoặc shift có thể được sử dụng để tinh chỉnh các thay đổi."
},
@@ -1003,5 +1034,24 @@
},
"confirmResetToDefault": {
"message": "Bạn chắc chắn muốn đặt lại cài đặt về mặc định? Điều này sẽ không thể hoàn tác được."
},
"chooseACountry": {
"message": "Chọn một quốc gia"
},
"selectYourCountry": {
"message": "Chọn quốc gia"
},
"patreonSignIn": {
"message": "Đăng nhập bằng Patreon"
},
"joinOnPatreon": {
"message": "Đăng ký trên Patreon"
},
"enterLicenseKey": {
"message": "Nhập mã bản quyền"
},
"hideUnsubmittedSegments": {
"message": "Ẩn các phân đoạn",
"description": "Show/hide button for the unsubmitted segments list"
}
}

View File

@@ -131,11 +131,11 @@
"closeIcon": {
"message": "关闭图标"
},
"SubmitTimes": {
"message": "提交片段"
"OpenSubmissionMenu": {
"message": "打开提交菜单"
},
"sortSegments": {
"message": "分类段"
"message": "排序片段"
},
"submitCheck": {
"message": "您确定要提交它吗?"
@@ -171,9 +171,6 @@
"clearTimesButton": {
"message": "清除时间"
},
"submitTimesButton": {
"message": "提交时间"
},
"publicStats": {
"message": "这被用于在公开统计页面上展示您的贡献。查看它"
},
@@ -184,7 +181,7 @@
"message": "设定用户名"
},
"copyPublicID": {
"message": "复制公用户ID"
"message": "复制公开的用户ID"
},
"copySegmentID": {
"message": "复制片段 ID"
@@ -208,7 +205,7 @@
"message": "这将隐藏在 YouTube 播放器上提交赞助商广告的按钮。我了解这个东西打扰到了某些人。除了使用那个按钮,这个弹窗也可以用来提交赞助商广告。 要隐藏出现的通知,请使用通知中显示的写着 ”不再显示“ 的按钮。您可以在以后再次启用这些设置。"
},
"showSkipButton": {
"message": "保持播放器上的跳过高亮按钮"
"message": "播放器显示跳至精华片段按钮"
},
"showInfoButton": {
"message": "在 Youtube 播放器上显示信息按钮"
@@ -235,13 +232,13 @@
"message": "在私人/隐身标签中启用跳过计数跟踪"
},
"enableTrackDownvotes": {
"message": "商店部分的下线"
"message": "保存差评片段"
},
"whatTrackDownvotes": {
"message": "任何被你降权的片段,即使在刷新后也会保持隐藏状态"
"message": "任何被你差评的片段,即使在刷新后也会保持隐藏"
},
"trackDownvotesWarning": {
"message": "警告禁用此功能将删除所有先前存储的降级投票"
"message": "警告禁用此功能将删除所有先前保存的差评"
},
"enableQueryByHashPrefix": {
"message": "按哈希前缀查询"
@@ -274,16 +271,16 @@
"message": "全尺寸的跳过通知"
},
"noticeVisibilityMode1": {
"message": "自动跳车的小跳车通知"
"message": "缩小自动跳过的提醒"
},
"noticeVisibilityMode2": {
"message": "所有的小跳槽通知"
"message": "缩小所有的跳过提醒"
},
"noticeVisibilityMode3": {
"message": "褪色的自动跳车通知书"
"message": "减弱自动跳过的提醒"
},
"noticeVisibilityMode4": {
"message": "所有褪色的跳过通知"
"message": "减弱所有的跳过提醒"
},
"longDescription": {
"message": "SponsorBlock 可帮您跳过 YouTube 视频中的赞助商广告、开场、结尾、订阅提醒和其他烦人片段。SponsorBlock 是一个众包的浏览器扩展,可以让任何人提交 YouTube 视频的赞助商广告和其他片段的开始和结束时间。若有一人提交了信息,其他所有使用此扩展的人都能直接跳过赞助商广告片段。您也可以跳过音乐视频中的非音乐部分。",
@@ -306,17 +303,28 @@
"description": "The second line of the message displayed after the notice was upgraded."
},
"setSkipShortcut": {
"message": "跳过部分",
"message": "跳过片段",
"description": "Keybind label"
},
"setStartSponsorShortcut": {
"message": "启动/停止部分",
"message": "片段开始/停止",
"description": "Keybind label"
},
"setSubmitKeybind": {
"message": "提交片段",
"description": "Keybind label"
},
"nextChapterKeybind": {
"message": "下一章节",
"description": "Keybind label"
},
"previousChapterKeybind": {
"message": "上一章节",
"description": "Keybind label"
},
"keybindDescription": {
"message": "请按下想绑定的按键。如果您想使用组合快捷键,请勾选左侧的选项。"
},
"0": {
"message": "连接超时。请检查您的网络连接。如果您的网络运行正常,则可能是服务器过载或宕机。"
},
@@ -349,6 +357,25 @@
"skip_category": {
"message": "跳过{0}"
},
"mute_category": {
"message": "要静音 {0} 吗?"
},
"skip_to_category": {
"message": "要跳到 {0} 吗?",
"description": "Used for skipping to things (Skip to Highlight)"
},
"skipped": {
"message": "{0} 已跳过",
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} 已静音",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
"message": "已跳至 {0}",
"description": "Used for skipping to things (Skipped to Highlight)"
},
"disableAutoSkip": {
"message": "禁用自动跳过"
},
@@ -393,18 +420,40 @@
"statusReminder": {
"message": "在 status.sponsor.ajay.app 检查服务器状态。"
},
"changeUserID": {
"message": "导入/导出您的私人用户ID"
},
"whatChangeUserID": {
"message": "这应该被保密。这就像一个密码且不应该告诉任何人。如果有人拥有它他就可以冒充您。如果您要找的是公开用户ID请单击弹出窗口中的剪贴板图标。"
},
"setUserID": {
"message": "设置私人用户ID"
},
"userIDChangeWarning": {
"message": "警告:更改私人用户 ID 是永久性的。您确定要这么做吗?请务必备份您的旧用户 ID 以防万一。"
},
"createdBy": {
"message": "创建者"
},
"supportOtherSites": {
"message": "支持第三方 YouTube 网站"
},
"supportOtherSitesDescription": {
"message": "支持第三方 YouTube 客户端。要启用支持,您必须允许额外的权限。",
"description": "This replaces the 'supports Invidious' option because it now works on other YouTube sites such as Cloudtube"
},
"supportedSites": {
"message": "支持的站点: "
},
"optionsInfo": {
"message": "启用 Invidious 支持,禁用自动跳过,隐藏按钮等等。"
},
"addInvidiousInstance": {
"message": "添加第三方客户端实例"
},
"addInvidiousInstanceDescription": {
"message": "添加自定义实例。它必须只包含域名。例如invidious.ajay.app"
},
"add": {
"message": "添加"
},
@@ -426,9 +475,24 @@
"minDurationDescription": {
"message": "短于设定值的片段将不会被跳过或显示在播放器中。"
},
"enableManualSkipOnFullVideo": {
"message": "当整个视频都是相同内容时使用手动跳过"
},
"whatManualSkipOnFullVideo": {
"message": "用于在观看整个视频都是赞助商广告或自我推广时不受打扰"
},
"skipNoticeDuration": {
"message": "跳过提醒持续时间(秒):"
},
"skipNoticeDurationDescription": {
"message": "跳过提醒将显示至少这么多秒。手动跳过的提醒可能会显示更久。"
},
"shortCheck": {
"message": "以下的提交短于您的最小持续时间选项。这代表它们可能已经被提交,只是由于该选项被忽略了。您确定要提交吗?"
},
"liveOrPremiere": {
"message": "无法在进行中的直播或首播提交片段。请等待直播结束后刷新页面并确认片段仍然有效,再次提交。"
},
"showUploadButton": {
"message": "显示上传按钮"
},
@@ -465,6 +529,9 @@
"exportOptionsUpload": {
"message": "从文件加载"
},
"whatExportOptions": {
"message": "这是您所有设置的 JSON 格式。它包含了您的私人用户 ID ,所以您一定要谨慎的保管它。"
},
"setOptions": {
"message": "设定选项"
},
@@ -505,7 +572,7 @@
"message": "复制到剪贴板失败"
},
"copyDebugInformationOptions": {
"message": "复制信息到剪贴板,在提交错误或开发者需要时提供给他。 敏感信息如您的用户ID白名单频道和自定义服务器地址等已被删除。然而它仍然包含诸如您的 useragent ,浏览器,操作系统和扩展版本号等信息。 "
"message": "复制信息到剪贴板,在提交错误或开发者需要时提供给他。 敏感信息如您的用户ID白名单频道和自定义服务器地址等已被删除。然而它仍然包含诸如您的 useragent ,浏览器,操作系统和插件版本号等信息。 "
},
"copyDebugInformationComplete": {
"message": "调试信息已复制到剪切板中。 您可以随意移除任何您不想分享的信息。请将其另存为 .txt 文件或粘贴到错误报告中。"
@@ -521,6 +588,12 @@
"message": "复制成功!",
"description": "Used after something has been copied to the clipboard. Example: 'Copied!'"
},
"generic_guideline1": {
"message": "包括衔接转场"
},
"generic_guideline2": {
"message": "装成没有跳过内容一样播放"
},
"category_sponsor": {
"message": "赞助商广告"
},
@@ -534,7 +607,7 @@
"message": "捐赠或自制周边不属于此项"
},
"category_selfpromo": {
"message": "未收钱的/自我推"
"message": "无偿的/自我推广"
},
"category_selfpromo_description": {
"message": "类似于 “赞助商广告” ,但为无报酬或自我推广。包括有关商品、捐赠的部分或合作者的信息。"
@@ -542,12 +615,40 @@
"category_selfpromo_guideline1": {
"message": "捐赠、会员和自制周边"
},
"category_selfpromo_guideline2": {
"message": "与视频无关的免费推广"
},
"category_selfpromo_guideline3": {
"message": "不是公司设计的产品和周边"
},
"category_exclusive_access": {
"message": "独家限定"
},
"category_exclusive_access_description": {
"message": "仅用于标记整个视频。当视频展示了免费或被帮助以获得产品、服务或访问地点时使用。"
},
"category_exclusive_access_pill": {
"message": "此视频展示了免费或被帮助以获得产品、服务或访问地点",
"description": "Short description for this category"
},
"category_exclusive_access_guideline1": {
"message": "整个视频都在展示免费/受助以获得和访问的事物"
},
"category_interaction": {
"message": "互动提醒(订阅)"
},
"category_interaction_description": {
"message": "视频中间简短提醒观众来点赞、订阅或关注。 如果片段较长,或是关于某个具体事物,则应分类为自我推广。"
},
"category_interaction_guideline1": {
"message": "短暂提醒要喜欢、订阅或关注"
},
"category_interaction_guideline2": {
"message": "包括提醒发表评论,即使是间接的"
},
"category_interaction_guideline3": {
"message": "不是常见的推广互动,只是行动呼吁"
},
"category_interaction_short": {
"message": "互动提醒"
},
@@ -560,12 +661,54 @@
"category_intro_short": {
"message": "过场"
},
"category_intro_guideline1": {
"message": "无实际内容的片段"
},
"category_intro_guideline2": {
"message": "不包括含有信息的转场"
},
"category_outro": {
"message": "结束画面/结尾职员表"
},
"category_outro_description": {
"message": "鸣谢画面或出现 YouTube 片尾画面。不应用于包含信息的结尾。"
},
"category_outro_guideline1": {
"message": "不应包含内容,即使结尾演职员表已经出现。"
},
"category_preview": {
"message": "预览/概要"
},
"category_preview_description": {
"message": "展示此视频或同系列后续视频将出现的画面集锦,所有内容都将在之后再次出现。"
},
"category_preview_guideline1": {
"message": "在之后或未来视频会出现的片段"
},
"category_preview_guideline2": {
"message": "往期视频的回顾总结"
},
"category_preview_guideline3": {
"message": "不含有新添加的内容"
},
"category_filler": {
"message": "离题的闲聊/笑话"
},
"category_filler_description": {
"message": "离题片段标签仅在出现不需要理解视频主要内容的拖时间/无关笑话片段时使用。此标签不能包含有意义的内容或背景细节。这是非常激进的类别,代表您没有心情娱乐。"
},
"category_filler_short": {
"message": "离题"
},
"category_filler_guideline1": {
"message": "拖时间/无意义笑话等离题片段"
},
"category_filler_guideline2": {
"message": "分心、花絮、重播"
},
"category_filler_guideline3": {
"message": "不需要理解主题的片段"
},
"category_music_offtopic": {
"message": "音乐:非音乐部分"
},
@@ -573,7 +716,43 @@
"message": "仅用于音乐视频。此分类只能用于音乐视频中未包括于其他分类的部分。"
},
"category_music_offtopic_short": {
"message": "音乐"
"message": "音乐"
},
"category_music_offtopic_guideline1": {
"message": "不在官方版本中的部分"
},
"category_music_offtopic_guideline2": {
"message": "现场表演中的非音乐片段"
},
"category_poi_highlight": {
"message": "精彩时刻"
},
"category_poi_highlight_description": {
"message": "大部分人都在寻找的视频片段。类似于“封面在12:34”的评论。"
},
"category_poi_highlight_guideline1": {
"message": "大部分人想看的片段"
},
"category_poi_highlight_guideline2": {
"message": "可以帮助略过之前的内容"
},
"category_poi_highlight_guideline3": {
"message": "可以跳到标题或封面"
},
"category_chapter": {
"message": "章节"
},
"category_chapter_description": {
"message": "自定义命名章节描述了视频的主要部分。"
},
"category_chapter_guideline1": {
"message": "不要提到赞助商品牌名称"
},
"category_chapter_guideline2": {
"message": "在一般普通的环节使用较长的章节"
},
"category_chapter_guideline3": {
"message": "小章节可以放在大章节内"
},
"category_livestream_messages": {
"message": "直播:捐赠/消息阅读"
@@ -588,13 +767,42 @@
"message": "手动跳过"
},
"showOverlay": {
"message": "在搜索栏中显示"
"message": "在进度条中显示"
},
"disable": {
"message": "禁用"
},
"autoSkip_POI": {
"message": "跳至开始位置"
},
"manualSkip_POI": {
"message": "视频加载时询问"
},
"showOverlay_POI": {
"message": "在进度条中显示"
},
"showOverlay_full": {
"message": "显示标签"
},
"showOverlay_chapter": {
"message": "显示章节"
},
"autoSkipOnMusicVideos": {
"message": "自动跳过所有非音乐片段"
},
"muteSegments": {
"message": "允许静音的片段而不是跳过"
},
"fullVideoSegments": {
"message": "当整个视频都是广告时显示图标",
"description": "Referring to the category pill that is now shown on videos that are entirely sponsor or entirely selfpromo"
},
"previewColor": {
"message": "未提交颜色",
"description": "Referring to submissions that have not been sent to the server yet."
},
"seekBarColor": {
"message": "拖动条颜色"
"message": "进度条颜色"
},
"category": {
"message": "类别"
@@ -625,24 +833,47 @@
"message": "要提交“{0}”类别的片段,您必须在选项中启用此类别。现在将重定向到选项。",
"description": "Used when submitting segments to only let them select a certain category if they have it enabled in the options."
},
"poiOnlyOneSegment": {
"message": "警告:此类型的片段一次最多只能使用一个。提交多个片段将随机显示。"
},
"youMustSelectACategory": {
"message": "您必须为所有您要提交的片段选择类别!"
},
"bracketEnd": {
"message": "(结束)"
},
"End": {
"message": "结束",
"description": "Button that skips to the end of a segment"
},
"hiddenDueToDownvote": {
"message": "隐藏:差评"
},
"hiddenDueToDuration": {
"message": "隐藏:过短"
},
"manuallyHidden": {
"message": "手动隐藏"
},
"channelDataNotFound": {
"description": "This error appears in an alert when they try to whitelist a channel and the extension is unable to determine what channel they are looking at.",
"message": "未检测到频道ID。如果您正在使用嵌入式视频播放器请转到 Youtube 网站观看。也可能是 Youtube 更改了页面布局,如果您认为是此问题,请在此评论:"
},
"invidiousPermissionRefresh": {
"message": "浏览器已撤销在 Invidious 及其他第三方网站运行所需的权限。请点击下方按钮重新激活权限。"
},
"acceptPermission": {
"message": "接受权限"
},
"permissionRequestSuccess": {
"message": "权限请求成功!"
},
"permissionRequestFailed": {
"message": "权限请求失败,您是否点击拒绝?"
},
"adblockerIssueWhitelist": {
"message": "如果您无法解决这个问题,请禁用“跳过前强制进行频道检查”选项,因为 SponsorBlock 无法获得此视频的频道信息"
},
"forceChannelCheck": {
"message": "跳过前强制进行频道检查"
},
@@ -655,6 +886,16 @@
"downvoteDescription": {
"message": "不正确/错误的时间"
},
"incorrectVote": {
"message": "不正确"
},
"harmfulVote": {
"message": "有害的",
"description": "Used for chapter segments when the text is harmful/offensive to remove it faster"
},
"incorrectCategory": {
"message": "更改类别"
},
"nonMusicCategoryOnMusic": {
"message": "此视频的分类为音乐。 您确定其中包含赞助商广告吗?如果这是“非音乐片段”,请打开扩展选项并启用此类别。 之后,您可以以“非音乐”而不是赞助商广告类别提交此片段。如果您不太明白,请阅读指南。"
},
@@ -672,9 +913,341 @@
"message": "类别在这里!"
},
"categoryUpdate2": {
"message": "开选项跳过开头结尾商业等。"
"message": "开选项跳过开头结尾商业等内容。"
},
"help": {
"message": "帮助"
},
"GotIt": {
"message": "明白了",
"description": "Used as the button to dismiss a tooltip"
},
"fullVideoTooltipWarning": {
"message": "片段过长。如果整个视频都是关于同一个主题,请将“跳过”改成“整个视频”标签。查看指南了解详情。"
},
"categoryPillTitleText": {
"message": "整个视频都被标记为此分类且内容过于紧凑,无法分开。"
},
"chapterNameTooltipWarning": {
"message": "提交的章节名称与现有类别名称相似。如果已经存在分类,您应该优先使用它。"
},
"experiementOptOut": {
"message": "关闭所有实验性功能",
"description": "This is used in a popup about a new experiment to get a list of unlisted videos to back up since all unlisted videos uploaded before 2017 will be set to private."
},
"hideForever": {
"message": "永远隐藏"
},
"warningChatInfo": {
"message": "我们注意到你犯了一些常见错误。我们非常赞赏你迄今所做的工作,但我们努力追求完美,所以即使是非常小的错误,也需要重视:)"
},
"warningTitle": {
"message": "你收到了警告"
},
"questionButton": {
"message": "我有疑问"
},
"warningConfirmButton": {
"message": "我理解原因"
},
"warningError": {
"message": "尝试确认警告时发生错误:"
},
"Donate": {
"message": "捐赠"
},
"considerDonating": {
"message": "资助开发"
},
"hideDonationLink": {
"message": "隐藏捐赠链接"
},
"darkModeOptionsPage": {
"message": "深色模式选项页面"
},
"helpPageThanksForInstalling": {
"message": "感谢安装 SponsorBlock。"
},
"helpPageReviewOptions": {
"message": "请查看下面的选项"
},
"helpPageFeatureDisclaimer": {
"message": "许多功能默认禁用。如果您想跳过开头、结尾或使用 Invidious 等,请在下方开启。您也可以显示/隐藏界面内容。"
},
"helpPageHowSkippingWorks": {
"message": "跳过是如何运作的"
},
"helpPageHowSkippingWorks1": {
"message": "视频片段如果在数据库中存在将被自动跳过。您可以点击插件图标打开弹窗查看预览。"
},
"helpPageHowSkippingWorks2": {
"message": "当跳过片段时,您会收到提醒。如果时间不对,请点击差评!您也可以在插件弹窗中投票。"
},
"Submitting": {
"message": "提交中"
},
"helpPageSubmitting1": {
"message": "您可以使用插件弹窗中的“片段现在开始”按钮或播放器中的按钮提交片段。"
},
"helpPageSubmitting2": {
"message": "点击播放按钮标记片段开始,点击停止按钮标记片段结束。您可以一次提交多个片段。点击上传按钮会提交片段。点击垃圾桶按钮会删除片段。"
},
"Editing": {
"message": "正在编辑"
},
"helpPageEditing1": {
"message": "如果您选错了,您可以点击左侧箭头按钮编辑或删除您的片段。"
},
"helpPageTooSlow": {
"message": "太慢了"
},
"helpPageTooSlow1": {
"message": "常用功能支持快捷键。按下分号键“;”标记赞助商广告片段开始和结束,按下撇号“ ”提交。可以在选项中更改按键。如果您使用的不是QWERTY序列键盘您可能需要更改键位绑定。"
},
"helpPageCopyOfDatabase": {
"message": "我可以下载数据库吗?如果你人没了会怎样?"
},
"helpPageCopyOfDatabase1": {
"message": "数据库是公开的,在此访问:"
},
"helpPageCopyOfDatabase2": {
"message": "源代码是免费公开的。所以即使我出了什么事,你的提交也不会丢失。"
},
"helpPageNews": {
"message": "新闻和更新记录"
},
"helpPageSourceCode": {
"message": "在哪里可以获得源代码?"
},
"Credits": {
"message": "鸣谢"
},
"LearnMore": {
"message": "了解详情"
},
"FullDetails": {
"message": "全部细节"
},
"CopyDownvoteButtonInfo": {
"message": "差评并创建本地副本供您再次提交"
},
"OpenCategoryWikiPage": {
"message": "打开此类别的百科页面。"
},
"CopyAndDownvote": {
"message": "复制并差评"
},
"ContinueVoting": {
"message": "继续投票"
},
"ChangeCategoryTooltip": {
"message": "这会立即应用到您所有的片段"
},
"downvote": {
"message": "差评"
},
"upvote": {
"message": "点赞"
},
"hideSegment": {
"message": "隐藏片段"
},
"skipSegment": {
"message": "跳过片段"
},
"playChapter": {
"message": "播放章节"
},
"SponsorTimeEditScrollNewFeature": {
"message": "将鼠标悬停在编辑框上,操作鼠标滚轮可以快速调整时间。包含 Ctrl 和 Shift 的组合快捷键可以微调时间。"
},
"categoryPillNewFeature": {
"message": "新功能!知道视频是否完全是赞助广告或自我推广"
},
"dayAbbreviation": {
"message": "天",
"description": "100d"
},
"hourAbbreviation": {
"message": "小时",
"description": "100h"
},
"optionsTabBehavior": {
"message": "行为",
"description": "Appears in Options as a tab header for options related to categories and skipping behavior. To fit inside the button, it should not be longer than ~20-25 characters (depending on their width)."
},
"optionsTabInterface": {
"message": "界面",
"description": "Appears in Options as a tab header for options related to GUI and sounds. To fit inside the button, it should not be longer than ~20-25 characters (depending on their width)."
},
"optionsTabKeyBinds": {
"message": "快捷键",
"description": "Appears in Options as a tab header for keybinds. To fit inside the button, it should not be longer than ~20-25 characters (depending on their width)."
},
"optionsTabBackup": {
"message": "备份/恢复",
"description": "Appears in Options as a tab header for options related to saving/restoring your settings. To fit inside the button, it should not be longer than ~20-25 characters (depending on their width)."
},
"optionsTabAdvanced": {
"message": "其他",
"description": "Appears in Options as a tab header for advanced/niche options. To fit inside the button, it should not be longer than ~20-25 characters (depending on their width)."
},
"noticeVisibilityLabel": {
"message": "跳过提醒外观",
"description": "Option label"
},
"unbind": {
"message": "解除绑定",
"description": "Unbind keyboard shortcut"
},
"notSet": {
"message": "未设置"
},
"change": {
"message": "更改"
},
"youtubeKeybindWarning": {
"message": "这是 Youtube 内置的快捷方式。您确定要使用吗?"
},
"betaServerWarning": {
"message": "测试服务器已启用!"
},
"openOptionsPage": {
"message": "打开选项页面"
},
"resetToDefault": {
"message": "重置所有设置"
},
"confirmResetToDefault": {
"message": "您确定要将所有设置重置为默认值吗?此操作无法撤销。"
},
"exportSegments": {
"message": "导出片段"
},
"importSegments": {
"message": "导入片段"
},
"Import": {
"message": "导入",
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
},
"redeemSuccess": {
"message": "兑换成功!"
},
"redeemFailed": {
"message": "注册码无效"
},
"hideUpsells": {
"message": "隐藏需要额外付费才能使用的选项"
},
"chooseACountry": {
"message": "选择国家/地区"
},
"noDiscount": {
"message": "您无法使用折扣"
},
"discountLink": {
"message": "优惠折扣链接(查看粉色价格)"
},
"selectYourCountry": {
"message": "选择所在国家/地区"
},
"alreadyDonated": {
"message": "如果您以前曾捐赠过任何金额,您可以通过电子邮件联系以获得使用权限:",
"description": "After the colon is an email address"
},
"cantAfford": {
"message": "如果您无法负担得起许可证的价格,请点击 {here} 查看您是否有资格获得折扣",
"description": "Keep the curly braces. The word 'here' should be translated as well."
},
"patreonSignIn": {
"message": "使用 Patreon 登录"
},
"redeem": {
"message": "兑换"
},
"joinOnPatreon": {
"message": "在 Patreon 上支持我"
},
"oneTimePurchase": {
"message": "一次性购买"
},
"enterLicenseKey": {
"message": "输入注册码"
},
"chaptersPage1": {
"message": "SponsorBlock 的众包章节功能仅供付费或贡献突出的用户使用"
},
"chaptersPage2": {
"message": "注意:提交章节的权限仍然基于信誉积分。购买许可证只允许您查看他人提交的章节",
"description": "On the chapters page for getting access to the paid chapters feature"
},
"chapterNewFeature": {
"message": "新功能:众包自定义章节。这些视频中自定义命名的部分可以叠加并获得更精确的信息。购买许可证以查看此视频的章节,例如:",
"description": "After the comma, a list of chapters for this video will appear"
},
"chapterNewFeature2": {
"message": "新功能:众包自定义章节。这些视频中自定义命名的部分可以叠加并获得更精确的信息。您有免费使用权限,请在选项中开启。"
},
"unsubmittedSegmentCounts": {
"message": "您在 {1} 中有 {0}",
"description": "Example: You currently have 12 unsubmitted segments on 5 videos"
},
"unsubmittedSegmentCountsZero": {
"message": "您目前没有未提交的片段",
"description": "Replaces 'unsubmittedSegmentCounts' string when there are no unsubmitted segments"
},
"unsubmittedSegmentsSingular": {
"message": "未提交的片段",
"description": "Example: You currently have 1 *unsubmitted segment* on 1 video"
},
"unsubmittedSegmentsPlural": {
"message": "未提交的片段",
"description": "Example: You currently have 12 *unsubmitted segments* on 5 videos"
},
"videosSingular": {
"message": "视频",
"description": "Example: You currently have 3 unsubmitted segments on 1 *video*"
},
"videosPlural": {
"message": "视频",
"description": "Example: You currently have 12 unsubmitted segments on 5 *videos*"
},
"clearUnsubmittedSegments": {
"message": "清除所有片段",
"description": "Label for a button in settings"
},
"clearUnsubmittedSegmentsConfirm": {
"message": "您确定要清除所有未提交的片段吗?",
"description": "Confirmation message for the Clear unsubmitted segments button"
},
"showUnsubmittedSegments": {
"message": "显示片段",
"description": "Show/hide button for the unsubmitted segments list"
},
"hideUnsubmittedSegments": {
"message": "隐藏片段",
"description": "Show/hide button for the unsubmitted segments list"
},
"videoID": {
"message": "视频ID",
"description": "Header of the unsubmitted segments list"
},
"segmentCount": {
"message": "片段数",
"description": "Header of the unsubmitted segments list"
},
"actions": {
"message": "操作",
"description": "Header of the unsubmitted segments list"
},
"exportSegmentsAsURL": {
"message": "分享链接"
},
"segmentFetchFailureWarning": {
"message": "警告:服务器未响应。片段可能已提交,只是由于服务器问题您未收到回应。"
},
"allowScrollingToEdit": {
"message": "允许滚动编辑时间"
}
}

View File

@@ -35,6 +35,9 @@
"message": "以章節渲染片段",
"description": "Refers to drawing segments on the YouTube seek bar as split up chapters, similar to the existing chapter system"
},
"showSegmentNameInChapterBar": {
"message": "在影片時間旁顯示目前片段"
},
"upvoteButtonInfo": {
"message": "為這個提交按讚"
},
@@ -113,6 +116,9 @@
"connectionError": {
"message": "已發生連線錯誤。錯誤碼: "
},
"segmentsStillLoading": {
"message": "片段還在載入..."
},
"clearTimes": {
"message": "清除片段"
},
@@ -122,8 +128,8 @@
"closePopup": {
"message": "關閉彈出視窗"
},
"SubmitTimes": {
"message": "提交分段"
"closeIcon": {
"message": "關閉圖示"
},
"sortSegments": {
"message": "排序片段"
@@ -162,9 +168,6 @@
"clearTimesButton": {
"message": "清除時間"
},
"submitTimesButton": {
"message": "提交時間"
},
"publicStats": {
"message": "這會被公開的統計頁面來展示您的貢獻。查看它"
},
@@ -408,9 +411,18 @@
"statusReminder": {
"message": "在 status.sponsor.ajay.app 檢查伺服器狀態"
},
"changeUserID": {
"message": "匯入/匯出您的密鑰 ID"
},
"whatChangeUserID": {
"message": "密鑰應被保密。它就像是密碼不應與他人分享。若密鑰落入他人手中他人將可以冒充你。若你在尋找你的公開使用者ID點擊彈出視窗上的剪貼簿圖示"
},
"setUserID": {
"message": "設定密鑰 ID"
},
"userIDChangeWarning": {
"message": "警告:更改用戶 ID 是永久性的。您確定要這麼做嗎?請務必備份您的舊用戶 ID 來以防萬一。"
},
"createdBy": {
"message": "作者"
},
@@ -508,6 +520,9 @@
"exportOptionsUpload": {
"message": "從檔案載入"
},
"whatExportOptions": {
"message": "這是您全部設定的 JSON 格式。它包含了您的密鑰 ID ,所以您一定要謹慎的保管它。"
},
"setOptions": {
"message": "設定選項"
},
@@ -833,7 +848,7 @@
"message": "未偵測到頻道ID如果您正在使用嵌入式YouTube播放器請移至YouTube網站上觀看本影片。此問題亦有可能是由於YouTube改變了系統架構如果你認為這是造成此問題的原因請留言告訴我們"
},
"invidiousPermissionRefresh": {
"message": "瀏覽器已收回存取第三方網頁 (例如 Invidious) 的權限請點擊下方按鈕以重新給予此權限。"
"message": "瀏覽器已撤銷在 Invidious 和其他第三方網站上運行所需的權限請點擊下方按鈕以重新給予此權限。"
},
"acceptPermission": {
"message": "允許權限"
@@ -911,9 +926,6 @@
"hideForever": {
"message": "永久隱藏"
},
"warningChatInfo": {
"message": "我們注意到你犯下了一些不帶有惡意的常見錯誤"
},
"warningTitle": {
"message": "你收到了一支警告"
},
@@ -1025,6 +1037,12 @@
"hideSegment": {
"message": "隱藏片段"
},
"skipSegment": {
"message": "略過片段"
},
"playChapter": {
"message": "播放章節"
},
"SponsorTimeEditScrollNewFeature": {
"message": "在滑鼠鼠標放在編輯框上時使用滾輪以快速調製時間。Ctrl和Shift可以用於精密調整"
},
@@ -1091,6 +1109,9 @@
"exportSegments": {
"message": "匯出片段"
},
"importSegments": {
"message": "匯入片段"
},
"Import": {
"message": "匯入",
"description": "Button to initiate importing segments. Appears under the textbox where they paste in the data"
@@ -1111,13 +1132,13 @@
"message": "你不能使用優惠"
},
"discountLink": {
"message": "優惠連結 (看粉色的價格)"
"message": "優惠連結看粉色的價格"
},
"selectYourCountry": {
"message": "選擇國家"
},
"alreadyDonated": {
"message": "如果你在之前捐獻過 (任何金額),你可以發送電子郵件到以下地址以獲得免費存取權:",
"message": "如果你在之前捐獻過任何金額,你可以發送電子郵件到以下地址以獲得免費存取權:",
"description": "After the colon is an email address"
},
"cantAfford": {
@@ -1183,7 +1204,7 @@
"description": "Show/hide button for the unsubmitted segments list"
},
"videoID": {
"message": "影片ID",
"message": "影片 ID",
"description": "Header of the unsubmitted segments list"
},
"segmentCount": {
@@ -1196,5 +1217,8 @@
},
"exportSegmentsAsURL": {
"message": "分享連結"
},
"allowScrollingToEdit": {
"message": "允許在編輯時滾動"
}
}

View File

@@ -585,6 +585,7 @@ input::-webkit-inner-spin-button {
font-size: 14px;
-moz-appearance: textfield;
appearance: textfield;
}
.sponsorTimeEditInput {

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

View File

@@ -3,7 +3,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@@ -11,7 +11,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@@ -19,7 +19,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@@ -27,7 +27,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@@ -35,7 +35,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@@ -43,7 +43,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@@ -51,7 +51,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2) format('woff2');
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@@ -59,7 +59,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@@ -67,7 +67,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@@ -75,7 +75,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@@ -83,7 +83,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@@ -91,7 +91,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@@ -99,7 +99,7 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@@ -107,6 +107,6 @@
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2) format('woff2');
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
}

View File

@@ -442,7 +442,7 @@
<div id="advanced" class="option-group hidden">
<div id="support-invidious" data-type="toggle" data-sync="supportInvidious" data-no-safari="true">
<div id="support-invidious" data-type="toggle" data-sync="supportInvidious">
<div class="switch-container">
<label class="switch">
<input id="supportInvidious" type="checkbox">
@@ -453,11 +453,11 @@
</label>
</div>
<div class="small-description">(__MSG_supportedSites__ Invidious, CloudTube)</div>
<div class="small-description">(__MSG_supportedSites__ Invidious, CloudTube, Piped)</div>
<div class="small-description">__MSG_supportOtherSitesDescription__ </div>
</div>
<div data-type="private-text-change" data-sync="invidiousInstances" data-no-safari="true" data-dependent-on="supportInvidious">
<div data-type="private-text-change" data-sync="invidiousInstances" data-dependent-on="supportInvidious">
<div class="option-button trigger-button">
__MSG_addInvidiousInstance__
</div>

View File

@@ -1,3 +1,204 @@
@ajayyy/maze-utils
1.1.7 <https://github.com/ajayyy/SponsorBlock>
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
******************************
content-scripts-register-polyfill
4.0.2 <https://github.com/fregante/content-scripts-register-polyfill>
MIT License
Copyright (c) Federico Brigante <me@fregante.com> (https://fregante.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************
escape-string-regexp
5.0.0 <https://github.com/sindresorhus/escape-string-regexp>
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************
js-tokens
4.0.0 <https://github.com/lydell/js-tokens>
The MIT License (MIT)
@@ -129,3 +330,48 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************
webext-content-scripts
2.5.2 <https://github.com/fregante/webext-content-scripts>
MIT License
Copyright (c) Federico Brigante <me@fregante.com> (https://fregante.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************
webext-patterns
1.3.0 <https://github.com/fregante/webext-patterns>
MIT License
Copyright (c) Federico Brigante <me@fregante.com> (https://fregante.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************
webext-polyfill-kinda
1.0.0 <https://github.com/fregante/webext-polyfill-kinda>
MIT License
Copyright (c) Federico Brigante <me@fregante.com> (https://fregante.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -105,7 +105,7 @@
<sub class="sponsorStartHint grey-text">__MSG_popupHint__</sub>
<div style="text-align: center; margin: 8px 0;">
<button id="sponsorStart" class="sbMediumButton" style="margin-right: 8px">__MSG_sponsorStart__</button>
<button id="submitTimes" class="sbMediumButton" style="display: none">__MSG_submitTimesButton__</button>
<button id="submitTimes" class="sbMediumButton" style="display: none">__MSG_OpenSubmissionMenu__</button>
</div>
<span id="submissionHint" style="display: none">__MSG_submissionEditHint__</span>
</div>

View File

@@ -2,13 +2,16 @@ import * as CompileConfig from "../config.json";
import Config from "./config";
import { Registration } from "./types";
import registerContentScript from 'content-scripts-register-polyfill/ponyfill.js';
import { sendRealRequestToCustomServer, setupBackgroundRequestProxy } from "@ajayyy/maze-utils/lib/background-request-proxy";
import { setupTabUpdates } from "@ajayyy/maze-utils/lib/tab-updates";
import { generateUserID } from "@ajayyy/maze-utils/lib/setup";
// Make the config public for debugging purposes
window.SB = Config;
import Utils from "./utils";
import { GenericUtils } from "./utils/genericUtils";
const utils = new Utils({
registerFirefoxContentScript,
unregisterFirefoxContentScript
@@ -20,40 +23,12 @@ const popupPort: Record<string, chrome.runtime.Port> = {};
const contentScriptRegistrations = {};
// Register content script if needed
if (utils.isFirefox()) {
utils.wait(() => Config.config !== null).then(function() {
if (Config.config.supportInvidious) utils.setupExtraSiteContentScripts();
});
}
function onTabUpdatedListener(tabId: number) {
chrome.tabs.sendMessage(tabId, {
message: 'update',
}, () => void chrome.runtime.lastError ); // Suppress error on Firefox
}
function onNavigationApiAvailableChange(changes: {[key: string]: chrome.storage.StorageChange}) {
if (changes.navigationApiAvailable) {
if (changes.navigationApiAvailable.newValue) {
chrome.tabs.onUpdated.removeListener(onTabUpdatedListener);
} else {
chrome.tabs.onUpdated.addListener(onTabUpdatedListener);
}
}
}
// If Navigation API is not supported, then background has to inform content script about video change.
// This happens on Safari, Firefox, and Chromium 101 (inclusive) and below.
chrome.tabs.onUpdated.addListener(onTabUpdatedListener);
utils.wait(() => Config.local !== null).then(() => {
if (Config.local.navigationApiAvailable) {
chrome.tabs.onUpdated.removeListener(onTabUpdatedListener);
}
utils.wait(() => Config.config !== null).then(function() {
if (Config.config.supportInvidious) utils.setupExtraSiteContentScripts();
});
if (!Config.configSyncListeners.includes(onNavigationApiAvailableChange)) {
Config.configSyncListeners.push(onNavigationApiAvailableChange);
}
setupBackgroundRequestProxy();
setupTabUpdates(Config);
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
switch(request.message) {
@@ -69,16 +44,6 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
case "openPage":
chrome.tabs.create({url: chrome.runtime.getURL(request.url)});
return false;
case "sendRequest":
sendRequestToCustomServer(request.type, request.url, request.data).then(async (response) => {
callback({
responseText: await response.text(),
status: response.status,
ok: response.ok
});
});
return true;
case "submitVote":
submitVote(request.type, request.UUID, request.category).then(callback);
@@ -141,7 +106,7 @@ chrome.runtime.onInstalled.addListener(function () {
chrome.tabs.create({url: chrome.extension.getURL("/help/index.html")});
//generate a userID
const newUserID = GenericUtils.generateUserID();
const newUserID = generateUserID();
//save this UUID
Config.config.userID = newUserID;
@@ -167,7 +132,7 @@ function registerFirefoxContentScript(options: Registration) {
const oldRegistration = contentScriptRegistrations[options.id];
if (oldRegistration) oldRegistration.unregister();
browser.contentScripts.register({
registerContentScript({
allFrames: options.allFrames,
js: options.js,
css: options.css,
@@ -181,8 +146,10 @@ function registerFirefoxContentScript(options: Registration) {
*
*/
function unregisterFirefoxContentScript(id: string) {
contentScriptRegistrations[id].unregister();
delete contentScriptRegistrations[id];
if (contentScriptRegistrations[id]) {
contentScriptRegistrations[id].unregister();
delete contentScriptRegistrations[id];
}
}
async function submitVote(type: number, UUID: string, category: string) {
@@ -190,7 +157,7 @@ async function submitVote(type: number, UUID: string, category: string) {
if (userID == undefined || userID === "undefined") {
//generate one
userID = GenericUtils.generateUserID();
userID = generateUserID();
Config.config.userID = userID;
}
@@ -221,35 +188,9 @@ async function submitVote(type: number, UUID: string, category: string) {
}
}
async function asyncRequestToServer(type: string, address: string, data = {}) {
const serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
return await (sendRequestToCustomServer(type, serverAddress + address, data));
}
/**
* Sends a request to the specified url
*
* @param type The request type "GET", "POST", etc.
* @param address The address to add to the SponsorBlock server address
* @param callback
*/
async function sendRequestToCustomServer(type: string, url: string, data = {}) {
// If GET, convert JSON to parameters
if (type.toLowerCase() === "get") {
url = GenericUtils.objectToURI(url, data, true);
data = null;
}
const response = await fetch(url, {
method: type,
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow',
body: data ? JSON.stringify(data) : null
});
return response;
}
return await (sendRealRequestToCustomServer(type, serverAddress + address, data));
}

View File

@@ -13,7 +13,7 @@ import ThumbsUpSvg from "../svg-icons/thumbs_up_svg";
import ThumbsDownSvg from "../svg-icons/thumbs_down_svg";
import PencilSvg from "../svg-icons/pencil_svg";
import { downvoteButtonColor, SkipNoticeAction } from "../utils/noticeUtils";
import { GenericUtils } from "../utils/genericUtils";
import { generateUserID } from "@ajayyy/maze-utils/lib/setup";
enum SkipButtonState {
Undo, // Unskip
@@ -542,7 +542,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
const sponsorVideoID = this.props.contentContainer().sponsorVideoID;
const sponsorTimesSubmitting : SponsorTime = {
segment: this.segments[index].segment,
UUID: GenericUtils.generateUserID() as SegmentUUID,
UUID: generateUserID() as SegmentUUID,
category: this.segments[index].category,
actionType: this.segments[index].actionType,
source: SponsorSourceType.Local

View File

@@ -6,10 +6,9 @@ import Utils from "../utils";
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
import { RectangleTooltip } from "../render/RectangleTooltip";
import SelectorComponent, { SelectorOption } from "./SelectorComponent";
import { GenericUtils } from "../utils/genericUtils";
import { noRefreshFetchingChaptersAllowed } from "../utils/licenseKey";
import { DEFAULT_CATEGORY } from "../utils/categoryUtils";
import { getFormattedTime, getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating";
const utils = new Utils();
@@ -181,9 +180,9 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
style={timeDisplayStyle}
className="sponsorTimeDisplay"
onClick={this.toggleEditTime.bind(this)}>
{GenericUtils.getFormattedTime(segment[0], true) +
{getFormattedTime(segment[0], true) +
((!isNaN(segment[1]) && sponsorTime.actionType !== ActionType.Poi)
? " " + chrome.i18n.getMessage("to") + " " + GenericUtils.getFormattedTime(segment[1], true) : "")}
? " " + chrome.i18n.getMessage("to") + " " + getFormattedTime(segment[1], true) : "")}
</div>
);
}
@@ -308,8 +307,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
const sponsorTimeEdits = this.state.sponsorTimeEdits;
// check if change is small engough to show tooltip
const before = GenericUtils.getFormattedTimeToSeconds(sponsorTimeEdits[index]);
const after = GenericUtils.getFormattedTimeToSeconds(targetValue);
const before = getFormattedTimeToSeconds(sponsorTimeEdits[index]);
const after = getFormattedTimeToSeconds(targetValue);
const difference = Math.abs(before - after);
if (0 < difference && difference < 0.5) this.showScrollToEditToolTip();
@@ -333,7 +332,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
}
const sponsorTimeEdits = this.state.sponsorTimeEdits;
let timeAsNumber = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[index]);
let timeAsNumber = getFormattedTimeToSeconds(this.state.sponsorTimeEdits[index]);
if (timeAsNumber !== null && e.deltaY != 0) {
if (e.deltaY < 0) {
timeAsNumber += step;
@@ -343,7 +342,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
timeAsNumber = 0;
}
sponsorTimeEdits[index] = GenericUtils.getFormattedTime(timeAsNumber, true);
sponsorTimeEdits[index] = getFormattedTime(timeAsNumber, true);
if (sponsorTime.actionType === ActionType.Poi) sponsorTimeEdits[1] = sponsorTimeEdits[0];
this.setState({sponsorTimeEdits});
@@ -575,8 +574,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
/** Returns an array in the sponsorTimeEdits form (formatted time string) from a normal seconds sponsor time */
getFormattedSponsorTimesEdits(sponsorTime: SponsorTime): [string, string] {
return [GenericUtils.getFormattedTime(sponsorTime.segment[0], true),
GenericUtils.getFormattedTime(sponsorTime.segment[1], true)];
return [getFormattedTime(sponsorTime.segment[0], true),
getFormattedTime(sponsorTime.segment[1], true)];
}
saveEditTimes(): void {
@@ -584,8 +583,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
const category = this.categoryOptionRef.current.value as Category
if (this.state.editing) {
const startTime = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]);
const endTime = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1]);
const startTime = getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]);
const endTime = getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1]);
// Change segment time only if the format was correct
if (startTime !== null && endTime !== null) {

View File

@@ -124,7 +124,7 @@ class KeybindDialogComponent extends React.Component<KeybindDialogProps, Keybind
let youtubeShortcuts: Keybind[];
if (/[a-zA-Z0-9,.+\-\][:]/.test(this.state.key.key)) {
youtubeShortcuts = [{key: "k"}, {key: "j"}, {key: "l"}, {key: "p", shift: true}, {key: "n", shift: true}, {key: ","}, {key: "."}, {key: ",", shift: true}, {key: ".", shift: true},
{key: "ArrowRight"}, {key: "ArrowLeft"}, {key: "ArrowUp"}, {key: "ArrowDown"}, {key: "ArrowRight", ctrl: true}, {key: "ArrowLeft", ctrl: true}, {key: "c"}, {key: "o"},
{key: "ArrowRight"}, {key: "ArrowLeft"}, {key: "ArrowUp"}, {key: "ArrowDown"}, {key: "c"}, {key: "o"},
{key: "w"}, {key: "+"}, {key: "-"}, {key: "f"}, {key: "t"}, {key: "i"}, {key: "m"}, {key: "a"}, {key: "s"}, {key: "d"}, {key: "Home"}, {key: "End"},
{key: "0"}, {key: "1"}, {key: "2"}, {key: "3"}, {key: "4"}, {key: "5"}, {key: "6"}, {key: "7"}, {key: "8"}, {key: "9"}, {key: "]"}, {key: "["}];
} else {

View File

@@ -1,7 +1,9 @@
import * as CompileConfig from "../config.json";
import * as invidiousList from "../ci/invidiouslist.json";
import { Category, CategorySelection, CategorySkipOption, NoticeVisbilityMode, PreviewBarOption, SponsorTime, StorageChangesObject, Keybind, HashedValue, VideoID, SponsorHideType } from "./types";
import { Category, CategorySelection, CategorySkipOption, NoticeVisbilityMode, PreviewBarOption, SponsorTime, Keybind, VideoID, SponsorHideType } from "./types";
import { keybindEquals } from "./utils/configUtils";
import { ProtoConfig } from "@ajayyy/maze-utils/lib/config";
import { HashedValue } from "@ajayyy/maze-utils/lib/hash";
export interface Permission {
canSubmit: boolean;
@@ -121,7 +123,7 @@ interface SBConfig {
};
}
export type VideoDownvotes = { segments: { uuid: HashedValue; hidden: SponsorHideType }[] ; lastAccess: number };
export type VideoDownvotes = { segments: { uuid: HashedValue; hidden: SponsorHideType }[]; lastAccess: number };
interface SBStorage {
/* VideoID prefixes to UUID prefixes */
@@ -129,336 +131,16 @@ interface SBStorage {
navigationApiAvailable: boolean;
}
export interface SBObject {
configLocalListeners: Array<(changes: StorageChangesObject) => unknown>;
configSyncListeners: Array<(changes: StorageChangesObject) => unknown>;
syncDefaults: SBConfig;
localDefaults: SBStorage;
cachedSyncConfig: SBConfig;
cachedLocalStorage: SBStorage;
config: SBConfig;
local: SBStorage;
forceSyncUpdate(prop: string): void;
forceLocalUpdate(prop: string): void;
resetToDefault(): void;
}
const Config: SBObject = {
/**
* Callback function when an option is updated
*/
configLocalListeners: [],
configSyncListeners: [],
syncDefaults: {
userID: null,
isVip: false,
permissions: {},
unsubmittedSegments: {},
defaultCategory: "chooseACategory" as Category,
renderSegmentsAsChapters: false,
whitelistedChannels: [],
forceChannelCheck: false,
minutesSaved: 0,
skipCount: 0,
sponsorTimesContributed: 0,
submissionCountSinceCategories: 0,
showTimeWithSkips: true,
disableSkipping: false,
muteSegments: true,
fullVideoSegments: true,
manualSkipOnFullVideo: false,
trackViewCount: true,
trackViewCountInPrivate: true,
trackDownvotes: true,
dontShowNotice: false,
noticeVisibilityMode: NoticeVisbilityMode.FadedForAutoSkip,
hideVideoPlayerControls: false,
hideInfoButtonPlayerControls: false,
hideDeleteButtonPlayerControls: false,
hideUploadButtonPlayerControls: false,
hideSkipButtonPlayerControls: false,
hideDiscordLaunches: 0,
hideDiscordLink: false,
invidiousInstances: ["invidious.snopyta.org"], // leave as default
supportInvidious: false,
serverAddress: CompileConfig.serverAddress,
minDuration: 0,
skipNoticeDuration: 4,
audioNotificationOnSkip: false,
checkForUnlistedVideos: false,
testingServer: false,
refetchWhenNotFound: true,
ytInfoPermissionGranted: false,
allowExpirements: true,
showDonationLink: true,
showPopupDonationCount: 0,
showUpsells: true,
donateClicked: 0,
autoHideInfoButton: true,
autoSkipOnMusicVideos: false,
scrollToEditTimeUpdate: false, // false means the tooltip will be shown
categoryPillUpdate: false,
showChapterInfoMessage: true,
darkMode: true,
showCategoryGuidelines: true,
showCategoryWithoutPermission: false,
showSegmentNameInChapterBar: true,
useVirtualTime: true,
showSegmentFailedToFetchWarning: true,
allowScrollingToEdit: true,
categoryPillColors: {},
/**
* Default keybinds should not set "code" as that's gonna be different based on the user's locale. They should also only use EITHER ctrl OR alt modifiers (or none).
* Using ctrl+alt, or shift may produce a different character that we will not be able to recognize in different locales.
* The exception for shift is letters, where it only capitalizes. So shift+A is fine, but shift+1 isn't.
* Don't forget to add the new keybind to the checks in "KeybindDialogComponent.isKeybindAvailable()" and in "migrateOldFormats()"!
* TODO: Find a way to skip having to update these checks. Maybe storing keybinds in a Map?
*/
skipKeybind: {key: "Enter"},
startSponsorKeybind: {key: ";"},
submitKeybind: {key: "'"},
nextChapterKeybind: {key: "]", ctrl: true},
previousChapterKeybind: {key: "[", ctrl: true},
categorySelections: [{
name: "sponsor" as Category,
option: CategorySkipOption.AutoSkip
}, {
name: "poi_highlight" as Category,
option: CategorySkipOption.ManualSkip
}, {
name: "exclusive_access" as Category,
option: CategorySkipOption.ShowOverlay
}],
payments: {
licenseKey: null,
lastCheck: 0,
lastFreeCheck: 0,
freeAccess: false,
chaptersAllowed: false
},
colorPalette: {
red: "#780303",
white: "#ffffff",
locked: "#ffc83d"
},
// Preview bar
barTypes: {
"preview-chooseACategory": {
color: "#ffffff",
opacity: "0.7"
},
"sponsor": {
color: "#00d400",
opacity: "0.7"
},
"preview-sponsor": {
color: "#007800",
opacity: "0.7"
},
"selfpromo": {
color: "#ffff00",
opacity: "0.7"
},
"preview-selfpromo": {
color: "#bfbf35",
opacity: "0.7"
},
"exclusive_access": {
color: "#008a5c",
opacity: "0.7"
},
"interaction": {
color: "#cc00ff",
opacity: "0.7"
},
"preview-interaction": {
color: "#6c0087",
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"
},
"preview": {
color: "#008fd6",
opacity: "0.7"
},
"preview-preview": {
color: "#005799",
opacity: "0.7"
},
"music_offtopic": {
color: "#ff9900",
opacity: "0.7"
},
"preview-music_offtopic": {
color: "#a6634a",
opacity: "0.7"
},
"poi_highlight": {
color: "#ff1684",
opacity: "0.7"
},
"preview-poi_highlight": {
color: "#9b044c",
opacity: "0.7"
},
"filler": {
color: "#7300FF",
opacity: "0.9"
},
"preview-filler": {
color: "#2E0066",
opacity: "0.7"
}
}
},
localDefaults: {
downvotedSegments: {},
navigationApiAvailable: null
},
cachedSyncConfig: null,
cachedLocalStorage: null,
config: null,
local: null,
forceSyncUpdate,
forceLocalUpdate,
resetToDefault
};
// Function setup
function configProxy(): { sync: SBConfig; local: SBStorage } {
chrome.storage.onChanged.addListener((changes: {[key: string]: chrome.storage.StorageChange}, areaName) => {
if (areaName === "sync") {
for (const key in changes) {
Config.cachedSyncConfig[key] = changes[key].newValue;
}
for (const callback of Config.configSyncListeners) {
callback(changes);
}
} else if (areaName === "local") {
for (const key in changes) {
Config.cachedLocalStorage[key] = changes[key].newValue;
}
for (const callback of Config.configLocalListeners) {
callback(changes);
}
}
});
const syncHandler: ProxyHandler<SBConfig> = {
set<K extends keyof SBConfig>(obj: SBConfig, prop: K, value: SBConfig[K]) {
Config.cachedSyncConfig[prop] = value;
chrome.storage.sync.set({
[prop]: value
});
return true;
},
get<K extends keyof SBConfig>(obj: SBConfig, prop: K): SBConfig[K] {
const data = Config.cachedSyncConfig[prop];
return obj[prop] || data;
},
deleteProperty(obj: SBConfig, prop: keyof SBConfig) {
chrome.storage.sync.remove(<string> prop);
return true;
}
};
const localHandler: ProxyHandler<SBStorage> = {
set<K extends keyof SBStorage>(obj: SBStorage, prop: K, value: SBStorage[K]) {
Config.cachedLocalStorage[prop] = value;
chrome.storage.local.set({
[prop]: value
});
return true;
},
get<K extends keyof SBStorage>(obj: SBStorage, prop: K): SBStorage[K] {
const data = Config.cachedLocalStorage[prop];
return obj[prop] || data;
},
deleteProperty(obj: SBStorage, prop: keyof SBStorage) {
chrome.storage.local.remove(<string> prop);
return true;
}
};
return {
sync: new Proxy<SBConfig>({ handler: syncHandler } as unknown as SBConfig, syncHandler),
local: new Proxy<SBStorage>({ handler: localHandler } as unknown as SBStorage, localHandler)
};
}
function forceSyncUpdate(prop: string): void {
const value = Config.cachedSyncConfig[prop];
if (prop === "unsubmittedSegments") {
// Early to be safe
if (JSON.stringify(value).length + prop.length > 8000) {
for (const key in value) {
if (!value[key] || value[key].length <= 0) {
delete value[key];
}
}
}
class ConfigClass extends ProtoConfig<SBConfig, SBStorage> {
resetToDefault() {
chrome.storage.sync.set({
...this.syncDefaults,
userID: this.config.userID,
minutesSaved: this.config.minutesSaved,
skipCount: this.config.skipCount,
sponsorTimesContributed: this.config.sponsorTimesContributed
});
}
chrome.storage.sync.set({
[prop]: value
});
}
function forceLocalUpdate(prop: string): void {
chrome.storage.local.set({
[prop]: Config.cachedLocalStorage[prop]
});
}
async function fetchConfig(): Promise<void> {
await Promise.all([new Promise<void>((resolve) => {
chrome.storage.sync.get(null, function(items) {
Config.cachedSyncConfig = <SBConfig> <unknown> items;
resolve();
});
}), new Promise<void>((resolve) => {
chrome.storage.local.get(null, function(items) {
Config.cachedLocalStorage = <SBStorage> <unknown> items;
resolve();
});
})]);
}
function migrateOldSyncFormats(config: SBConfig) {
@@ -500,7 +182,7 @@ function migrateOldSyncFormats(config: SBConfig) {
config["autoSkipOnMusicVideosUpdate"] = true;
for (const selection of config.categorySelections) {
if (selection.name === "music_offtopic"
&& selection.option === CategorySkipOption.AutoSkip) {
&& selection.option === CategorySkipOption.AutoSkip) {
config.autoSkipOnMusicVideos = true;
break;
@@ -519,20 +201,20 @@ function migrateOldSyncFormats(config: SBConfig) {
}
if (typeof config["skipKeybind"] == "string") {
config["skipKeybind"] = {key: config["skipKeybind"]};
config["skipKeybind"] = { key: config["skipKeybind"] };
}
if (typeof config["startSponsorKeybind"] == "string") {
config["startSponsorKeybind"] = {key: config["startSponsorKeybind"]};
config["startSponsorKeybind"] = { key: config["startSponsorKeybind"] };
}
if (typeof config["submitKeybind"] == "string") {
config["submitKeybind"] = {key: config["submitKeybind"]};
config["submitKeybind"] = { key: config["submitKeybind"] };
}
// Unbind key if it matches a previous one set by the user (should be ordered oldest to newest)
const keybinds = ["skipKeybind", "startSponsorKeybind", "submitKeybind"];
for (let i = keybinds.length-1; i >= 0; i--) {
for (let i = keybinds.length - 1; i >= 0; i--) {
for (let j = 0; j < keybinds.length; j++) {
if (i == j)
continue;
@@ -550,59 +232,202 @@ function migrateOldSyncFormats(config: SBConfig) {
}
// populate invidiousInstances with new instances if 3p support is **DISABLED**
if (!config["supportInvidious"] && config["invidiousInstances"].length !== invidiousList.length) {
config["invidiousInstances"] = invidiousList;
if (!config["supportInvidious"] && config["invidiousInstances"].length < invidiousList.length) {
config["invidiousInstances"] = [...new Set([...invidiousList, ...config["invidiousInstances"]])];
}
if (config["lastIsVipUpdate"]) {
chrome.storage.sync.remove("lastIsVipUpdate");
}
}
async function setupConfig() {
if (typeof(chrome) === "undefined") return;
const syncDefaults = {
userID: null,
isVip: false,
permissions: {},
unsubmittedSegments: {},
defaultCategory: "chooseACategory" as Category,
renderSegmentsAsChapters: false,
whitelistedChannels: [],
forceChannelCheck: false,
minutesSaved: 0,
skipCount: 0,
sponsorTimesContributed: 0,
submissionCountSinceCategories: 0,
showTimeWithSkips: true,
disableSkipping: false,
muteSegments: true,
fullVideoSegments: true,
manualSkipOnFullVideo: false,
trackViewCount: true,
trackViewCountInPrivate: true,
trackDownvotes: true,
dontShowNotice: false,
noticeVisibilityMode: NoticeVisbilityMode.FadedForAutoSkip,
hideVideoPlayerControls: false,
hideInfoButtonPlayerControls: false,
hideDeleteButtonPlayerControls: false,
hideUploadButtonPlayerControls: false,
hideSkipButtonPlayerControls: false,
hideDiscordLaunches: 0,
hideDiscordLink: false,
invidiousInstances: ["invidious.snopyta.org"], // leave as default
supportInvidious: false,
serverAddress: CompileConfig.serverAddress,
minDuration: 0,
skipNoticeDuration: 4,
audioNotificationOnSkip: false,
checkForUnlistedVideos: false,
testingServer: false,
refetchWhenNotFound: true,
ytInfoPermissionGranted: false,
allowExpirements: true,
showDonationLink: true,
showPopupDonationCount: 0,
showUpsells: true,
donateClicked: 0,
autoHideInfoButton: true,
autoSkipOnMusicVideos: false,
scrollToEditTimeUpdate: false, // false means the tooltip will be shown
categoryPillUpdate: false,
showChapterInfoMessage: true,
darkMode: true,
showCategoryGuidelines: true,
showCategoryWithoutPermission: false,
showSegmentNameInChapterBar: true,
useVirtualTime: true,
showSegmentFailedToFetchWarning: true,
allowScrollingToEdit: true,
await fetchConfig();
addDefaults();
const config = configProxy();
migrateOldSyncFormats(config.sync);
categoryPillColors: {},
Config.config = config.sync;
Config.local = config.local;
}
/**
* Default keybinds should not set "code" as that's gonna be different based on the user's locale. They should also only use EITHER ctrl OR alt modifiers (or none).
* Using ctrl+alt, or shift may produce a different character that we will not be able to recognize in different locales.
* The exception for shift is letters, where it only capitalizes. So shift+A is fine, but shift+1 isn't.
* Don't forget to add the new keybind to the checks in "KeybindDialogComponent.isKeybindAvailable()" and in "migrateOldFormats()"!
* TODO: Find a way to skip having to update these checks. Maybe storing keybinds in a Map?
*/
skipKeybind: { key: "Enter" },
startSponsorKeybind: { key: ";" },
submitKeybind: { key: "'" },
nextChapterKeybind: { key: "ArrowRight", ctrl: true },
previousChapterKeybind: { key: "ArrowLeft", ctrl: true },
// Add defaults
function addDefaults() {
for (const key in Config.syncDefaults) {
if(!Object.prototype.hasOwnProperty.call(Config.cachedSyncConfig, key)) {
Config.cachedSyncConfig[key] = Config.syncDefaults[key];
} else if (key === "barTypes") {
for (const key2 in Config.syncDefaults[key]) {
if(!Object.prototype.hasOwnProperty.call(Config.cachedSyncConfig[key], key2)) {
Config.cachedSyncConfig[key][key2] = Config.syncDefaults[key][key2];
}
}
categorySelections: [{
name: "sponsor" as Category,
option: CategorySkipOption.AutoSkip
}, {
name: "poi_highlight" as Category,
option: CategorySkipOption.ManualSkip
}, {
name: "exclusive_access" as Category,
option: CategorySkipOption.ShowOverlay
}],
payments: {
licenseKey: null,
lastCheck: 0,
lastFreeCheck: 0,
freeAccess: false,
chaptersAllowed: false
},
colorPalette: {
red: "#780303",
white: "#ffffff",
locked: "#ffc83d"
},
// Preview bar
barTypes: {
"preview-chooseACategory": {
color: "#ffffff",
opacity: "0.7"
},
"sponsor": {
color: "#00d400",
opacity: "0.7"
},
"preview-sponsor": {
color: "#007800",
opacity: "0.7"
},
"selfpromo": {
color: "#ffff00",
opacity: "0.7"
},
"preview-selfpromo": {
color: "#bfbf35",
opacity: "0.7"
},
"exclusive_access": {
color: "#008a5c",
opacity: "0.7"
},
"interaction": {
color: "#cc00ff",
opacity: "0.7"
},
"preview-interaction": {
color: "#6c0087",
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"
},
"preview": {
color: "#008fd6",
opacity: "0.7"
},
"preview-preview": {
color: "#005799",
opacity: "0.7"
},
"music_offtopic": {
color: "#ff9900",
opacity: "0.7"
},
"preview-music_offtopic": {
color: "#a6634a",
opacity: "0.7"
},
"poi_highlight": {
color: "#ff1684",
opacity: "0.7"
},
"preview-poi_highlight": {
color: "#9b044c",
opacity: "0.7"
},
"filler": {
color: "#7300FF",
opacity: "0.9"
},
"preview-filler": {
color: "#2E0066",
opacity: "0.7"
}
}
};
for (const key in Config.localDefaults) {
if(!Object.prototype.hasOwnProperty.call(Config.cachedLocalStorage, key)) {
Config.cachedLocalStorage[key] = Config.localDefaults[key];
}
}
}
const localDefaults = {
downvotedSegments: {},
navigationApiAvailable: null
};
function resetToDefault() {
chrome.storage.sync.set({
...Config.syncDefaults,
userID: Config.config.userID,
minutesSaved: Config.config.minutesSaved,
skipCount: Config.config.skipCount,
sponsorTimesContributed: Config.config.sponsorTimesContributed
});
}
// Sync config
setupConfig();
export default Config;
const Config = new ConfigClass(syncDefaults, localDefaults, migrateOldSyncFormats);
export default Config;

File diff suppressed because it is too large Load Diff

View File

@@ -1,95 +1,3 @@
/*
Content script are run in an isolated DOM so it is not possible to access some key details that are sanitized when passed cross-dom
This script is used to get the details from the page and make them available for the content script by being injected directly into the page
*/
import { init } from "@ajayyy/maze-utils/lib/injected/document";
import { PageType } from "./types";
interface StartMessage {
type: "navigation";
pageType: PageType;
videoID: string | null;
}
interface FinishMessage extends StartMessage {
channelID: string;
channelTitle: string;
}
interface AdMessage {
type: "ad";
playing: boolean;
}
interface VideoData {
type: "data";
videoID: string;
isLive: boolean;
isPremiere: boolean;
}
type WindowMessage = StartMessage | FinishMessage | AdMessage | VideoData;
// global playerClient - too difficult to type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let playerClient: any;
let lastVideo = "";
const sendMessage = (message: WindowMessage): void => {
window.postMessage({ source: "sponsorblock", ...message }, "/");
}
function setupPlayerClient(e: CustomEvent): void {
if (playerClient) return; // early exit if already defined
playerClient = e.detail;
sendVideoData(); // send playerData after setup
e.detail.addEventListener('onAdStart', () => sendMessage({ type: "ad", playing: true } as AdMessage));
e.detail.addEventListener('onAdFinish', () => sendMessage({ type: "ad", playing: false } as AdMessage));
}
document.addEventListener("yt-player-updated", setupPlayerClient);
document.addEventListener("yt-navigate-start", navigationStartSend);
document.addEventListener("yt-navigate-finish", navigateFinishSend);
function navigationParser(event: CustomEvent): StartMessage {
const pageType: PageType = event.detail.pageType;
if (pageType) {
const result: StartMessage = { type: "navigation", pageType, videoID: null };
if (pageType === "shorts" || pageType === "watch") {
const endpoint = event.detail.endpoint
if (!endpoint) return null;
result.videoID = (pageType === "shorts" ? endpoint.reelWatchEndpoint : endpoint.watchEndpoint).videoId;
}
return result;
} else {
return null;
}
}
function navigationStartSend(event: CustomEvent): void {
const message = navigationParser(event) as StartMessage;
if (message) {
sendMessage(message);
}
}
function navigateFinishSend(event: CustomEvent): void {
sendVideoData(); // arrived at new video, send video data
const videoDetails = event.detail?.response?.playerResponse?.videoDetails;
if (videoDetails) {
sendMessage({ channelID: videoDetails.channelId, channelTitle: videoDetails.author, ...navigationParser(event) } as FinishMessage);
}
}
function sendVideoData(): void {
if (!playerClient) return;
const videoData = playerClient.getVideoData();
if (videoData && videoData.video_id !== lastVideo) {
lastVideo = videoData.video_id;
sendMessage({ type: "data", videoID: videoData.video_id, isLive: videoData.isLive, isPremiere: videoData.isPremiere } as VideoData);
}
}
init();

View File

@@ -2,14 +2,14 @@ import Config from "./config";
import { showDonationLink } from "./utils/configUtils";
import { localizeHtmlPage } from "./utils/pageUtils";
import { GenericUtils } from "./utils/genericUtils";
import { waitFor } from "@ajayyy/maze-utils";
window.addEventListener('DOMContentLoaded', init);
async function init() {
localizeHtmlPage();
await GenericUtils.wait(() => Config.config !== null);
await waitFor(() => Config.config !== null);
if (!Config.config.darkMode) {
document.documentElement.setAttribute("data-theme", "light");

View File

@@ -11,8 +11,8 @@ import { ActionType, Category, SegmentContainer, SponsorHideType, SponsorSourceT
import { partition } from "../utils/arrayUtils";
import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
import { normalizeChapterName } from "../utils/exporter";
import { GenericUtils } from "../utils/genericUtils";
import { findValidElement } from "../utils/pageUtils";
import { getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating";
import { findValidElement } from "@ajayyy/maze-utils/lib/dom";
const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible';
const MIN_CHAPTER_SIZE = 0.003;
@@ -140,7 +140,7 @@ class PreviewBar {
const tooltipText = tooltipTextElement.textContent;
if (tooltipText === null || tooltipText.length === 0) continue;
timeInSeconds = GenericUtils.getFormattedTimeToSeconds(tooltipText);
timeInSeconds = getFormattedTimeToSeconds(tooltipText);
if (timeInSeconds !== null) break;
}
@@ -314,7 +314,7 @@ class PreviewBar {
if (chapterChevron) {
if (this.segments.some((segment) => segment.source === SponsorSourceType.YouTube)) {
chapterChevron.style.removeProperty("display");
} else {
} else if (this.segments) {
chapterChevron.style.display = "none";
}
}
@@ -814,7 +814,16 @@ class PreviewBar {
chapterButton.disabled = false;
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;
chapterTitle.innerText = chosenSegment.description || shortCategoryName(chosenSegment.category);
chapterTitle.innerText = "";
const chapterCustomText = (chapterTitle.querySelector(".sponsorChapterText") || (() => {
const elem = document.createElement("div");
chapterTitle.appendChild(elem);
elem.classList.add("sponsorChapterText");
return elem;
})()) as HTMLDivElement;
chapterCustomText.innerText = chosenSegment.description || shortCategoryName(chosenSegment.category);
if (chosenSegment.actionType !== ActionType.Chapter) {
chapterTitle.classList.add("sponsorBlock-segment-title");
} else {
@@ -838,7 +847,13 @@ class PreviewBar {
this.chapterVote.setVisibility(false);
}
} else {
chaptersContainer.style.display = "none";
chaptersContainer.querySelector(".sponsorChapterText")?.remove();
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;
if (chapterTitle.innerText === "") {
chaptersContainer.style.display = "none";
} else {
chaptersContainer.style.removeProperty("display");
}
this.chapterVote.setVisibility(false);
}
}

View File

@@ -14,7 +14,8 @@ import UnsubmittedVideos from "./render/UnsubmittedVideos";
import KeybindComponent from "./components/options/KeybindComponent";
import { showDonationLink } from "./utils/configUtils";
import { localizeHtmlPage } from "./utils/pageUtils";
import { StorageChangesObject } from "./types";
import { StorageChangesObject } from "@ajayyy/maze-utils/lib/config";
import { getHash } from "@ajayyy/maze-utils/lib/hash";
const utils = new Utils();
let embed = false;
@@ -430,7 +431,7 @@ function invidiousInstanceAddInit(element: HTMLElement, option: string) {
let instanceList = Config.config[option];
if (!instanceList) instanceList = [];
instanceList.push(textBox.value);
instanceList.push(textBox.value.trim().toLowerCase());
Config.config[option] = instanceList;
@@ -532,7 +533,7 @@ function activatePrivateTextChange(element: HTMLElement) {
case "userID":
if (Config.config[option]) {
utils.asyncRequestToServer("GET", "/api/userInfo", {
publicUserID: utils.getHash(Config.config[option]),
publicUserID: getHash(Config.config[option]),
values: ["warnings", "banned"]
}).then((result) => {
const userInfo = JSON.parse(result.responseText);

View File

@@ -7,7 +7,6 @@ import {
SponsorHideType,
SponsorSourceType,
SponsorTime,
StorageChangesObject,
} from "./types";
import {
GetChannelIDResponse,
@@ -27,6 +26,9 @@ import { localizeHtmlPage } from "./utils/pageUtils";
import { exportTimes } from "./utils/exporter";
import GenericNotice from "./render/GenericNotice";
import { noRefreshFetchingChaptersAllowed } from "./utils/licenseKey";
import { getFormattedTime } from "@ajayyy/maze-utils/lib/formating";
import { StorageChangesObject } from "@ajayyy/maze-utils/lib/config";
import { getHash } from "@ajayyy/maze-utils/lib/hash";
const utils = new Utils();
@@ -230,7 +232,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
PageElements.optionsButton.addEventListener("click", openOptions);
PageElements.helpButton.addEventListener("click", openHelp);
PageElements.refreshSegmentsButton.addEventListener("click", refreshSegments);
PageElements.sbPopupIconCopyUserID.addEventListener("click", async () => copyToClipboard(await utils.getHash(Config.config.userID)));
PageElements.sbPopupIconCopyUserID.addEventListener("click", async () => copyToClipboard(await getHash(Config.config.userID)));
// Forward click events
if (window !== window.top) {
@@ -283,7 +285,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
if (!Config.config.payments.freeAccess && !noRefreshFetchingChaptersAllowed()) values.push("freeChaptersAccess");
utils.asyncRequestToServer("GET", "/api/userInfo", {
publicUserID: await utils.getHash(Config.config.userID),
publicUserID: await getHash(Config.config.userID),
values
}).then((res) => {
if (res.status === 200) {
@@ -593,9 +595,9 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
if (downloadedTimes[i].actionType === ActionType.Full) {
segmentTimeFromToNode.innerText = chrome.i18n.getMessage("full");
} else {
segmentTimeFromToNode.innerText = GenericUtils.getFormattedTime(downloadedTimes[i].segment[0], true) +
segmentTimeFromToNode.innerText = getFormattedTime(downloadedTimes[i].segment[0], true) +
(actionType !== ActionType.Poi
? " " + chrome.i18n.getMessage("to") + " " + GenericUtils.getFormattedTime(downloadedTimes[i].segment[1], true)
? " " + chrome.i18n.getMessage("to") + " " + getFormattedTime(downloadedTimes[i].segment[1], true)
: "");
}

View File

@@ -4,17 +4,23 @@ import CategoryPillComponent, { CategoryPillState } from "../components/Category
import Config from "../config";
import { VoteResponse } from "../messageTypes";
import { Category, SegmentUUID, SponsorTime } from "../types";
import { GenericUtils } from "../utils/genericUtils";
import { Tooltip } from "./Tooltip";
import { waitFor } from "@ajayyy/maze-utils";
import { getYouTubeTitleNode } from "@ajayyy/maze-utils/lib/elements";
const id = "categoryPill";
export class CategoryPill {
container: HTMLElement;
ref: React.RefObject<CategoryPillComponent>;
root: Root;
unsavedState: CategoryPillState;
lastState: CategoryPillState;
mutationObserver?: MutationObserver;
onMobileYouTube: boolean;
onInvidious: boolean;
vote: (type: number, UUID: SegmentUUID, category?: Category) => Promise<VoteResponse>;
constructor() {
this.ref = React.createRef();
@@ -22,45 +28,58 @@ export class CategoryPill {
async attachToPage(onMobileYouTube: boolean, onInvidious: boolean,
vote: (type: number, UUID: SegmentUUID, category?: Category) => Promise<VoteResponse>): Promise<void> {
this.onMobileYouTube = onMobileYouTube;
this.onInvidious = onInvidious;
this.vote = vote;
this.attachToPageInternal();
}
private async attachToPageInternal(): Promise<void> {
const referenceNode =
await GenericUtils.wait(() =>
// New YouTube Title, YouTube, Mobile YouTube, Invidious
document.querySelector("#title h1, .ytd-video-primary-info-renderer.title, .slim-video-information-title, #player-container + .h-box > h1") as HTMLElement);
await waitFor(() => getYouTubeTitleNode());
if (referenceNode && !referenceNode.contains(this.container)) {
this.container = document.createElement('span');
this.container.id = "categoryPill";
this.container.style.display = "relative";
if (!this.container) {
this.container = document.createElement('span');
this.container.id = id;
this.container.style.display = "relative";
referenceNode.prepend(this.container);
referenceNode.style.display = "flex";
this.root = createRoot(this.container);
this.ref = React.createRef();
this.root.render(<CategoryPillComponent ref={this.ref} vote={this.vote} />);
if (this.ref.current) {
this.unsavedState = this.ref.current.state;
}
this.root = createRoot(this.container);
this.root.render(<CategoryPillComponent ref={this.ref} vote={vote} />);
if (this.unsavedState) {
GenericUtils.wait(() => this.ref.current).then(() => {
this.ref.current?.setState(this.unsavedState);
this.unsavedState = null;
});
}
if (onMobileYouTube) {
if (this.mutationObserver) {
this.mutationObserver.disconnect();
if (this.onMobileYouTube) {
if (this.mutationObserver) {
this.mutationObserver.disconnect();
}
this.mutationObserver = new MutationObserver((changes) => {
if (changes.some((change) => change.removedNodes.length > 0)) {
this.attachToPageInternal();
}
});
this.mutationObserver.observe(referenceNode, {
childList: true,
subtree: true
});
}
this.mutationObserver = new MutationObserver(() => this.attachToPage(onMobileYouTube, onInvidious, vote));
}
this.mutationObserver.observe(referenceNode, {
childList: true,
subtree: true
if (this.lastState) {
waitFor(() => this.ref.current).then(() => {
this.ref.current?.setState(this.lastState);
});
}
// Use a parent because YouTube does weird things to the top level object
// react would have to rerender if container was the top level
const parent = document.createElement("span");
parent.appendChild(this.container);
referenceNode.prepend(parent);
referenceNode.style.display = "flex";
}
}
@@ -75,11 +94,8 @@ export class CategoryPill {
open: show ? this.ref.current?.state.open : false
};
if (this.ref.current) {
this.ref.current?.setState(newState);
} else {
this.unsavedState = newState;
}
this.ref.current?.setState(newState);
this.lastState = newState;
}
async setSegment(segment: SponsorTime): Promise<void> {
@@ -90,16 +106,13 @@ export class CategoryPill {
open: false
};
if (this.ref.current) {
this.ref.current?.setState(newState);
} else {
this.unsavedState = newState;
}
this.ref.current?.setState(newState);
this.lastState = newState;
if (!Config.config.categoryPillUpdate) {
Config.config.categoryPillUpdate = true;
const watchDiv = await GenericUtils.wait(() => document.querySelector("#info.ytd-watch-flexy") as HTMLElement);
const watchDiv = await waitFor(() => document.querySelector("#info.ytd-watch-flexy") as HTMLElement);
if (watchDiv) {
new Tooltip({
text: chrome.i18n.getMessage("categoryPillNewFeature"),
@@ -113,5 +126,9 @@ export class CategoryPill {
}
}
}
if (this.onMobileYouTube && !document.contains(this.container)) {
this.attachToPageInternal();
}
}
}

View File

@@ -26,14 +26,6 @@ export interface ContentContainer {
};
}
export interface FetchResponse {
responseText: string;
status: number;
ok: boolean;
}
export type HashedValue = string & { __hashBrand: unknown };
export interface VideoDurationResponse {
duration: number;
}
@@ -194,8 +186,6 @@ export interface VideoInfo {
export type VideoID = string;
export type StorageChangesObject = { [key: string]: chrome.storage.StorageChange };
export type UnEncodedSegmentTimes = [string, SponsorTime[]][];
export enum ChannelIDStatus {
@@ -239,15 +229,6 @@ export type Keybind = {
shift?: boolean;
}
export enum PageType {
Shorts = "shorts",
Watch = "watch",
Search = "search",
Browse = "browse",
Channel = "channel",
Embed = "embed"
}
export interface ButtonListener {
name: string;
listener: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;

View File

@@ -1,9 +1,12 @@
import Config, { VideoDownvotes } from "./config";
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration, HashedValue, VideoID, SponsorHideType } from "./types";
import { CategorySelection, SponsorTime, BackgroundScriptContainer, Registration, VideoID, SponsorHideType } from "./types";
import { getHash, HashedValue } from "@ajayyy/maze-utils/lib/hash";
import * as CompileConfig from "../config.json";
import { findValidElement, findValidElementFromSelector } from "./utils/pageUtils";
import { GenericUtils } from "./utils/genericUtils";
import { waitFor } from "@ajayyy/maze-utils";
import { isSafari } from "./utils/configUtils";
import { findValidElementFromSelector } from "@ajayyy/maze-utils/lib/dom";
import { FetchResponse, sendRequestToCustomServer } from "@ajayyy/maze-utils/lib/background-request-proxy"
export default class Utils {
@@ -18,88 +21,16 @@ export default class Utils {
css = [
"content.css",
"./libs/Source+Sans+Pro.css",
"popup.css"
"popup.css",
"shared.css"
];
/* Used for waitForElement */
creatingWaitingMutationObserver = false;
waitingMutationObserver: MutationObserver = null;
waitingElements: { selector: string; visibleCheck: boolean; callback: (element: Element) => void }[] = [];
constructor(backgroundScriptContainer: BackgroundScriptContainer = null) {
this.backgroundScriptContainer = backgroundScriptContainer;
}
async wait<T>(condition: () => T, timeout = 5000, check = 100): Promise<T> {
return GenericUtils.wait(condition, timeout, check);
}
/* Uses a mutation observer to wait asynchronously */
async waitForElement(selector: string, visibleCheck = false): Promise<Element> {
return await new Promise((resolve) => {
const initialElement = this.getElement(selector, visibleCheck);
if (initialElement) {
resolve(initialElement);
return;
}
this.waitingElements.push({
selector,
visibleCheck,
callback: resolve
});
if (!this.creatingWaitingMutationObserver) {
this.creatingWaitingMutationObserver = true;
if (document.body) {
this.setupWaitingMutationListener();
} else {
window.addEventListener("DOMContentLoaded", () => {
this.setupWaitingMutationListener();
});
}
}
});
}
private setupWaitingMutationListener(): void {
if (!this.waitingMutationObserver) {
const checkForObjects = () => {
const foundSelectors = [];
for (const { selector, visibleCheck, callback } of this.waitingElements) {
const element = this.getElement(selector, visibleCheck);
if (element) {
callback(element);
foundSelectors.push(selector);
}
}
this.waitingElements = this.waitingElements.filter((element) => !foundSelectors.includes(element.selector));
if (this.waitingElements.length === 0) {
this.waitingMutationObserver?.disconnect();
this.waitingMutationObserver = null;
this.creatingWaitingMutationObserver = false;
}
};
// Do an initial check over all objects
checkForObjects();
if (this.waitingElements.length > 0) {
this.waitingMutationObserver = new MutationObserver(checkForObjects);
this.waitingMutationObserver.observe(document.body, {
childList: true,
subtree: true
});
}
}
}
private getElement(selector: string, visibleCheck: boolean) {
return visibleCheck ? findValidElement(document.querySelectorAll(selector)) : document.querySelector(selector);
return waitFor(condition, timeout, check);
}
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
@@ -117,9 +48,9 @@ export default class Utils {
* @param {CallableFunction} callback
*/
setupExtraSitePermissions(callback: (granted: boolean) => void): void {
// Request permission
let permissions = ["declarativeContent"];
if (this.isFirefox()) permissions = [];
let permissions = ["webNavigation"];
if (!isSafari()) permissions.push("declarativeContent");
if (this.isFirefox() && !isSafari()) permissions = [];
chrome.permissions.request({
origins: this.getPermissionRegex(),
@@ -143,52 +74,28 @@ export default class Utils {
* For now, it is just SB.config.invidiousInstances.
*/
setupExtraSiteContentScripts(): void {
if (this.isFirefox()) {
const firefoxJS = [];
for (const file of this.js) {
firefoxJS.push({file});
}
const firefoxCSS = [];
for (const file of this.css) {
firefoxCSS.push({file});
}
const firefoxJS = [];
for (const file of this.js) {
firefoxJS.push({file});
}
const firefoxCSS = [];
for (const file of this.css) {
firefoxCSS.push({file});
}
const registration: Registration = {
message: "registerContentScript",
id: "invidious",
allFrames: true,
js: firefoxJS,
css: firefoxCSS,
matches: this.getPermissionRegex()
};
const registration: Registration = {
message: "registerContentScript",
id: "invidious",
allFrames: true,
js: firefoxJS,
css: firefoxCSS,
matches: this.getPermissionRegex()
};
if (this.backgroundScriptContainer) {
this.backgroundScriptContainer.registerFirefoxContentScript(registration);
} else {
chrome.runtime.sendMessage(registration);
}
if (this.backgroundScriptContainer) {
this.backgroundScriptContainer.registerFirefoxContentScript(registration);
} else {
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], () => {
const conditions = [];
for (const regex of this.getPermissionRegex()) {
conditions.push(new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlMatches: regex }
}));
}
// Add page rule
const rule = {
id: "invidious",
conditions,
actions: [new chrome.declarativeContent.RequestContentScript({
allFrames: true,
js: this.js,
css: this.css
})]
};
chrome.declarativeContent.onPageChanged.addRules([rule]);
});
chrome.runtime.sendMessage(registration);
}
}
@@ -196,18 +103,18 @@ export default class Utils {
* Removes the permission and content script registration.
*/
removeExtraSiteRegistration(): void {
if (this.isFirefox()) {
const id = "invidious";
const id = "invidious";
if (this.backgroundScriptContainer) {
this.backgroundScriptContainer.unregisterFirefoxContentScript(id);
} else {
chrome.runtime.sendMessage({
message: "unregisterContentScript",
id: id
});
}
} else if (chrome.declarativeContent) {
if (this.backgroundScriptContainer) {
this.backgroundScriptContainer.unregisterFirefoxContentScript(id);
} else {
chrome.runtime.sendMessage({
message: "unregisterContentScript",
id: id
});
}
if (!this.isFirefox() && chrome.declarativeContent) {
// Only if we have permission
chrome.declarativeContent.onPageChanged.removeRules(["invidious"]);
}
@@ -346,18 +253,8 @@ export default class Utils {
* @param address The address to add to the SponsorBlock server address
* @param callback
*/
async asyncRequestToCustomServer(type: string, url: string, data = {}): Promise<FetchResponse> {
return new Promise((resolve) => {
// Ask the background script to do the work
chrome.runtime.sendMessage({
message: "sendRequest",
type,
url,
data
}, (response) => {
resolve(response);
});
});
asyncRequestToCustomServer(type: string, url: string, data = {}): Promise<FetchResponse> {
return sendRequestToCustomServer(type, url, data);
}
/**
@@ -401,14 +298,15 @@ export default class Utils {
"#player-container", // Preview on hover
"#main-panel.ytmusic-player-page", // YouTube music
"#player-container .video-js", // Invidious
".main-video-section > .video-container" // Cloudtube
".main-video-section > .video-container", // Cloudtube
".shaka-video-container" // Piped
];
let referenceNode = findValidElementFromSelector(selectors)
if (referenceNode == null) {
//for embeds
const player = document.getElementById("player");
referenceNode = player.firstChild as HTMLElement;
referenceNode = player?.firstChild as HTMLElement;
if (referenceNode) {
let index = 1;
@@ -439,25 +337,11 @@ export default class Utils {
return typeof(browser) !== "undefined";
}
async getHash<T extends string>(value: T, times = 5000): Promise<T & HashedValue> {
if (times <= 0) return "" as T & HashedValue;
let hashHex: string = value;
for (let i = 0; i < times; i++) {
const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(hashHex).buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
return hashHex as T & HashedValue;
}
async addHiddenSegment(videoID: VideoID, segmentUUID: string, hidden: SponsorHideType) {
if (chrome.extension.inIncognitoContext || !Config.config.trackDownvotes) return;
const hashedVideoID = (await this.getHash(videoID, 1)).slice(0, 4) as VideoID & HashedValue;
const UUIDHash = await this.getHash(segmentUUID, 1);
const hashedVideoID = (await getHash(videoID, 1)).slice(0, 4) as VideoID & HashedValue;
const UUIDHash = await getHash(segmentUUID, 1);
const allDownvotes = Config.local.downvotedSegments;
const currentVideoData = allDownvotes[hashedVideoID] || { segments: [], lastAccess: 0 };
@@ -465,7 +349,11 @@ export default class Utils {
currentVideoData.lastAccess = Date.now();
const existingData = currentVideoData.segments.find((segment) => segment.uuid === UUIDHash);
if (hidden === SponsorHideType.Visible) {
delete allDownvotes[hashedVideoID];
currentVideoData.segments.splice(currentVideoData.segments.indexOf(existingData), 1);
if (currentVideoData.segments.length === 0) {
delete allDownvotes[hashedVideoID];
}
} else {
if (existingData) {
existingData.hidden = hidden;

View File

@@ -6,7 +6,7 @@ export function showDonationLink(): boolean {
}
export function isSafari(): boolean {
return navigator.vendor === "Apple Computer, Inc.";
return typeof(navigator) !== "undefined" && navigator.vendor === "Apple Computer, Inc.";
}
export function keybindEquals(first: Keybind, second: Keybind): boolean {

View File

@@ -1,7 +1,8 @@
import { ActionType, Category, SegmentUUID, SponsorSourceType, SponsorTime } from "../types";
import { shortCategoryName } from "./categoryUtils";
import { GenericUtils } from "./genericUtils";
import * as CompileConfig from "../../config.json";
import { getFormattedTime, getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating";
import { generateUserID } from "@ajayyy/maze-utils/lib/setup";
const inTest = typeof chrome === "undefined";
@@ -26,9 +27,9 @@ export function exportTimes(segments: SponsorTime[]): string {
function exportTime(segment: SponsorTime): string {
const name = segment.description || shortCategoryName(segment.category);
return `${GenericUtils.getFormattedTime(segment.segment[0], true)}${
return `${getFormattedTime(segment.segment[0], true)}${
segment.segment[1] && segment.segment[0] !== segment.segment[1]
? ` - ${GenericUtils.getFormattedTime(segment.segment[1], true)}` : ""} ${name}`;
? ` - ${getFormattedTime(segment.segment[1], true)}` : ""} ${name}`;
}
export function importTimes(data: string, videoDuration: number): SponsorTime[] {
@@ -37,26 +38,31 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[]
for (const line of lines) {
const match = line.match(/(?:((?:\d+:)?\d+:\d+)+(?:\.\d+)?)|(?:\d+(?=s| second))/g);
if (match) {
const startTime = GenericUtils.getFormattedTimeToSeconds(match[0]);
const startTime = getFormattedTimeToSeconds(match[0]);
if (startTime !== null) {
// Remove "seconds", "at", special characters, and ")" if there was a "("
const specialCharsMatcher = /^(?:\s+seconds?)?[-:()\s]*|(?:\s+at)?[-:(\s]+$|(?<=^\s*\(.+)[-:()\s]*$/g
const titleLeft = line.split(match[0])[0].replace(specialCharsMatcher, "");
const specialCharMatchers = [{
matcher: /^(?:\s+seconds?)?[-:()\s]*|(?:\s+at)?[-:(\s]+$/g
}, {
matcher: /[-:()\s]*$/g,
condition: (value) => !!value.match(/^\s*\(/)
}];
const titleLeft = removeIf(line.split(match[0])[0], specialCharMatchers);
let titleRight = null;
const split2 = line.split(match[1] || match[0]);
titleRight = split2[split2.length - 1].replace(specialCharsMatcher, "");
titleRight = removeIf(split2[split2.length - 1], specialCharMatchers)
const title = titleLeft?.length > titleRight?.length ? titleLeft : titleRight;
if (title) {
const determinedCategory = chapterNames.find(c => c.names.includes(title))?.code as Category;
const segment: SponsorTime = {
segment: [startTime, GenericUtils.getFormattedTimeToSeconds(match[1])],
segment: [startTime, getFormattedTimeToSeconds(match[1])],
category: determinedCategory ?? ("chapter" as Category),
actionType: determinedCategory ? ActionType.Skip : ActionType.Chapter,
description: title,
source: SponsorSourceType.Local,
UUID: GenericUtils.generateUserID() as SegmentUUID
UUID: generateUserID() as SegmentUUID
};
if (result.length > 0 && result[result.length - 1].segment[1] === null) {
@@ -76,6 +82,17 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[]
return result;
}
function removeIf(value: string, matchers: Array<{ matcher: RegExp; condition?: (value: string) => boolean }>): string {
let result = value;
for (const matcher of matchers) {
if (!matcher.condition || matcher.condition(value)) {
result = result.replace(matcher.matcher, "");
}
}
return result;
}
export function exportTimesAsHashParam(segments: SponsorTime[]): string {
const hashparamSegments = segments.map(segment => ({
actionType: segment.actionType,

View File

@@ -1,70 +1,3 @@
/** Function that can be used to wait for a condition before returning. */
async function wait<T>(condition: () => T, timeout = 5000, check = 100, predicate?: (obj: T) => boolean): Promise<T> {
return await new Promise((resolve, reject) => {
setTimeout(() => {
clearInterval(interval);
reject("TIMEOUT");
}, timeout);
const intervalCheck = () => {
const result = condition();
if (predicate ? predicate(result) : result) {
resolve(result);
clearInterval(interval);
}
};
const interval = setInterval(intervalCheck, check);
//run the check once first, this speeds it up a lot
intervalCheck();
});
}
function getFormattedTimeToSeconds(formatted: string): number | null {
const fragments = /^(?:(?:(\d+):)?(\d+):)?(\d*(?:[.,]\d+)?)$/.exec(formatted);
if (fragments === null) {
return null;
}
const hours = fragments[1] ? parseInt(fragments[1]) : 0;
const minutes = fragments[2] ? parseInt(fragments[2] || '0') : 0;
const seconds = fragments[3] ? parseFloat(fragments[3].replace(',', '.')) : 0;
return hours * 3600 + minutes * 60 + seconds;
}
function getFormattedTime(seconds: number, precise?: boolean): string {
seconds = Math.max(seconds, 0);
const hours = Math.floor(seconds / 60 / 60);
const minutes = Math.floor(seconds / 60) % 60;
let minutesDisplay = String(minutes);
let secondsNum = seconds % 60;
if (!precise) {
secondsNum = Math.floor(secondsNum);
}
let secondsDisplay = String(precise ? secondsNum.toFixed(3) : secondsNum);
if (secondsNum < 10) {
//add a zero
secondsDisplay = "0" + secondsDisplay;
}
if (hours && minutes < 10) {
//add a zero
minutesDisplay = "0" + minutesDisplay;
}
if (isNaN(hours) || isNaN(minutes)) {
return null;
}
const formatted = (hours ? hours + ":" : "") + minutesDisplay + ":" + secondsDisplay;
return formatted;
}
/**
* Gets the error message in a nice string
*
@@ -116,44 +49,8 @@ function indexesOf<T>(array: T[], value: T): number[] {
return array.map((v, i) => v === value ? i : -1).filter(i => i !== -1);
}
function objectToURI<T>(url: string, data: T, includeQuestionMark: boolean): string {
let counter = 0;
for (const key in data) {
const seperator = (url.includes("?") || counter > 0) ? "&" : (includeQuestionMark ? "?" : "");
const value = (typeof(data[key]) === "string") ? data[key] as unknown as string : JSON.stringify(data[key]);
url += seperator + encodeURIComponent(key) + "=" + encodeURIComponent(value);
counter++;
}
return url;
}
function generateUserID(length = 36): string {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
if (window.crypto && window.crypto.getRandomValues) {
const values = new Uint32Array(length);
window.crypto.getRandomValues(values);
for (let i = 0; i < length; i++) {
result += charset[values[i] % charset.length];
}
return result;
} else {
for (let i = 0; i < length; i++) {
result += charset[Math.floor(Math.random() * charset.length)];
}
return result;
}
}
export const GenericUtils = {
wait,
getFormattedTime,
getFormattedTimeToSeconds,
getErrorMessage,
getLuminance,
generateUserID,
indexesOf,
objectToURI
indexesOf
}

View File

@@ -1,6 +1,7 @@
import Config from "../config";
import Utils from "../utils";
import * as CompileConfig from "../../config.json";
import { getHash } from "@ajayyy/maze-utils/lib/hash";
const utils = new Utils();
@@ -53,7 +54,7 @@ export async function fetchingChaptersAllowed(): Promise<boolean> {
// Check for free access if no license key, and it is the first time
const result = await utils.asyncRequestToServer("GET", "/api/userInfo", {
value: "freeChaptersAccess",
publicUserID: await utils.getHash(Config.config.userID)
publicUserID: await getHash(Config.config.userID)
});
try {

View File

@@ -1,5 +1,5 @@
import { ActionType, Category, SponsorSourceType, SponsorTime, VideoID } from "../types";
import { GenericUtils } from "./genericUtils";
import { getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating";
export function getControls(): HTMLElement {
const controlsSelectors = [
@@ -9,6 +9,8 @@ export function getControls(): HTMLElement {
".player-controls-top",
// Invidious/videojs video element's controls element
".vjs-control-bar",
// Piped shaka player
".shaka-bottom-controls"
];
for (const controlsSelector of controlsSelectors) {
@@ -26,25 +28,6 @@ export function isVisible(element: HTMLElement): boolean {
return element && element.offsetWidth > 0 && element.offsetHeight > 0;
}
export function findValidElementFromSelector(selectors: string[]): HTMLElement {
return findValidElementFromGenerator(selectors, (selector) => document.querySelector(selector));
}
export function findValidElement(elements: HTMLElement[] | NodeListOf<HTMLElement>): HTMLElement {
return findValidElementFromGenerator(elements);
}
function findValidElementFromGenerator<T>(objects: T[] | NodeListOf<HTMLElement>, generator?: (obj: T) => HTMLElement): HTMLElement {
for (const obj of objects) {
const element = generator ? generator(obj as T) : obj as HTMLElement;
if (element && isVisible(element)) {
return element;
}
}
return null;
}
export function getHashParams(): Record<string, unknown> {
const windowHash = window.location.hash.slice(1);
if (windowHash) {
@@ -80,7 +63,7 @@ export function getExistingChapters(currentVideoID: VideoID, duration: number):
const timeElement = link.querySelector("#time") as HTMLElement;
const description = link.querySelector("#details h4") as HTMLElement;
if (timeElement && description?.innerText?.length > 0 && link.getAttribute("href")?.includes(currentVideoID)) {
const time = GenericUtils.getFormattedTimeToSeconds(timeElement.innerText);
const time = getFormattedTimeToSeconds(timeElement.innerText.replace(".", ":"));
if (time === null) return [];
if (lastSegment) {

View File

@@ -1,8 +1,9 @@
import { objectToURI } from "@ajayyy/maze-utils";
import { getHash } from "@ajayyy/maze-utils/lib/hash";
import Config from "../config";
import GenericNotice, { NoticeOptions } from "../render/GenericNotice";
import { ContentContainer } from "../types";
import Utils from "../utils";
import { GenericUtils } from "./genericUtils";
const utils = new Utils();
export interface ChatConfig {
@@ -13,7 +14,7 @@ export interface ChatConfig {
export async function openWarningDialog(contentContainer: ContentContainer): Promise<void> {
const userInfo = await utils.asyncRequestToServer("GET", "/api/userInfo", {
publicUserID: await utils.getHash(Config.config.userID),
publicUserID: await getHash(Config.config.userID),
values: ["warningReason"]
});
@@ -21,7 +22,7 @@ export async function openWarningDialog(contentContainer: ContentContainer): Pro
const warningReason = JSON.parse(userInfo.responseText)?.warningReason;
const userNameData = await utils.asyncRequestToServer("GET", "/api/getUsername?userID=" + Config.config.userID);
const userName = userNameData.ok ? JSON.parse(userNameData.responseText).userName : "";
const publicUserID = await utils.getHash(Config.config.userID);
const publicUserID = await getHash(Config.config.userID);
let notice: GenericNotice = null;
const options: NoticeOptions = {
@@ -62,5 +63,5 @@ export async function openWarningDialog(contentContainer: ContentContainer): Pro
}
export function openChat(config: ChatConfig): void {
window.open("https://chat.sponsor.ajay.app/#" + GenericUtils.objectToURI("", config, false));
window.open("https://chat.sponsor.ajay.app/#" + objectToURI("", config, false));
}

View File

@@ -41,7 +41,7 @@ test("Selenium Chrome test", async () => {
// Save file incase there is a layout change
const source = await driver.getPageSource();
fs.mkdirSync("./test-results");
if (!fs.existsSync("./test-results")) fs.mkdirSync("./test-results");
fs.writeFileSync("./test-results/source.html", source);
throw e;
@@ -55,7 +55,7 @@ async function setup(): Promise<WebDriver> {
options.addArguments("--load-extension=" + Path.join(__dirname, "../dist/"));
options.addArguments("--mute-audio");
options.addArguments("--disable-features=PreloadMediaEngagementData, MediaEngagementBypassAutoplayPolicies");
options.addArguments("--headless=chrome");
options.addArguments("--headless=new");
options.addArguments("--window-size=1920,1080");
const driver = await new Builder().forBrowser("chrome").setChromeOptions(options).build();

View File

@@ -3,7 +3,6 @@
const webpack = require("webpack");
const path = require('path');
const { validate } = require('schema-utils');
const fs = require('fs');
const manifest = require("../manifest/manifest.json");