mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-15 16:07:06 +03:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1676e50e15 | ||
|
|
f165b3b602 | ||
|
|
0f82c16940 | ||
|
|
9ef3ef03a4 | ||
|
|
ef17cae9a1 | ||
|
|
05acb1669e | ||
|
|
0850421afb | ||
|
|
edf06ac908 | ||
|
|
842d35235a | ||
|
|
45d20574d9 | ||
|
|
252da8c56a | ||
|
|
99373c3e55 | ||
|
|
dce69b3642 | ||
|
|
bb670b93e9 | ||
|
|
c011ad105d | ||
|
|
856125f7fd | ||
|
|
178b122ab8 | ||
|
|
7b0488d068 | ||
|
|
02a9238869 | ||
|
|
2fb97409a1 | ||
|
|
3640463112 | ||
|
|
d872ed642d | ||
|
|
1ab1f33caf | ||
|
|
ba13f5951e | ||
|
|
f66e8ddf92 | ||
|
|
cff72b19c7 | ||
|
|
c046df7d18 | ||
|
|
941bd41cdb | ||
|
|
dd5ed6ce42 | ||
|
|
3a0d5221f6 | ||
|
|
a72f571bd4 | ||
|
|
50c9c9fe8a | ||
|
|
7f8badb34d | ||
|
|
f9d8daeca0 | ||
|
|
55070d5852 | ||
|
|
789bd5939b | ||
|
|
b591fbfc4b | ||
|
|
57eb122fce | ||
|
|
aec287f0cf | ||
|
|
c68aabaa40 |
76
.github/workflows/release.yml
vendored
76
.github/workflows/release.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
- run: npm install
|
||||
- name: Copy configuration
|
||||
run: cp config.json.example config.json
|
||||
|
||||
|
||||
# Create Chrome artifacts
|
||||
- name: Create Chrome artifacts
|
||||
run: npm run build:chrome
|
||||
@@ -26,9 +26,8 @@ jobs:
|
||||
name: ChromeExtension
|
||||
path: dist
|
||||
- run: mkdir ./builds
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtension.zip ./dist/*
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist ; zip -r ../builds/ChromeExtension.zip *
|
||||
|
||||
# Create Firefox artifacts
|
||||
- name: Create Firefox artifacts
|
||||
@@ -37,9 +36,8 @@ jobs:
|
||||
with:
|
||||
name: FirefoxExtension
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtension.zip ./dist/*
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist ; zip -r ../builds/FirefoxExtension.zip *
|
||||
|
||||
# Create Beta artifacts (Builds with the name changed to beta)
|
||||
- name: Create Chrome Beta artifacts
|
||||
@@ -48,19 +46,41 @@ jobs:
|
||||
with:
|
||||
name: ChromeExtensionBeta
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtensionBeta.zip ./dist/*
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist ; zip -r ../builds/ChromeExtensionBeta.zip *
|
||||
|
||||
# Upload each release asset
|
||||
- name: Upload ChromeExtension to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtension.zip
|
||||
name: ChromeExtension.zip
|
||||
path: ./builds/ChromeExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload ChromeExtensionBeta to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtensionBeta.zip
|
||||
name: ChromeExtensionBeta.zip
|
||||
path: ./builds/ChromeExtensionBeta.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload FirefoxExtension to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/FirefoxExtension.zip
|
||||
name: FirefoxExtension.zip
|
||||
path: ./builds/FirefoxExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Firefox Beta
|
||||
- name: Create Firefox Beta artifacts
|
||||
run: npm run build:firefox -- --env.stream=beta
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtensionBeta
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtensionBeta.zip ./dist/*
|
||||
- name: Zip Artifacts
|
||||
run: cd ./dist ; zip -r ../builds/FirefoxExtensionBeta.zip *
|
||||
|
||||
# Create Firefox Signed Beta version
|
||||
- name: Create Firefox Signed Beta artifacts
|
||||
@@ -70,38 +90,14 @@ jobs:
|
||||
WEB_EXT_API_SECRET: ${{ secrets.WEB_EXT_API_SECRET }}
|
||||
- name: Install rename
|
||||
run: sudo apt-get install rename
|
||||
- name: Install signed file
|
||||
run: cd ./web-ext-artifacts
|
||||
- run: rename 's/.*/FirefoxSignedInstaller.xpi/' *
|
||||
- run: cd ..
|
||||
- name: Rename signed file
|
||||
run: cd ./web-ext-artifacts ; rename 's/.*/FirefoxSignedInstaller.xpi/' *
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtensionSigned.xpi
|
||||
path: ./web-ext-artifacts/FirefoxSignedInstaller.xpi
|
||||
|
||||
# Upload each release asset
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtension.zip
|
||||
name: ChromeExtension.zip
|
||||
path: ./builds/ChromeExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtensionBeta.zip
|
||||
name: ChromeExtensionBeta.zip
|
||||
path: ./builds/ChromeExtensionBeta.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/FirefoxExtension.zip
|
||||
name: FirefoxExtension.zip
|
||||
path: ./builds/FirefoxExtension.zip
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
- name: Upload FirefoxSignedInstaller.xpi to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: web-ext-artifacts/FirefoxSignedInstaller.xpi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"serverAddress": "https://sponsor.ajay.app",
|
||||
"testingServerAddress": "https://sponsor.ajay.app/test",
|
||||
"serverAddressComment": "This specifies the default SponsorBlock server to conect to",
|
||||
"serverAddressComment": "This specifies the default SponsorBlock server to connect to",
|
||||
"categoryList": ["sponsor", "intro", "outro", "interaction", "selfpromo", "music_offtopic"]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "__MSG_Name__",
|
||||
"version": "1.2.28.1",
|
||||
"version": "1.2.29",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"content_scripts": [{
|
||||
@@ -30,6 +30,8 @@
|
||||
"icons/PlayerUploadFailedIconSponsorBlocker256px.png",
|
||||
"icons/upvote.png",
|
||||
"icons/downvote.png",
|
||||
"icons/thumbs_down.svg",
|
||||
"icons/thumbs_up.svg",
|
||||
"icons/report.png",
|
||||
"icons/close.png",
|
||||
"icons/beep.ogg",
|
||||
|
||||
3171
package-lock.json
generated
3171
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"web-ext": "^4.0.0",
|
||||
"web-ext": "^4.2.0",
|
||||
"@types/chrome": "0.0.91",
|
||||
"@types/firefox-webext-browser": "70.0.1",
|
||||
"@types/jest": "^24.0.23",
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"web-run": "npm run web-run:chrome",
|
||||
"web-sign": "web-ext sign -s dist",
|
||||
"web-sign": "web-ext sign -s dist --id sponsorBlockerBETA@ajay.app",
|
||||
"web-run:firefox": "cd dist && web-ext run --start-url https://addons.mozilla.org/firefox/addon/ublock-origin/",
|
||||
"web-run:chrome": "cd dist && web-ext run --start-url https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm -t chromium",
|
||||
"build": "npm run build:chrome",
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
"Segments": {
|
||||
"message": "sponsor segments"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsor Skipped"
|
||||
"upvoteButtonInfo": {
|
||||
"message": "Upvote this submission"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Report"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Report this sponsor submission as incorrect."
|
||||
"message": "Report this submission as incorrect."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Dismiss"
|
||||
@@ -71,6 +71,9 @@
|
||||
"paused": {
|
||||
"message": "Paused"
|
||||
},
|
||||
"manualPaused": {
|
||||
"message": "Timer Stopped"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "To edit or delete individual values, click the info button or open the extension popup by clicking the extension icon in the top right corner."
|
||||
},
|
||||
@@ -105,7 +108,7 @@
|
||||
"message": "You have already voted this way before."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "It seems the sever is down. Contact the dev immediately."
|
||||
"message": "It seems the server is down. Contact the dev immediately."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "A connection error has occured. Error code: "
|
||||
@@ -272,12 +275,12 @@
|
||||
"errorCode": {
|
||||
"message": "Error Code: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Skip Sponsor?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Skip"
|
||||
},
|
||||
"skipped": {
|
||||
"message": "Skipped"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Disable Auto Skip"
|
||||
},
|
||||
@@ -377,12 +380,6 @@
|
||||
"currentInstances": {
|
||||
"message": "Current Instances:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto Upvote"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "With this enabled, the extension will upvote all submissions you view if you do not report them. If the notice is disabled, this will not occur."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimum duration (seconds):"
|
||||
},
|
||||
@@ -559,12 +556,15 @@
|
||||
"message": "Consider Enabling Force Channel Check Before Skipping Sponsors"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Incorrect"
|
||||
"message": "Incorrect/Wrong Timing"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "Wrong Category"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "This video is categorized as music. Are you sure you would like to submit segments with non-music categories? Unless this video is not actually music, you should not be submitting this segment. Please read the guidelines if you are confused."
|
||||
},
|
||||
"multipleSegments": {
|
||||
"message": "Multiple Segments"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock para YouTube - Pule patrocínios",
|
||||
"description": "Name of the extension."
|
||||
@@ -149,22 +153,22 @@
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
"message": "Clique no botão abaixo quando o patrocínio começar e quando terminar para registrar e submetê-lo à base de dados."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
"message": "Dica: Aperte a tecla ; enquanto reproduzir o vídeo para registar o começo/fim de um patrocínio e \" para enviar. (Essa configuração pode ser mudada em opções.)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
"message": "Últimos Intervalos de Patrocínios Seleciados"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Submeter Intervalos"
|
||||
"message": "Enviar Intervalos"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Isto é usado na página pública de estatísticas que mostra o quanto já contríbuíu. Veje-a"
|
||||
"message": "Isso é usado na página pública de estatísticas que mostra o quanto você já contríbuíu. Veja-a"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Criar nomde de utilizador"
|
||||
@@ -228,5 +232,339 @@
|
||||
"sourceCode": {
|
||||
"message": "Código fonte",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "A notificação foi atualizada!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Se você ainda não gostar dessa, aperte o botão não mostrar novamente.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Defina a tecla para que marca o início do patrocínio"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Defina a tecla para enviar o segmento de patrocínio"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Selecione uma tecla apertando-a"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "A tecla foi definida para: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Tempo limite de conexão excedida. Cheque a sua conexão de internet. Se a sua internet estiver funcionando, o servidor está sobrecarregado ou fora do ar."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Desativar SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Ativar SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Suas submissões",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "O servidor parece estar sobrecarregado. Tente novamente em alguns segundos."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Código de erro: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Pular patrocinador?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Pular"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Desativar Salto Automático"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Ativar Salto Automático"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Pular automaticamente irá pular patrocínios por você. Se desabilitado, um aviso irá aparecer perguntando se deseja pular o anúncio."
|
||||
},
|
||||
"audioNotification": {
|
||||
"message": "Notificação de áudio ao pular"
|
||||
},
|
||||
"audioNotificationDescription": {
|
||||
"message": "A notificação de áudio ao pular irá tocar um som sempre que um patrocínio for ignorado. Se desativado (ou o pulo automático estiver desativado), nenhum som será reproduzido."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Você pulou "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Você poupou "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuto"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minutos"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "hora"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "horas"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Você poupou outros"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " de suas vidas."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Certifique-se de que seu segmento contém apenas patrocínio, nada mais.\n- Certifique-se de que pular esse segmento não vai pular conteúdo importante.\n- Se todo o vídeo for patrocinado, por favor não o denuncie. Um sistema completo de relatório de vídeo virá em breve.\n- Por favor, não denuncie avisos de parcialidade do vídeo (se um vídeo de avaliação for patrocinado, não pule quando eles mencionarem que é patrocinado)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Verifique status.sponsor.ajay.app para o status do servidor."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Importar/Exportar seu ID de usuário"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Isso deve ser mantido em segredo. É como se fosse uma senha e não deve ser compartilhado com ninguém. Se alguém tiver isso, poderá se passar por você."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Definir ID de usuário"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Atenção: A alteração do ID de usuário é permanente. Você tem certeza que deseja fazer isso? Certifique-se de fazer backup de seu ID antigo por precaução."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Criado por"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Pular automaticamente"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Mostrar aviso após um patrocínio ser ignorado"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Atualmente, está definido para:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Apoiar Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) é um cliente para YouTube de terceiros. Para ativar o apoio, você precisa aceitar as permissões adicionais. Isso não funciona em modo anônimo no Chrome ou em outras variantes do Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Ativar apoio ao Invidious, desabilitar pular automaticamente, ocultar botões e mais."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Adicionar instância do Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Adicionar uma instância personalizada do Invidious. Deve ser formatado com APENAS o domínio. Exemplo: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Adicionar"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Este é um domínio inválido. Ele deve incluir APENAS a parte do domínio. Exemplo: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Redefinir Lista de Instâncias do Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Você está prestes a redefinir a lista de instâncias do Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Instâncias Atuais:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Upvote automático"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Com isto habilitado, a extensão dará upvote em todas as submissões que você ver se você não reportar. Não funcionará se o aviso estiver desativado."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Duração mínima (segundos):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Segmentos de patrocinadores menores do que o valor definido não serão pulados ou mostrados no reprodutor."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "A seguinte submissão é mais curta do que sua opção de duração mínima. Isto significa que já foi enviada e que está sendo ignorada devido a esta opção. Tem certeza que deseja enviar mesmo assim?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Mostrar botão de envio"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Este botão aparece no reprodutor do YouTube depois de ter selecionado um carimbo de data/hora e está pronto para ser enviado."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "Endereço do servidor do SponsorBlock"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Endereço que o SponsorBlock usa para fazer chamadas ao servidor.\nA menos que você tenha sua própria instância de servidor, isso não deve ser alterado."
|
||||
},
|
||||
"save": {
|
||||
"message": "Salvar"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Redefinir"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Este endereço não está na forma correta. Certifique-se de que possui http:// ou https:// no início e sem barras no final."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Tem certeza que deseja redefinir?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "O este vídeo está marcado como não listado. Clique em cancelar se você não deseja verificar se há patrocínios."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignorar vídeos não listados/privados"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Esta configuração irá diminuir um pouco o desempenho do SponsorBlock. As pesquisas do patrocinador exigem que se envie o ID do vídeo para o servidor. Se você estiver preocupado com o envio de IDs de vídeo não listados pela internet, habilite essa opção."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com agora é suportado"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Importar/Exportar Todas as Opções"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "Essa suas preferências em JSON. Isso inclui seu ID de usuário, então lembre-se de compartilhar com cuidado."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Definir Opções"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Aviso: Alterar as opções é permanente e pode fazer a extensão parar de funcionar. Tem certeza que deseja fazer isso? Certifique-se de fazer um backup de seu antigo por precaução."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "Este JSON não está formatado corretamente. Suas opções não foram alteradas."
|
||||
},
|
||||
"confirmNoticeTitle": {
|
||||
"message": "Enviar Segmento"
|
||||
},
|
||||
"submit": {
|
||||
"message": "Enviar"
|
||||
},
|
||||
"cancel": {
|
||||
"message": "Cancelar"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Deletar"
|
||||
},
|
||||
"preview": {
|
||||
"message": "Pré-visualizar"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Editar"
|
||||
},
|
||||
"copyDebugInformation": {
|
||||
"message": "Copiar Informações de Depuração Para Área de Transferência"
|
||||
},
|
||||
"copyDebugInformationFailed": {
|
||||
"message": "Erro ao copiar para a área de transferência"
|
||||
},
|
||||
"copyDebugInformationOptions": {
|
||||
"message": "Copia informações para a área de transferência para serem fornecidas a um desenvolvedor quando houver um bug / quando um solicitado pelo desenvolvedor. Informações sensíveis como seu ID de usuário, canais na lista de permissões e endereço personalizado do servidor foram removidos. No entanto, ele contém informações como seu useragent, navegador, sistema operacional e número de versão de extensão. "
|
||||
},
|
||||
"copyDebugInformationComplete": {
|
||||
"message": "A informação de depuração foi copiada para a área de transferência. Sinta-se à vontade para remover qualquer informação que prefira não compartilhar. Salve em um arquivo de texto ou cole-a no relatório de bug."
|
||||
},
|
||||
"theKey": {
|
||||
"message": "A tecla"
|
||||
},
|
||||
"keyAlreadyUsedByYouTube": {
|
||||
"message": "já está sendo usado pelo youtube. Por favor, selecione outra tecla."
|
||||
},
|
||||
"keyAlreadyUsed": {
|
||||
"message": "está vinculado a outra ação. Por favor, selecione outra tecla."
|
||||
},
|
||||
"to": {
|
||||
"message": "até",
|
||||
"description": "Used between sponsor times. Example: 1:20 to 1:30"
|
||||
},
|
||||
"category_sponsor": {
|
||||
"message": "Patrocinador"
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "Animação de Introdução"
|
||||
},
|
||||
"category_outro": {
|
||||
"message": "Finalização/Créditos"
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "Lembrete de interação (inscrever-se)"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "Auto-Promoção e Mercadorias"
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "Música: Seção sem música"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "Livestream: Leituras de Doação/Mensagem"
|
||||
},
|
||||
"disable": {
|
||||
"message": "Desativar"
|
||||
},
|
||||
"manualSkip": {
|
||||
"message": "Pular manualmente"
|
||||
},
|
||||
"showOverlay": {
|
||||
"message": "Mostrar barra de progresso"
|
||||
},
|
||||
"enableTestingServer": {
|
||||
"message": "Habilitar Servidor em teste Beta"
|
||||
},
|
||||
"whatEnableTestingServer": {
|
||||
"message": "Seus envios e votos NÃO SERÃO ENVIADOS para o servidor principal. Use isso apenas para testes."
|
||||
},
|
||||
"testingServerWarning": {
|
||||
"message": "Todas os envios e votos NÃO SERÃO ENVIADOS para o servidor principal enquanto se conecta ao servidor de teste. Certifique-se de desativar isso quando você quiser fazer envios reais."
|
||||
},
|
||||
"bracketNow": {
|
||||
"message": "(agora)"
|
||||
},
|
||||
"moreCategories": {
|
||||
"message": "Mais categorias"
|
||||
},
|
||||
"bracketEnd": {
|
||||
"message": "(Fim)"
|
||||
},
|
||||
"hiddenDueToDownvote": {
|
||||
"message": "oculto: Downvote"
|
||||
},
|
||||
"hiddenDueToDuration": {
|
||||
"message": "oculto: muito curto"
|
||||
},
|
||||
"channelDataNotFound": {
|
||||
"message": "ID do canal ainda não carregado."
|
||||
},
|
||||
"adblockerIssue": {
|
||||
"message": "Parece que algo está bloqueando o SponsorBlock de obter dados de vídeo. Isso é provavelmente o seu bloqueador de anúncios. Por favor, verifique https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock-Requests"
|
||||
},
|
||||
"itCouldBeAdblockerIssue": {
|
||||
"message": "Se isso continuar acontecendo, pode ser causado pelo seu bloqueador de anúncios. Por favor, verifique https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock-Requests"
|
||||
},
|
||||
"forceChannelCheck": {
|
||||
"message": "Forçar verificação do canal antes de pular os patrocínios"
|
||||
},
|
||||
"whatForceChannelCheck": {
|
||||
"message": "Por padrão, isso pulará os patrocínios imediatamente mesmo antes de saber qual é o canal. Por padrão, alguns patrocinadores de zero segundo podem ser ignorados nos canais da lista branca. Habilitar esta opção evitará isso, mas irá fazer com que todos os saltos tenham um ligeiro atraso, já que obter o channelID pode levar algum tempo. Este atraso pode não ser perceptível se você tiver internet rápida."
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "Considere habilitar a verificação de canal forçada antes de pular os patrocinadores"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "Incorreto"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "Categoria errada"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "Este vídeo é classificado como música. Você tem certeza que deseja enviar segmentos com categorias que não são músicas? A menos que esse vídeo não seja de fato música, você não deve enviar esse segmento. Por favor leia as orientações se estiver em dúvidas."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,6 +350,9 @@
|
||||
"supportInvidious": {
|
||||
"message": "支持 Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) 是一个第三方 Youtube 客户端。要启用支持,您必须允许额外的权限。在 Chrome 及其他 Chromium 变种的匿名模式中无法工作。"
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "启用 Invidious 支持,禁用自动跳过,隐藏按钮等等。"
|
||||
},
|
||||
@@ -486,9 +489,21 @@
|
||||
"category_sponsor": {
|
||||
"message": "赞助商广告"
|
||||
},
|
||||
"category_intro": {
|
||||
"message": "介绍动画"
|
||||
},
|
||||
"category_interaction": {
|
||||
"message": "互动提醒(订阅)"
|
||||
},
|
||||
"category_selfpromo": {
|
||||
"message": "自我推销和商品"
|
||||
},
|
||||
"category_music_offtopic": {
|
||||
"message": "音乐:非音乐部分"
|
||||
},
|
||||
"category_livestream_messages": {
|
||||
"message": "直播:捐赠/消息阅读"
|
||||
},
|
||||
"disable": {
|
||||
"message": "禁用"
|
||||
},
|
||||
@@ -539,5 +554,14 @@
|
||||
},
|
||||
"forceChannelCheckPopup": {
|
||||
"message": "请考虑启用跳过赞助商广告前强制进行频道检查"
|
||||
},
|
||||
"downvoteDescription": {
|
||||
"message": "不正确"
|
||||
},
|
||||
"incorrectCategory": {
|
||||
"message": "错误的类别"
|
||||
},
|
||||
"nonMusicCategoryOnMusic": {
|
||||
"message": "此视频被归类为音乐。您确定要提交带有非音乐类别的片段吗?除非此视频实际上不是音乐,否则您不应提交此片段。如果您感到困惑,请阅读指南。"
|
||||
}
|
||||
}
|
||||
|
||||
58
public/icons/thumbs_down.svg
Normal file
58
public/icons/thumbs_down.svg
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="thumbs_down.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="730"
|
||||
inkscape:window-height="480"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.8333333"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="12"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="M0 0h24v24H0z"
|
||||
fill="none"
|
||||
id="path2" />
|
||||
<path
|
||||
d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"
|
||||
id="path4"
|
||||
style="fill:#ffffff" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
59
public/icons/thumbs_up.svg
Normal file
59
public/icons/thumbs_up.svg
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 24 24"
|
||||
fill="black"
|
||||
width="18px"
|
||||
height="18px"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="thumbs_up.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="730"
|
||||
inkscape:window-height="480"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="13.111111"
|
||||
inkscape:cx="9"
|
||||
inkscape:cy="9"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
id="path2" />
|
||||
<path
|
||||
d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"
|
||||
id="path4"
|
||||
style="fill:#ffffff" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -237,23 +237,6 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="autoUpvote">
|
||||
<label class="switch-container" label-name="__MSG_enableAutoUpvote__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatAutoUpvote__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="trackViewCount">
|
||||
<label class="switch-container" label-name="__MSG_enableViewTracking__">
|
||||
<label class="switch">
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface NoticeState {
|
||||
|
||||
countdownTime: number,
|
||||
countdownText: string,
|
||||
countdownManuallyPaused: boolean,
|
||||
}
|
||||
|
||||
class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
@@ -55,6 +56,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
//the countdown until this notice closes
|
||||
countdownTime: maxCountdownTime(),
|
||||
countdownText: null,
|
||||
countdownManuallyPaused: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +73,8 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
<table id={"sponsorSkipNotice" + this.idSuffix}
|
||||
className={"sponsorSkipObject sponsorSkipNotice" + (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")}
|
||||
style={noticeStyle}
|
||||
onMouseEnter={this.pauseCountdown.bind(this)}
|
||||
onMouseLeave={this.startCountdown.bind(this)}>
|
||||
onMouseEnter={() => this.timerMouseEnter()}
|
||||
onMouseLeave={() => this.timerMouseLeave()}>
|
||||
<tbody>
|
||||
|
||||
{/* First row */}
|
||||
@@ -99,6 +101,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
{/* Time left */}
|
||||
{this.props.timed ? (
|
||||
<span id={"sponsorSkipNoticeTimeLeft" + this.idSuffix}
|
||||
onClick={() => this.toggleManualPause()}
|
||||
className="sponsorSkipObject sponsorSkipNoticeTimeLeft">
|
||||
|
||||
{this.state.countdownText || (this.state.countdownTime + "s")}
|
||||
@@ -121,6 +124,30 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
);
|
||||
}
|
||||
|
||||
timerMouseEnter() {
|
||||
if (this.state.countdownManuallyPaused) return;
|
||||
|
||||
this.pauseCountdown();
|
||||
}
|
||||
|
||||
timerMouseLeave() {
|
||||
if (this.state.countdownManuallyPaused) return;
|
||||
|
||||
this.startCountdown();
|
||||
}
|
||||
|
||||
toggleManualPause() {
|
||||
this.setState({
|
||||
countdownManuallyPaused: !this.state.countdownManuallyPaused
|
||||
}, () => {
|
||||
if (this.state.countdownManuallyPaused) {
|
||||
this.pauseCountdown();
|
||||
} else {
|
||||
this.startCountdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//called every second to lower the countdown before hiding the notice
|
||||
countdown() {
|
||||
if (!this.props.timed) return;
|
||||
@@ -159,7 +186,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
//reset countdown and inform the user
|
||||
this.setState({
|
||||
countdownTime: this.state.maxCountdownTime(),
|
||||
countdownText: chrome.i18n.getMessage("paused")
|
||||
countdownText: this.state.countdownManuallyPaused ? chrome.i18n.getMessage("manualPaused") : chrome.i18n.getMessage("paused")
|
||||
});
|
||||
|
||||
//remove the fade out class if it exists
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "react";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import Config from "../config"
|
||||
import { ContentContainer, SponsorHideType } from "../types";
|
||||
import { ContentContainer, SponsorHideType, SponsorTime } from "../types";
|
||||
|
||||
import Utils from "../utils";
|
||||
var utils = new Utils();
|
||||
@@ -9,9 +9,17 @@ var utils = new Utils();
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
|
||||
enum SkipNoticeAction {
|
||||
None,
|
||||
Upvote,
|
||||
Downvote,
|
||||
CategoryVote,
|
||||
Unskip
|
||||
}
|
||||
|
||||
export interface SkipNoticeProps {
|
||||
segments: SponsorTime[];
|
||||
|
||||
export interface SkipNoticeProps {
|
||||
UUID: string;
|
||||
autoSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
@@ -29,14 +37,17 @@ export interface SkipNoticeState {
|
||||
countdownText: string;
|
||||
|
||||
unskipText: string;
|
||||
unskipCallback: () => void;
|
||||
unskipCallback: (index: number) => void;
|
||||
|
||||
downvoting: boolean;
|
||||
choosingCategory: boolean;
|
||||
thanksForVotingText: boolean; //null until the voting buttons should be hidden
|
||||
|
||||
actionState: SkipNoticeAction;
|
||||
}
|
||||
|
||||
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
|
||||
UUID: string;
|
||||
segments: SponsorTime[];
|
||||
autoSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: ContentContainer;
|
||||
@@ -57,22 +68,30 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
this.noticeRef = React.createRef();
|
||||
this.categoryOptionRef = React.createRef();
|
||||
|
||||
this.UUID = props.UUID;
|
||||
this.segments = props.segments;
|
||||
this.autoSkip = props.autoSkip;
|
||||
this.contentContainer = props.contentContainer;
|
||||
this.audio = null;
|
||||
|
||||
let noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||
|
||||
|
||||
let categoryName = chrome.i18n.getMessage(this.segments.length > 1 ? "multipleSegments" : "category_" + this.segments[0].category);
|
||||
let noticeTitle = categoryName + " " + chrome.i18n.getMessage("skipped");
|
||||
if (!this.autoSkip) {
|
||||
noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped");
|
||||
noticeTitle = chrome.i18n.getMessage("skip") + " " + categoryName + "?";
|
||||
}
|
||||
|
||||
//add notice
|
||||
this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
|
||||
// Sort segments
|
||||
if (this.segments.length > 1) {
|
||||
this.segments.sort((a, b) => a.segment[0] - b.segment[0]);
|
||||
}
|
||||
|
||||
//this is the suffix added at the end of every id
|
||||
this.idSuffix = this.UUID + this.amountOfPreviousNotices;
|
||||
for (const segment of this.segments) {
|
||||
this.idSuffix += segment.UUID;
|
||||
}
|
||||
this.idSuffix += this.amountOfPreviousNotices;
|
||||
|
||||
if (this.amountOfPreviousNotices > 0) {
|
||||
//another notice exists
|
||||
@@ -92,14 +111,18 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
countdownText: null,
|
||||
|
||||
unskipText: chrome.i18n.getMessage("unskip"),
|
||||
unskipCallback: this.unskip.bind(this),
|
||||
unskipCallback: (index) => this.unskip(index),
|
||||
|
||||
downvoting: false,
|
||||
choosingCategory: false
|
||||
choosingCategory: false,
|
||||
thanksForVotingText: null,
|
||||
|
||||
actionState: SkipNoticeAction.None
|
||||
}
|
||||
|
||||
if (!this.autoSkip) {
|
||||
Object.assign(this.state, this.getUnskippedModeInfo(chrome.i18n.getMessage("skip")));
|
||||
// Assume manual skip is only skipping 1 submission
|
||||
Object.assign(this.state, this.getUnskippedModeInfo(0, chrome.i18n.getMessage("skip")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,35 +163,46 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
<tr id={"sponsorSkipNoticeSecondRow" + this.idSuffix}>
|
||||
|
||||
{/* Vote Button Container */}
|
||||
<td id={"sponsorTimesVoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorTimesVoteButtonsContainer">
|
||||
{!this.state.thanksForVotingText ?
|
||||
<td id={"sponsorTimesVoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorTimesVoteButtonsContainer">
|
||||
|
||||
{/* Report Text */}
|
||||
<span id={"sponsorTimesReportText" + this.idSuffix}
|
||||
className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
|
||||
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||
style={{marginRight: "5px"}}>
|
||||
{/* Upvote Button */}
|
||||
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorSkipObject voteButton"
|
||||
style={{marginRight: "10px"}}
|
||||
src={chrome.extension.getURL("icons/thumbs_up.svg")}
|
||||
title={chrome.i18n.getMessage("upvoteButtonInfo")}
|
||||
onClick={() => this.prepAction(SkipNoticeAction.Upvote)}>
|
||||
|
||||
</img>
|
||||
|
||||
{chrome.i18n.getMessage("reportButtonTitle")}
|
||||
</span>
|
||||
{/* Report Button */}
|
||||
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorSkipObject voteButton"
|
||||
src={chrome.extension.getURL("icons/thumbs_down.svg")}
|
||||
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||
onClick={() => this.adjustDownvotingState(true)}>
|
||||
|
||||
</img>
|
||||
|
||||
{/* Report Button */}
|
||||
<img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
|
||||
className="sponsorSkipObject voteButton"
|
||||
src={chrome.extension.getURL("icons/report.png")}
|
||||
title={chrome.i18n.getMessage("reportButtonInfo")}
|
||||
onClick={() => this.adjustDownvotingState(true)}>
|
||||
|
||||
</img>
|
||||
</td>
|
||||
|
||||
</td>
|
||||
:
|
||||
|
||||
<td id={"sponsorTimesVoteButtonInfoMessage" + this.idSuffix}
|
||||
className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
|
||||
style={{marginRight: "10px"}}>
|
||||
{this.state.thanksForVotingText}
|
||||
</td>
|
||||
}
|
||||
|
||||
{/* Unskip Button */}
|
||||
<td className="sponsorSkipNoticeUnskipSection">
|
||||
<button id={"sponsorSkipUnskipButton" + this.idSuffix}
|
||||
className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
style={{marginLeft: "4px"}}
|
||||
onClick={this.state.unskipCallback}>
|
||||
onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
|
||||
|
||||
{this.state.unskipText}
|
||||
</button>
|
||||
@@ -193,18 +227,16 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
|
||||
{/* Normal downvote */}
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.contentContainer().vote(0, this.UUID, undefined, this)}>
|
||||
onClick={() => this.prepAction(SkipNoticeAction.Downvote)}>
|
||||
{chrome.i18n.getMessage("downvoteDescription")}
|
||||
</button>
|
||||
|
||||
{/* Category vote */}
|
||||
{Config.config.testingServer &&
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.openCategoryChooser()}>
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.openCategoryChooser()}>
|
||||
|
||||
{chrome.i18n.getMessage("incorrectCategory")}
|
||||
</button>
|
||||
}
|
||||
{chrome.i18n.getMessage("incorrectCategory")}
|
||||
</button>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
@@ -217,7 +249,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
{/* Category Selector */}
|
||||
<select id={"sponsorTimeCategories" + this.idSuffix}
|
||||
className="sponsorTimeCategories"
|
||||
defaultValue={utils.getSponsorTimeFromUUID(this.props.contentContainer().sponsorTimes, this.props.UUID).category}
|
||||
defaultValue={this.segments[0].category} //Just default to the first segment, as we don't know which they'll choose
|
||||
ref={this.categoryOptionRef}
|
||||
onChange={this.categorySelectionChange.bind(this)}>
|
||||
|
||||
@@ -225,11 +257,23 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
</select>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.contentContainer().vote(undefined, this.UUID, this.categoryOptionRef.current.value, this)}>
|
||||
{this.segments.length === 1 &&
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.prepAction(SkipNoticeAction.CategoryVote)}>
|
||||
|
||||
{chrome.i18n.getMessage("submit")}
|
||||
</button>
|
||||
{chrome.i18n.getMessage("submit")}
|
||||
</button>
|
||||
}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
{/* Segment Chooser Row */}
|
||||
{this.state.actionState !== SkipNoticeAction.None &&
|
||||
<tr id={"sponsorSkipNoticeSubmissionOptionsRow" + this.idSuffix}>
|
||||
<td id={"sponsorTimesSubmissionOptionsContainer" + this.idSuffix}>
|
||||
{this.getSubmissionChooser()}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@@ -238,6 +282,32 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
);
|
||||
}
|
||||
|
||||
getSubmissionChooser(): JSX.Element[] {
|
||||
let elements: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < this.segments.length; i++) {
|
||||
elements.push(
|
||||
<button className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
onClick={() => this.performAction(i)}
|
||||
key={"submission" + i + this.segments[i].category + this.idSuffix}>
|
||||
{(i + 1) + ". " + chrome.i18n.getMessage("category_" + this.segments[i].category)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
prepAction(action: SkipNoticeAction) {
|
||||
if (this.segments.length === 1) {
|
||||
this.performAction(0, action);
|
||||
} else {
|
||||
this.setState({
|
||||
actionState: action
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getMessageBoxes(): JSX.Element[] | JSX.Element {
|
||||
if (this.state.messages.length === 0) {
|
||||
// Add a spacer if there is no text
|
||||
@@ -262,6 +332,34 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the action from the current state
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
performAction(index: number, action?: SkipNoticeAction) {
|
||||
switch (action ?? this.state.actionState) {
|
||||
case SkipNoticeAction.None:
|
||||
break;
|
||||
case SkipNoticeAction.Upvote:
|
||||
this.contentContainer().vote(1, this.segments[index].UUID, undefined, this);
|
||||
break;
|
||||
case SkipNoticeAction.Downvote:
|
||||
this.contentContainer().vote(0, this.segments[index].UUID, undefined, this);
|
||||
break;
|
||||
case SkipNoticeAction.CategoryVote:
|
||||
this.contentContainer().vote(undefined, this.segments[index].UUID, this.categoryOptionRef.current.value, this)
|
||||
break;
|
||||
case SkipNoticeAction.Unskip:
|
||||
this.state.unskipCallback(index);
|
||||
break;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
actionState: SkipNoticeAction.None
|
||||
});
|
||||
}
|
||||
|
||||
adjustDownvotingState(value: boolean) {
|
||||
if (!value) this.clearConfigListener();
|
||||
|
||||
@@ -286,6 +384,11 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
this.setState({
|
||||
choosingCategory: true,
|
||||
downvoting: false
|
||||
}, () => {
|
||||
if (this.segments.length > 1) {
|
||||
// Use the action selectors as a submit button
|
||||
this.prepAction(SkipNoticeAction.CategoryVote);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -321,37 +424,38 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
chrome.runtime.sendMessage({"message": "openConfig"});
|
||||
|
||||
// Reset option to original
|
||||
event.target.value = utils.getSponsorTimeFromUUID(this.props.contentContainer().sponsorTimes, this.props.UUID).category;
|
||||
event.target.value = this.segments[0].category;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unskip() {
|
||||
this.contentContainer().unskipSponsorTime(this.UUID);
|
||||
unskip(index: number) {
|
||||
this.contentContainer().unskipSponsorTime(this.segments[index]);
|
||||
|
||||
this.unskippedMode(chrome.i18n.getMessage("reskip"));
|
||||
this.unskippedMode(index, chrome.i18n.getMessage("reskip"));
|
||||
}
|
||||
|
||||
/** Sets up notice to be not skipped yet */
|
||||
unskippedMode(buttonText: string) {
|
||||
unskippedMode(index: number, buttonText: string) {
|
||||
//setup new callback and reset countdown
|
||||
this.setState(this.getUnskippedModeInfo(buttonText), () => {
|
||||
this.setState(this.getUnskippedModeInfo(index, buttonText), () => {
|
||||
this.noticeRef.current.resetCountdown();
|
||||
});
|
||||
}
|
||||
|
||||
getUnskippedModeInfo(buttonText: string) {
|
||||
getUnskippedModeInfo(index: number, buttonText: string) {
|
||||
let self = this;
|
||||
let maxCountdownTime = function() {
|
||||
let sponsorTime = utils.getSponsorTimeFromUUID(this.contentContainer().sponsorTimes, this.UUID);
|
||||
let duration = Math.round((sponsorTime.segment[1] - this.contentContainer().v.currentTime) * (1 / this.contentContainer().v.playbackRate));
|
||||
let sponsorTime = self.segments[index];
|
||||
let duration = Math.round((sponsorTime.segment[1] - self.contentContainer().v.currentTime) * (1 / self.contentContainer().v.playbackRate));
|
||||
|
||||
return Math.max(duration, 4);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
return {
|
||||
unskipText: buttonText,
|
||||
|
||||
unskipCallback: this.reskip.bind(this),
|
||||
unskipCallback: (index) => this.reskip(index),
|
||||
|
||||
//change max duration to however much of the sponsor is left
|
||||
maxCountdownTime: maxCountdownTime,
|
||||
@@ -360,8 +464,8 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
}
|
||||
|
||||
reskip() {
|
||||
this.contentContainer().reskipSponsorTime(this.UUID);
|
||||
reskip(index: number) {
|
||||
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
||||
|
||||
//reset countdown
|
||||
this.setState({
|
||||
@@ -377,24 +481,23 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
this.setState({
|
||||
noticeTitle: chrome.i18n.getMessage("noticeTitle")
|
||||
});
|
||||
|
||||
if(Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
afterDownvote(type: number, category: string) {
|
||||
afterVote(segment: SponsorTime, type: number, category: string) {
|
||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||
this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
|
||||
|
||||
this.adjustDownvotingState(false);
|
||||
if (type === 0) {
|
||||
this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
|
||||
this.adjustDownvotingState(false);
|
||||
}
|
||||
|
||||
// Change the sponsor locally
|
||||
let sponsorTime = utils.getSponsorTimeFromUUID(this.contentContainer().sponsorTimes, this.UUID);
|
||||
if (sponsorTime) {
|
||||
if (segment) {
|
||||
if (type === 0) {
|
||||
sponsorTime.hidden = SponsorHideType.Downvoted;
|
||||
segment.hidden = SponsorHideType.Downvoted;
|
||||
} else if (category) {
|
||||
sponsorTime.category = category;
|
||||
segment.category = category;
|
||||
}
|
||||
|
||||
this.contentContainer().updatePreviewBar();
|
||||
@@ -404,41 +507,19 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
setNoticeInfoMessage(...messages: string[]) {
|
||||
this.setState({
|
||||
messages
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
addVoteButtonInfo(message) {
|
||||
this.resetVoteButtonInfo();
|
||||
|
||||
//hide report button and text for it
|
||||
let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
|
||||
if (downvoteButton != null) {
|
||||
downvoteButton.style.display = "none";
|
||||
}
|
||||
let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
|
||||
if (downvoteButtonText != null) {
|
||||
downvoteButtonText.style.display = "none";
|
||||
}
|
||||
|
||||
//add info
|
||||
let thanksForVotingText = document.createElement("td");
|
||||
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
|
||||
this.setState({
|
||||
thanksForVotingText: message
|
||||
});
|
||||
}
|
||||
|
||||
resetVoteButtonInfo() {
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
//show button again
|
||||
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
|
||||
this.setState({
|
||||
thanksForVotingText: null
|
||||
});
|
||||
}
|
||||
|
||||
closeListener() {
|
||||
|
||||
@@ -260,7 +260,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
|
||||
setTimeToNow(index: number) {
|
||||
this.setTimeTo(index, this.props.contentContainer().getRoughCurrentTime());
|
||||
this.setTimeTo(index, this.props.contentContainer().getRealCurrentTime());
|
||||
}
|
||||
|
||||
setTimeToEnd() {
|
||||
|
||||
@@ -161,7 +161,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
}
|
||||
|
||||
// Check if any non music categories are being used on a music video
|
||||
if (this.contentContainer().videoInfo.microformat.playerMicroformatRenderer.category === "Music") {
|
||||
if (this.contentContainer().videoInfo?.microformat?.playerMicroformatRenderer?.category === "Music") {
|
||||
let sponsorTimesSubmitting = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
for (const sponsorTime of sponsorTimesSubmitting) {
|
||||
if (!sponsorTime.category.startsWith("music_")) {
|
||||
|
||||
@@ -24,7 +24,6 @@ interface SBConfig {
|
||||
hideDiscordLaunches: number,
|
||||
hideDiscordLink: boolean,
|
||||
invidiousInstances: string[],
|
||||
autoUpvote: boolean,
|
||||
supportInvidious: boolean,
|
||||
serverAddress: string,
|
||||
minDuration: number,
|
||||
@@ -124,7 +123,6 @@ var Config: SBObject = {
|
||||
hideDiscordLaunches: 0,
|
||||
hideDiscordLink: false,
|
||||
invidiousInstances: ["invidio.us", "invidious.snopyta.org"],
|
||||
autoUpvote: true,
|
||||
supportInvidious: false,
|
||||
serverAddress: CompileConfig.serverAddress,
|
||||
minDuration: 0,
|
||||
@@ -252,6 +250,11 @@ async function migrateOldFormats() {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto vote removal
|
||||
if (Config.config["autoUpvote"]) {
|
||||
chrome.storage.sync.remove("autoUpvote");
|
||||
}
|
||||
|
||||
// Channel URLS
|
||||
if (Config.config.whitelistedChannels.length > 0 &&
|
||||
(Config.config.whitelistedChannels[0] == null || Config.config.whitelistedChannels[0].includes("/"))) {
|
||||
|
||||
178
src/content.ts
178
src/content.ts
@@ -41,9 +41,6 @@ var sponsorSkipped: boolean[] = [];
|
||||
//the video
|
||||
var video: HTMLVideoElement;
|
||||
|
||||
/** The last time this video was seeking to */
|
||||
var lastVideoTime: number = null;
|
||||
|
||||
var onInvidious;
|
||||
var onMobileYouTube;
|
||||
|
||||
@@ -81,12 +78,6 @@ utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYo
|
||||
//this only happens if there is an error
|
||||
var sponsorLookupRetries = 0;
|
||||
|
||||
//the last time in the video a sponsor was skipped
|
||||
//used for the go back button
|
||||
var lastSponsorTimeSkipped: number = null;
|
||||
//used for ratings
|
||||
var lastSponsorTimeSkippedUUID: string = null;
|
||||
|
||||
//if showing the start sponsor button or the end sponsor button on the player
|
||||
var showingStartSponsor = true;
|
||||
|
||||
@@ -99,6 +90,9 @@ var popupInitialised = false;
|
||||
|
||||
var submissionNotice: SubmissionNotice = null;
|
||||
|
||||
// If there is an advert playing (or about to be played), this is true
|
||||
var isAdPlaying = false;
|
||||
|
||||
// Contains all of the functions and variables needed by the skip notice
|
||||
var skipNoticeContentContainer: ContentContainer = () => ({
|
||||
vote,
|
||||
@@ -116,7 +110,7 @@ var skipNoticeContentContainer: ContentContainer = () => ({
|
||||
changeStartSponsorButton,
|
||||
previewTime,
|
||||
videoInfo,
|
||||
getRoughCurrentTime
|
||||
getRealCurrentTime: getRealCurrentTime
|
||||
});
|
||||
|
||||
//get messages from the background script and the popup
|
||||
@@ -180,7 +174,7 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
|
||||
return
|
||||
case "getCurrentTime":
|
||||
sendResponse({
|
||||
currentTime: getRoughCurrentTime()
|
||||
currentTime: getRealCurrentTime()
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -281,6 +275,9 @@ function resetValues() {
|
||||
} else {
|
||||
switchingVideos = true;
|
||||
}
|
||||
|
||||
// Reset advert playing flag
|
||||
isAdPlaying = false;
|
||||
}
|
||||
|
||||
async function videoIDChange(id) {
|
||||
@@ -446,6 +443,7 @@ function createPreviewBar(): void {
|
||||
* This happens when the resolution changes or at random time to clear memory.
|
||||
*/
|
||||
function durationChangeListener() {
|
||||
updateAdFlag();
|
||||
updatePreviewBar();
|
||||
}
|
||||
|
||||
@@ -464,13 +462,22 @@ function cancelSponsorSchedule(): void {
|
||||
function startSponsorSchedule(includeIntersectingSegments: boolean = false, currentTime?: number): void {
|
||||
cancelSponsorSchedule();
|
||||
|
||||
// Don't skip if advert playing and reset last checked time
|
||||
if (isAdPlaying) {
|
||||
// Reset lastCheckVideoTime
|
||||
lastCheckVideoTime = -1;
|
||||
lastCheckTime = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (video.paused) return;
|
||||
|
||||
if (Config.config.disableSkipping || channelWhitelisted || (channelID === null && Config.config.forceChannelCheck)){
|
||||
return;
|
||||
}
|
||||
|
||||
if (incorrectVideoIDCheck()) return;
|
||||
if (incorrectVideoCheck()) return;
|
||||
|
||||
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
||||
|
||||
@@ -483,6 +490,19 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
|
||||
let timeUntilSponsor = skipTime[0] - currentTime;
|
||||
let videoID = sponsorVideoID;
|
||||
|
||||
// Find all indexes in between the start and end
|
||||
let skippingSegments = [skipInfo.array[skipInfo.index]];
|
||||
if (skipInfo.index !== skipInfo.endIndex) {
|
||||
skippingSegments = [];
|
||||
|
||||
for (const segment of skipInfo.array) {
|
||||
if (utils.getCategorySelection(segment.category).option === CategorySkipOption.AutoSkip &&
|
||||
segment.segment[0] >= skipTime[0] && segment.segment[1] <= skipTime[1]) {
|
||||
skippingSegments.push(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't skip if this category should not be skipped
|
||||
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ShowOverlay) return;
|
||||
|
||||
@@ -490,10 +510,10 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
|
||||
let forcedSkipTime: number = null;
|
||||
let forcedIncludeIntersectingSegments = false;
|
||||
|
||||
if (incorrectVideoIDCheck(videoID)) return;
|
||||
if (incorrectVideoCheck(videoID, currentSkip)) return;
|
||||
|
||||
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
|
||||
skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice);
|
||||
skipToTime(video, skipTime, skippingSegments, skipInfo.openNotice);
|
||||
|
||||
// TODO: Know the autoSkip settings for ALL items being skipped
|
||||
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) {
|
||||
@@ -515,13 +535,11 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
|
||||
}
|
||||
|
||||
/**
|
||||
* This makes sure the videoID is still correct
|
||||
*
|
||||
* TODO: Remove this bug catching if statement when the bug is found
|
||||
* This makes sure the videoID is still correct and if the sponsorTime is included
|
||||
*/
|
||||
function incorrectVideoIDCheck(videoID?: string): boolean {
|
||||
function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean {
|
||||
let currentVideoID = getYouTubeVideoID(document.URL);
|
||||
if (currentVideoID !== (videoID || sponsorVideoID)) {
|
||||
if (currentVideoID !== (videoID || sponsorVideoID) || (sponsorTime && (!sponsorTimes || !sponsorTimes.includes(sponsorTime)) && !sponsorTimesSubmitting.includes(sponsorTime))) {
|
||||
// Something has really gone wrong
|
||||
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be.");
|
||||
console.error("[SponsorBlock] VideoID recorded: " + sponsorVideoID + ". Actual VideoID: " + currentVideoID);
|
||||
@@ -556,6 +574,9 @@ function sponsorsLookup(id: string) {
|
||||
video.addEventListener('play', () => {
|
||||
switchingVideos = false;
|
||||
|
||||
// Check if an ad is playing
|
||||
updateAdFlag();
|
||||
|
||||
// Make sure it doesn't get double called with the playing event
|
||||
if (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000) {
|
||||
lastCheckTime = Date.now();
|
||||
@@ -563,6 +584,7 @@ function sponsorsLookup(id: string) {
|
||||
|
||||
startSponsorSchedule();
|
||||
}
|
||||
|
||||
});
|
||||
video.addEventListener('playing', () => {
|
||||
// Make sure it doesn't get double called with the play event
|
||||
@@ -578,8 +600,6 @@ function sponsorsLookup(id: string) {
|
||||
lastCheckVideoTime = -1
|
||||
lastCheckTime = 0;
|
||||
|
||||
lastVideoTime = video.currentTime;
|
||||
|
||||
if (!video.paused){
|
||||
startSponsorSchedule();
|
||||
}
|
||||
@@ -590,8 +610,6 @@ function sponsorsLookup(id: string) {
|
||||
lastCheckVideoTime = -1;
|
||||
lastCheckTime = 0;
|
||||
|
||||
lastVideoTime = video.currentTime;
|
||||
|
||||
cancelSponsorSchedule();
|
||||
});
|
||||
|
||||
@@ -660,7 +678,7 @@ function sponsorsLookup(id: string) {
|
||||
|
||||
//check if this video was uploaded recently
|
||||
utils.wait(() => !!videoInfo).then(() => {
|
||||
let dateUploaded = videoInfo.microformat.playerMicroformatRenderer.uploadDate;
|
||||
let dateUploaded = videoInfo?.microformat?.playerMicroformatRenderer?.uploadDate;
|
||||
|
||||
//if less than 3 days old
|
||||
if (Date.now() - new Date(dateUploaded).getTime() < 259200000) {
|
||||
@@ -783,6 +801,11 @@ function updatePreviewBarPositionMobile(parent: Element) {
|
||||
}
|
||||
|
||||
function updatePreviewBar() {
|
||||
if(isAdPlaying) {
|
||||
previewBar.set([], [], 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (previewBar === null || video === null) return;
|
||||
|
||||
let localSponsorTimes = sponsorTimes;
|
||||
@@ -812,7 +835,12 @@ function updatePreviewBar() {
|
||||
|
||||
//checks if this channel is whitelisted, should be done only after the channelID has been loaded
|
||||
function whitelistCheck() {
|
||||
channelID = videoInfo.videoDetails.channelId;
|
||||
channelID = videoInfo?.videoDetails?.channelId;
|
||||
if (!channelID) {
|
||||
channelID = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//see if this is a whitelisted channel
|
||||
let whitelistedChannels = Config.config.whitelistedChannels;
|
||||
@@ -952,58 +980,58 @@ function previewTime(time: number) {
|
||||
}
|
||||
|
||||
//skip from the start time to the end time for a certain index sponsor time
|
||||
function skipToTime(v: HTMLVideoElement, index: number, sponsorTimes: SponsorTime[], openNotice: boolean) {
|
||||
let autoSkip: boolean = utils.getCategorySelection(sponsorTimes[index].category).option === CategorySkipOption.AutoSkip;
|
||||
function skipToTime(v: HTMLVideoElement, skipTime: number[], skippingSegments: SponsorTime[], openNotice: boolean) {
|
||||
// There will only be one submission if it is manual skip
|
||||
let autoSkip: boolean = utils.getCategorySelection(skippingSegments[0].category).option === CategorySkipOption.AutoSkip;
|
||||
|
||||
if (autoSkip || previewResetter !== null) {
|
||||
v.currentTime = sponsorTimes[index].segment[1];
|
||||
v.currentTime = skipTime[1];
|
||||
}
|
||||
|
||||
lastSponsorTimeSkipped = sponsorTimes[index].segment[0];
|
||||
|
||||
let currentUUID: string = sponsorTimes[index].UUID;
|
||||
lastSponsorTimeSkippedUUID = currentUUID;
|
||||
|
||||
if (openNotice) {
|
||||
//send out the message saying that a sponsor message was skipped
|
||||
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||
let skipNotice = new SkipNotice(currentUUID, autoSkip, skipNoticeContentContainer);
|
||||
|
||||
//auto-upvote this sponsor
|
||||
if (Config.config.trackViewCount && autoSkip && Config.config.autoUpvote) {
|
||||
vote(1, currentUUID);
|
||||
}
|
||||
let skipNotice = new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer);
|
||||
}
|
||||
|
||||
//send telemetry that a this sponsor was skipped
|
||||
if (Config.config.trackViewCount && !sponsorSkipped[index] && autoSkip) {
|
||||
utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID);
|
||||
if (Config.config.trackViewCount && autoSkip) {
|
||||
let alreadySkipped = false;
|
||||
let isPreviewSegment = false;
|
||||
|
||||
for (const segment of skippingSegments) {
|
||||
let index = sponsorTimes.indexOf(segment);
|
||||
if (index !== -1 && !sponsorSkipped[index]) {
|
||||
utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + segment.UUID);
|
||||
|
||||
sponsorSkipped[index] = true;
|
||||
} else if (sponsorSkipped[index]) {
|
||||
alreadySkipped = true;
|
||||
}
|
||||
|
||||
if (index !== -1) isPreviewSegment = true;
|
||||
}
|
||||
|
||||
// Count this as a skip
|
||||
Config.config.minutesSaved = Config.config.minutesSaved + (sponsorTimes[index].segment[1] - sponsorTimes[index].segment[0]) / 60;
|
||||
Config.config.skipCount = Config.config.skipCount + 1;
|
||||
|
||||
sponsorSkipped[index] = true;
|
||||
if (!alreadySkipped && !isPreviewSegment) {
|
||||
Config.config.minutesSaved = Config.config.minutesSaved + (skipTime[1] - skipTime[0]) / 60;
|
||||
Config.config.skipCount = Config.config.skipCount + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unskipSponsorTime(UUID) {
|
||||
function unskipSponsorTime(segment: SponsorTime) {
|
||||
if (sponsorTimes != null) {
|
||||
//add a tiny bit of time to make sure it is not skipped again
|
||||
video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[0] + 0.001;
|
||||
video.currentTime = segment.segment[0] + 0.001;
|
||||
|
||||
checkIfInsideSegment();
|
||||
}
|
||||
}
|
||||
|
||||
function reskipSponsorTime(UUID) {
|
||||
if (sponsorTimes != null) {
|
||||
video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1];
|
||||
|
||||
// See if any skips need to be done if this is inside of another segment
|
||||
startSponsorSchedule(true, utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1]);
|
||||
}
|
||||
function reskipSponsorTime(segment: SponsorTime) {
|
||||
video.currentTime = segment.segment[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1126,29 +1154,14 @@ async function updateVisibilityOfPlayerControlsButton(): Promise<boolean> {
|
||||
* current time is out of date while scrubbing or at the end of the video. This is not needed
|
||||
* for sponsor skipping as the video is not playing during these times.
|
||||
*/
|
||||
function getRoughCurrentTime(): number {
|
||||
let htmlCurrentTimeString = document.querySelector(".ytp-time-current").textContent;
|
||||
let htmlDurationString = document.querySelector(".ytp-time-duration").textContent;
|
||||
|
||||
if (htmlCurrentTimeString == htmlDurationString) {
|
||||
// At the end of the video
|
||||
return video.duration;
|
||||
}
|
||||
|
||||
function getRealCurrentTime(): number {
|
||||
// Used to check if replay button
|
||||
let playButtonSVGData = document.querySelector("ytp-play-button")?.querySelector("ytp-svg-fill")?.getAttribute("d");
|
||||
let playButtonSVGData = document.querySelector(".ytp-play-button")?.querySelector(".ytp-svg-fill")?.getAttribute("d");
|
||||
let replaceSVGData = "M 18,11 V 7 l -5,5 5,5 v -4 c 3.3,0 6,2.7 6,6 0,3.3 -2.7,6 -6,6 -3.3,0 -6,-2.7 -6,-6 h -2 c 0,4.4 3.6,8 8,8 4.4,0 8,-3.6 8,-8 0,-4.4 -3.6,-8 -8,-8 z";
|
||||
|
||||
if (playButtonSVGData === replaceSVGData) {
|
||||
// At the end of the video
|
||||
return video.duration;
|
||||
}
|
||||
|
||||
let htmlCurrentTimeSections = htmlCurrentTimeString.split(":")[0];
|
||||
let htmlCurrentTime: number = parseInt(htmlCurrentTimeSections[0]) * 60 + parseInt(htmlCurrentTimeSections[1]);
|
||||
|
||||
if (Math.abs(video.currentTime - htmlCurrentTime) > 3) {
|
||||
return htmlCurrentTime;
|
||||
} else {
|
||||
return video.currentTime;
|
||||
}
|
||||
@@ -1163,11 +1176,11 @@ function startSponsorClicked() {
|
||||
//add to sponsorTimes
|
||||
if (sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length < 2) {
|
||||
//it is an end time
|
||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment[1] = getRoughCurrentTime();
|
||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment[1] = getRealCurrentTime();
|
||||
} else {
|
||||
//it is a start time
|
||||
sponsorTimesSubmitting.push({
|
||||
segment: [getRoughCurrentTime()],
|
||||
segment: [getRealCurrentTime()],
|
||||
UUID: null,
|
||||
// Default to sponsor
|
||||
category: "sponsor"
|
||||
@@ -1381,9 +1394,7 @@ function vote(type: number, UUID: string, category?: string, skipNotice?: SkipNo
|
||||
if (skipNotice != null) {
|
||||
if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) {
|
||||
//success (treat rate limits as a success)
|
||||
if (type === 0 || category) {
|
||||
skipNotice.afterDownvote.bind(skipNotice)(type, category);
|
||||
}
|
||||
skipNotice.afterVote.bind(skipNotice)(utils.getSponsorTimeFromUUID(sponsorTimes, UUID), type, category);
|
||||
} else if (response.successType == 0) {
|
||||
//failure: duplicate vote
|
||||
skipNotice.setNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail"))
|
||||
@@ -1545,7 +1556,7 @@ function getSegmentsMessage(segments: number[][]): string {
|
||||
* Assumes that the the privacy info is available.
|
||||
*/
|
||||
function isUnlisted(): boolean {
|
||||
return videoInfo.microformat.playerMicroformatRenderer.isUnlisted || videoInfo.videoDetails.isPrivate;
|
||||
return videoInfo?.microformat?.playerMicroformatRenderer?.isUnlisted || videoInfo?.videoDetails?.isPrivate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1587,3 +1598,16 @@ function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||
//submit this request
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the isAdPlaying flag and hide preview bar/controls if ad is playing
|
||||
*/
|
||||
function updateAdFlag() {
|
||||
let wasAdPlaying = isAdPlaying;
|
||||
isAdPlaying = document.getElementsByClassName('ad-showing').length > 0;
|
||||
|
||||
if(wasAdPlaying != isAdPlaying) {
|
||||
updatePreviewBar();
|
||||
updateVisibilityOfPlayerControlsButton();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +103,14 @@ class PreviewBar {
|
||||
categoryTooltip.classList.add("sbHidden");
|
||||
});
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
const observer = new MutationObserver((mutations, observer) => {
|
||||
if (!mouseOnSeekBar) return;
|
||||
|
||||
// See if mutation observed is only this ID (if so, ignore)
|
||||
if (mutations.length == 1 && (mutations[0].target as HTMLElement).id === "sponsor-block-category-tooltip") {
|
||||
return;
|
||||
}
|
||||
|
||||
let tooltips = document.querySelectorAll(".ytp-tooltip-text");
|
||||
for (const tooltip of tooltips) {
|
||||
let splitData = tooltip.textContent.split(":");
|
||||
@@ -115,7 +120,7 @@ class PreviewBar {
|
||||
|
||||
// Find category at that location
|
||||
let category = null;
|
||||
for (let i = 0; i < this.timestamps.length; i++) {
|
||||
for (let i = 0; i < this.timestamps?.length; i++) {
|
||||
if (this.timestamps[i][0] < timeInSeconds && this.timestamps[i][1] > timeInSeconds){
|
||||
category = this.types[i];
|
||||
}
|
||||
|
||||
@@ -2,17 +2,18 @@ import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import SkipNoticeComponent from "../components/SkipNoticeComponent";
|
||||
import { SponsorTime } from "../types";
|
||||
|
||||
class SkipNotice {
|
||||
UUID: string;
|
||||
segments: SponsorTime[];
|
||||
autoSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: () => any;
|
||||
|
||||
noticeElement: HTMLDivElement;
|
||||
|
||||
constructor(UUID: string, autoSkip: boolean = false, contentContainer) {
|
||||
this.UUID = UUID;
|
||||
constructor(segments: SponsorTime[], autoSkip: boolean = false, contentContainer) {
|
||||
this.segments = segments;
|
||||
this.autoSkip = autoSkip;
|
||||
this.contentContainer = contentContainer;
|
||||
|
||||
@@ -35,7 +36,11 @@ class SkipNotice {
|
||||
|
||||
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
|
||||
//this is the suffix added at the end of every id
|
||||
let idSuffix = this.UUID + amountOfPreviousNotices;
|
||||
let idSuffix = "";
|
||||
for (const segment of this.segments) {
|
||||
idSuffix += segment.UUID;
|
||||
}
|
||||
idSuffix += amountOfPreviousNotices;
|
||||
|
||||
this.noticeElement = document.createElement("div");
|
||||
this.noticeElement.id = "sponsorSkipNoticeContainer" + idSuffix;
|
||||
@@ -43,7 +48,7 @@ class SkipNotice {
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
ReactDOM.render(
|
||||
<SkipNoticeComponent UUID={UUID}
|
||||
<SkipNoticeComponent segments={segments}
|
||||
autoSkip={autoSkip}
|
||||
contentContainer={contentContainer}
|
||||
closeListener={() => this.close()} />,
|
||||
|
||||
@@ -5,12 +5,12 @@ interface ContentContainer {
|
||||
(): {
|
||||
vote: (type: any, UUID: any, category?: string, skipNotice?: SkipNoticeComponent) => void,
|
||||
dontShowNoticeAgain: () => void,
|
||||
unskipSponsorTime: (UUID: any) => void,
|
||||
unskipSponsorTime: (segment: SponsorTime) => void,
|
||||
sponsorTimes: SponsorTime[],
|
||||
sponsorTimesSubmitting: SponsorTime[],
|
||||
v: HTMLVideoElement,
|
||||
sponsorVideoID,
|
||||
reskipSponsorTime: (UUID: any) => void,
|
||||
reskipSponsorTime: (segment: SponsorTime) => void,
|
||||
updatePreviewBar: () => void,
|
||||
onMobileYouTube: boolean,
|
||||
sponsorSubmissionNotice: SubmissionNotice,
|
||||
@@ -18,7 +18,7 @@ interface ContentContainer {
|
||||
changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise<boolean>,
|
||||
previewTime: (time: number) => void,
|
||||
videoInfo: any,
|
||||
getRoughCurrentTime: () => number
|
||||
getRealCurrentTime: () => number
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user