mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-14 03:41:46 +00:00
QOL: Move source code under the src directory. (#1318)
This commit is contained in:
52
src/plugins/sponsorblock/back.ts
Normal file
52
src/plugins/sponsorblock/back.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { BrowserWindow, ipcMain } from 'electron';
|
||||
import is from 'electron-is';
|
||||
|
||||
import { sortSegments } from './segments';
|
||||
|
||||
import { SkipSegment } from './types';
|
||||
|
||||
import defaultConfig from '../../config/defaults';
|
||||
|
||||
import type { GetPlayerResponse } from '../../types/get-player-response';
|
||||
import type { ConfigType } from '../../config/dynamic';
|
||||
|
||||
export default (win: BrowserWindow, options: ConfigType<'sponsorblock'>) => {
|
||||
const { apiURL, categories } = {
|
||||
...defaultConfig.plugins.sponsorblock,
|
||||
...options,
|
||||
};
|
||||
|
||||
ipcMain.on('video-src-changed', async (_, data: GetPlayerResponse) => {
|
||||
const segments = await fetchSegments(apiURL, categories, data?.videoDetails?.videoId);
|
||||
win.webContents.send('sponsorblock-skip', segments);
|
||||
});
|
||||
};
|
||||
|
||||
const fetchSegments = async (apiURL: string, categories: string[], videoId: string) => {
|
||||
const sponsorBlockURL = `${apiURL}/api/skipSegments?videoID=${videoId}&categories=${JSON.stringify(
|
||||
categories,
|
||||
)}`;
|
||||
try {
|
||||
const resp = await fetch(sponsorBlockURL, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
redirect: 'follow',
|
||||
});
|
||||
if (resp.status !== 200) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const segments = await resp.json() as SkipSegment[];
|
||||
return sortSegments(
|
||||
segments.map((submission) => submission.segment),
|
||||
);
|
||||
} catch (error) {
|
||||
if (is.dev()) {
|
||||
console.log('error on sponsorblock request:', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
};
|
||||
37
src/plugins/sponsorblock/front.ts
Normal file
37
src/plugins/sponsorblock/front.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import is from 'electron-is';
|
||||
|
||||
import { Segment } from './types';
|
||||
|
||||
let currentSegments: Segment[] = [];
|
||||
|
||||
export default () => {
|
||||
ipcRenderer.on('sponsorblock-skip', (_, segments: Segment[]) => {
|
||||
currentSegments = segments;
|
||||
});
|
||||
|
||||
document.addEventListener('apiLoaded', () => {
|
||||
const video = document.querySelector<HTMLVideoElement>('video');
|
||||
if (!video) return;
|
||||
|
||||
video.addEventListener('timeupdate', (e) => {
|
||||
if (e.target instanceof HTMLVideoElement) {
|
||||
const target = e.target;
|
||||
|
||||
for (const segment of currentSegments) {
|
||||
if (
|
||||
target.currentTime >= segment[0]
|
||||
&& target.currentTime < segment[1]
|
||||
) {
|
||||
target.currentTime = segment[1];
|
||||
if (is.dev()) {
|
||||
console.log('SponsorBlock: skipping segment', segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Reset segments on song end
|
||||
video.addEventListener('emptied', () => currentSegments = []);
|
||||
}, { once: true, passive: true });
|
||||
};
|
||||
34
src/plugins/sponsorblock/segments.ts
Normal file
34
src/plugins/sponsorblock/segments.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// Segments are an array [ [start, end], … ]
|
||||
import { Segment } from './types';
|
||||
|
||||
export const sortSegments = (segments: Segment[]) => {
|
||||
segments.sort((segment1, segment2) =>
|
||||
segment1[0] === segment2[0]
|
||||
? segment1[1] - segment2[1]
|
||||
: segment1[0] - segment2[0],
|
||||
);
|
||||
|
||||
const compiledSegments: Segment[] = [];
|
||||
let currentSegment: Segment | undefined;
|
||||
|
||||
for (const segment of segments) {
|
||||
if (!currentSegment) {
|
||||
currentSegment = segment;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentSegment[1] < segment[0]) {
|
||||
compiledSegments.push(currentSegment);
|
||||
currentSegment = segment;
|
||||
continue;
|
||||
}
|
||||
|
||||
currentSegment[1] = Math.max(currentSegment[1], segment[1]);
|
||||
}
|
||||
|
||||
if (currentSegment) {
|
||||
compiledSegments.push(currentSegment);
|
||||
}
|
||||
|
||||
return compiledSegments;
|
||||
};
|
||||
36
src/plugins/sponsorblock/tests/segments.test.js
Normal file
36
src/plugins/sponsorblock/tests/segments.test.js
Normal file
@ -0,0 +1,36 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
const { sortSegments } = require('../segments');
|
||||
|
||||
test('Segment sorting', () => {
|
||||
expect(
|
||||
sortSegments([
|
||||
[0, 3],
|
||||
[7, 8],
|
||||
[5, 6],
|
||||
]),
|
||||
).toEqual([
|
||||
[0, 3],
|
||||
[5, 6],
|
||||
[7, 8],
|
||||
]);
|
||||
|
||||
expect(
|
||||
sortSegments([
|
||||
[0, 5],
|
||||
[6, 8],
|
||||
[4, 6],
|
||||
]),
|
||||
).toEqual([[0, 8]]);
|
||||
|
||||
expect(
|
||||
sortSegments([
|
||||
[0, 6],
|
||||
[7, 8],
|
||||
[4, 6],
|
||||
]),
|
||||
).toEqual([
|
||||
[0, 6],
|
||||
[7, 8],
|
||||
]);
|
||||
});
|
||||
12
src/plugins/sponsorblock/types.ts
Normal file
12
src/plugins/sponsorblock/types.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export type Segment = [number, number];
|
||||
|
||||
export interface SkipSegment { // Array of this object
|
||||
segment: Segment; //[0, 15.23] start and end time in seconds
|
||||
UUID: string,
|
||||
category: string, // [1]
|
||||
videoDuration: number // Duration of video when submission occurred (to be used to determine when a submission is out of date). 0 when unknown. +- 1 second
|
||||
actionType: string, // [3]
|
||||
locked: number, // if submission is locked
|
||||
votes: number, // Votes on segment
|
||||
description: string, // title for chapters, empty string for other segments
|
||||
}
|
||||
Reference in New Issue
Block a user