Added skip button in control bar instead of using skip notice

This commit is contained in:
Ajay Ramachandran 2021-08-18 02:07:24 -04:00
parent 2a0e893dfc
commit e126b59078
11 changed files with 237 additions and 50 deletions

View file

@ -41,6 +41,7 @@
"icons/help.svg",
"icons/report.png",
"icons/close.png",
"icons/skipIcon.svg",
"icons/refresh.svg",
"icons/beep.ogg",
"icons/pause.svg",

View file

@ -501,4 +501,17 @@ input::-webkit-inner-spin-button {
.sbChatClose {
height: 14px;
cursor: pointer;
}
.skipButtonControlBarContainer {
cursor: pointer;
display: flex;
}
#sbSkipIconControlBarImage {
height: 60%;
top: 0px;
bottom: 0px;
display: block;
margin: auto;
}

View file

@ -41,12 +41,13 @@
id="namedview18"
showgrid="false"
inkscape:zoom="0.83098592"
inkscape:cx="-238.41697"
inkscape:cy="258.22009"
inkscape:cx="220.07455"
inkscape:cy="308.76246"
inkscape:window-x="477"
inkscape:window-y="961"
inkscape:window-maximized="1"
inkscape:current-layer="svg16" />
inkscape:current-layer="svg16"
inkscape:pagecheckerboard="true" />
<defs
id="defs4">
<style

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

