-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
youtube_subscriptions_opml.user.js
85 lines (79 loc) · 3.15 KB
/
youtube_subscriptions_opml.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// ==UserScript==
// @name Download YouTube Subscriptions OPML
// @namespace https://idaemons.org/
// @version 0.2
// @author Akinori MUSHA
// @description adds a "Download OPML" button to your YouTube Channel List page
// @match https://www.youtube.com/feed/channels
// @match https://www.youtube.com/feed/channels?*
// @grant none
// @license BSD-2-Clause
// @homepage https://github.com/knu/userjs-youtube_subscriptions_opml
// ==/UserScript==
(function () {
"use strict";
const loadAll = () =>
new Promise((resolve) => {
const initialY = document.documentElement.scrollTop;
let lastHeight = document.documentElement.scrollHeight;
const scroller = window.setInterval(
() => window.scrollTo(0, document.documentElement.scrollHeight),
100
);
const observer = window.setInterval(() => {
const spinner = document.querySelector("paper-spinner-lite");
if (spinner && spinner.getAttribute("aria-hidden") !== "true") return;
const currentHeight = document.documentElement.scrollHeight;
if (currentHeight !== lastHeight) {
lastHeight = currentHeight;
return;
}
window.clearInterval(scroller);
window.clearInterval(observer);
window.scrollTo(0, initialY);
resolve();
}, 1500);
});
const div = document.createElement("div");
const button = document.createElement("button");
button.textContent = "Download OPML";
const download = () => {
const doc = document.implementation.createDocument("", "", null);
doc.appendChild(doc.createProcessingInstruction("xml", 'version="1.0"'));
const opml = doc.createElement("opml");
opml.setAttribute("version", "1.0");
doc.appendChild(opml);
const head = doc.createElement("head");
opml.appendChild(head);
const title = doc.createElement("title");
title.textContent = "My YouTube Subscriptions";
head.appendChild(title);
const body = doc.createElement("body");
opml.appendChild(body);
document.querySelectorAll("ytd-channel-renderer").forEach((li) => {
const title = li.querySelector("#channel-title #text").textContent;
const href = li.querySelector("a#main-link").getAttribute("href");
const id = /\/channel\/([^/]+)/.test(href) && RegExp.$1;
const url = "https://www.youtube.com/feeds/videos.xml?channel_id=" + id;
const outline = doc.createElement("outline");
outline.setAttribute("type", "atom");
outline.setAttribute("text", title);
outline.setAttribute("title", title);
outline.setAttribute("xmlUrl", url);
body.appendChild(outline);
});
const blob = new Blob([new XMLSerializer(doc).serializeToString(doc)], {
type: "text/x-opml",
});
const link = document.createElement("a");
link.download = "youtube_subscriptions.opml";
link.href = URL.createObjectURL(blob);
link.click();
};
button.addEventListener("click", (e) => {
loadAll().then(download);
});
div.appendChild(button);
const topElement = document.querySelector("ytd-section-list-renderer");
topElement.parentNode.insertBefore(div, topElement);
})();