Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Feature : Advance notice skip #84

Merged
merged 10 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions public/_locales/en/en.messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,11 @@
"description": "Used for skipping to things (Skip to Highlight)"
},
"skipped": {
"message": "{0} Skipped",
"message": "{0} Ready Skipped",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

en.message.json 文件其实不需要更新,这个文件是用来追踪原插件的文本,每次合并原插件版本的时候才更新一次

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同目录下的message.json 也不需要吗?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

message.json是需要的,en.message.json不需要,不过问题不大,因为下次同步会覆盖的

"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} Muted",
"message": "{0} Ready Muted",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
Expand Down
4 changes: 2 additions & 2 deletions public/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,11 @@
"description": "Used for skipping to things (Skip to Highlight)"
},
"skipped": {
"message": "{0} 已跳过",
"message": "{0} 准备跳过",
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} 已静音",
"message": "{0} 准备静音",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
Expand Down
4 changes: 2 additions & 2 deletions public/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,11 @@
"description": "Used for skipping to things (Skip to Highlight)"
},
"skipped": {
"message": "{0} 已跳过",
"message": "{0} 准备跳过",
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} 已静音",
"message": "{0} 准备静音",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
Expand Down
4 changes: 2 additions & 2 deletions public/_locales/zh_TW/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,11 @@
"description": "Used for skipping to things (Skip to Highlight)"
},
"skipped": {
"message": "{0} 已跳過",
"message": "{0} 準備跳過",
"description": "Example: Sponsor Skipped"
},
"muted": {
"message": "{0} 已靜音",
"message": "{0} 準備靜音",
"description": "Example: Sponsor Muted"
},
"skipped_to_category": {
Expand Down
9 changes: 8 additions & 1 deletion src/components/SkipNoticeComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
smaller: boolean;

unskipTime?: number;
readySkip: NodeJS.Timeout

Check warning on line 47 in src/components/SkipNoticeComponent.tsx

View workflow job for this annotation

GitHub Actions / Create artifacts

Expected a semicolon
}

export interface SkipNoticeState {
Expand Down Expand Up @@ -72,6 +73,8 @@

voted?: SkipNoticeAction[];
copied?: SkipNoticeAction[];

readySkip: NodeJS.Timeout;
}

class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
Expand Down Expand Up @@ -173,6 +176,8 @@
// Keep track of what segment the user interacted with.
voted: new Array(this.props.segments.length).fill(SkipNoticeAction.None),
copied: new Array(this.props.segments.length).fill(SkipNoticeAction.None),

readySkip: this.props.readySkip,
};

if (!this.autoSkip) {
Expand Down Expand Up @@ -678,7 +683,8 @@
}

unskip(buttonIndex: number, index: number, forceSeek: boolean): void {
this.contentContainer().unskipSponsorTime(this.segments[index], this.props.unskipTime, forceSeek);
this.contentContainer().unskipSponsorTime(this.segments[index], this.props.unskipTime, this.state.readySkip, forceSeek);
this.setState({ readySkip: null });

this.unskippedMode(buttonIndex, index, SkipButtonState.Redo);
}
Expand All @@ -698,6 +704,7 @@

maxCountdownTime: () => Config.config.skipNoticeDuration,
countdownTime: Config.config.skipNoticeDuration,
readySkip: null
};

//reset countdown
Expand Down
120 changes: 72 additions & 48 deletions src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ let retryFetchTimeout: NodeJS.Timeout = null;
let shownSegmentFailedToFetchWarning = false;
let selectedSegment: SegmentUUID | null = null;
let previewedSegment = false;
let readySkip: NodeJS.Timeout