71
public/icons/skipIcon.svg Normal file
View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 565.15 568"
version="1.1"
id="svg16"
sodipodi:docname="skipIcon.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
inkscape:export-filename="D:\Dell Data\_Projects\_____SponsorSkip\ignored\svg\SponsorBlocker4.png"
inkscape:export-xdpi="43.436523"
inkscape:export-ydpi="43.436523">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>LogoSponsorBlocker2</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1001"
id="namedview18"
showgrid="false"
inkscape:zoom="1.6619718"
inkscape:cx="316.31071"
inkscape:cy="330.01409"
inkscape:window-x="477"
inkscape:window-y="961"
inkscape:window-maximized="1"
inkscape:current-layer="svg16"
inkscape:pagecheckerboard="true" />
<defs
id="defs4">
<style
id="style2">.cls-1{fill:red;}.cls-2{fill:#fff;}</style>
</defs>
<title
id="title6">LogoSponsorBlocker2</title>
<path
class="cls-1"
d="m 282.58,568 a 65,65 0 0 1 -34.14,-9.66 C 95.41,463.94 2.54,300.46 0,121 a 64.91,64.91 0 0 1 34,-58.09 522.56,522.56 0 0 1 497.16,0 64.91,64.91 0 0 1 34,58.12 c -2.53,179.43 -95.4,342.91 -248.42,437.3 A 65,65 0 0 1 282.58,568 Z m 0,-548.31 A 502.24,502.24 0 0 0 43.4,80.22 45.27,45.27 0 0 0 19.7,120.75 c 2.44,172.67 91.81,330 239.07,420.83 a 46.19,46.19 0 0 0 47.61,0 C 453.64,450.73 543,293.42 545.45,120.75 A 45.26,45.26 0 0 0 521.75,80.21 502.26,502.26 0 0 0 282.58,19.69 Z"
id="path8"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
style="fill:#ffffff"
d="M 284.70508 42.693359 A 479.9 479.9 0 0 0 54.369141 100.41992 A 22.53 22.53 0 0 0 42.669922 120.41992 C 45.069922 290.25992 135.67008 438.63977 270.83008 522.00977 A 22.48 22.48 0 0 0 294.32031 522.00977 C 429.48031 438.63977 520.08047 290.25992 522.48047 120.41992 A 22.53 22.53 0 0 0 510.7793 100.41992 A 479.9 479.9 0 0 0 284.70508 42.693359 z M 188.7168 140.07227 L 312.64844 264.00586 L 188.7168 387.9375 L 159.5918 358.8125 L 254.19336 264.00586 L 159.5918 169.19727 L 188.7168 140.07227 z M 305.625 140.07227 L 429.55859 264.00586 L 305.625 387.9375 L 276.50195 358.8125 L 371.10352 264.00586 L 276.50195 169.19727 L 305.625 140.07227 z "
id="path10" />
<g
id="g825"
transform="translate(-3.86549,36.564644)" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -4,6 +4,7 @@ import Config from "../config"
import { Category, CategorySkipOption } from "../types";
import Utils from "../utils";
import { getCategoryActionType } from "../utils/categoryUtils";
const utils = new Utils();
export interface CategorySkipOptionsProps {
@ -152,12 +153,12 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
const optionNames = ["disable", "showOverlay", "manualSkip", "autoSkip"];
console.log(utils.getCategoryActionType(this.props.category))
console.log(getCategoryActionType(this.props.category))
for (const optionName of optionNames) {
elements.push(
<option key={optionName} value={optionName}>
{chrome.i18n.getMessage(optionName !== "disable" ? optionName + utils.getCategoryActionType(this.props.category)
{chrome.i18n.getMessage(optionName !== "disable" ? optionName + getCategoryActionType(this.props.category)
: optionName)}
</option>
);

View file

@ -5,8 +5,7 @@ import { Category, ContentContainer, CategoryActionType, SponsorHideType, Sponso
import NoticeComponent from "./NoticeComponent";
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
import Utils from "../utils";
const utils = new Utils();
import { getCategoryActionType, getSkippingText } from "../utils/categoryUtils";
export enum SkipNoticeAction {
None,
@ -82,18 +81,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
this.contentContainer = props.contentContainer;
this.audio = null;
const categoryName = chrome.i18n.getMessage(this.segments.length > 1 ? "multipleSegments"
: "category_" + this.segments[0].category + "_short") || chrome.i18n.getMessage("category_" + this.segments[0].category);
let noticeTitle = "";
if (this.autoSkip) {
const messageId = utils.getCategoryActionType(this.segments[0].category) === CategoryActionType.Skippable
? "skipped" : "skipped_to_category";
noticeTitle = chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
} else {
const messageId = utils.getCategoryActionType(this.segments[0].category) === CategoryActionType.Skippable
? "skip_category" : "skip_to_category";
noticeTitle = chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
}
const noticeTitle = getSkippingText(this.segments, this.props.autoSkip);
const previousSkipNotices = document.getElementsByClassName("sponsorSkipNoticeParent");
this.amountOfPreviousNotices = previousSkipNotices.length;
@ -308,7 +296,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
getSkipButton(): JSX.Element {
if (this.segments.length > 1
|| utils.getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|| getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|| this.props.unskipTime) {
return (
<span className="sponsorSkipNoticeUnskipSection">
@ -451,7 +439,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
getCategoryOptions(): React.ReactElement[] {
const elements = [];
const categories = CompileConfig.categoryList.filter((cat => utils.getCategoryActionType(cat as Category) === CategoryActionType.Skippable));
const categories = CompileConfig.categoryList.filter((cat => getCategoryActionType(cat as Category) === CategoryActionType.Skippable));
for (const category of categories) {
elements.push(
<option value={category}
@ -479,7 +467,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
}
getUnskippedModeInfo(index: number, buttonText: string): SkipNoticeState {
const changeCountdown = utils.getCategoryActionType(this.segments[index].category) === CategoryActionType.Skippable;
const changeCountdown = getCategoryActionType(this.segments[index].category) === CategoryActionType.Skippable;
const maxCountdownTime = changeCountdown ? () => {
const sponsorTime = this.segments[index];

View file

@ -6,6 +6,7 @@ import * as CompileConfig from "../../config.json";
import Utils from "../utils";
import { Category, CategoryActionType, ContentContainer, SponsorTime } from "../types";
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
import { getCategoryActionType } from "../utils/categoryUtils";
const utils = new Utils();
export interface SponsorTimeEditProps {
@ -107,14 +108,14 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
onChange={(e) => {
const sponsorTimeEdits = this.state.sponsorTimeEdits;
sponsorTimeEdits[0] = e.target.value;
if (utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTimeEdits[1] = e.target.value;
if (getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTimeEdits[1] = e.target.value;
this.setState({sponsorTimeEdits});
this.saveEditTimes();
}}>
</input>
{utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable ? (
{getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable ? (
<span>
<span>
{" " + chrome.i18n.getMessage("to") + " "}
@ -156,7 +157,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
className="sponsorTimeDisplay"
onClick={this.toggleEditTime.bind(this)}>
{utils.getFormattedTime(segment[0], true) +
((!isNaN(segment[1]) && utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable)
((!isNaN(segment[1]) && getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable)
? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segment[1], true) : "")}
</div>
);
@ -197,7 +198,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
{chrome.i18n.getMessage("delete")}
</span>
{(!isNaN(segment[1]) && utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable) ? (
{(!isNaN(segment[1]) && getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable) ? (
<span id={"sponsorTimePreviewButton" + this.idSuffix}
className="sponsorTimeEditButton"
onClick={this.previewTime.bind(this)}>
@ -260,7 +261,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
return;
}
if (utils.getCategoryActionType(event.target.value as Category) === CategoryActionType.POI) {
if (getCategoryActionType(event.target.value as Category) === CategoryActionType.POI) {
this.setTimeTo(1, null);
this.props.contentContainer().updateEditButtonsOnPlayer();
}
@ -285,7 +286,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
if (time === null) time = sponsorTime.segment[0];
sponsorTime.segment[index] = time;
if (utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTime.segment[1] = time;
if (getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTime.segment[1] = time;
this.setState({
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)

View file

@ -13,6 +13,8 @@ import SkipNoticeComponent from "./components/SkipNoticeComponent";
import SubmissionNotice from "./render/SubmissionNotice";
import { Message, MessageResponse } from "./messageTypes";
import * as Chat from "./js-components/chat";
import { getCategoryActionType } from "./utils/categoryUtils";
import { SkipButtonControlBar } from "./js-components/skipButtonControlBar";
// Hack to get the CSS loaded on permission-based sites (Invidious)
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
@ -68,6 +70,7 @@ let channelWhitelisted = false;
// create preview bar
let previewBar: PreviewBar = null;
let skipButtonControlBar: SkipButtonControlBar = null;
/** Element containing the player controls on the YouTube player. */
let controls: HTMLElement | null = null;
@ -515,6 +518,7 @@ function refreshVideoAttachments() {
videosWithEventListeners.push(video);
setupVideoListeners();
setupSkipButtonControlBar();
}
}
}
@ -569,7 +573,7 @@ function setupVideoListeners() {
if (!Config.config.dontShowNotice) {
const currentPoiSegment = sponsorTimes.find((segment) =>
utils.getCategoryActionType(segment.category) === CategoryActionType.POI &&
getCategoryActionType(segment.category) === CategoryActionType.POI &&
video.currentTime - segment.segment[0] > 0 &&
video.currentTime - segment.segment[0] < video.duration * 0.006); // Approximate size on preview bar
if (currentPoiSegment && !skipNotices.some((notice) => notice.segments.some((s) => s.UUID === currentPoiSegment.UUID))) {
@ -598,6 +602,22 @@ function setupVideoListeners() {
}
}
function setupSkipButtonControlBar() {
if (!skipButtonControlBar) {
skipButtonControlBar = new SkipButtonControlBar({
skip: (segment) => skipToTime({
v: video,
skipTime: segment.segment,
skippingSegments: [segment],
openNotice: true,
forceAutoSkip: true
})
});
}
skipButtonControlBar.attachToPage();
}
async function sponsorsLookup(id: string, keepOldSubmissions = true) {
if (!video) refreshVideoAttachments();
//there is still no video here
@ -731,7 +751,7 @@ function startSkipScheduleCheckingForStartSponsors() {
let startingSegment: SponsorTime = null;
for (const time of sponsorTimes) {
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > video.currentTime
&& utils.getCategoryActionType(time.category) === CategoryActionType.Skippable) {
&& getCategoryActionType(time.category) === CategoryActionType.Skippable) {
startingSegmentTime = time.segment[0];
startingSegment = time;
break;
@ -740,7 +760,7 @@ function startSkipScheduleCheckingForStartSponsors() {
if (startingSegmentTime === -1) {
for (const time of sponsorTimesSubmitting) {
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > video.currentTime
&& utils.getCategoryActionType(time.category) === CategoryActionType.Skippable) {
&& getCategoryActionType(time.category) === CategoryActionType.Skippable) {
startingSegmentTime = time.segment[0];
startingSegment = time;
break;
@ -750,7 +770,7 @@ function startSkipScheduleCheckingForStartSponsors() {
// For highlight category
const poiSegments = sponsorTimes
.filter((time) => time.segment[1] > video.currentTime && utils.getCategoryActionType(time.category) === CategoryActionType.POI)
.filter((time) => time.segment[1] > video.currentTime && getCategoryActionType(time.category) === CategoryActionType.POI)
.sort((a, b) => b.segment[0] - a.segment[0]);
for (const time of poiSegments) {
const skipOption = utils.getCategorySelection(time.category)?.option;
@ -862,7 +882,7 @@ function updatePreviewBar(): void {
segment: segment.segment as [number, number],
category: segment.category,
unsubmitted: false,
showLarger: utils.getCategoryActionType(segment.category) === CategoryActionType.POI
showLarger: getCategoryActionType(segment.category) === CategoryActionType.POI
});
});
}
@ -872,7 +892,7 @@ function updatePreviewBar(): void {
segment: segment.segment as [number, number],
category: segment.category,
unsubmitted: true,
showLarger: utils.getCategoryActionType(segment.category) === CategoryActionType.POI
showLarger: getCategoryActionType(segment.category) === CategoryActionType.POI
});
});
@ -1022,7 +1042,7 @@ function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments:
|| (includeIntersectingSegments && sponsorTimes[i].segment[0] < minimum && sponsorTimes[i].segment[1] > minimum)))
&& (!onlySkippableSponsors || utils.getCategorySelection(sponsorTimes[i].category).option !== CategorySkipOption.ShowOverlay)
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
&& utils.getCategoryActionType(sponsorTimes[i].category) === CategoryActionType.Skippable) {
&& getCategoryActionType(sponsorTimes[i].category) === CategoryActionType.Skippable) {
startTimes.push(sponsorTimes[i].segment[0]);
}
@ -1080,11 +1100,17 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
}
}
if (openNotice) {
//send out the message saying that a sponsor message was skipped
if (!Config.config.dontShowNotice || !autoSkip) {
skipNotices.forEach((notice) => notice.setShowKeybindHint(false));
skipNotices.push(new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer, unskipTime));
if (!autoSkip
&& skippingSegments.length === 1
&& getCategoryActionType(skippingSegments[0].category) === CategoryActionType.POI) {
skipButtonControlBar.enable(skippingSegments[0]);
} else {
if (openNotice) {
//send out the message saying that a sponsor message was skipped
if (!Config.config.dontShowNotice || !autoSkip) {
skipNotices.forEach((notice) => notice.setShowKeybindHint(false));
skipNotices.push(new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer, unskipTime));
}
}
}

View file

@ -0,0 +1,70 @@
import Config from "../config";
import { SponsorTime } from "../types";
import { getSkippingText } from "../utils/categoryUtils";
export interface SkipButtonControlBarProps {
skip: (segment: SponsorTime) => void;
}
export class SkipButtonControlBar {
container: HTMLElement;
skipIcon: HTMLImageElement;
textContainer: HTMLElement;
chapterText: HTMLElement;
segment: SponsorTime;
timeout: NodeJS.Timeout;
skip: (segment: SponsorTime) => void;
constructor(props: SkipButtonControlBarProps) {
this.skip = props.skip;
this.container = document.createElement("div");
this.container.classList.add("skipButtonControlBarContainer");
this.container.classList.add("hidden");
this.skipIcon = document.createElement("img");
this.skipIcon.src = chrome.runtime.getURL("icons/skipIcon.svg");
this.skipIcon.classList.add("ytp-button");
this.skipIcon.id = "sbSkipIconControlBarImage";
this.textContainer = document.createElement("div");
this.container.appendChild(this.skipIcon);
this.container.appendChild(this.textContainer);
this.container.addEventListener("click", () => this.onClick());
}
attachToPage(): void {
const leftControlsContainer = document.querySelector(".ytp-left-controls");
this.chapterText = document.querySelector(".ytp-chapter-container");
if (!leftControlsContainer.contains(this.container)) {
leftControlsContainer.insertBefore(this.container, this.chapterText);
}
}
enable(segment: SponsorTime): void {
this.segment = segment;
this.chapterText?.classList?.add("hidden");
this.container.classList.remove("hidden");
this.textContainer.innerText = getSkippingText([segment], false);
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => this.disable(), Config.config.skipNoticeDuration * 1000);
}
disable(): void {
this.container.classList.add("hidden");
this.chapterText?.classList?.remove("hidden");
}
onClick(): void {
this.skip(this.segment);
this.disable();
}
}

View file

@ -1,5 +1,5 @@
import Config from "./config";
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration, Category, CategoryActionType } from "./types";
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration } from "./types";
import * as CompileConfig from "../config.json";
@ -43,14 +43,6 @@ export default class Utils {
});
}
getCategoryActionType(category: Category): CategoryActionType {
if (category.startsWith("poi_")) {
return CategoryActionType.POI;
} else {
return CategoryActionType.Skippable;
}
}
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
return new Promise((resolve) => {
chrome.permissions.contains(permissions, resolve)
@ -364,7 +356,7 @@ export default class Utils {
}, (response) => {
resolve(response);
});
})
});
}
/**

View file

@ -0,0 +1,23 @@
import { Category, CategoryActionType, SponsorTime } from "../types";
export function getSkippingText(segments: SponsorTime[], autoSkip: boolean): string {
const categoryName = chrome.i18n.getMessage(segments.length > 1 ? "multipleSegments"
: "category_" + segments[0].category + "_short") || chrome.i18n.getMessage("category_" + segments[0].category);
if (autoSkip) {
const messageId = getCategoryActionType(segments[0].category) === CategoryActionType.Skippable
? "skipped" : "skipped_to_category";
return chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
} else {
const messageId = getCategoryActionType(segments[0].category) === CategoryActionType.Skippable
? "skip_category" : "skip_to_category";
return chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
}
}
export function getCategoryActionType(category: Category): CategoryActionType {
if (category.startsWith("poi_")) {
return CategoryActionType.POI;
} else {
return CategoryActionType.Skippable;
}
}