mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-15 04:11:47 +00:00
Add SponsorBlock plugin
This commit is contained in:
@ -63,7 +63,19 @@ const defaultConfig = {
|
|||||||
volumeDown: "Shift+PageDown"
|
volumeDown: "Shift+PageDown"
|
||||||
},
|
},
|
||||||
savedVolume: undefined //plugin save volume between session here
|
savedVolume: undefined //plugin save volume between session here
|
||||||
}
|
},
|
||||||
|
sponsorblock: {
|
||||||
|
enabled: false,
|
||||||
|
apiURL: "https://sponsor.ajay.app",
|
||||||
|
categories: [
|
||||||
|
"sponsor",
|
||||||
|
"intro",
|
||||||
|
"outro",
|
||||||
|
"interaction",
|
||||||
|
"selfpromo",
|
||||||
|
"music_offtopic",
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
51
plugins/sponsorblock/back.js
Normal file
51
plugins/sponsorblock/back.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
|
const defaultConfig = require("../../config/defaults");
|
||||||
|
const registerCallback = require("../../providers/song-info");
|
||||||
|
const { sortSegments } = require("./segments");
|
||||||
|
|
||||||
|
let videoID;
|
||||||
|
|
||||||
|
module.exports = (win, options) => {
|
||||||
|
const { apiURL, categories } = {
|
||||||
|
...defaultConfig.plugins.sponsorblock,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
registerCallback(async (info) => {
|
||||||
|
const newURL = info.url || win.webContents.getURL();
|
||||||
|
const newVideoID = new URL(newURL).searchParams.get("v");
|
||||||
|
|
||||||
|
if (videoID !== newVideoID) {
|
||||||
|
videoID = newVideoID;
|
||||||
|
const segments = await fetchSegments(apiURL, categories);
|
||||||
|
win.webContents.send("sponsorblock-skip", segments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchSegments = async (apiURL, categories) => {
|
||||||
|
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();
|
||||||
|
const sortedSegments = sortSegments(
|
||||||
|
segments.map((submission) => submission.segment)
|
||||||
|
);
|
||||||
|
|
||||||
|
return sortedSegments;
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
27
plugins/sponsorblock/front.js
Normal file
27
plugins/sponsorblock/front.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const { ipcRenderer } = require("electron");
|
||||||
|
|
||||||
|
const is = require("electron-is");
|
||||||
|
|
||||||
|
const { ontimeupdate } = require("../../providers/video-element");
|
||||||
|
|
||||||
|
let currentSegments = [];
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
ipcRenderer.on("sponsorblock-skip", (_, segments) => {
|
||||||
|
currentSegments = segments;
|
||||||
|
});
|
||||||
|
|
||||||
|
ontimeupdate((videoElement) => {
|
||||||
|
if (
|
||||||
|
currentSegments.length > 0 &&
|
||||||
|
videoElement.currentTime >= currentSegments[0][0] &&
|
||||||
|
videoElement.currentTime <= currentSegments[0][1]
|
||||||
|
) {
|
||||||
|
videoElement.currentTime = currentSegments[0][1];
|
||||||
|
const skipped = currentSegments.shift();
|
||||||
|
if (is.dev()) {
|
||||||
|
console.log("SponsorBlock: skipping segment", skipped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
29
plugins/sponsorblock/segments.js
Normal file
29
plugins/sponsorblock/segments.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Segments are an array [ [start, end], … ]
|
||||||
|
module.exports.sortSegments = (segments) => {
|
||||||
|
segments.sort((segment1, segment2) =>
|
||||||
|
segment1[0] === segment2[0]
|
||||||
|
? segment1[1] - segment2[1]
|
||||||
|
: segment1[0] - segment2[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
const compiledSegments = [];
|
||||||
|
let currentSegment;
|
||||||
|
|
||||||
|
segments.forEach((segment) => {
|
||||||
|
if (!currentSegment) {
|
||||||
|
currentSegment = segment;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSegment[1] < segment[0]) {
|
||||||
|
compiledSegments.push(currentSegment);
|
||||||
|
currentSegment = segment;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSegment[1] = Math.max(currentSegment[1], segment[1]);
|
||||||
|
});
|
||||||
|
compiledSegments.push(currentSegment);
|
||||||
|
|
||||||
|
return compiledSegments;
|
||||||
|
};
|
||||||
34
plugins/sponsorblock/tests/segments.test.js
Normal file
34
plugins/sponsorblock/tests/segments.test.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
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],
|
||||||
|
]);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user