Merge pull request #322 from ajayyy/react

Categories Improvements
This commit is contained in:
Ajay Ramachandran
2020-04-26 23:16:53 -04:00
committed by GitHub
14 changed files with 364 additions and 327 deletions

View File

@@ -68,11 +68,13 @@ jobs:
with: with:
args: builds/ChromeExtension.zip args: builds/ChromeExtension.zip
name: ChromeExtension.zip name: ChromeExtension.zip
path: ./builds/ChromeExtension.zip
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload to release - name: Upload to release
uses: Shopify/upload-to-release@master uses: Shopify/upload-to-release@master
with: with:
args: builds/FirefoxExtension.zip args: builds/FirefoxExtension.zip
name: FirefoxExtension.zip name: FirefoxExtension.zip
path: ./builds/FirefoxExtension.zip
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,7 +1,7 @@
{ {
"name": "__MSG_fullName__", "name": "__MSG_fullName__",
"short_name": "__MSG_Name__", "short_name": "__MSG_Name__",
"version": "1.2.26", "version": "1.2.27",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_Description__", "description": "__MSG_Description__",
"content_scripts": [{ "content_scripts": [{

View File

@@ -189,7 +189,7 @@
"message": "Hide Buttons On YouTube Player" "message": "Hide Buttons On YouTube Player"
}, },
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "This hides the buttons that appear on the YouTube player to submit sponsors. I can see this being annoying for some\n people. Instead of using the button there, this popup can be used to submit sponsors. To hide the notice that appears, \n use the button that appears on the notice saying \"Don't show this again\". You can always enable these settings again later." "message": "This hides the buttons that appear on the YouTube player to submit skip segments."
}, },
"showInfoButton": { "showInfoButton": {
"message": "Show Info Button On YouTube Player" "message": "Show Info Button On YouTube Player"
@@ -207,7 +207,7 @@
"message": "Show Delete Button On YouTube Player" "message": "Show Delete Button On YouTube Player"
}, },
"whatDeleteButton": { "whatDeleteButton": {
"message": "This is the button that allows you to clear all sponsors on the YouTube player." "message": "This is the button on the YouTube player that will clear all your un-submitted segments for the current video."
}, },
"disableViewTracking": { "disableViewTracking": {
"message": "Disable Sponsor Skip Count Tracking" "message": "Disable Sponsor Skip Count Tracking"
@@ -420,10 +420,10 @@
"message": "The video has been detected as unlisted. Click cancel if you do not want to check for sponsors." "message": "The video has been detected as unlisted. Click cancel if you do not want to check for sponsors."
}, },
"unlistedCheck": { "unlistedCheck": {
"message": "Ignore Unlisted Videos" "message": "Ignore Unlisted/Private Videos"
}, },
"whatUnlistedCheck": { "whatUnlistedCheck": {
"message": "This setting will significantly slow down SponsorBlock. Sponsor lookups require sending the video ID to the server. If you are concerned about unlisted video IDs being sent over the internet, enable this option." "message": "This setting will slightly slow down SponsorBlock. Sponsor lookups require sending the video ID to the server. If you are concerned about unlisted video IDs being sent over the internet, enable this option."
}, },
"mobileUpdateInfo": { "mobileUpdateInfo": {
"message": "m.youtube.com is now supported" "message": "m.youtube.com is now supported"
@@ -527,5 +527,32 @@
}, },
"moreCategories": { "moreCategories": {
"message": "More Categories" "message": "More Categories"
},
"bracketEnd": {
"message": "(End)"
},
"hiddenDueToDownvote": {
"message": "hidden: downvote"
},
"hiddenDueToDuration": {
"message": "hidden: too short"
},
"channelDataNotFound": {
"message": "Channel ID not loaded yet."
},
"adblockerIssue": {
"message": "It seems that something is blocking SponsorBlock's ability to get video data. This is probably your ad blocker. Please check https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
},
"itCouldBeAdblockerIssue": {
"message": "If this keeps occuring, it could be caused by your ad blocker. Please check https://github.com/ajayyy/SponsorBlock/wiki/Fix-Ad-Blocker-Blocking-SponsorBlock's-Requests"
},
"forceChannelCheck": {
"message": "Force Channel Check Before Skipping Sponsors"
},
"whatForceChannelCheck": {
"message": "By default, it will skip sponsors right away before it even knows what the channel is. By default, some zero second sponsors might be skipped on whitelisted channels. Enabling this option will prevent this but making all skipping have a slight delay as getting the channelID can take some time. This delay might be unnoticeable if you have fast internet."
},
"forceChannelCheckPopup": {
"message": "Consider Enabling Force Channel Check Before Skipping Sponsors"
} }
} }

View File