// JSON video info
let videoInfo: VideoInfo = null;
Expand Down Expand Up @@ -307,6 +308,7 @@ function messageListener(
unskipSponsorTime(
sponsorTimes.find((segment) => segment.UUID === request.UUID),
null,
null,
true
);
break;
Expand Down Expand Up @@ -651,7 +653,7 @@ async function startSponsorSchedule(
shouldSkip(currentSkip) ||
sponsorTimesSubmitting?.some((segment) => segment.segment === currentSkip.segment)
) {
if (forceVideoTime >= skipTime[0] - skipBuffer && forceVideoTime < skipTime[1]) {
if (forceVideoTime >= skipTime[0] - skipBuffer - Config.config.skipNoticeDuration * 1000 && forceVideoTime < skipTime[1]) {
skipToTime({
v: getVideo(),
skipTime,
Expand Down Expand Up @@ -757,7 +759,7 @@ async function startSponsorSchedule(

const offset = isFirefoxOrSafari() && !isSafari() ? 600 : 150;
// Schedule for right before to be more precise than normal timeout
currentSkipSchedule = setTimeout(skippingFunction, Math.max(0, delayTime - offset));
currentSkipSchedule = setTimeout(skippingFunction, Math.max(0, delayTime - offset - Config.config.skipNoticeDuration * 1000));
}
}
}
Expand Down Expand Up @@ -1850,50 +1852,54 @@ function skipToTime({ v, skipTime, skippingSegments, openNotice, forceAutoSkip,
const autoSkip: boolean = forceAutoSkip || shouldAutoSkip(skippingSegments[0]);
const isSubmittingSegment = sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment);

if ((autoSkip || isSubmittingSegment) && v.currentTime !== skipTime[1]) {
switch (skippingSegments[0].actionType) {
case ActionType.Poi:
case ActionType.Skip: {
// Fix for looped videos not working when skipping to the end #426
// for some reason you also can't skip to 1 second before the end
if (v.loop && v.duration > 1 && skipTime[1] >= v.duration - 1) {
v.currentTime = 0;
} else if (
v.duration > 1 &&
skipTime[1] >= v.duration &&
(navigator.vendor === "Apple Computer, Inc." || isPlayingPlaylist())
) {
// MacOS will loop otherwise #1027
// Sometimes playlists loop too #1804
v.currentTime = v.duration - 0.001;
} else if (
v.duration > 1 &&
Math.abs(skipTime[1] - v.duration) < endTimeSkipBuffer &&
isFirefoxOrSafari() &&
!isSafari()
) {
v.currentTime = v.duration;
} else {
if (inMuteSegment(skipTime[1], true)) {
// Make sure not to mute if skipping into a mute segment
v.muted = true;
videoMuted = true;
//防止重复调用导致反复横跳
clearTimeout(readySkip)
readySkip = setTimeout(function () {
if ((autoSkip || isSubmittingSegment) && v.currentTime !== skipTime[1]) {
switch (skippingSegments[0].actionType) {
case ActionType.Poi:
case ActionType.Skip: {
// Fix for looped videos not working when skipping to the end #426
// for some reason you also can't skip to 1 second before the end
if (v.loop && v.duration > 1 && skipTime[1] >= v.duration - 1) {
v.currentTime = 0;
} else if (
v.duration > 1 &&
skipTime[1] >= v.duration &&
(navigator.vendor === "Apple Computer, Inc." || isPlayingPlaylist())
) {
// MacOS will loop otherwise #1027
// Sometimes playlists loop too #1804
v.currentTime = v.duration - 0.001;
} else if (
v.duration > 1 &&
Math.abs(skipTime[1] - v.duration) < endTimeSkipBuffer &&
isFirefoxOrSafari() &&
!isSafari()
) {
v.currentTime = v.duration;
} else {
if (inMuteSegment(skipTime[1], true)) {
// Make sure not to mute if skipping into a mute segment
v.muted = true;
videoMuted = true;
}

v.currentTime = skipTime[1];
}

v.currentTime = skipTime[1];
break;
}

break;
}
case ActionType.Mute: {
if (!v.muted) {
v.muted = true;
videoMuted = true;
case ActionType.Mute: {
if (!v.muted) {
v.muted = true;
videoMuted = true;
}
break;
}
break;
}
}
}
}, howLongToSkip(skippingSegments, skipTime));

if (autoSkip && Config.config.audioNotificationOnSkip && !isSubmittingSegment && !getVideo()?.muted) {
const beep = new Audio(chrome.runtime.getURL("icons/beep.ogg"));
Expand All @@ -1919,15 +1925,15 @@ function skipToTime({ v, skipTime, skippingSegments, openNotice, forceAutoSkip,
if (openNotice) {
//send out the message saying that a sponsor message was skipped
if (!Config.config.dontShowNotice || !autoSkip) {
createSkipNotice(skippingSegments, autoSkip, unskipTime, false);
createSkipNotice(skippingSegments, autoSkip, unskipTime, false, readySkip);
} else if (autoSkip) {
activeSkipKeybindElement?.setShowKeybindHint(false);
activeSkipKeybindElement = {
setShowKeybindHint: () => {}, //eslint-disable-line @typescript-eslint/no-empty-function
setShowKeybindHint: () => {},
toggleSkip: () => {
unskipSponsorTime(skippingSegments[0], unskipTime);
createSkipNotice(skippingSegments, autoSkip, unskipTime, true, readySkip);

createSkipNotice(skippingSegments, autoSkip, unskipTime, true);
readySkip = unskipSponsorTime(skippingSegments[0], unskipTime, readySkip);
},
};
}
Expand All @@ -1942,7 +1948,8 @@ function createSkipNotice(
skippingSegments: SponsorTime[],
autoSkip: boolean,
unskipTime: number,
startReskip: boolean
startReskip: boolean,
readySkip: NodeJS.Timeout
) {
for (const skipNotice of skipNotices) {
if (
Expand All @@ -1959,7 +1966,8 @@ function createSkipNotice(
autoSkip,
skipNoticeContentContainer,
unskipTime,
startReskip
startReskip,
readySkip
);
if (Config.config.skipKeybind == null) newSkipNotice.setShowKeybindHint(false);
skipNotices.push(newSkipNotice);
Expand All @@ -1968,15 +1976,31 @@ function createSkipNotice(
activeSkipKeybindElement = newSkipNotice;
}

function unskipSponsorTime(segment: SponsorTime, unskipTime: number = null, forceSeek = false) {
function unskipSponsorTime(segment: SponsorTime, unskipTime: number, readySkip: NodeJS.Timeout, forceSeek = false) {
if (segment.actionType === ActionType.Mute) {
getVideo().muted = false;
videoMuted = false;
}

if (forceSeek || segment.actionType === ActionType.Skip) {
//add a tiny bit of time to make sure it is not skipped again
getVideo().currentTime = unskipTime ?? segment.segment[0] + 0.001;
if(readySkip){
clearTimeout(readySkip)
return null
}else{
getVideo().currentTime = unskipTime ?? segment.segment[0] + 0.001;
}
}
}

//适配不同的片段
function howLongToSkip(skippingSegments: SponsorTime[], skipTime: number[]){
if (skippingSegments[0].category === "sponsor" || skippingSegments[0].category === "selfpromo" || skippingSegments[0].category === "filler" || skippingSegments[0].category === "music_offtopic") {
return Math.min(Config.config.skipNoticeDuration * 1000 / getVideo().playbackRate, (skipTime[0] - getVideo().currentTime) * 1000 / getVideo().playbackRate)
} else if (skippingSegments[0].category === "poi_highlight" || skippingSegments[0].category === "preview" || skippingSegments[0].category === "interaction" || skippingSegments[0].category === "intro" || skippingSegments[0].category === "outro") {
return 0
} else {//防止未来加入新的片段类型导致不可用
return Math.min(Config.config.skipNoticeDuration * 1000 / getVideo().playbackRate, (skipTime[0] - getVideo().currentTime) * 1000 / getVideo().playbackRate)
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/render/SkipNotice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class SkipNotice {
autoSkip = false,
contentContainer: ContentContainer,
unskipTime: number = null,
startReskip = false
startReskip = false,
readySkip: NodeJS.Timeout
) {
this.skipNoticeRef = React.createRef();

Expand Down Expand Up @@ -63,6 +64,7 @@ class SkipNotice {
(Config.config.noticeVisibilityMode >= NoticeVisbilityMode.MiniForAutoSkip && autoSkip)
}
unskipTime={unskipTime}
readySkip={readySkip}
/>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface ContentContainer {
(): {
vote: (type: number, UUID: SegmentUUID, category?: Category, skipNotice?: SkipNoticeComponent) => void;
dontShowNoticeAgain: () => void;
unskipSponsorTime: (segment: SponsorTime, unskipTime: number, forceSeek?: boolean) => void;
unskipSponsorTime: (segment: SponsorTime, unskipTime: number, readySkip: NodeJS.Timeout, forceSeek?: boolean) => void;
sponsorTimes: SponsorTime[];
sponsorTimesSubmitting: SponsorTime[];
skipNotices: SkipNotice[];
Expand Down