mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-24 16:38:47 +03:00
Merge pull request #1322 from NDevTK/master
Move popup to iframe and restrict embeds
This commit is contained in:
@@ -8,9 +8,13 @@
|
||||
<link id="sponsorBlockStyleSheet" href="popup.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body id="sponsorBlockPopupBody">
|
||||
<body id="sponsorBlockPopupBody" style="visibility: hidden">
|
||||
<div id="sponsorblockPopup" class="sponsorBlockPageBody sb-preload">
|
||||
|
||||
<button id="sbCloseButton" title="__MSG_closePopup__" class="sbCloseButton hidden">
|
||||
<img src="icons/close.png" width="15" height="15">
|
||||
</button>
|
||||
|
||||
<div id="sbBetaServerWarning" class="hidden" title="__MSG_openOptionsPage__">
|
||||
__MSG_betaServerWarning__
|
||||
</div>
|
||||
|
||||
@@ -84,7 +84,20 @@ chrome.runtime.onMessage.addListener(function (request, _, callback) {
|
||||
case "unregisterContentScript":
|
||||
unregisterFirefoxContentScript(request.id)
|
||||
return false;
|
||||
}
|
||||
case "tabs":
|
||||
chrome.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
chrome.tabs.sendMessage(
|
||||
tabs[0].id,
|
||||
request.data,
|
||||
(response) => callback(response)
|
||||
);
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//add help page on install
|
||||
|
||||
111
src/content.ts
111
src/content.ts
@@ -5,8 +5,6 @@ import { ContentContainer, Keybind } from "./types";
|
||||
import Utils from "./utils";
|
||||
const utils = new Utils();
|
||||
|
||||
import runThePopup from "./popup";
|
||||
|
||||
import PreviewBar, {PreviewBarSegment} from "./js-components/previewBar";
|
||||
import SkipNotice from "./render/SkipNotice";
|
||||
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
@@ -219,6 +217,9 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
||||
utils.addHiddenSegment(sponsorVideoID, request.UUID, request.type);
|
||||
updatePreviewBar();
|
||||
break;
|
||||
case "closePopup":
|
||||
closeInfoMenu();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1686,73 +1687,30 @@ function openInfoMenu() {
|
||||
//hide info button
|
||||
if (playerButtons.info) playerButtons.info.button.style.display = "none";
|
||||
|
||||
sendRequestToCustomServer('GET', chrome.extension.getURL("popup.html"), function(xmlhttp) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
const popup = document.createElement("div");
|
||||
popup.id = "sponsorBlockPopupContainer";
|
||||
|
||||
const popup = document.createElement("div");
|
||||
popup.id = "sponsorBlockPopupContainer";
|
||||
|
||||
const frame = document.createElement("iframe");
|
||||
frame.width = "374";
|
||||
frame.height = "500";
|
||||
frame.addEventListener("load", () => frame.contentWindow.postMessage("", "*"));
|
||||
frame.src = chrome.extension.getURL("popup.html");
|
||||
popup.appendChild(frame);
|
||||
|
||||
let htmlData = xmlhttp.responseText;
|
||||
// Hack to replace head data (title, favicon)
|
||||
htmlData = htmlData.replace(/<head>[\S\s]*<\/head>/gi, "");
|
||||
// Hack to replace body and html tag with div
|
||||
htmlData = htmlData.replace(/<body/gi, "<div");
|
||||
htmlData = htmlData.replace(/<\/body/gi, "</div");
|
||||
htmlData = htmlData.replace(/<html/gi, "<div");
|
||||
htmlData = htmlData.replace(/<\/html/gi, "</div");
|
||||
|
||||
popup.innerHTML = htmlData;
|
||||
|
||||
//close button
|
||||
const closeButton = document.createElement("button");
|
||||
const closeButtonIcon = document.createElement("img");
|
||||
closeButtonIcon.src = chrome.extension.getURL("icons/close.png");
|
||||
closeButtonIcon.width = 15;
|
||||
closeButtonIcon.height = 15;
|
||||
closeButton.appendChild(closeButtonIcon);
|
||||
closeButton.setAttribute("title", chrome.i18n.getMessage("closePopup"));
|
||||
closeButton.classList.add("sbCloseButton");
|
||||
closeButton.addEventListener("click", closeInfoMenu);
|
||||
|
||||
//add the close button
|
||||
popup.prepend(closeButton);
|
||||
|
||||
const parentNodes = document.querySelectorAll("#secondary");
|
||||
let parentNode = null;
|
||||
for (let i = 0; i < parentNodes.length; i++) {
|
||||
if (parentNodes[i].firstElementChild !== null) {
|
||||
parentNode = parentNodes[i];
|
||||
}
|
||||
}
|
||||
if (parentNode == null) {
|
||||
//old youtube theme
|
||||
parentNode = document.getElementById("watch7-sidebar-contents");
|
||||
}
|
||||
|
||||
//make the logo source not 404
|
||||
//query selector must be used since getElementByID doesn't work on a node and this isn't added to the document yet
|
||||
const logo = <HTMLImageElement> popup.querySelector("#sponsorBlockPopupLogo");
|
||||
const settings = <HTMLImageElement> popup.querySelector("#sbPopupIconSettings");
|
||||
const edit = <HTMLImageElement> popup.querySelector("#sbPopupIconEdit");
|
||||
const copy = <HTMLImageElement> popup.querySelector("#sbPopupIconCopyUserID");
|
||||
const check = <HTMLImageElement> popup.querySelector("#sbPopupIconCheck");
|
||||
const refreshSegments = <HTMLImageElement> popup.querySelector("#refreshSegments");
|
||||
const heart = <HTMLImageElement> popup.querySelector(".sbHeart");
|
||||
const close = <HTMLImageElement> popup.querySelector("#sbCloseDonate");
|
||||
logo.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png");
|
||||
settings.src = chrome.extension.getURL("icons/settings.svg");
|
||||
edit.src = chrome.extension.getURL("icons/pencil.svg");
|
||||
copy.src = chrome.extension.getURL("icons/clipboard.svg");
|
||||
check.src = chrome.extension.getURL("icons/check.svg");
|
||||
heart.src = chrome.extension.getURL("icons/heart.svg");
|
||||
close.src = chrome.extension.getURL("icons/close.png");
|
||||
refreshSegments.src = chrome.extension.getURL("icons/refresh.svg");
|
||||
|
||||
parentNode.insertBefore(popup, parentNode.firstChild);
|
||||
|
||||
//run the popup init script
|
||||
runThePopup(messageListener);
|
||||
const parentNodes = document.querySelectorAll("#secondary");
|
||||
let parentNode = null;
|
||||
for (let i = 0; i < parentNodes.length; i++) {
|
||||
if (parentNodes[i].firstElementChild !== null) {
|
||||
parentNode = parentNodes[i];
|
||||
}
|
||||
});
|
||||
}
|
||||
if (parentNode == null) {
|
||||
//old youtube theme
|
||||
parentNode = document.getElementById("watch7-sidebar-contents");
|
||||
}
|
||||
|
||||
parentNode.insertBefore(popup, parentNode.firstChild);
|
||||
}
|
||||
|
||||
function closeInfoMenu() {
|
||||
@@ -2113,25 +2071,6 @@ function addCSS() {
|
||||
}
|
||||
}
|
||||
|
||||
function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||
const xmlhttp = new XMLHttpRequest();
|
||||
|
||||
xmlhttp.open(type, fullAddress, true);
|
||||
|
||||
if (callback != undefined) {
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
callback(xmlhttp, false);
|
||||
};
|
||||
|
||||
xmlhttp.onerror = function() {
|
||||
callback(xmlhttp, true);
|
||||
};
|
||||
}
|
||||
|
||||
//submit this request
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the isAdPlaying flag and hide preview bar/controls if ad is playing
|
||||
*/
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import Config from "./config";
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
|
||||
import Utils from "./utils";
|
||||
const utils = new Utils();
|
||||
import { localizeHtmlPage } from "./utils/pageUtils";
|
||||
import { GenericUtils } from "./utils/genericUtils";
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
async function init() {
|
||||
utils.localizeHtmlPage();
|
||||
localizeHtmlPage();
|
||||
|
||||
await utils.wait(() => Config.config !== null);
|
||||
await GenericUtils.wait(() => Config.config !== null);
|
||||
|
||||
if (!Config.config.darkMode) {
|
||||
document.documentElement.setAttribute("data-theme", "light");
|
||||
|
||||
@@ -16,7 +16,8 @@ interface DefaultMessage {
|
||||
| "getChannelID"
|
||||
| "isChannelWhitelisted"
|
||||
| "submitTimes"
|
||||
| "refreshSegments";
|
||||
| "refreshSegments"
|
||||
| "closePopup";
|
||||
}
|
||||
|
||||
interface BoolValueMessage {
|
||||
|
||||
@@ -12,13 +12,14 @@ import Utils from "./utils";
|
||||
import CategoryChooser from "./render/CategoryChooser";
|
||||
import KeybindComponent from "./components/KeybindComponent";
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
import { localizeHtmlPage } from "./utils/pageUtils";
|
||||
const utils = new Utils();
|
||||
let embed = false;
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
async function init() {
|
||||
utils.localizeHtmlPage();
|
||||
localizeHtmlPage();
|
||||
|
||||
// selected tab
|
||||
if (location.hash != "") {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Config from "./config";
|
||||
import Utils from "./utils";
|
||||
import { localizeHtmlPage } from "./utils/pageUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
// This is needed, if Config is not imported before Utils, things break.
|
||||
@@ -9,7 +10,7 @@ Config.config;
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
async function init() {
|
||||
utils.localizeHtmlPage();
|
||||
localizeHtmlPage();
|
||||
|
||||
const domains = document.location.hash.replace("#", "").split(",");
|
||||
|
||||
|
||||
82
src/popup.ts
82
src/popup.ts
@@ -6,6 +6,7 @@ import { Message, MessageResponse, IsInfoFoundMessageResponse } from "./messageT
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
import { AnimationUtils } from "./utils/animationUtils";
|
||||
import { GenericUtils } from "./utils/genericUtils";
|
||||
import { localizeHtmlPage } from "./utils/pageUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
interface MessageListener {
|
||||
@@ -22,13 +23,15 @@ class MessageHandler {
|
||||
sendMessage(id: number, request: Message, callback?) {
|
||||
if (this.messageListener) {
|
||||
this.messageListener(request, null, callback);
|
||||
} else {
|
||||
} else if (chrome.tabs) {
|
||||
chrome.tabs.sendMessage(id, request, callback);
|
||||
} else {
|
||||
chrome.runtime.sendMessage({ message: "tabs", data: request }, callback);
|
||||
}
|
||||
}
|
||||
|
||||
query(config, callback) {
|
||||
if (this.messageListener) {
|
||||
if (this.messageListener || !chrome.tabs) {
|
||||
// Send back dummy info
|
||||
callback([{
|
||||
url: document.URL,
|
||||
@@ -41,15 +44,17 @@ class MessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// To prevent clickjacking
|
||||
let allowPopup = window === window.top;
|
||||
window.addEventListener("message", async (e) => {
|
||||
if (e.source !== window.parent) return;
|
||||
if (e.origin.endsWith('.youtube.com')) return allowPopup = true;
|
||||
});
|
||||
|
||||
//make this a function to allow this to run on the content page
|
||||
async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
const messageHandler = new MessageHandler(messageListener);
|
||||
|
||||
utils.localizeHtmlPage();
|
||||
|
||||
await utils.wait(() => Config.config !== null);
|
||||
localizeHtmlPage();
|
||||
|
||||
type InputPageElements = {
|
||||
whitelistToggle?: HTMLInputElement,
|
||||
@@ -58,6 +63,15 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
};
|
||||
type PageElements = { [key: string]: HTMLElement } & InputPageElements
|
||||
|
||||
/** If true, the content script is in the process of creating a new segment. */
|
||||
let creatingSegment = false;
|
||||
|
||||
//the start and end time pairs (2d)
|
||||
let sponsorTimes: SponsorTime[] = [];
|
||||
|
||||
//current video ID of this tab
|
||||
let currentVideoID = null;
|
||||
|
||||
const PageElements: PageElements = {};
|
||||
|
||||
[
|
||||
@@ -112,9 +126,24 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
"sponsorTimesDonateContainer",
|
||||
"sbConsiderDonateLink",
|
||||
"sbCloseDonate",
|
||||
"sbBetaServerWarning"
|
||||
"sbBetaServerWarning",
|
||||
"sbCloseButton"
|
||||
].forEach(id => PageElements[id] = document.getElementById(id));
|
||||
|
||||
getSegmentsFromContentScript(false);
|
||||
await utils.wait(() => Config.config !== null && allowPopup, 5000, 5);
|
||||
document.querySelector("body").style.removeProperty("visibility");
|
||||
|
||||
PageElements.sbCloseButton.addEventListener("click", () => {
|
||||
sendTabMessage({
|
||||
message: "closePopup"
|
||||
});
|
||||
});
|
||||
|
||||
if (window !== window.top) {
|
||||
PageElements.sbCloseButton.classList.remove("hidden");
|
||||
}
|
||||
|
||||
// Hide donate button if wanted (Safari, or user choice)
|
||||
if (!showDonationLink()) {
|
||||
PageElements.sbDonate.style.display = "none";
|
||||
@@ -151,15 +180,6 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
PageElements.refreshSegmentsButton.addEventListener("click", refreshSegments);
|
||||
PageElements.sbPopupIconCopyUserID.addEventListener("click", async () => navigator.clipboard.writeText(await utils.getHash(Config.config.userID)));
|
||||
|
||||
/** If true, the content script is in the process of creating a new segment. */
|
||||
let creatingSegment = false;
|
||||
|
||||
//the start and end time pairs (2d)
|
||||
let sponsorTimes: SponsorTime[] = [];
|
||||
|
||||
//current video ID of this tab
|
||||
let currentVideoID = null;
|
||||
|
||||
//show proper disable skipping button
|
||||
const disableSkipping = Config.config.disableSkipping;
|
||||
if (disableSkipping != undefined && disableSkipping) {
|
||||
@@ -239,8 +259,6 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
// Must be delayed so it only happens once loaded
|
||||
setTimeout(() => PageElements.sponsorblockPopup.classList.remove("preload"), 250);
|
||||
|
||||
getSegmentsFromContentScript(false);
|
||||
|
||||
function showDonateWidget(viewCount: number) {
|
||||
if (Config.config.showDonationLink && Config.config.donateClicked <= 0 && Config.config.showPopupDonationCount < 5
|
||||
&& viewCount < 50000 && !Config.config.isVip && Config.config.skipCount > 10) {
|
||||
@@ -272,13 +290,14 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
function loadTabData(tabs, updating: boolean): void {
|
||||
async function loadTabData(tabs, updating: boolean): Promise<void> {
|
||||
if (!currentVideoID) {
|
||||
//this isn't a YouTube video then
|
||||
displayNoVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
await utils.wait(() => Config.config !== null, 5000, 10);
|
||||
sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] ?? [];
|
||||
updateSegmentEditingUI();
|
||||
|
||||
@@ -578,6 +597,22 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
chrome.runtime.sendMessage({ "message": "openHelp" });
|
||||
}
|
||||
|
||||
function sendTabMessage(data: Message): Promise<unknown> {
|
||||
return new Promise((resolve) => {
|
||||
messageHandler.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, tabs => {
|
||||
messageHandler.sendMessage(
|
||||
tabs[0].id,
|
||||
data,
|
||||
(response) => resolve(response)
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
//make the options username setting option visible
|
||||
function setUsernameButton() {
|
||||
PageElements.usernameInput.value = PageElements.usernameValue.innerText;
|
||||
@@ -822,9 +857,4 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
//end of function
|
||||
}
|
||||
|
||||
if (chrome.tabs != undefined) {
|
||||
//this means it is actually opened in the popup
|
||||
runThePopup();
|
||||
}
|
||||
|
||||
export default runThePopup;
|
||||
runThePopup();
|
||||
|
||||
25
src/utils.ts
25
src/utils.ts
@@ -256,31 +256,6 @@ export default class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
localizeHtmlPage(): void {
|
||||
//Localize by replacing __MSG_***__ meta tags
|
||||
const localizedMessage = this.getLocalizedMessage(document.title);
|
||||
if (localizedMessage) document.title = localizedMessage;
|
||||
const objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
for (let j = 0; j < objects.length; j++) {
|
||||
const obj = objects[j];
|
||||
const localizedMessage = this.getLocalizedMessage(obj.innerHTML.toString());
|
||||
if (localizedMessage) obj.innerHTML = localizedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
getLocalizedMessage(text: string): string | false {
|
||||
const valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) {
|
||||
return v1 ? chrome.i18n.getMessage(v1).replace(/</g, "<")
|
||||
.replace(/"/g, """).replace(/\n/g, "<br/>") : "";
|
||||
});
|
||||
|
||||
if(valNewH != text) {
|
||||
return valNewH;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String[]} Domains in regex form
|
||||
*/
|
||||
|
||||
@@ -61,4 +61,29 @@ export function getHashParams(): Record<string, unknown> {
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
export function localizeHtmlPage(): void {
|
||||
//Localize by replacing __MSG_***__ meta tags
|
||||
const localizedMessage = getLocalizedMessage(document.title);
|
||||
if (localizedMessage) document.title = localizedMessage;
|
||||
const objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
for (let j = 0; j < objects.length; j++) {
|
||||
const obj = objects[j];
|
||||
const localizedMessage = getLocalizedMessage(obj.innerHTML.toString());
|
||||
if (localizedMessage) obj.innerHTML = localizedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
export function getLocalizedMessage(text: string): string | false {
|
||||
const valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) {
|
||||
return v1 ? chrome.i18n.getMessage(v1).replace(/</g, "<")
|
||||
.replace(/"/g, """).replace(/\n/g, "<br/>") : "";
|
||||
});
|
||||
|
||||
if (valNewH != text) {
|
||||
return valNewH;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user