@@ -83,6 +83,8 @@
border-spacing: 5px 10px; border-spacing: 5px 10px;
padding-left: 5px; padding-left: 5px;
padding-right: 5px; padding-right: 5px;
border-collapse: unset;
} }
.sponsorSkipNoticeFadeIn { .sponsorSkipNoticeFadeIn {

View File

@@ -39,10 +39,8 @@ sub.popupElement {
vertical-align: text-bottom; vertical-align: text-bottom;
} }
.popupElement { .logoText {
font-family: 'Source Sans Pro', sans-serif; color: white;
color: black;
} }
h1.popupElement { h1.popupElement {
@@ -52,12 +50,21 @@ h1.popupElement {
.popupBody { .popupBody {
font-size: 14px; font-size: 14px;
background-color: #ffd9d9; background-color: #333;
padding: 0px 5px; padding: 0px 5px;
font-family: 'Source Sans Pro', sans-serif;
color: #dddddd;
}
.outerPopupBody {
background-color: #222626;
overflow-y: scroll;
} }
.discreteLink.popupElement { .discreteLink.popupElement {
color: black; color: #dddddd;
} }
.recordingSubtitle.popupElement { .recordingSubtitle.popupElement {
@@ -102,7 +109,7 @@ h1.popupElement {
} }
.whitelistButton.popupElement { .whitelistButton.popupElement {
background-color:#3acc3a; background-color:#27a52d;
-moz-border-radius:28px; -moz-border-radius:28px;
-webkit-border-radius:28px; -webkit-border-radius:28px;
border-radius:28px; border-radius:28px;
@@ -114,13 +121,15 @@ h1.popupElement {
padding:8px 37px; padding:8px 37px;
text-decoration:none; text-decoration:none;
text-shadow:0px 0px 0px #27663c; text-shadow:0px 0px 0px #27663c;
}
transition: 0.01s background-color;
}
.whitelistButton:hover.popupElement { .whitelistButton:hover.popupElement {
background-color:#218b26; background-color:#3acc3a;
} }
.whitelistButton:focus.popupElement { .whitelistButton:focus.popupElement {
outline: none; outline: none;
background-color:#218b26; background-color:#3acc3a;
} }
.whitelistButton:active.popupElement { .whitelistButton:active.popupElement {
position:relative; position:relative;
@@ -128,25 +137,27 @@ h1.popupElement {
} }
.greenButton.popupElement { .greenButton.popupElement {
background-color:#ec1c1c; background-color:#cc1717;
-moz-border-radius:28px; -moz-border-radius:28px;
-webkit-border-radius:28px; -webkit-border-radius:28px;
border-radius:28px; border-radius:28px;
border:1px solid #d31919; border: none;
display:inline-block; display:inline-block;
cursor:pointer; cursor:pointer;
color:#ffffff; color:#ffffff;
font-size:16px; font-size:16px;
padding:8px 37px; padding:8px 37px;
text-decoration:none; text-decoration:none;
text-shadow:0px 0px 0px #662727; text-shadow:0px 0px 0px #662727;
transition: 0.01s background-color;
} }
.greenButton:hover.popupElement { .greenButton:hover.popupElement {
background-color:#bf2a2a; background-color:#ec1c1c;
} }
.greenButton:focus.popupElement { .greenButton:focus.popupElement {
outline: none; outline: none;
background-color:#bf2a2a; background-color:#ec1c1c;
} }
.greenButton:active.popupElement { .greenButton:active.popupElement {
position:relative; position:relative;
@@ -154,14 +165,11 @@ h1.popupElement {
} }
.dangerButton.popupElement { .dangerButton.popupElement {
-moz-box-shadow:inset 0px 1px 0px 0px #cf866c; background-color:#bc3315;
-webkit-box-shadow:inset 0px 1px 0px 0px #cf866c;
box-shadow:inset 0px 1px 0px 0px #cf866c;
background-color:#d0451b;
-moz-border-radius:3px; -moz-border-radius:3px;
-webkit-border-radius:3px; -webkit-border-radius:3px;
border-radius:3px; border-radius:3px;
border:1px solid #942911; border: none;
display:inline-block; display:inline-block;
cursor:pointer; cursor:pointer;
color:#ffffff; color:#ffffff;
@@ -171,11 +179,11 @@ h1.popupElement {
text-shadow:0px 1px 0px #854629; text-shadow:0px 1px 0px #854629;
} }
.dangerButton:hover.popupElement { .dangerButton:hover.popupElement {
background-color:#bc3315; background-color:#d0451b;
} }
.dangerButton:focus.popupElement { .dangerButton:focus.popupElement {
outline: none; outline: none;
background-color:#bc3315; background-color:#d0451b;
} }
.dangerButton:active.popupElement { .dangerButton:active.popupElement {
position:relative; position:relative;
@@ -183,14 +191,11 @@ h1.popupElement {
} }
.warningButton.popupElement { .warningButton.popupElement {
-moz-box-shadow:inset 0px 1px 0px 0px #cfbd6c; background-color:#bc8215;
-webkit-box-shadow:inset 0px 1px 0px 0px #cfbd6c;
box-shadow:inset 0px 1px 0px 0px #cfbd6c;
background-color:#d0821b;
-moz-border-radius:3px; -moz-border-radius:3px;
-webkit-border-radius:3px; -webkit-border-radius:3px;
border-radius:3px; border-radius:3px;
border:1px solid #948b11; border: none;
display:inline-block; display:inline-block;
cursor:pointer; cursor:pointer;
color:#ffffff; color:#ffffff;
@@ -200,11 +205,11 @@ h1.popupElement {
text-shadow:0px 1px 0px #856829; text-shadow:0px 1px 0px #856829;
} }
.warningButton:hover.popupElement { .warningButton:hover.popupElement {
background-color:#bc8215; background-color:#d0821b;
} }
.warningButton:focus.popupElement { .warningButton:focus.popupElement {
outline: none; outline: none;
background-color:#bc8215; background-color:#d0821b;
} }
.warningButton:active.popupElement { .warningButton:active.popupElement {
position:relative; position:relative;

View File

@@ -5,10 +5,10 @@
<link id="sponsorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/> <link id="sponsorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/>
</head> </head>
<body class="popupBody"> <body class="outerPopupBody">
<center> <center>
<div id="app" class="popupBody sponsorBlockPageBody"> <div id="app" class="popupBody sponsorBlockPageBody">
<h1 class="popupElement"> <h1 class="popupElement logoText">
<img src="icons/IconSponsorBlocker256px.png" height="32px" id="sponsorBlockPopupLogo"/> <img src="icons/IconSponsorBlocker256px.png" height="32px" id="sponsorBlockPopupLogo"/>
__MSG_Name__ __MSG_Name__
</h1> </h1>
@@ -71,6 +71,10 @@
<button id="whitelistChannel" class="whitelistButton popupElement">__MSG_whitelistChannel__</button> <button id="whitelistChannel" class="whitelistButton popupElement">__MSG_whitelistChannel__</button>
<button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">__MSG_removeFromWhitelist__</button> <button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">__MSG_removeFromWhitelist__</button>
<div id="whitelistForceCheck" style="text-decoration: underline; cursor: pointer;display: none">
__MSG_forceChannelCheckPopup__
</div>
</div> </div>
<br/> <br/>

View File

@@ -31,11 +31,6 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
case "openConfig": case "openConfig":
chrome.runtime.openOptionsPage(); chrome.runtime.openOptionsPage();
return return
case "submitTimes":
submitTimes(request.videoID, callback);
//this allows the callback to be called later by the submitTimes function
return true;
case "addSponsorTime": case "addSponsorTime":
addSponsorTime(request.time, request.videoID, callback); addSponsorTime(request.time, request.videoID, callback);
@@ -183,60 +178,3 @@ function submitVote(type, UUID, callback) {
}); });
} }
async function submitTimes(videoID: string, callback) {
//get the video times from storage
let sponsorTimes = Config.config.sponsorTimes.get(videoID);
let userID = Config.config.userID;
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
let durationResult = <Types.VideoDurationResponse> await new Promise((resolve, reject) => {
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
message: "getVideoDuration"
}, (response) => resolve(response));
});
});
//check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i][1] > durationResult.duration) {
sponsorTimes[i][1] = durationResult.duration;
}
}
//submit these times
for (let i = 0; i < sponsorTimes.length; i++) {
//to prevent it from happeneing twice
let increasedContributionAmount = false;
//submit the sponsorTime
utils.sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
+ "&userID=" + userID, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && !error) {
callback({
statusCode: xmlhttp.status,
responseText: xmlhttp.responseText
});
if (xmlhttp.status == 200) {
//save the amount contributed
if (!increasedContributionAmount) {
increasedContributionAmount = true;
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimes.length;
}
}
} else if (error) {
callback({
statusCode: -1
});
}
});
}
}
}

