diff --git a/src/background.ts b/src/background.ts index 3b55743b..9391d610 100644 --- a/src/background.ts +++ b/src/background.ts @@ -24,7 +24,7 @@ if (utils.isFirefox()) { utils.wait(() => Config.config !== null).then(function() { if (Config.config.supportInvidious) utils.setupExtraSiteContentScripts(); }); -} +} function onTabUpdatedListener(tabId: number) { chrome.tabs.sendMessage(tabId, { @@ -77,17 +77,17 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) { ok: response.ok }); }); - + return true; case "submitVote": submitVote(request.type, request.UUID, request.category).then(callback); - + //this allows the callback to be called later return true; - case "registerContentScript": + case "registerContentScript": registerFirefoxContentScript(request); return false; - case "unregisterContentScript": + case "unregisterContentScript": unregisterFirefoxContentScript(request.id) return false; case "tabs": { @@ -106,6 +106,8 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) { return true; } case "time": + case "infoUpdated": + case "videoChanged": if (sender.tab) { popupPort[sender.tab.id]?.postMessage(request); } @@ -156,8 +158,8 @@ chrome.runtime.onInstalled.addListener(function () { /** * Only works on Firefox. * Firefox requires that it be applied after every extension restart. - * - * @param {JSON} options + * + * @param {JSON} options */ function registerFirefoxContentScript(options: Registration) { const oldRegistration = contentScriptRegistrations[options.id]; @@ -174,7 +176,7 @@ function registerFirefoxContentScript(options: Registration) { /** * Only works on Firefox. * Firefox requires that this is handled by the background script - * + * */ function unregisterFirefoxContentScript(id: string) { contentScriptRegistrations[id].unregister(); @@ -225,10 +227,10 @@ async function asyncRequestToServer(type: string, address: string, data = {}) { /** * Sends a request to the specified url - * + * * @param type The request type "GET", "POST", etc. * @param address The address to add to the SponsorBlock server address - * @param callback + * @param callback */ async function sendRequestToCustomServer(type: string, url: string, data = {}) { // If GET, convert JSON to parameters @@ -248,4 +250,4 @@ async function sendRequestToCustomServer(type: string, url: string, data = {}) { }); return response; -} \ No newline at end of file +} diff --git a/src/content.ts b/src/content.ts index 2c65e4d6..7458edf7 100644 --- a/src/content.ts +++ b/src/content.ts @@ -215,7 +215,6 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo case "getVideoID": sendResponse({ videoID: sponsorVideoID, - creatingSegment: isSegmentCreationInProgress(), }); break; @@ -243,15 +242,9 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo // update video on refresh if videoID invalid if (!sponsorVideoID) videoIDChange(getYouTubeVideoID(document)); // fetch segments - sponsorsLookup(false).then(() => sendResponse({ - found: sponsorDataFound, - status: lastResponseStatus, - sponsorTimes: sponsorTimes, - time: video.currentTime, - onMobileYouTube - })); + sponsorsLookup(false); - return true; + break; case "unskip": unskipSponsorTime(sponsorTimes.find((segment) => segment.UUID === request.UUID), null, true); break; @@ -384,7 +377,7 @@ function resetValues() { categoryPill?.setVisibility(false); } -async function videoIDChange(id): Promise { +async function videoIDChange(id: string): Promise { // don't switch to invalid value if (!id && sponsorVideoID && !document?.URL?.includes("youtube.com/clip/")) return; //if the id has not changed return unless the video element has changed @@ -438,10 +431,14 @@ async function videoIDChange(id): Promise { } } - //close popup - closeInfoMenu(); + // Notify the popup about the video change + chrome.runtime.sendMessage({ + message: "videoChanged", + videoID: sponsorVideoID, + whitelisted: channelWhitelisted + }); - sponsorsLookup(id); + sponsorsLookup(); // Make sure all player buttons are properly added updateVisibilityOfPlayerControlsButton(); @@ -1004,6 +1001,14 @@ async function sponsorsLookup(keepOldSubmissions = true) { ?.sort((a, b) => a.segment[0] - b.segment[0]); if (!recievedSegments || !recievedSegments.length) { // return if no video found + chrome.runtime.sendMessage({ + message: "infoUpdated", + found: false, + status: lastResponseStatus, + sponsorTimes: sponsorTimes, + time: video.currentTime, + onMobileYouTube + }); retryFetch(404); return; } @@ -1093,6 +1098,16 @@ async function sponsorsLookup(keepOldSubmissions = true) { importExistingChapters(true); + // notify popup of segment changes + chrome.runtime.sendMessage({ + message: "infoUpdated", + found: sponsorDataFound, + status: lastResponseStatus, + sponsorTimes: sponsorTimes, + time: video.currentTime, + onMobileYouTube + }); + if (Config.config.isVip) { lockedCategoriesLookup(); } @@ -1138,8 +1153,8 @@ async function lockedCategoriesLookup(): Promise { } function retryFetch(errorCode: number): void { - if (!Config.config.refetchWhenNotFound) return; sponsorDataFound = false; + if (!Config.config.refetchWhenNotFound) return; if (retryFetchTimeout) clearTimeout(retryFetchTimeout); if ((errorCode !== 404 && retryCount > 1) || (errorCode !== 404 && retryCount > 10)) { @@ -1219,12 +1234,12 @@ function startSkipScheduleCheckingForStartSponsors() { } } -function getYouTubeVideoID(document: Document, url?: string): string | boolean { +function getYouTubeVideoID(document: Document, url?: string): string { url ||= document.URL; // pageType shortcut - if (pageType === PageType.Channel) return getYouTubeVideoIDFromDocument() + if (pageType === PageType.Channel) return getYouTubeVideoIDFromDocument(); // clips should never skip, going from clip to full video has no indications. - if (url.includes("youtube.com/clip/")) return false; + if (url.includes("youtube.com/clip/")) return null; // skip to document and don't hide if on /embed/ if (url.includes("/embed/") && url.includes("youtube.com")) return getYouTubeVideoIDFromDocument(false, PageType.Embed); // skip to URL if matches youtube watch or invidious or matches youtube pattern @@ -1235,7 +1250,7 @@ function getYouTubeVideoID(document: Document, url?: string): string | boolean { return getYouTubeVideoIDFromURL(url) || getYouTubeVideoIDFromDocument(false); } -function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watch): string | boolean { +function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watch): string { const selector = "a.ytp-title-link[data-sessionlink='feature=player-title']"; // get ID from document (channel trailer / embedded playlist) const element = pageHint === PageType.Embed ? document.querySelector(selector) @@ -1247,11 +1262,11 @@ function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watc pageType = pageHint; return getYouTubeVideoIDFromURL(videoURL); } else { - return false; + return null; } } -function getYouTubeVideoIDFromURL(url: string): string | boolean { +function getYouTubeVideoIDFromURL(url: string): string { if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", ""); //Attempt to parse url @@ -1260,7 +1275,7 @@ function getYouTubeVideoIDFromURL(url: string): string | boolean { urlObject = new URL(url); } catch (e) { console.error("[SB] Unable to parse URL: " + url); - return false; + return null; } // Check if valid hostname @@ -1274,7 +1289,7 @@ function getYouTubeVideoIDFromURL(url: string): string | boolean { utils.wait(() => Config.config !== null).then(() => videoIDChange(getYouTubeVideoIDFromURL(url))); } - return false; + return null; } else { onInvidious = false; } @@ -1282,17 +1297,17 @@ function getYouTubeVideoIDFromURL(url: string): string | boolean { //Get ID from searchParam if (urlObject.searchParams.has("v") && ["/watch", "/watch/"].includes(urlObject.pathname) || urlObject.pathname.startsWith("/tv/watch")) { const id = urlObject.searchParams.get("v"); - return id.length == 11 ? id : false; + return id.length == 11 ? id : null; } else if (urlObject.pathname.startsWith("/embed/") || urlObject.pathname.startsWith("/shorts/")) { try { const id = urlObject.pathname.split("/")[2] if (id?.length >=11 ) return id.slice(0, 11); } catch (e) { console.error("[SB] Video ID not valid for " + url); - return false; + return null; } } - return false; + return null; } /** @@ -1794,7 +1809,8 @@ async function updateVisibilityOfPlayerControlsButton(): Promise { updateEditButtonsOnPlayer(); // Don't show the info button on embeds - if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) { + if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious + || document.getElementById("sponsorBlockPopupContainer") != null) { playerButtons.info.button.style.display = "none"; } else { playerButtons.info.button.style.removeProperty("display"); diff --git a/src/messageTypes.ts b/src/messageTypes.ts index c48aba34..78cf59cf 100644 --- a/src/messageTypes.ts +++ b/src/messageTypes.ts @@ -9,7 +9,7 @@ interface BaseMessage { } interface DefaultMessage { - message: + message: "update" | "sponsorStart" | "getVideoID" @@ -83,19 +83,19 @@ interface GetVideoIdResponse { videoID: string; } -interface GetChannelIDResponse { +export interface GetChannelIDResponse { channelID: string; } -interface SponsorStartResponse { +export interface SponsorStartResponse { creatingSegment: boolean; } -interface IsChannelWhitelistedResponse { +export interface IsChannelWhitelistedResponse { value: boolean; } -export type MessageResponse = +export type MessageResponse = IsInfoFoundMessageResponse | GetVideoIdResponse | GetChannelIDResponse @@ -111,7 +111,7 @@ export interface VoteResponse { responseText: string; } -export interface ImportSegmentsResponse { +interface ImportSegmentsResponse { importedSegments: SponsorTime[]; } @@ -120,4 +120,14 @@ export interface TimeUpdateMessage { time: number; } -export type PopupMessage = TimeUpdateMessage; +export type InfoUpdatedMessage = IsInfoFoundMessageResponse & { + message: "infoUpdated"; +} + +export interface VideoChangedPopupMessage { + message: "videoChanged"; + videoID: string; + whitelisted: boolean; +} + +export type PopupMessage = TimeUpdateMessage | InfoUpdatedMessage | VideoChangedPopupMessage; diff --git a/src/popup.ts b/src/popup.ts index 338ecfcd..ede826e2 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -1,8 +1,24 @@ import Config from "./config"; import Utils from "./utils"; -import { SponsorTime, SponsorHideType, ActionType, SegmentUUID, SponsorSourceType, StorageChangesObject } from "./types"; -import { Message, MessageResponse, IsInfoFoundMessageResponse, ImportSegmentsResponse, PopupMessage } from "./messageTypes"; +import { + ActionType, + SegmentUUID, + SponsorHideType, + SponsorSourceType, + SponsorTime, + StorageChangesObject, +} from "./types"; +import { + GetChannelIDResponse, + IsChannelWhitelistedResponse, + IsInfoFoundMessageResponse, + Message, + MessageResponse, + PopupMessage, + SponsorStartResponse, + VoteResponse, +} from "./messageTypes"; import { showDonationLink } from "./utils/configUtils"; import { AnimationUtils } from "./utils/animationUtils"; import { GenericUtils } from "./utils/genericUtils"; @@ -11,6 +27,7 @@ import { localizeHtmlPage } from "./utils/pageUtils"; import { exportTimes } from "./utils/exporter"; import GenericNotice from "./render/GenericNotice"; import { noRefreshFetchingChaptersAllowed } from "./utils/licenseKey"; + const utils = new Utils(); interface MessageListener { @@ -67,8 +84,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { }; type PageElements = { [key: string]: HTMLElement } & InputPageElements - /** If true, the content script is in the process of creating a new segment. */ - let creatingSegment = false; + let stopLoadingAnimation = null; //the start and end time pairs (2d) let sponsorTimes: SponsorTime[] = []; @@ -188,7 +204,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { } PageElements.exportSegmentsButton.addEventListener("click", exportSegments); - PageElements.importSegmentsButton.addEventListener("click", + PageElements.importSegmentsButton.addEventListener("click", () => PageElements.importSegmentsMenu.classList.toggle("hidden")); PageElements.importSegmentsSubmit.addEventListener("click", importSegments); @@ -260,7 +276,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { if (dontShowNotice != undefined && dontShowNotice) { PageElements.showNoticeAgain.style.display = "unset"; } - + const values = ["userName", "viewCount", "minutesSaved", "vip", "permissions"]; if (!Config.config.payments.freeAccess && !noRefreshFetchingChaptersAllowed()) values.push("freeChaptersAccess"); @@ -376,7 +392,6 @@ async function runThePopup(messageListener?: MessageListener): Promise { messageHandler.sendMessage(tabs[0].id, { message: 'getVideoID' }, function (result) { if (result !== undefined && result.videoID) { currentVideoID = result.videoID; - creatingSegment = result.creatingSegment; loadTabData(tabs, updating); } else if (result === undefined && chrome.runtime.lastError) { @@ -411,7 +426,13 @@ async function runThePopup(messageListener?: MessageListener): Promise { }, (tabs) => onTabs(tabs, updating)); } - function infoFound(request: IsInfoFoundMessageResponse) { + async function infoFound(request: IsInfoFoundMessageResponse) { + // End any loading animation + if (stopLoadingAnimation != null) { + stopLoadingAnimation(); + stopLoadingAnimation = null; + } + if (chrome.runtime.lastError) { //This page doesn't have the injected content script, or at least not yet displayNoVideo(); @@ -427,13 +448,10 @@ async function runThePopup(messageListener?: MessageListener): Promise { PageElements.loadingIndicator.style.display = "none"; downloadedTimes = request.sponsorTimes ?? []; + displayDownloadedSponsorTimes(downloadedTimes, request.time); if (request.found) { PageElements.videoFound.innerHTML = chrome.i18n.getMessage("sponsorFound"); - PageElements.issueReporterImportExport.classList.remove("hidden"); - if (request.sponsorTimes) { - displayDownloadedSponsorTimes(request.sponsorTimes, request.time); - } } else if (request.status == 404 || request.status == 200) { PageElements.videoFound.innerHTML = chrome.i18n.getMessage("sponsor404"); PageElements.issueReporterImportExport.classList.remove("hidden"); @@ -444,62 +462,40 @@ async function runThePopup(messageListener?: MessageListener): Promise { } //see if whitelist button should be swapped - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { message: 'isChannelWhitelisted' }, - function (response) { - if (response.value) { - PageElements.whitelistChannel.style.display = "none"; - PageElements.unwhitelistChannel.style.display = "unset"; - PageElements.whitelistToggle.checked = true; - document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated"); - } - }); + const response = await sendTabMessageAsync({ message: 'isChannelWhitelisted' }) as IsChannelWhitelistedResponse; + if (response.value) { + PageElements.whitelistChannel.style.display = "none"; + PageElements.unwhitelistChannel.style.display = "unset"; + PageElements.whitelistToggle.checked = true; + document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated"); } - ); } - function sendSponsorStartMessage() { + async function sendSponsorStartMessage() { //the content script will get the message if a YouTube page is open - messageHandler.query({ - active: true, - currentWindow: true, - }, (tabs) => { - messageHandler.sendMessage( - tabs[0].id, - { from: 'popup', message: 'sponsorStart' }, - async (response) => { - startSponsorCallback(response); + const response = await sendTabMessageAsync({ from: 'popup', message: 'sponsorStart' }) as SponsorStartResponse; + startSponsorCallback(response); - // Perform a second update after the config changes take effect as a workaround for a race condition - const removeListener = (listener: typeof lateUpdate) => { - const index = Config.configSyncListeners.indexOf(listener); - if (index !== -1) Config.configSyncListeners.splice(index, 1); - }; + // Perform a second update after the config changes take effect as a workaround for a race condition + const removeListener = (listener: typeof lateUpdate) => { + const index = Config.configSyncListeners.indexOf(listener); + if (index !== -1) Config.configSyncListeners.splice(index, 1); + }; - const lateUpdate = () => { - startSponsorCallback(response); - removeListener(lateUpdate); - }; + const lateUpdate = () => { + startSponsorCallback(response); + removeListener(lateUpdate); + }; - Config.configSyncListeners.push(lateUpdate); + Config.configSyncListeners.push(lateUpdate); - // Remove the listener after 200ms in case the changes were propagated by the time we got the response - setTimeout(() => removeListener(lateUpdate), 200); - }, - ); - }); + // Remove the listener after 200ms in case the changes were propagated by the time we got the response + setTimeout(() => removeListener(lateUpdate), 200); } - function startSponsorCallback(response: { creatingSegment: boolean }) { - creatingSegment = response.creatingSegment; - + function startSponsorCallback(response: SponsorStartResponse) { // Only update the segments after a segment was created - if (!creatingSegment) { + if (!response.creatingSegment) { sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] || []; } @@ -514,7 +510,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { PageElements.issueReporterTabs.classList.add("hidden"); currentSegmentTab = SegmentTab.Segments; } else { - if (currentSegmentTab === SegmentTab.Segments + if (currentSegmentTab === SegmentTab.Segments && sponsorTimes.every((segment) => segment.actionType === ActionType.Chapter)) { PageElements.issueReporterTabs.classList.add("hidden"); currentSegmentTab = SegmentTab.Chapters; @@ -529,7 +525,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { if (currentSegmentTab === SegmentTab.Segments) { return segment.actionType !== ActionType.Chapter; } else if (currentSegmentTab === SegmentTab.Chapters) { - return segment.actionType === ActionType.Chapter + return segment.actionType === ActionType.Chapter && segment.source !== SponsorSourceType.YouTube; } else { return true; @@ -546,7 +542,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { if (downloadedTimes.length > 0) { PageElements.exportSegmentsButton.classList.remove("hidden"); - } else { + } else { PageElements.exportSegmentsButton.classList.add("hidden"); } @@ -590,7 +586,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { if (downloadedTimes[i].actionType === ActionType.Full) { segmentTimeFromToNode.innerText = chrome.i18n.getMessage("full"); } else { - segmentTimeFromToNode.innerText = GenericUtils.getFormattedTime(downloadedTimes[i].segment[0], true) + + segmentTimeFromToNode.innerText = GenericUtils.getFormattedTime(downloadedTimes[i].segment[0], true) + (actionType !== ActionType.Poi ? " " + chrome.i18n.getMessage("to") + " " + GenericUtils.getFormattedTime(downloadedTimes[i].segment[1], true) : ""); @@ -676,26 +672,18 @@ async function runThePopup(messageListener?: MessageListener): Promise { downloadedTimes[i].hidden = SponsorHideType.Hidden; } - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { - message: "hideSegment", - type: downloadedTimes[i].hidden, - UUID: UUID - } - ); - }); + sendTabMessage({ + message: "hideSegment", + type: downloadedTimes[i].hidden, + UUID: UUID + }) }); const skipButton = document.createElement("img"); skipButton.id = "sponsorTimesSkipButtonContainer" + UUID; skipButton.className = "voteButton"; skipButton.src = chrome.runtime.getURL("icons/skip.svg"); - skipButton.title = actionType === ActionType.Chapter ? chrome.i18n.getMessage("playChapter") + skipButton.title = actionType === ActionType.Chapter ? chrome.i18n.getMessage("playChapter") : chrome.i18n.getMessage("skipSegment"); skipButton.addEventListener("click", () => skipSegment(actionType, UUID, skipButton)); votingButtons.addEventListener("dblclick", () => skipSegment(actionType, UUID)); @@ -733,15 +721,7 @@ async function runThePopup(messageListener?: MessageListener): Promise { function submitTimes() { if (sponsorTimes.length > 0) { - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { message: 'submitTimes' }, - ); - }); + sendTabMessage({ message: 'submitTimes' }) } } @@ -751,9 +731,16 @@ async function runThePopup(messageListener?: MessageListener): Promise { PageElements.showNoticeAgain.style.display = "none"; } + function isCreatingSegment(): boolean { + const segments = Config.config.unsubmittedSegments[currentVideoID]; + if (!segments) return false; + const lastSegment = segments[segments.length - 1]; + return lastSegment && lastSegment?.segment?.length !== 2; + } + /** Updates any UI related to segment editing and submission according to the current state. */ function updateSegmentEditingUI() { - PageElements.sponsorStart.innerText = chrome.i18n.getMessage(creatingSegment ? "sponsorEnd" : "sponsorStart"); + PageElements.sponsorStart.innerText = chrome.i18n.getMessage(isCreatingSegment() ? "sponsorEnd" : "sponsorStart"); PageElements.submitTimes.style.display = sponsorTimes && sponsorTimes.length > 0 ? "unset" : "none"; PageElements.submissionHint.style.display = sponsorTimes && sponsorTimes.length > 0 ? "unset" : "none"; @@ -772,20 +759,22 @@ async function runThePopup(messageListener?: MessageListener): Promise { chrome.runtime.sendMessage({ "message": "openHelp" }); } - function sendTabMessage(data: Message): Promise { - return new Promise((resolve) => { - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - data, - (response) => resolve(response) - ); - } + function sendTabMessage(data: Message, callback?) { + messageHandler.query({ + active: true, + currentWindow: true + }, tabs => { + messageHandler.sendMessage( + tabs[0].id, + data, + callback ); - }); + } + ); + } + + function sendTabMessageAsync(data: Message): Promise { + return new Promise((resolve) => sendTabMessage(data, (response) => resolve(response))) } //make the options username setting option visible @@ -862,186 +851,122 @@ async function runThePopup(messageListener?: MessageListener): Promise { thanksForVotingText.removeAttribute("innerText"); } - function vote(type, UUID) { + async function vote(type, UUID) { //add loading info addVoteMessage(chrome.i18n.getMessage("Loading"), UUID); + const response = await sendTabMessageAsync({ + message: "submitVote", + type: type, + UUID: UUID + }) as VoteResponse; - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { - message: "submitVote", - type: type, - UUID: UUID - }, function (response) { - if (response != undefined) { - //see if it was a success or failure - if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) { - //success (treat rate limits as a success) - addVoteMessage(chrome.i18n.getMessage("voted"), UUID); - } else if (response.successType == -1) { - addVoteMessage(GenericUtils.getErrorMessage(response.statusCode, response.responseText), UUID); - } - setTimeout(() => removeVoteMessage(UUID), 1500); - } - } - ); + if (response != undefined) { + //see if it was a success or failure + if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) { + //success (treat rate limits as a success) + addVoteMessage(chrome.i18n.getMessage("voted"), UUID); + } else if (response.successType == -1) { + addVoteMessage(GenericUtils.getErrorMessage(response.statusCode, response.responseText), UUID); + } + setTimeout(() => removeVoteMessage(UUID), 1500); + } + } + + async function whitelistChannel() { + //get the channel url + const response = await sendTabMessageAsync({ message: 'getChannelID' }) as GetChannelIDResponse; + if (!response.channelID) { + alert(chrome.i18n.getMessage("channelDataNotFound") + " https://github.com/ajayyy/SponsorBlock/issues/753"); + return; + } + + //get whitelisted channels + let whitelistedChannels = Config.config.whitelistedChannels; + if (whitelistedChannels == undefined) { + whitelistedChannels = []; + } + + //add on this channel + whitelistedChannels.push(response.channelID); + + //change button + PageElements.whitelistChannel.style.display = "none"; + PageElements.unwhitelistChannel.style.display = "unset"; + document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated"); + + //show 'consider force channel check' alert + if (!Config.config.forceChannelCheck) PageElements.whitelistForceCheck.classList.remove("hidden"); + + //save this + Config.config.whitelistedChannels = whitelistedChannels; + + //send a message to the client + sendTabMessage({ + message: 'whitelistChange', + value: true }); } - function whitelistChannel() { + async function unwhitelistChannel() { //get the channel url - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { message: 'getChannelID' }, - function (response) { - if (!response.channelID) { - alert(chrome.i18n.getMessage("channelDataNotFound") + " https://github.com/ajayyy/SponsorBlock/issues/753"); - return; - } + const response = await sendTabMessageAsync({ message: 'getChannelID' }) as GetChannelIDResponse; - //get whitelisted channels - let whitelistedChannels = Config.config.whitelistedChannels; - if (whitelistedChannels == undefined) { - whitelistedChannels = []; - } + //get whitelisted channels + let whitelistedChannels = Config.config.whitelistedChannels; + if (whitelistedChannels == undefined) { + whitelistedChannels = []; + } - //add on this channel - whitelistedChannels.push(response.channelID); + //remove this channel + const index = whitelistedChannels.indexOf(response.channelID); + whitelistedChannels.splice(index, 1); - //change button - PageElements.whitelistChannel.style.display = "none"; - PageElements.unwhitelistChannel.style.display = "unset"; - document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated"); + //change button + PageElements.whitelistChannel.style.display = "unset"; + PageElements.unwhitelistChannel.style.display = "none"; + document.querySelectorAll('.SBWhitelistIcon')[0].classList.remove("rotated"); - //show 'consider force channel check' alert - if (!Config.config.forceChannelCheck) PageElements.whitelistForceCheck.classList.remove("hidden"); + //hide 'consider force channel check' alert + PageElements.whitelistForceCheck.classList.add("hidden"); - //save this - Config.config.whitelistedChannels = whitelistedChannels; + //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 - }); - } - ); - } - ); + //send a message to the client + sendTabMessage({ + message: 'whitelistChange', + value: false }); } - function unwhitelistChannel() { - //get the channel url - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { message: 'getChannelID' }, - function (response) { - //get whitelisted channels - let whitelistedChannels = Config.config.whitelistedChannels; - if (whitelistedChannels == undefined) { - whitelistedChannels = []; - } - - //remove this channel - const index = whitelistedChannels.indexOf(response.channelID); - whitelistedChannels.splice(index, 1); - - //change button - PageElements.whitelistChannel.style.display = "unset"; - PageElements.unwhitelistChannel.style.display = "none"; - document.querySelectorAll('.SBWhitelistIcon')[0].classList.remove("rotated"); - - //hide 'consider force channel check' alert - PageElements.whitelistForceCheck.classList.add("hidden"); - - //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: false - }); - } - ); - } - ); - }); + function startLoadingAnimation() { + stopLoadingAnimation = AnimationUtils.applyLoadingAnimation(PageElements.refreshSegmentsButton, 0.3); } function refreshSegments() { - const stopAnimation = AnimationUtils.applyLoadingAnimation(PageElements.refreshSegmentsButton, 0.3); - - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - { message: 'refreshSegments' }, - (response) => { - infoFound(response); - stopAnimation(); - } - ) - } - ); + startLoadingAnimation(); + sendTabMessage({ message: 'refreshSegments' }); } function skipSegment(actionType: ActionType, UUID: SegmentUUID, element?: HTMLElement): void { if (actionType === ActionType.Chapter) { - sendMessage({ + sendTabMessage({ message: "unskip", UUID: UUID }); } else { - sendMessage({ + sendTabMessage({ message: "reskip", UUID: UUID }); } - + if (element) { const stopAnimation = AnimationUtils.applyLoadingAnimation(element, 0.3); stopAnimation(); } } - function sendMessage(request: Message): void { - messageHandler.query({ - active: true, - currentWindow: true - }, tabs => { - messageHandler.sendMessage( - tabs[0].id, - request - ); - }); - } - /** * Should skipping be disabled (visuals stay) */ @@ -1074,10 +999,10 @@ async function runThePopup(messageListener?: MessageListener): Promise { async function importSegments() { const text = (PageElements.importSegmentsText as HTMLInputElement).value; - await sendTabMessage({ + sendTabMessage({ message: "importSegments", data: text - }) as ImportSegmentsResponse; + }); PageElements.importSegmentsMenu.classList.add("hidden"); } @@ -1142,6 +1067,27 @@ async function runThePopup(messageListener?: MessageListener): Promise { case "time": displayDownloadedSponsorTimes(downloadedTimes, msg.time); break; + case "infoUpdated": + infoFound(msg); + break; + case "videoChanged": + currentVideoID = msg.videoID + sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] ?? []; + updateSegmentEditingUI(); + + if (msg.whitelisted) { + PageElements.whitelistChannel.style.display = "none"; + PageElements.unwhitelistChannel.style.display = "unset"; + PageElements.whitelistToggle.checked = true; + document.querySelectorAll('.SBWhitelistIcon')[0].classList.add("rotated"); + } + + // Clear segments list & start loading animation + // We'll get a ping once they're loaded + startLoadingAnimation(); + PageElements.videoFound.innerHTML = chrome.i18n.getMessage("Loading"); + displayDownloadedSponsorTimes([], 0); + break; } } }