aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAjay <[email protected]>2022-01-05 02:35:58 -0500
committerAjay <[email protected]>2022-01-05 02:35:58 -0500
commit2883a50f2796628960775c7d241f44f58ac52ef5 (patch)
treecec0ec5f602bec59807149080a03dff9ea48e4c3
parentd36b4a54f3154fdcfbd2e5f059c401bdd6ceeee3 (diff)
downloadSponsorBlock-2883a50f2796628960775c7d241f44f58ac52ef5.tar.gz
SponsorBlock-2883a50f2796628960775c7d241f44f58ac52ef5.zip
Add pill beside title for full video reports
-rw-r--r--public/content.css12
-rw-r--r--src/components/CategoryPillComponent.tsx47
-rw-r--r--src/content.ts22
-rw-r--r--src/render/CategoryPill.tsx71
-rw-r--r--src/utils.ts22
-rw-r--r--src/utils/genericUtils.ts26
6 files changed, 178 insertions, 22 deletions
diff --git a/public/content.css b/public/content.css
index b9f19080..98a6b4f2 100644
--- a/public/content.css
+++ b/public/content.css
@@ -613,3 +613,15 @@ input::-webkit-inner-spin-button {
line-height: 1.5em;
}
+.sponsorBlockCategoryPill {
+ border-radius: 25px;
+ padding-left: 8px;
+ padding-right: 8px;
+ margin-right: 3px;
+ color: white;
+}
+
+.sponsorBlockCategoryPillTitleSection {
+ display: flex;
+ align-items: center;
+} \ No newline at end of file
diff --git a/src/components/CategoryPillComponent.tsx b/src/components/CategoryPillComponent.tsx
new file mode 100644
index 00000000..0f20c82f
--- /dev/null
+++ b/src/components/CategoryPillComponent.tsx
@@ -0,0 +1,47 @@
+import * as React from "react";
+import Config from "../config";
+import { SponsorTime } from "../types";
+
+export interface CategoryPillProps {
+
+}
+
+export interface CategoryPillState {
+ segment?: SponsorTime;
+ show: boolean;
+}
+
+class CategoryPillComponent extends React.Component<CategoryPillProps, CategoryPillState> {
+
+ constructor(props: CategoryPillProps) {
+ super(props);
+
+ this.state = {
+ segment: null,
+ show: false
+ };
+ }
+
+ render(): React.ReactElement {
+ const style: React.CSSProperties = {
+ backgroundColor: Config.config.barTypes["preview-" + this.state.segment?.category]?.color,
+ display: this.state.show ? "flex" : "none"
+ }
+
+ return (
+ <span style={style}
+ className="sponsorBlockCategoryPill" >
+ <span className="sponsorBlockCategoryPillTitleSection">
+ <img className="sponsorSkipLogo sponsorSkipObject"
+ src={chrome.extension.getURL("icons/IconSponsorBlocker256px.png")}>
+ </img>
+ <span className="sponsorBlockCategoryPillTitle">
+ {chrome.i18n.getMessage("category_" + this.state.segment?.category)}
+ </span>
+ </span>
+ </span>
+ );
+ }
+}
+
+export default CategoryPillComponent;
diff --git a/src/content.ts b/src/content.ts
index 681ef10c..f3d589cc 100644
--- a/src/content.ts
+++ b/src/content.ts
@@ -18,6 +18,7 @@ import { SkipButtonControlBar } from "./js-components/skipButtonControlBar";
import { Tooltip } from "./render/Tooltip";
import { getStartTimeFromUrl } from "./utils/urlParser";
import { getControls } from "./utils/pageUtils";
+import { CategoryPill } from "./render/CategoryPill";
// Hack to get the CSS loaded on permission-based sites (Invidious)
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
@@ -75,9 +76,11 @@ let lastCheckVideoTime = -1;
//is this channel whitelised from getting sponsors skipped
let channelWhitelisted = false;
-// create preview bar
let previewBar: PreviewBar = null;
+// Skip to highlight button
let skipButtonControlBar: SkipButtonControlBar = null;
+// For full video sponsors/selfpromo
+let categoryPill: CategoryPill = null;
/** Element containing the player controls on the YouTube player. */
let controls: HTMLElement | null = null;
@@ -263,6 +266,7 @@ function resetValues() {
}
skipButtonControlBar?.disable();
+ categoryPill?.setVisibility(false);
}
async function videoIDChange(id) {
@@ -549,6 +553,7 @@ function refreshVideoAttachments() {
setupVideoListeners();
setupSkipButtonControlBar();
+ setupCategoryPill();
}
}
}
@@ -637,6 +642,14 @@ function setupSkipButtonControlBar() {
skipButtonControlBar.attachToPage();
}
+function setupCategoryPill() {
+ if (!categoryPill) {
+ categoryPill = new CategoryPill();
+ }
+
+ categoryPill.attachToPage();
+}
+
async function sponsorsLookup(id: string, keepOldSubmissions = true) {
if (!video) refreshVideoAttachments();
//there is still no video here
@@ -672,7 +685,7 @@ async function sponsorsLookup(id: string, keepOldSubmissions = true) {
const hashPrefix = (await utils.getHash(id, 1)).substr(0, 4);
const response = await utils.asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, {
categories,
- actionTypes: Config.config.muteSegments ? [ActionType.Skip, ActionType.Mute] : [ActionType.Skip],
+ actionTypes: Config.config.muteSegments ? [ActionType.Skip, ActionType.Mute, ActionType.Full] : [ActionType.Skip, ActionType.Full],
userAgent: `${chrome.runtime.id}`,
...extraRequestData
});
@@ -864,6 +877,11 @@ function startSkipScheduleCheckingForStartSponsors() {
}
}
+ const fullVideoSegment = sponsorTimes.filter((time) => time.actionType === ActionType.Full)[0];
+ if (fullVideoSegment) {
+ categoryPill?.setSegment(fullVideoSegment);
+ }
+
if (startingSegmentTime !== -1) {
startSponsorSchedule(undefined, startingSegmentTime);
} else {
diff --git a/src/render/CategoryPill.tsx b/src/render/CategoryPill.tsx
new file mode 100644
index 00000000..6c6695e2
--- /dev/null
+++ b/src/render/CategoryPill.tsx
@@ -0,0 +1,71 @@
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import CategoryPillComponent, { CategoryPillState } from "../components/CategoryPillComponent";
+import { SponsorTime } from "../types";
+import { GenericUtils } from "../utils/genericUtils";
+
+export class CategoryPill {
+ container: HTMLElement;
+ ref: React.RefObject<CategoryPillComponent>;
+
+ unsavedState: CategoryPillState;
+
+ constructor() {
+ this.ref = React.createRef();
+ }
+
+ async attachToPage(): Promise<void> {
+ // TODO: Mobile and invidious
+ const referenceNode = await GenericUtils.wait(() => document.querySelector(".ytd-video-primary-info-renderer.title") as HTMLElement);
+
+ if (referenceNode && !referenceNode.contains(this.container)) {
+ this.container = document.createElement('span');
+ this.container.id = "categoryPill";
+ this.container.style.display = "relative";
+
+ referenceNode.prepend(this.container);
+ referenceNode.style.display = "flex";
+
+ ReactDOM.render(
+ <CategoryPillComponent ref={this.ref} />,
+ this.container
+ );
+
+ if (this.unsavedState) {
+ this.ref.current?.setState(this.unsavedState);
+ this.unsavedState = null;
+ }
+ }
+ }
+
+ close(): void {
+ ReactDOM.unmountComponentAtNode(this.container);
+ this.container.remove();
+ }
+
+ setVisibility(show: boolean): void {
+ const newState = {
+ show
+ };
+
+ if (this.ref.current) {
+ this.ref.current?.setState(newState);
+ } else {
+ this.unsavedState = newState;
+ }
+ }
+
+ setSegment(segment: SponsorTime): void {
+ const newState = {
+ segment,
+ show: true
+ };
+
+ if (this.ref.current) {
+ this.ref.current?.setState(newState);
+ } else {
+ this.unsavedState = newState;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/utils.ts b/src/utils.ts
index 661ca0bb..7cffa45a 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -2,6 +2,7 @@ import Config from "./config";
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration } from "./types";
import * as CompileConfig from "../config.json";
+import { GenericUtils } from "./utils/genericUtils";
export default class Utils {
@@ -23,27 +24,8 @@ export default class Utils {
this.backgroundScriptContainer = backgroundScriptContainer;
}
- /** Function that can be used to wait for a condition before returning. */
async wait<T>(condition: () => T | false, timeout = 5000, check = 100): Promise<T> {
- return await new Promise((resolve, reject) => {
- setTimeout(() => {
- clearInterval(interval);
- reject("TIMEOUT");
- }, timeout);
-
- const intervalCheck = () => {
- const result = condition();
- if (result !== false) {
- resolve(result);
- clearInterval(interval);
- }
- };
-
- const interval = setInterval(intervalCheck, check);
-
- //run the check once first, this speeds it up a lot
- intervalCheck();
- });
+ return GenericUtils.wait(condition, timeout, check);
}
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
diff --git a/src/utils/genericUtils.ts b/src/utils/genericUtils.ts
new file mode 100644
index 00000000..32cf83f5
--- /dev/null
+++ b/src/utils/genericUtils.ts
@@ -0,0 +1,26 @@
+/** Function that can be used to wait for a condition before returning. */
+async function wait<T>(condition: () => T | false, timeout = 5000, check = 100): Promise<T> {
+ return await new Promise((resolve, reject) => {
+ setTimeout(() => {
+ clearInterval(interval);
+ reject("TIMEOUT");
+ }, timeout);
+
+ const intervalCheck = () => {
+ const result = condition();
+ if (result) {
+ resolve(result);
+ clearInterval(interval);
+ }
+ };
+
+ const interval = setInterval(intervalCheck, check);
+
+ //run the check once first, this speeds it up a lot
+ intervalCheck();
+ });
+}
+
+export const GenericUtils = {
+ wait
+} \ No newline at end of file