View File

@@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import Config from "../config" import Config from "../config"
import { ContentContainer } from "../types"; import { ContentContainer, SponsorHideType } from "../types";
import Utils from "../utils"; import Utils from "../utils";
var utils = new Utils(); var utils = new Utils();
@@ -269,7 +269,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
//this one is the one to hide //this one is the one to hide
//add this as a hidden sponsorTime //add this as a hidden sponsorTime
this.contentContainer().hiddenSponsorTimes.push(i); this.contentContainer().sponsorTimes[i].hidden = SponsorHideType.Downvoted;
this.contentContainer().updatePreviewBar(); this.contentContainer().updatePreviewBar();
break; break;

View File

@@ -47,6 +47,9 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
document.getElementById("sponsorTimesContainer" + this.idSuffix).addEventListener('keydown', function (event) { document.getElementById("sponsorTimesContainer" + this.idSuffix).addEventListener('keydown', function (event) {
event.stopPropagation(); event.stopPropagation();
}); });
// Add as a config listener
Config.configListeners.push(this.configUpdate.bind(this));
} }
render() { render() {
@@ -130,6 +133,12 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
onClick={() => this.setTimeToNow(1)}> onClick={() => this.setTimeToNow(1)}>
{chrome.i18n.getMessage("bracketNow")} {chrome.i18n.getMessage("bracketNow")}
</span> </span>
<span id={"endButton" + this.idSuffix}
className="sponsorNowButton"
onClick={() => this.setTimeToEnd()}>
{chrome.i18n.getMessage("bracketEnd")}
</span>
</div> </div>
); );
} else { } else {
@@ -227,10 +236,18 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
} }
setTimeToNow(index: number) { setTimeToNow(index: number) {
this.setTimeTo(index, this.props.contentContainer().v.currentTime);
}
setTimeToEnd() {
this.setTimeTo(1, this.props.contentContainer().v.duration);
}
setTimeTo(index: number, time: number) {
let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index]; let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
sponsorTime.segment[index] = sponsorTime.segment[index] =
this.props.contentContainer().v.currentTime; time;
this.setState({ this.setState({
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime) sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
@@ -319,6 +336,10 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
this.props.submissionNotice.forceUpdate(); this.props.submissionNotice.forceUpdate();
} }
} }
configUpdate() {
this.forceUpdate();
}
} }
export default SponsorTimeEditComponent; export default SponsorTimeEditComponent;

View File

