aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAjay Ramachandran <[email protected]>2020-05-20 23:52:40 -0400
committerGitHub <[email protected]>2020-05-20 23:52:40 -0400
commit1676e50e15ea068189a2bf94b883d02ed1f854d1 (patch)
treec5fd4b34a74b6b74f5d95bb12be76ff5f2f84ba8
parent0850421afb99b8655060db455c3ae4e471f25db8 (diff)
parentf165b3b602c822cfbd4fcd797d9d4e8653932ddd (diff)
downloadSponsorBlock-1676e50e15ea068189a2bf94b883d02ed1f854d1.tar.gz
SponsorBlock-1676e50e15ea068189a2bf94b883d02ed1f854d1.zip
Merge pull request #357 from ajayyy/react1.2.29
Categories Improvements
-rw-r--r--.github/workflows/release.yml50
-rw-r--r--manifest/manifest.json4
-rw-r--r--package.json2
-rw-r--r--public/_locales/en/messages.json16
-rw-r--r--public/icons/thumbs_down.svg58
-rw-r--r--public/icons/thumbs_up.svg59
-rw-r--r--public/options/options.html17
-rw-r--r--src/components/SkipNoticeComponent.tsx274
-rw-r--r--src/config.ts7
-rw-r--r--src/content.ts83
-rw-r--r--src/render/SkipNotice.tsx15
-rw-r--r--src/types.ts4
12 files changed, 392 insertions, 197 deletions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 50ec9d43..5a5abfdf 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -49,6 +49,30 @@ jobs:
- name: Zip Artifacts
run: cd ./dist ; zip -r ../builds/ChromeExtensionBeta.zip *
+ # Upload each release asset
+ - name: Upload ChromeExtension to release
+ uses: Shopify/upload-to-release@master
+ with:
+ args: builds/ChromeExtension.zip
+ name: ChromeExtension.zip
+ path: ./builds/ChromeExtension.zip
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload ChromeExtensionBeta to release
+ uses: Shopify/upload-to-release@master
+ with:
+ args: builds/ChromeExtensionBeta.zip
+ name: ChromeExtensionBeta.zip
+ path: ./builds/ChromeExtensionBeta.zip
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload FirefoxExtension to release
+ uses: Shopify/upload-to-release@master
+ with:
+ args: builds/FirefoxExtension.zip
+ name: FirefoxExtension.zip
+ path: ./builds/FirefoxExtension.zip
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+
+ # Firefox Beta
- name: Create Firefox Beta artifacts
run: npm run build:firefox -- --env.stream=beta
- uses: actions/upload-artifact@v1
@@ -66,36 +90,14 @@ jobs:
WEB_EXT_API_SECRET: ${{ secrets.WEB_EXT_API_SECRET }}
- name: Install rename
run: sudo apt-get install rename
- - name: Install signed file
+ - name: Rename signed file
run: cd ./web-ext-artifacts ; rename 's/.*/FirefoxSignedInstaller.xpi/' *
- uses: actions/upload-artifact@v1
with:
name: FirefoxExtensionSigned.xpi
path: ./web-ext-artifacts/FirefoxSignedInstaller.xpi
- # Upload each release asset
- - name: Upload to release
- uses: Shopify/upload-to-release@master
- with:
- args: builds/ChromeExtension.zip
- name: ChromeExtension.zip
- path: ./builds/ChromeExtension.zip
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload to release
- uses: Shopify/upload-to-release@master
- with:
- args: builds/ChromeExtensionBeta.zip
- name: ChromeExtensionBeta.zip
- path: ./builds/ChromeExtensionBeta.zip
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload to release
- uses: Shopify/upload-to-release@master
- with:
- args: builds/FirefoxExtension.zip
- name: FirefoxExtension.zip
- path: ./builds/FirefoxExtension.zip
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload to release
+ - name: Upload FirefoxSignedInstaller.xpi to release
uses: Shopify/upload-to-release@master
with:
args: web-ext-artifacts/FirefoxSignedInstaller.xpi
diff --git a/manifest/manifest.json b/manifest/manifest.json
index a64cbb13..f704bc77 100644
--- a/manifest/manifest.json
+++ b/manifest/manifest.json
@@ -1,7 +1,7 @@
{
"name": "__MSG_fullName__",
"short_name": "__MSG_Name__",
- "version": "1.2.28.4",
+ "version": "1.2.29",
"default_locale": "en",
"description": "__MSG_Description__",
"content_scripts": [{
@@ -30,6 +30,8 @@
"icons/PlayerUploadFailedIconSponsorBlocker256px.png",
"icons/upvote.png",
"icons/downvote.png",
+ "icons/thumbs_down.svg",
+ "icons/thumbs_up.svg",
"icons/report.png",
"icons/close.png",
"icons/beep.ogg",
diff --git a/package.json b/package.json
index 88833083..6450ade6 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
},
"scripts": {
"web-run": "npm run web-run:chrome",
- "web-sign": "web-ext sign -s dist",
+ "web-sign": "web-ext sign -s dist --id [email protected]",
"web-run:firefox": "cd dist && web-ext run --start-url https://addons.mozilla.org/firefox/addon/ublock-origin/",
"web-run:chrome": "cd dist && web-ext run --start-url https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm -t chromium",
"build": "npm run build:chrome",
diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json
index b9859414..c8fa5bb9 100644
--- a/public/_locales/en/messages.json
+++ b/public/_locales/en/messages.json
@@ -35,11 +35,14 @@
"Segments": {
"message": "sponsor segments"
},
+ "upvoteButtonInfo": {
+ "message": "Upvote this submission"
+ },
"reportButtonTitle": {
"message": "Report"
},
"reportButtonInfo": {
- "message": "Report this sponsor submission as incorrect."
+ "message": "Report this submission as incorrect."
},
"Dismiss": {
"message": "Dismiss"
@@ -105,7 +108,7 @@
"message": "You have already voted this way before."
},
"serverDown": {
- "message": "It seems the sever is down. Contact the dev immediately."
+ "message": "It seems the server is down. Contact the dev immediately."
},
"connectionError": {
"message": "A connection error has occured. Error code: "
@@ -377,12 +380,6 @@
"currentInstances": {
"message": "Current Instances:"
},
- "enableAutoUpvote": {
- "message": "Auto Upvote"
- },
- "whatAutoUpvote": {
- "message": "With this enabled, the extension will upvote all submissions you view if you do not report them. If the notice is disabled, this will not occur."
- },
"minDuration": {
"message": "Minimum duration (seconds):"
},
@@ -566,5 +563,8 @@
},
"nonMusicCategoryOnMusic": {
"message": "This video is categorized as music. Are you sure you would like to submit segments with non-music categories? Unless this video is not actually music, you should not be submitting this segment. Please read the guidelines if you are confused."
+ },
+ "multipleSegments": {
+ "message": "Multiple Segments"
}
}
diff --git a/public/icons/thumbs_down.svg b/public/icons/thumbs_down.svg
new file mode 100644
index 00000000..09b88432
--- /dev/null
+++ b/public/icons/thumbs_down.svg
@@ -0,0 +1,58 @@
+<?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"
+ height="24"
+ viewBox="0 0 24 24"
+ width="24"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="thumbs_down.svg"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="730"
+ inkscape:window-height="480"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="9.8333333"
+ inkscape:cx="12"
+ inkscape:cy="12"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6" />
+ <path
+ d="M0 0h24v24H0z"
+ fill="none"
+ id="path2" />
+ <path
+ d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"
+ id="path4"
+ style="fill:#ffffff" />
+</svg>
diff --git a/public/icons/thumbs_up.svg b/public/icons/thumbs_up.svg
new file mode 100644
index 00000000..85e1b743
--- /dev/null
+++ b/public/icons/thumbs_up.svg
@@ -0,0 +1,59 @@
+<?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 24 24"
+ fill="black"
+ width="18px"
+ height="18px"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="thumbs_up.svg"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="730"
+ inkscape:window-height="480"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="13.111111"
+ inkscape:cx="9"
+ inkscape:cy="9"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6" />
+ <path
+ d="M0 0h24v24H0V0z"
+ fill="none"
+ id="path2" />
+ <path
+ d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"
+ id="path4"
+ style="fill:#ffffff" />
+</svg>
diff --git a/public/options/options.html b/public/options/options.html
index 0a93ad22..3cd69b01 100644
--- a/public/options/options.html
+++ b/public/options/options.html
@@ -237,23 +237,6 @@
<br/>
<br/>
- <div option-type="toggle" sync-option="autoUpvote">
- <label class="switch-container" label-name="__MSG_enableAutoUpvote__">
- <label class="switch">
- <input type="checkbox" checked>
- <span class="slider round"></span>
- </label>
- </label>
-
- <br/>
- <br/>
-
- <div class="small-description">__MSG_whatAutoUpvote__</div>
- </div>
-
- <br/>
- <br/>
-
<div option-type="toggle" sync-option="trackViewCount">
<label class="switch-container" label-name="__MSG_enableViewTracking__">
<label class="switch">
diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx
index 602b0ffc..7e6c4751 100644
--- a/src/components/SkipNoticeComponent.tsx
+++ b/src/components/SkipNoticeComponent.tsx
@@ -1,7 +1,7 @@
import * as React from "react";
import * as CompileConfig from "../../config.json";
import Config from "../config"
-import { ContentContainer, SponsorHideType } from "../types";
+import { ContentContainer, SponsorHideType, SponsorTime } from "../types";
import Utils from "../utils";
var utils = new Utils();
@@ -9,9 +9,17 @@ var utils = new Utils();
import NoticeComponent from "./NoticeComponent";
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
+enum SkipNoticeAction {
+ None,
+ Upvote,
+ Downvote,
+ CategoryVote,
+ Unskip
+}
+
+export interface SkipNoticeProps {
+ segments: SponsorTime[];
-export interface SkipNoticeProps {
- UUID: string;
autoSkip: boolean;
// Contains functions and variables from the content script needed by the skip notice
contentContainer: ContentContainer;
@@ -29,14 +37,17 @@ export interface SkipNoticeState {
countdownText: string;
unskipText: string;
- unskipCallback: () => void;
+ unskipCallback: (index: number) => void;
downvoting: boolean;
choosingCategory: boolean;
+ thanksForVotingText: boolean; //null until the voting buttons should be hidden
+
+ actionState: SkipNoticeAction;
}
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
- UUID: string;
+ segments: SponsorTime[];
autoSkip: boolean;
// Contains functions and variables from the content script needed by the skip notice
contentContainer: ContentContainer;
@@ -57,22 +68,30 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
this.noticeRef = React.createRef();
this.categoryOptionRef = React.createRef();
- this.UUID = props.UUID;
+ this.segments = props.segments;
this.autoSkip = props.autoSkip;
this.contentContainer = props.contentContainer;
this.audio = null;
-
- let noticeTitle = chrome.i18n.getMessage("category_" + this.getSponsorTime().category) + " " + chrome.i18n.getMessage("skipped");
-
+
+ let categoryName = chrome.i18n.getMessage(this.segments.length > 1 ? "multipleSegments" : "category_" + this.segments[0].category);
+ let noticeTitle = categoryName + " " + chrome.i18n.getMessage("skipped");
if (!this.autoSkip) {
- noticeTitle = chrome.i18n.getMessage("skip") + " " + chrome.i18n.getMessage("category_" + this.getSponsorTime().category) + "?";
+ noticeTitle = chrome.i18n.getMessage("skip") + " " + categoryName + "?";
}
//add notice
this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
+
+ // Sort segments
+ if (this.segments.length > 1) {
+ this.segments.sort((a, b) => a.segment[0] - b.segment[0]);
+ }
//this is the suffix added at the end of every id
- this.idSuffix = this.UUID + this.amountOfPreviousNotices;
+ for (const segment of this.segments) {
+ this.idSuffix += segment.UUID;
+ }
+ this.idSuffix += this.amountOfPreviousNotices;
if (this.amountOfPreviousNotices > 0) {
//another notice exists
@@ -92,22 +111,21 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
countdownText: null,
unskipText: chrome.i18n.getMessage("unskip"),
- unskipCallback: this.unskip.bind(this),
+ unskipCallback: (index) => this.unskip(index),
downvoting: false,
- choosingCategory: false
+ choosingCategory: false,
+ thanksForVotingText: null,
+
+ actionState: SkipNoticeAction.None
}
if (!this.autoSkip) {
- Object.assign(this.state, this.getUnskippedModeInfo(chrome.i18n.getMessage("skip")));
+ // Assume manual skip is only skipping 1 submission
+ Object.assign(this.state, this.getUnskippedModeInfo(0, chrome.i18n.getMessage("skip")));
}
}
- // Helper method
- getSponsorTime() {
- return utils.getSponsorTimeFromUUID(this.contentContainer().sponsorTimes, this.UUID);
- }
-
componentDidMount() {
if (Config.config.audioNotificationOnSkip && this.audio) {
this.audio.volume = this.contentContainer().v.volume * 0.1;
@@ -145,35 +163,46 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
<tr id={"sponsorSkipNoticeSecondRow" + this.idSuffix}>
{/* Vote Button Container */}
- <td id={"sponsorTimesVoteButtonsContainer" + this.idSuffix}
- className="sponsorTimesVoteButtonsContainer">
-
- {/* Report Text */}
- <span id={"sponsorTimesReportText" + this.idSuffix}
- className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
- title={chrome.i18n.getMessage("reportButtonInfo")}
- style={{marginRight: "5px"}}>
-
- {chrome.i18n.getMessage("reportButtonTitle")}
- </span>
-
- {/* Report Button */}
- <img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
- className="sponsorSkipObject voteButton"
- src={chrome.extension.getURL("icons/report.png")}
- title={chrome.i18n.getMessage("reportButtonInfo")}
- onClick={() => this.adjustDownvotingState(true)}>
-
- </img>
+ {!this.state.thanksForVotingText ?
+ <td id={"sponsorTimesVoteButtonsContainer" + this.idSuffix}
+ className="sponsorTimesVoteButtonsContainer">
+
+ {/* Upvote Button */}
+ <img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
+ className="sponsorSkipObject voteButton"
+ style={{marginRight: "10px"}}
+ src={chrome.extension.getURL("icons/thumbs_up.svg")}
+ title={chrome.i18n.getMessage("upvoteButtonInfo")}
+ onClick={() => this.prepAction(SkipNoticeAction.Upvote)}>
+
+ </img>
+
+ {/* Report Button */}
+ <img id={"sponsorTimesDownvoteButtonsContainer" + this.idSuffix}
+ className="sponsorSkipObject voteButton"
+ src={chrome.extension.getURL("icons/thumbs_down.svg")}
+ title={chrome.i18n.getMessage("reportButtonInfo")}
+ onClick={() => this.adjustDownvotingState(true)}>
+
+ </img>
- </td>
+ </td>
+
+ :
+
+ <td id={"sponsorTimesVoteButtonInfoMessage" + this.idSuffix}
+ className="sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"
+ style={{marginRight: "10px"}}>
+ {this.state.thanksForVotingText}
+ </td>
+ }
{/* Unskip Button */}
<td className="sponsorSkipNoticeUnskipSection">
<button id={"sponsorSkipUnskipButton" + this.idSuffix}
className="sponsorSkipObject sponsorSkipNoticeButton"
style={{marginLeft: "4px"}}
- onClick={this.state.unskipCallback}>
+ onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
{this.state.unskipText}
</button>
@@ -198,7 +227,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
{/* Normal downvote */}
<button className="sponsorSkipObject sponsorSkipNoticeButton"
- onClick={() => this.contentContainer().vote(0, this.UUID, undefined, this)}>
+ onClick={() => this.prepAction(SkipNoticeAction.Downvote)}>
{chrome.i18n.getMessage("downvoteDescription")}
</button>
@@ -220,7 +249,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
{/* Category Selector */}
<select id={"sponsorTimeCategories" + this.idSuffix}
className="sponsorTimeCategories"
- defaultValue={this.getSponsorTime().category}
+ defaultValue={this.segments[0].category} //Just default to the first segment, as we don't know which they'll choose
ref={this.categoryOptionRef}
onChange={this.categorySelectionChange.bind(this)}>
@@ -228,11 +257,23 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
</select>
{/* Submit Button */}
- <button className="sponsorSkipObject sponsorSkipNoticeButton"
- onClick={() => this.contentContainer().vote(undefined, this.UUID, this.categoryOptionRef.current.value, this)}>
+ {this.segments.length === 1 &&
+ <button className="sponsorSkipObject sponsorSkipNoticeButton"
+ onClick={() => this.prepAction(SkipNoticeAction.CategoryVote)}>
+
+ {chrome.i18n.getMessage("submit")}
+ </button>
+ }
+
+ </td>
+ </tr>
+ }
- {chrome.i18n.getMessage("submit")}
- </button>
+ {/* Segment Chooser Row */}
+ {this.state.actionState !== SkipNoticeAction.None &&
+ <tr id={"sponsorSkipNoticeSubmissionOptionsRow" + this.idSuffix}>
+ <td id={"sponsorTimesSubmissionOptionsContainer" + this.idSuffix}>
+ {this.getSubmissionChooser()}
</td>
</tr>
}
@@ -241,6 +282,32 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
);
}
+ getSubmissionChooser(): JSX.Element[] {
+ let elements: JSX.Element[] = [];
+
+ for (let i = 0; i < this.segments.length; i++) {
+ elements.push(
+ <button className="sponsorSkipObject sponsorSkipNoticeButton"
+ onClick={() => this.performAction(i)}
+ key={"submission" + i + this.segments[i].category + this.idSuffix}>
+ {(i + 1) + ". " + chrome.i18n.getMessage("category_" + this.segments[i].category)}
+ </button>
+ );
+ }
+
+ return elements;
+ }
+
+ prepAction(action: SkipNoticeAction) {
+ if (this.segments.length === 1) {
+ this.performAction(0, action);
+ } else {
+ this.setState({
+ actionState: action
+ });
+ }
+ }
+
getMessageBoxes(): JSX.Element[] | JSX.Element {
if (this.state.messages.length === 0) {
// Add a spacer if there is no text
@@ -265,6 +332,34 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
return elements;
}
+ /**
+ * Performs the action from the current state
+ *
+ * @param index
+ */
+ performAction(index: number, action?: SkipNoticeAction) {
+ switch (action ?? this.state.actionState) {
+ case SkipNoticeAction.None:
+ break;
+ case SkipNoticeAction.Upvote:
+ this.contentContainer().vote(1, this.segments[index].UUID, undefined, this);
+ break;
+ case SkipNoticeAction.Downvote:
+ this.contentContainer().vote(0, this.segments[index].UUID, undefined, this);
+ break;
+ case SkipNoticeAction.CategoryVote:
+ this.contentContainer().vote(undefined, this.segments[index].UUID, this.categoryOptionRef.current.value, this)
+ break;
+ case SkipNoticeAction.Unskip:
+ this.state.unskipCallback(index);
+ break;
+ }
+
+ this.setState({
+ actionState: SkipNoticeAction.None
+ });
+ }
+
adjustDownvotingState(value: boolean) {
if (!value) this.clearConfigListener();
@@ -289,6 +384,11 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
this.setState({
choosingCategory: true,
downvoting: false
+ }, () => {
+ if (this.segments.length > 1) {
+ // Use the action selectors as a submit button
+ this.prepAction(SkipNoticeAction.CategoryVote);
+ }
});
}
@@ -324,37 +424,38 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
chrome.runtime.sendMessage({"message": "openConfig"});
// Reset option to original
- event.target.value = this.getSponsorTime().category;
+ event.target.value = this.segments[0].category;
return;
}
}
- unskip() {
- this.contentContainer().unskipSponsorTime(this.UUID);
+ unskip(index: number) {
+ this.contentContainer().unskipSponsorTime(this.segments[index]);
- this.unskippedMode(chrome.i18n.getMessage("reskip"));
+ this.unskippedMode(index, chrome.i18n.getMessage("reskip"));
}
/** Sets up notice to be not skipped yet */
- unskippedMode(buttonText: string) {
+ unskippedMode(index: number, buttonText: string) {
//setup new callback and reset countdown
- this.setState(this.getUnskippedModeInfo(buttonText), () => {
+ this.setState(this.getUnskippedModeInfo(index, buttonText), () => {
this.noticeRef.current.resetCountdown();
});
}
- getUnskippedModeInfo(buttonText: string) {
+ getUnskippedModeInfo(index: number, buttonText: string) {
+ let self = this;
let maxCountdownTime = function() {
- let sponsorTime = this.getSponsorTime();
- let duration = Math.round((sponsorTime.segment[1] - this.contentContainer().v.currentTime) * (1 / this.contentContainer().v.playbackRate));
+ let sponsorTime = self.segments[index];
+ let duration = Math.round((sponsorTime.segment[1] - self.contentContainer().v.currentTime) * (1 / self.contentContainer().v.playbackRate));
return Math.max(duration, 4);
- }.bind(this);
+ };
return {
unskipText: buttonText,
- unskipCallback: this.reskip.bind(this),
+ unskipCallback: (index) => this.reskip(index),
//change max duration to however much of the sponsor is left
maxCountdownTime: maxCountdownTime,
@@ -363,8 +464,8 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
}
}
- reskip() {
- this.contentContainer().reskipSponsorTime(this.UUID);
+ reskip(index: number) {
+ this.contentContainer().reskipSponsorTime(this.segments[index]);
//reset countdown
this.setState({
@@ -380,24 +481,23 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
this.setState({
noticeTitle: chrome.i18n.getMessage("noticeTitle")
});
-
- if(Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
}
}
- afterDownvote(type: number, category: string) {
+ afterVote(segment: SponsorTime, type: number, category: string) {
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
- this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
- this.adjustDownvotingState(false);
+ if (type === 0) {
+ this.setNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
+ this.adjustDownvotingState(false);
+ }
// Change the sponsor locally
- let sponsorTime = this.getSponsorTime();
- if (sponsorTime) {
+ if (segment) {
if (type === 0) {
- sponsorTime.hidden = SponsorHideType.Downvoted;
+ segment.hidden = SponsorHideType.Downvoted;
} else if (category) {
- sponsorTime.category = category;
+ segment.category = category;
}
this.contentContainer().updatePreviewBar();
@@ -407,41 +507,19 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
setNoticeInfoMessage(...messages: string[]) {
this.setState({
messages
- })
+ });
}
addVoteButtonInfo(message) {
- this.resetVoteButtonInfo();
-
- //hide report button and text for it
- let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
- if (downvoteButton != null) {
- downvoteButton.style.display = "none";
- }
- let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
- if (downvoteButtonText != null) {
- downvoteButtonText.style.display = "none";
- }
-
- //add info
- let thanksForVotingText = document.createElement("td");
- thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
- thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
- thanksForVotingText.innerText = message;
-
- //add element to div
- document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
+ this.setState({
+ thanksForVotingText: message
+ });
}
resetVoteButtonInfo() {
- let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
- if (previousInfoMessage != null) {
- //remove it
- document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
- }
-
- //show button again
- document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
+ this.setState({
+ thanksForVotingText: null
+ });
}
closeListener() {
diff --git a/src/config.ts b/src/config.ts
index 7b8fe15b..d26859ec 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -24,7 +24,6 @@ interface SBConfig {
hideDiscordLaunches: number,
hideDiscordLink: boolean,
invidiousInstances: string[],
- autoUpvote: boolean,
supportInvidious: boolean,
serverAddress: string,
minDuration: number,
@@ -124,7 +123,6 @@ var Config: SBObject = {
hideDiscordLaunches: 0,
hideDiscordLink: false,
invidiousInstances: ["invidio.us", "invidious.snopyta.org"],
- autoUpvote: true,
supportInvidious: false,
serverAddress: CompileConfig.serverAddress,
minDuration: 0,
@@ -252,6 +250,11 @@ async function migrateOldFormats() {
}
}
+ // Auto vote removal
+ if (Config.config["autoUpvote"]) {
+ chrome.storage.sync.remove("autoUpvote");
+ }
+
// Channel URLS
if (Config.config.whitelistedChannels.length > 0 &&
(Config.config.whitelistedChannels[0] == null || Config.config.whitelistedChannels[0].includes("/"))) {
diff --git a/src/content.ts b/src/content.ts
index 50ec0ec8..bf47077b 100644
--- a/src/content.ts
+++ b/src/content.ts
@@ -78,12 +78,6 @@ utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYo
//this only happens if there is an error
var sponsorLookupRetries = 0;
-//the last time in the video a sponsor was skipped
-//used for the go back button
-var lastSponsorTimeSkipped: number = null;
-//used for ratings
-var lastSponsorTimeSkippedUUID: string = null;
-
//if showing the start sponsor button or the end sponsor button on the player
var showingStartSponsor = true;
@@ -496,6 +490,19 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
let timeUntilSponsor = skipTime[0] - currentTime;
let videoID = sponsorVideoID;
+ // Find all indexes in between the start and end
+ let skippingSegments = [skipInfo.array[skipInfo.index]];
+ if (skipInfo.index !== skipInfo.endIndex) {
+ skippingSegments = [];
+
+ for (const segment of skipInfo.array) {
+ if (utils.getCategorySelection(segment.category).option === CategorySkipOption.AutoSkip &&
+ segment.segment[0] >= skipTime[0] && segment.segment[1] <= skipTime[1]) {
+ skippingSegments.push(segment);
+ }
+ }
+ }
+
// Don't skip if this category should not be skipped
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ShowOverlay) return;
@@ -506,7 +513,7 @@ function startSponsorSchedule(includeIntersectingSegments: boolean = false, curr
if (incorrectVideoCheck(videoID, currentSkip)) return;
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
- skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice);
+ skipToTime(video, skipTime, skippingSegments, skipInfo.openNotice);
// TODO: Know the autoSkip settings for ALL items being skipped
if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) {
@@ -973,58 +980,58 @@ function previewTime(time: number) {
}
//skip from the start time to the end time for a certain index sponsor time
-function skipToTime(v: HTMLVideoElement, index: number, sponsorTimes: SponsorTime[], openNotice: boolean) {
- let autoSkip: boolean = utils.getCategorySelection(sponsorTimes[index].category).option === CategorySkipOption.AutoSkip;
+function skipToTime(v: HTMLVideoElement, skipTime: number[], skippingSegments: SponsorTime[], openNotice: boolean) {
+ // There will only be one submission if it is manual skip
+ let autoSkip: boolean = utils.getCategorySelection(skippingSegments[0].category).option === CategorySkipOption.AutoSkip;
if (autoSkip || previewResetter !== null) {
- v.currentTime = sponsorTimes[index].segment[1];
+ v.currentTime = skipTime[1];
}
- lastSponsorTimeSkipped = sponsorTimes[index].segment[0];
-
- let currentUUID: string = sponsorTimes[index].UUID;
- lastSponsorTimeSkippedUUID = currentUUID;
-
if (openNotice) {
//send out the message saying that a sponsor message was skipped
if (!Config.config.dontShowNotice || !autoSkip) {
- let skipNotice = new SkipNotice(currentUUID, autoSkip, skipNoticeContentContainer);
-
- //auto-upvote this sponsor
- if (Config.config.trackViewCount && autoSkip && Config.config.autoUpvote) {
- vote(1, currentUUID);
- }
+ let skipNotice = new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer);
}
//send telemetry that a this sponsor was skipped
- if (Config.config.trackViewCount && !sponsorSkipped[index] && autoSkip) {
- utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + currentUUID);
+ if (Config.config.trackViewCount && autoSkip) {
+ let alreadySkipped = false;
+ let isPreviewSegment = false;
+
+ for (const segment of skippingSegments) {
+ let index = sponsorTimes.indexOf(segment);
+ if (index !== -1 && !sponsorSkipped[index]) {
+ utils.sendRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + segment.UUID);
+
+ sponsorSkipped[index] = true;
+ } else if (sponsorSkipped[index]) {
+ alreadySkipped = true;
+ }
+ if (index !== -1) isPreviewSegment = true;
+ }
+
// Count this as a skip
- Config.config.minutesSaved = Config.config.minutesSaved + (sponsorTimes[index].segment[1] - sponsorTimes[index].segment[0]) / 60;
- Config.config.skipCount = Config.config.skipCount + 1;
-
- sponsorSkipped[index] = true;
+ if (!alreadySkipped && !isPreviewSegment) {
+ Config.config.minutesSaved = Config.config.minutesSaved + (skipTime[1] - skipTime[0]) / 60;
+ Config.config.skipCount = Config.config.skipCount + 1;
+ }
}
}
}
-function unskipSponsorTime(UUID) {
+function unskipSponsorTime(segment: SponsorTime) {
if (sponsorTimes != null) {
//add a tiny bit of time to make sure it is not skipped again
- video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[0] + 0.001;
+ video.currentTime = segment.segment[0] + 0.001;
checkIfInsideSegment();
}
}
-function reskipSponsorTime(UUID) {
- if (sponsorTimes != null) {
- video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1];
-
- // See if any skips need to be done if this is inside of another segment
- startSponsorSchedule(true, utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1]);
- }
+function reskipSponsorTime(segment: SponsorTime) {
+ video.currentTime = segment.segment[1];
}
/**
@@ -1387,9 +1394,7 @@ function vote(type: number, UUID: string, category?: string, skipNotice?: SkipNo
if (skipNotice != null) {
if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) {
//success (treat rate limits as a success)
- if (type === 0 || category) {
- skipNotice.afterDownvote.bind(skipNotice)(type, category);
- }
+ skipNotice.afterVote.bind(skipNotice)(utils.getSponsorTimeFromUUID(sponsorTimes, UUID), type, category);
} else if (response.successType == 0) {
//failure: duplicate vote
skipNotice.setNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail"))
diff --git a/src/render/SkipNotice.tsx b/src/render/SkipNotice.tsx
index 49265fb8..4b969098 100644
--- a/src/render/SkipNotice.tsx
+++ b/src/render/SkipNotice.tsx
@@ -2,17 +2,18 @@ import * as React from "react";
import * as ReactDOM from "react-dom";
import SkipNoticeComponent from "../components/SkipNoticeComponent";
+import { SponsorTime } from "../types";
class SkipNotice {
- UUID: string;
+ segments: SponsorTime[];
autoSkip: boolean;
// Contains functions and variables from the content script needed by the skip notice
contentContainer: () => any;
noticeElement: HTMLDivElement;
- constructor(UUID: string, autoSkip: boolean = false, contentContainer) {
- this.UUID = UUID;
+ constructor(segments: SponsorTime[], autoSkip: boolean = false, contentContainer) {
+ this.segments = segments;
this.autoSkip = autoSkip;
this.contentContainer = contentContainer;
@@ -35,7 +36,11 @@ class SkipNotice {
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
//this is the suffix added at the end of every id
- let idSuffix = this.UUID + amountOfPreviousNotices;
+ let idSuffix = "";
+ for (const segment of this.segments) {
+ idSuffix += segment.UUID;
+ }
+ idSuffix += amountOfPreviousNotices;
this.noticeElement = document.createElement("div");
this.noticeElement.id = "sponsorSkipNoticeContainer" + idSuffix;
@@ -43,7 +48,7 @@ class SkipNotice {
referenceNode.prepend(this.noticeElement);
ReactDOM.render(
- <SkipNoticeComponent UUID={UUID}
+ <SkipNoticeComponent segments={segments}
autoSkip={autoSkip}
contentContainer={contentContainer}
closeListener={() => this.close()} />,
diff --git a/src/types.ts b/src/types.ts
index 0bf80bd9..002f4daf 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -5,12 +5,12 @@ interface ContentContainer {
(): {
vote: (type: any, UUID: any, category?: string, skipNotice?: SkipNoticeComponent) => void,
dontShowNoticeAgain: () => void,
- unskipSponsorTime: (UUID: any) => void,
+ unskipSponsorTime: (segment: SponsorTime) => void,
sponsorTimes: SponsorTime[],
sponsorTimesSubmitting: SponsorTime[],
v: HTMLVideoElement,
sponsorVideoID,
- reskipSponsorTime: (UUID: any) => void,
+ reskipSponsorTime: (segment: SponsorTime) => void,
updatePreviewBar: () => void,
onMobileYouTube: boolean,
sponsorSubmissionNotice: SubmissionNotice,