@@ -1,10 +1,14 @@
import * as CompileConfig from "../config.json"; import * as CompileConfig from "../config.json";
import { CategorySelection, CategorySkipOption } from "./types"; import { CategorySelection, CategorySkipOption } from "./types";
import Utils from "./utils";
const utils = new Utils();
interface SBConfig { interface SBConfig {
userID: string, userID: string,
sponsorTimes: SBMap<string, any>, sponsorTimes: SBMap<string, any>,
whitelistedChannels: Array<any>, whitelistedChannels: string[],
forceChannelCheck: boolean,
startSponsorKeybind: string, startSponsorKeybind: string,
submitKeybind: string, submitKeybind: string,
minutesSaved: number, minutesSaved: number,
@@ -104,6 +108,7 @@ var Config: SBObject = {
userID: null, userID: null,
sponsorTimes: new SBMap("sponsorTimes"), sponsorTimes: new SBMap("sponsorTimes"),
whitelistedChannels: [], whitelistedChannels: [],
forceChannelCheck: false,
startSponsorKeybind: ";", startSponsorKeybind: ";",
submitKeybind: "'", submitKeybind: "'",
minutesSaved: 0, minutesSaved: 0,
@@ -236,7 +241,7 @@ function fetchConfig() {
}); });
} }
function migrateOldFormats() { async function migrateOldFormats() {
if (Config.config["disableAutoSkip"]) { if (Config.config["disableAutoSkip"]) {
for (const selection of Config.config.categorySelections) { for (const selection of Config.config.categorySelections) {
if (selection.name === "sponsor") { if (selection.name === "sponsor") {
@@ -246,6 +251,36 @@ function migrateOldFormats() {
} }
} }
} }
// Channel URLS
if (Config.config.whitelistedChannels.length > 0 &&
(Config.config.whitelistedChannels[0].includes("/") || Config.config.whitelistedChannels[0] == null)) {
let newChannelList: string[] = [];
for (const item of Config.config.whitelistedChannels) {
if (item != null) {
if (item.includes("/channel/")) {
newChannelList.push(item.split("/")[2]);
} else if (item.includes("/user/") && utils.isContentScript()) {
// Replace channel URL with channelID
let response = await utils.asyncRequestToCustomServer("GET", "https://sponsor.ajay.app/invidious/api/v1/channels/" + item.split("/")[2] + "?fields=authorId");
if (response.ok) {
newChannelList.push((await response.json()).authorId);
} else {
// Add it at the beginning so it gets converted later
newChannelList.unshift(item);
}
} else if (item.includes("/user/")) {
// Add it at the beginning so it gets converted later (The API can only be called in the content script due to CORS issues)
newChannelList.unshift(item);
} else {
newChannelList.push(item);
}
}
}
Config.config.whitelistedChannels = newChannelList;
}
} }
async function setupConfig() { async function setupConfig() {

View File

@@ -1,6 +1,6 @@
import Config from "./config"; import Config from "./config";
import { SponsorTime, CategorySkipOption, CategorySelection, VideoID } from "./types"; import { SponsorTime, CategorySkipOption, CategorySelection, VideoID, SponsorHideType } from "./types";
import { ContentContainer } from "./types"; import { ContentContainer } from "./types";
import Utils from "./utils"; import Utils from "./utils";
@@ -24,15 +24,17 @@ var sponsorTimes: SponsorTime[] = null;
//what video id are these sponsors for //what video id are these sponsors for
var sponsorVideoID: VideoID = null; var sponsorVideoID: VideoID = null;
// JSON video info
var videoInfo: any = null;
//the channel this video is about
var channelID;
// Skips are scheduled to ensure precision. // Skips are scheduled to ensure precision.
// Skips are rescheduled every seeking event. // Skips are rescheduled every seeking event.
// Skips are canceled every seeking event // Skips are canceled every seeking event
var currentSkipSchedule: NodeJS.Timeout = null; var currentSkipSchedule: NodeJS.Timeout = null;
var seekListenerSetUp = false var seekListenerSetUp = false
//these are sponsors that have been downvoted
var hiddenSponsorTimes: number[] = [];
/** @type {Array[boolean]} Has the sponsor been skipped */ /** @type {Array[boolean]} Has the sponsor been skipped */
var sponsorSkipped: boolean[] = []; var sponsorSkipped: boolean[] = [];
@@ -59,12 +61,6 @@ var switchingVideos = null;
var lastCheckTime = 0; var lastCheckTime = 0;
var lastCheckVideoTime = -1; var lastCheckVideoTime = -1;
//the channel this video is about
var channelURL;
//the title of the last video loaded. Used to make sure the channel URL has been updated yet.
var title;
//is this channel whitelised from getting sponsors skipped //is this channel whitelised from getting sponsors skipped
var channelWhitelisted = false; var channelWhitelisted = false;
@@ -110,7 +106,6 @@ var skipNoticeContentContainer: ContentContainer = () => ({
unskipSponsorTime, unskipSponsorTime,
sponsorTimes, sponsorTimes,
sponsorTimesSubmitting, sponsorTimesSubmitting,
hiddenSponsorTimes,
v: video, v: video,
sponsorVideoID, sponsorVideoID,
reskipSponsorTime, reskipSponsorTime,
@@ -143,8 +138,7 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
//send the sponsor times along with if it's found //send the sponsor times along with if it's found
sendResponse({ sendResponse({
found: sponsorDataFound, found: sponsorDataFound,
sponsorTimes: sponsorTimes, sponsorTimes: sponsorTimes
hiddenSponsorTimes: hiddenSponsorTimes
}); });
if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) { if (popupInitialised && document.getElementById("sponsorBlockPopupContainer") != null) {
@@ -188,9 +182,9 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
}); });
break; break;
case "getChannelURL": case "getChannelID":
sendResponse({ sendResponse({
channelURL: channelURL channelID: channelID
}); });
break; break;
@@ -267,6 +261,10 @@ function resetValues() {
sponsorTimes = null; sponsorTimes = null;
sponsorLookupRetries = 0; sponsorLookupRetries = 0;
videoInfo = null;
channelWhitelisted = false;
channelID = null;
//empty the preview bar //empty the preview bar
if (previewBar !== null) { if (previewBar !== null) {
previewBar.set([], [], 0); previewBar.set([], [], 0);
@@ -298,9 +296,16 @@ async function videoIDChange(id) {
// Wait for options to be ready // Wait for options to be ready
await utils.wait(() => Config.config !== null, 5000, 1); await utils.wait(() => Config.config !== null, 5000, 1);
// Get new video info
getVideoInfo();
// If enabled, it will check if this video is private or unlisted and double check with the user if the sponsors should be looked up // If enabled, it will check if this video is private or unlisted and double check with the user if the sponsors should be looked up
if (Config.config.checkForUnlistedVideos) { if (Config.config.checkForUnlistedVideos) {
await utils.wait(isPrivacyInfoAvailable); try {
await utils.wait(() => !!videoInfo, 5000, 1);
} catch (err) {
alert(chrome.i18n.getMessage("adblockerIssue"));
}
if (isUnlisted()) { if (isUnlisted()) {
let shouldContinue = confirm(chrome.i18n.getMessage("confirmPrivacy")); let shouldContinue = confirm(chrome.i18n.getMessage("confirmPrivacy"));
@@ -308,10 +313,8 @@ async function videoIDChange(id) {
} }
} }
// TODO: Use a better method here than using type any // Update whitelist data when the video data is loaded
// This is done to be able to do channelIDPromise.isFulfilled and channelIDPromise.isRejected utils.wait(() => !!videoInfo, 5000, 10).then(whitelistCheck);
let channelIDPromise: any = utils.wait(getChannelID);
channelIDPromise.then(() => channelIDPromise.isFulfilled = true).catch(() => channelIDPromise.isRejected = true);
//setup the preview bar //setup the preview bar
if (previewBar === null) { if (previewBar === null) {
@@ -351,7 +354,7 @@ async function videoIDChange(id) {
//close popup //close popup
closeInfoMenu(); closeInfoMenu();
sponsorsLookup(id, channelIDPromise); sponsorsLookup(id);
//make sure everything is properly added //make sure everything is properly added
updateVisibilityOfPlayerControlsButton().then(() => { updateVisibilityOfPlayerControlsButton().then(() => {
@@ -460,10 +463,12 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
cancelSponsorSchedule(); cancelSponsorSchedule();
if (video.paused) return; if (video.paused) return;
if (Config.config.disableSkipping || channelWhitelisted){ if (Config.config.disableSkipping || channelWhitelisted || (channelID === null && Config.config.forceChannelCheck)){
return; return;
} }
if (incorrectVideoIDCheck()) return;
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime; if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
let skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments); let skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments);
@@ -481,27 +486,17 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
let forcedSkipTime: number = null; let forcedSkipTime: number = null;
let forcedIncludeIntersectingSegments = false; let forcedIncludeIntersectingSegments = false;
if (incorrectVideoIDCheck()) return;
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) { if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
// Double check that the videoID is correct skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice);
// TODO: Remove this bug catching if statement when the bug is found
let currentVideoID = getYouTubeVideoID(document.URL);
if (currentVideoID == sponsorVideoID) {
skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice);
// TODO: Know the autoSkip settings for ALL items being skipped // TODO: Know the autoSkip settings for ALL items being skipped
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) { if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) {
forcedSkipTime = skipTime[0] + 0.001; forcedSkipTime = skipTime[0] + 0.001;
} else {
forcedSkipTime = skipTime[1];
forcedIncludeIntersectingSegments = true;
}
} else { } else {
// Something has really gone wrong forcedSkipTime = skipTime[1];
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be."); forcedIncludeIntersectingSegments = true;
console.error("[SponsorBlock] VideoID recorded: " + sponsorVideoID + ". Actual VideoID: " + currentVideoID);
// Video ID change occured
videoIDChange(currentVideoID);
} }
} }
@@ -515,11 +510,32 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
} }
} }
function sponsorsLookup(id: string, channelIDPromise?) { /**
* This makes sure the videoID is still correct
*
* TODO: Remove this bug catching if statement when the bug is found
*/
function incorrectVideoIDCheck(): boolean {
let currentVideoID = getYouTubeVideoID(document.URL);
if (currentVideoID !== sponsorVideoID) {
// 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);
// Video ID change occured
videoIDChange(currentVideoID);
return true;
} else {
return false;
}
}
function sponsorsLookup(id: string) {
video = document.querySelector('video') // Youtube video player video = document.querySelector('video') // Youtube video player
//there is no video here //there is no video here
if (video == null) { if (video == null) {
setTimeout(() => sponsorsLookup(id, channelIDPromise), 100); setTimeout(() => sponsorsLookup(id), 100);
return; return;
} }
@@ -578,18 +594,6 @@ function sponsorsLookup(id: string, channelIDPromise?) {
startSponsorSchedule(); startSponsorSchedule();
} }
if (channelIDPromise !== undefined) {
if (channelIDPromise.isFulfilled) {
whitelistCheck();
} else if (channelIDPromise.isRejected) {
//try again
utils.wait(getChannelID).then(whitelistCheck).catch();
} else {
//add it as a then statement
channelIDPromise.then(whitelistCheck);
}
}
//check database for sponsor times //check database for sponsor times
//made true once a setTimeout has been created to try again after a server error //made true once a setTimeout has been created to try again after a server error
let recheckStarted = false; let recheckStarted = false;
@@ -624,43 +628,16 @@ function sponsorsLookup(id: string, channelIDPromise?) {
sponsorTimes = recievedSegments; sponsorTimes = recievedSegments;
// Remove all submissions smaller than the minimum duration // Hide all submissions smaller than the minimum duration
if (Config.config.minDuration !== 0) { if (Config.config.minDuration !== 0) {
let smallSegments: SponsorTime[] = [];
for (let i = 0; i < sponsorTimes.length; i++) { for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i].segment[1] - sponsorTimes[i].segment[0] >= Config.config.minDuration) { if (sponsorTimes[i].segment[1] - sponsorTimes[i].segment[0] < Config.config.minDuration) {
smallSegments.push(sponsorTimes[i]); sponsorTimes[i].hidden = SponsorHideType.MinimumDuration;
} }
} }
sponsorTimes = smallSegments;
} }
if (!switchingVideos) { startSkipScheduleCheckingForStartSponsors();
// See if there are any starting sponsors
let startingSponsor: number = -1;
for (const time of sponsorTimes) {
if (time[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
startingSponsor = time.segment[0];
break;
}
}
if (!startingSponsor) {
for (const time of sponsorTimesSubmitting) {
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
startingSponsor = time.segment[0];
break;
}
}
}
if (startingSponsor !== -1) {
startSponsorSchedule(false, startingSponsor);
} else {
startSponsorSchedule();
}
}
// Reset skip save // Reset skip save
sponsorSkipped = []; sponsorSkipped = [];
@@ -678,23 +655,13 @@ function sponsorsLookup(id: string, channelIDPromise?) {
sponsorDataFound = false; sponsorDataFound = false;
//check if this video was uploaded recently //check if this video was uploaded recently
//use the invidious api to get the time published utils.wait(() => !!videoInfo).then(() => {
sendRequestToCustomServer('GET', "https://www.youtube.com/get_video_info?video_id=" + id, function(xmlhttp, error) { let dateUploaded = videoInfo.microformat.playerMicroformatRenderer.uploadDate;
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let decodedData = decodeURIComponent(xmlhttp.responseText).match(/player_response=([^&]*)/)[1];
if (decodedData === undefined) { //if less than 3 days old
console.error("[SB] Failed at getting video upload date info from YouTube."); if (Date.now() - new Date(dateUploaded).getTime() < 259200000) {
return; //TODO lower when server becomes better
} setTimeout(() => sponsorsLookup(id), 180000);
let dateUploaded = JSON.parse(decodedData).microformat.playerMicroformatRenderer.uploadDate;
//if less than 3 days old
if (Date.now() - new Date(dateUploaded).getTime() < 259200000) {
//TODO lower when server becomes better
setTimeout(() => sponsorsLookup(id, channelIDPromise), 180000);
}
} }
}); });
@@ -704,13 +671,62 @@ function sponsorsLookup(id: string, channelIDPromise?) {
//TODO lower when server becomes better (back to 1 second) //TODO lower when server becomes better (back to 1 second)
//some error occurred, try again in a second //some error occurred, try again in a second
setTimeout(() => sponsorsLookup(id, channelIDPromise), 10000); setTimeout(() => sponsorsLookup(id), 10000);
sponsorLookupRetries++; sponsorLookupRetries++;
} }
}); });
} }
/**
* Only should be used when it is okay to skip a sponsor when in the middle of it
*
* Ex. When segments are first loaded
*/
function startSkipScheduleCheckingForStartSponsors() {
if (!switchingVideos) {
// See if there are any starting sponsors
let startingSponsor: number = -1;
for (const time of sponsorTimes) {
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
startingSponsor = time.segment[0];
break;
}
}
if (startingSponsor === -1) {
for (const time of sponsorTimesSubmitting) {
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSponsor && time.segment[1] > video.currentTime) {
startingSponsor = time.segment[0];
break;
}
}
}
if (startingSponsor !== -1) {
startSponsorSchedule(false, startingSponsor);
} else {
startSponsorSchedule();
}
}
}
/**
* Get the video info for the current tab from YouTube
*/
function getVideoInfo() {
sendRequestToCustomServer('GET', "https://www.youtube.com/get_video_info?video_id=" + sponsorVideoID, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let decodedData = decodeURIComponent(xmlhttp.responseText).match(/player_response=([^&]*)/)[1];
if (!decodedData) {
console.error("[SB] Failed at getting video info from YouTube.");
return;
}
videoInfo = JSON.parse(decodedData);
}
});
}
function getYouTubeVideoID(url: string) { function getYouTubeVideoID(url: string) {
// For YouTube TV support // For YouTube TV support
if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", ""); if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", "");
@@ -753,55 +769,6 @@ function getYouTubeVideoID(url: string) {
return false; return false;
} }
function getChannelID() {
//get channel id
let channelURLContainer = null;
channelURLContainer = document.querySelector("#channel-name > #container > #text-container > #text");
if (channelURLContainer !== null) {
channelURLContainer = channelURLContainer.firstElementChild;
} else if (onInvidious) {
// Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers...
channelURLContainer = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a");
} else {
//old YouTube theme
let channelContainers = document.getElementsByClassName("yt-user-info");
if (channelContainers.length != 0) {
channelURLContainer = channelContainers[0].firstElementChild;
}
}
if (channelURLContainer === null) {
//try later
return false;
}
//first get the title to make sure a title change has occurred (otherwise the next video might still be loading)
let titleInfoContainer = document.getElementById("info-contents");
let currentTitle = "";
if (titleInfoContainer != null) {
currentTitle = (<HTMLElement> titleInfoContainer.firstElementChild.firstElementChild.querySelector(".title").firstElementChild).innerText;
} else if (onInvidious) {
// Unfortunately, the Invidious HTML doesn't have much in the way of element identifiers...
currentTitle = document.querySelector("body > div > div.pure-u-1.pure-u-md-20-24 div.pure-u-1.pure-u-lg-3-5 > div > a > div > span").textContent;
} else {
//old YouTube theme
currentTitle = document.getElementById("eow-title").innerText;
}
if (title == currentTitle) {
//video hasn't changed yet, wait
//try later
return false;
}
title = currentTitle;
channelURL = channelURLContainer.getAttribute("href");
//reset variables
channelWhitelisted = false;
}
/** /**
* This function is required on mobile YouTube and will keep getting called whenever the preview bar disapears * This function is required on mobile YouTube and will keep getting called whenever the preview bar disapears
*/ */
@@ -822,7 +789,7 @@ function updatePreviewBar() {
//create an array of the sponsor types //create an array of the sponsor types
let types = []; let types = [];
for (let i = 0; i < localSponsorTimes.length; i++) { for (let i = 0; i < localSponsorTimes.length; i++) {
if (!hiddenSponsorTimes.includes(i)) { if (localSponsorTimes[i].hidden === SponsorHideType.Visible) {
types.push(localSponsorTimes[i].category); types.push(localSponsorTimes[i].category);
} else { } else {
// Don't show this sponsor // Don't show this sponsor
@@ -841,12 +808,17 @@ function updatePreviewBar() {
//checks if this channel is whitelisted, should be done only after the channelID has been loaded //checks if this channel is whitelisted, should be done only after the channelID has been loaded
function whitelistCheck() { function whitelistCheck() {
channelID = videoInfo.videoDetails.channelId;
//see if this is a whitelisted channel //see if this is a whitelisted channel
let whitelistedChannels = Config.config.whitelistedChannels; let whitelistedChannels = Config.config.whitelistedChannels;
if (whitelistedChannels != undefined && whitelistedChannels.includes(channelURL)) { if (whitelistedChannels != undefined && whitelistedChannels.includes(channelID)) {
channelWhitelisted = true; channelWhitelisted = true;
} }
// check if the start of segments were missed
if (sponsorTimes && sponsorTimes.length > 0) startSkipScheduleCheckingForStartSponsors();
} }
/** /**
@@ -856,13 +828,13 @@ function getNextSkipIndex(currentTime: number, includeIntersectingSegments: bool
{array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} { {array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} {
let sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments); let sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments);
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, currentTime, true); let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, currentTime, true, true);
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime)); let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
let endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex); let endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex);
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments); let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments);
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, currentTime, false); let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, currentTime, true, false);
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime)); let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
let previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex); let previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex);
@@ -911,7 +883,7 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
let latestEndTime = sponsorTimes[latestEndTimeIndex].segment[1]; let latestEndTime = sponsorTimes[latestEndTimeIndex].segment[1];
if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime
&& (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i)) && (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
&& utils.getCategorySelection(sponsorTimes[i].category).option === CategorySkipOption.AutoSkip) { && utils.getCategorySelection(sponsorTimes[i].category).option === CategorySkipOption.AutoSkip) {
// Overlapping segment // Overlapping segment
latestEndTimeIndex = i; latestEndTimeIndex = i;
@@ -937,14 +909,16 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
* the current time, but end after * the current time, but end after
*/ */
function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, minimum?: number, function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, minimum?: number,
hideHiddenSponsors: boolean = false): number[] { onlySkippableSponsors: boolean = false, hideHiddenSponsors: boolean = false): number[] {
if (sponsorTimes === null) return []; if (sponsorTimes === null) return [];
let startTimes: number[] = []; let startTimes: number[] = [];
for (let i = 0; i < sponsorTimes.length; i++) { for (let i = 0; i < sponsorTimes.length; i++) {
if ((minimum === undefined || (sponsorTimes[i].segment[0] >= minimum || (includeIntersectingSegments && sponsorTimes[i].segment[1] > minimum))) if ((minimum === undefined || (sponsorTimes[i].segment[0] >= minimum || (includeIntersectingSegments && sponsorTimes[i].segment[1] > minimum)))
&& (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) { && (!onlySkippableSponsors || utils.getCategorySelection(sponsorTimes[i].category).option !== CategorySkipOption.ShowOverlay)
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)) {
startTimes.push(sponsorTimes[i].segment[0]); startTimes.push(sponsorTimes[i].segment[0]);
} }
} }
@@ -1490,6 +1464,9 @@ async function sendSubmitMessage(){
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting); sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);
// Increase contribution count
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimesSubmitting.length;
// Empty the submitting times // Empty the submitting times
sponsorTimesSubmitting = []; sponsorTimesSubmitting = [];
@@ -1525,30 +1502,12 @@ function getSegmentsMessage(segments: number[][]): string {
return sponsorTimesMessage; return sponsorTimesMessage;
} }
// Privacy utils
function isPrivacyInfoAvailable(): boolean {
if(document.location.pathname.startsWith("/embed/")) return true;
return document.getElementsByClassName("style-scope ytd-badge-supported-renderer").length >= 2;
}
/**
* What privacy level is this YouTube video?
*/
function getPrivacy(): string {
if(document.location.pathname.startsWith("/embed/")) return "Public";
let privacyElement = <HTMLElement> document.getElementsByClassName("style-scope ytd-badge-supported-renderer")[2];
return privacyElement.innerText;
}
/** /**
* Is this an unlisted YouTube video. * Is this an unlisted YouTube video.
* Assumes that the the privacy info is available. * Assumes that the the privacy info is available.
*/ */
function isUnlisted(): boolean { function isUnlisted(): boolean {
let privacyElement = <HTMLElement> document.getElementsByClassName("style-scope ytd-badge-supported-renderer")[2]; return videoInfo.microformat.playerMicroformatRenderer.isUnlisted || videoInfo.videoDetails.isPrivate;
return privacyElement.innerText.toLocaleLowerCase() === "unlisted";
} }
/** /**

View File

@@ -1,7 +1,7 @@
import Config from "./config"; import Config from "./config";
import Utils from "./utils"; import Utils from "./utils";
import { SponsorTime } from "./types"; import { SponsorTime, SponsorHideType } from "./types";
var utils = new Utils(); var utils = new Utils();
interface MessageListener { interface MessageListener {
@@ -51,6 +51,7 @@ async function runThePopup(messageListener?: MessageListener) {
// Top toggles // Top toggles
"whitelistChannel", "whitelistChannel",
"unwhitelistChannel", "unwhitelistChannel",
"whitelistForceCheck",
"disableSkipping", "disableSkipping",
"enableSkipping", "enableSkipping",
// Options // Options
@@ -102,6 +103,7 @@ async function runThePopup(messageListener?: MessageListener) {
//setup click listeners //setup click listeners
PageElements.sponsorStart.addEventListener("click", sendSponsorStartMessage); PageElements.sponsorStart.addEventListener("click", sendSponsorStartMessage);
PageElements.whitelistChannel.addEventListener("click", whitelistChannel); PageElements.whitelistChannel.addEventListener("click", whitelistChannel);
PageElements.whitelistForceCheck.addEventListener("click", openOptions);
PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel); PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel);
PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true)); PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true));
PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false)); PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false));
@@ -273,7 +275,7 @@ async function runThePopup(messageListener?: MessageListener) {
); );
} }
function infoFound(request: {found: boolean, sponsorTimes: SponsorTime[], hiddenSponsorTimes: number[]}) { function infoFound(request: {found: boolean, sponsorTimes: SponsorTime[]}) {
if(chrome.runtime.lastError) { if(chrome.runtime.lastError) {
//This page doesn't have the injected content script, or at least not yet //This page doesn't have the injected content script, or at least not yet
displayNoVideo(); displayNoVideo();
@@ -364,7 +366,7 @@ async function runThePopup(messageListener?: MessageListener) {
} }
//display the video times from the array at the top, in a different section //display the video times from the array at the top, in a different section
function displayDownloadedSponsorTimes(request: {found: boolean, sponsorTimes: SponsorTime[], hiddenSponsorTimes: number[]}) { function displayDownloadedSponsorTimes(request: {found: boolean, sponsorTimes: SponsorTime[]}) {
if (request.sponsorTimes != undefined) { if (request.sponsorTimes != undefined) {
//set it to the message //set it to the message
if (PageElements.downloadedSponsorMessageTimes.innerText != chrome.i18n.getMessage("channelWhitelisted")) { if (PageElements.downloadedSponsorMessageTimes.innerText != chrome.i18n.getMessage("channelWhitelisted")) {
@@ -378,9 +380,12 @@ async function runThePopup(messageListener?: MessageListener) {
sponsorTimeButton.className = "warningButton popupElement"; sponsorTimeButton.className = "warningButton popupElement";
let extraInfo = ""; let extraInfo = "";
if (request.hiddenSponsorTimes.includes(i)) { if (request.sponsorTimes[i].hidden === SponsorHideType.Downvoted) {
//this one is hidden //this one is downvoted
extraInfo = " (hidden)"; extraInfo = " (" + chrome.i18n.getMessage("hiddenDueToDownvote") + ")";
} else if (request.sponsorTimes[i].hidden === SponsorHideType.MinimumDuration) {
//this one is too short
extraInfo = " (" + chrome.i18n.getMessage("hiddenDueToDuration") + ")";
} }
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i].segment[0]) + " to " + getFormattedTime(request.sponsorTimes[i].segment[1]) + extraInfo; sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i].segment[0]) + " to " + getFormattedTime(request.sponsorTimes[i].segment[1]) + extraInfo;
@@ -445,6 +450,14 @@ async function runThePopup(messageListener?: MessageListener) {
timeMessage = ", " + timeMessage; timeMessage = ", " + timeMessage;
} }
if (sponsorTimes[i].hidden === SponsorHideType.Downvoted) {
//this one is downvoted
timeMessage += " (" + chrome.i18n.getMessage("hiddenDueToDownvote") + ")";
} else if (sponsorTimes[i].hidden === SponsorHideType.MinimumDuration) {
//this one is too short
timeMessage += " (" + chrome.i18n.getMessage("hiddenDueToDuration") + ")";
}
sponsorTimesMessage += timeMessage; sponsorTimesMessage += timeMessage;
} }
} }
@@ -908,39 +921,46 @@ async function runThePopup(messageListener?: MessageListener) {
}, tabs => { }, tabs => {
messageHandler.sendMessage( messageHandler.sendMessage(
tabs[0].id, tabs[0].id,
{message: 'getChannelURL'}, {message: 'getChannelID'},
function(response) { function(response) {
if (!response.channelID) {
alert(chrome.i18n.getMessage("channelDataNotFound") + "\n\n" +
chrome.i18n.getMessage("itCouldBeAdblockerIssue"));
return;
}
//get whitelisted channels //get whitelisted channels
let whitelistedChannels = Config.config.whitelistedChannels; let whitelistedChannels = Config.config.whitelistedChannels;
if (whitelistedChannels == undefined) { if (whitelistedChannels == undefined) {
whitelistedChannels = []; whitelistedChannels = [];
}
//add on this channel
whitelistedChannels.push(response.channelID);
//change button
PageElements.whitelistChannel.style.display = "none";
PageElements.unwhitelistChannel.style.display = "unset";
if (!Config.config.forceChannelCheck) PageElements.whitelistForceCheck.style.display = "unset";
PageElements.downloadedSponsorMessageTimes.innerText = chrome.i18n.getMessage("channelWhitelisted");
PageElements.downloadedSponsorMessageTimes.style.fontWeight = "bold";
//save this
Config.config.whitelistedChannels = whitelistedChannels;
//send a message to the client
messageHandler.query({
active: true,
currentWindow: true
}, tabs => {
messageHandler.sendMessage(
tabs[0].id, {
message: 'whitelistChange',
value: true
});
} }
);
//add on this channel
whitelistedChannels.push(response.channelURL);
//change button
PageElements.whitelistChannel.style.display = "none";
PageElements.unwhitelistChannel.style.display = "unset";
PageElements.downloadedSponsorMessageTimes.innerText = chrome.i18n.getMessage("channelWhitelisted");
PageElements.downloadedSponsorMessageTimes.style.fontWeight = "bold";
//save this
Config.config.whitelistedChannels = whitelistedChannels;
//send a message to the client
messageHandler.query({
active: true,
currentWindow: true
}, tabs => {
messageHandler.sendMessage(
tabs[0].id, {
message: 'whitelistChange',
value: true
});
}
);
} }
); );
}); });
@@ -954,7 +974,7 @@ async function runThePopup(messageListener?: MessageListener) {
}, tabs => { }, tabs => {
messageHandler.sendMessage( messageHandler.sendMessage(
tabs[0].id, tabs[0].id,
{message: 'getChannelURL'}, {message: 'getChannelID'},
function(response) { function(response) {
//get whitelisted channels //get whitelisted channels
let whitelistedChannels = Config.config.whitelistedChannels; let whitelistedChannels = Config.config.whitelistedChannels;
@@ -963,7 +983,7 @@ async function runThePopup(messageListener?: MessageListener) {
} }
//remove this channel //remove this channel
let index = whitelistedChannels.indexOf(response.channelURL); let index = whitelistedChannels.indexOf(response.channelID);
whitelistedChannels.splice(index, 1); whitelistedChannels.splice(index, 1);
//change button //change button

View File

@@ -8,7 +8,6 @@ interface ContentContainer {
unskipSponsorTime: (UUID: any) => void, unskipSponsorTime: (UUID: any) => void,
sponsorTimes: SponsorTime[], sponsorTimes: SponsorTime[],
sponsorTimesSubmitting: SponsorTime[], sponsorTimesSubmitting: SponsorTime[],
hiddenSponsorTimes: number[],
v: HTMLVideoElement, v: HTMLVideoElement,
sponsorVideoID, sponsorVideoID,
reskipSponsorTime: (UUID: any) => void, reskipSponsorTime: (UUID: any) => void,
@@ -36,11 +35,19 @@ interface CategorySelection {
option: CategorySkipOption option: CategorySkipOption
} }
enum SponsorHideType {
Visible = undefined,
Downvoted = 1,
MinimumDuration
}
interface SponsorTime { interface SponsorTime {
segment: number[]; segment: number[];
UUID: string; UUID: string;
category: string; category: string;
hidden?: SponsorHideType;
} }
type VideoID = string; type VideoID = string;
@@ -51,5 +58,6 @@ export {
CategorySelection, CategorySelection,
CategorySkipOption, CategorySkipOption,
SponsorTime, SponsorTime,
VideoID VideoID,
SponsorHideType
}; };

View File

@@ -270,27 +270,26 @@ class Utils {
} }
/** /**
* Sends a request to the SponsorBlock server with address added as a query * Sends a request to a custom server
* *
* @param type The request type. "GET", "POST", etc. * @param type The request type. "GET", "POST", etc.
* @param address The address to add to the SponsorBlock server address * @param address The address to add to the SponsorBlock server address
* @param callback * @param callback
*/ */
async asyncRequestToServer(type: string, address: string, data = {}) { async asyncRequestToCustomServer(type: string, url: string, data = {}) {
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
// If GET, convert JSON to parameters // If GET, convert JSON to parameters
if (type.toLowerCase() === "get") { if (type.toLowerCase() === "get") {
for (const key in data) { for (const key in data) {
let seperator = address.includes("?") ? "&" : "?"; let seperator = url.includes("?") ? "&" : "?";
let value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]); let value = (typeof(data[key]) === "string") ? data[key]: JSON.stringify(data[key]);
address += seperator + key + "=" + value; url += seperator + key + "=" + value;
} }
data = null; data = null;
} }
const response = await fetch(serverAddress + address, { const response = await fetch(url, {
method: type, method: type,
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@@ -302,6 +301,19 @@ class Utils {
return response; return response;
} }
/**
* Sends a request to the SponsorBlock server with address added as a query
*
* @param type The request type. "GET", "POST", etc.
* @param address The address to add to the SponsorBlock server address
* @param callback
*/
async asyncRequestToServer(type: string, address: string, data = {}) {
let serverAddress = Config.config.testingServer ? CompileConfig.testingServerAddress : Config.config.serverAddress;
return await (this.asyncRequestToCustomServer(type, serverAddress + address, data));
}
/** /**
* Sends a request to the SponsorBlock server with address added as a query * Sends a request to the SponsorBlock server with address added as a query
* *
@@ -361,10 +373,14 @@ class Utils {
return minutes * 60 + seconds; return minutes * 60 + seconds;
} }
isContentScript(): boolean {
return window.location.protocol === "http:" || window.location.protocol === "https:";
}
/** /**
* Is this Firefox (web-extensions) * Is this Firefox (web-extensions)
*/ */
isFirefox() { isFirefox(): boolean {
return typeof(browser) !== "undefined"; return typeof(browser) !== "undefined";
} }
} }