-
Notifications
You must be signed in to change notification settings - Fork 3
/
netflix-top-10-aggregated.user.js
141 lines (125 loc) Β· 5.39 KB
/
netflix-top-10-aggregated.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// ==UserScript==
// @name Aggregate the top ten from each of the four categories
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Aggregate the top ten from each of the four categories
// @author Josh Parker
// @match https://top10.netflix.com
// @match https://top10.netflix.com/*
// @icon https://www.google.com/s2/favicons?domain=netflix.com
// @grant none
// ==/UserScript==
(function userScript() {
const links = [
{ url: 'https://top10.netflix.com/films.html', categoryName: 'Films (English)' },
{ url: 'https://top10.netflix.com/films-non-english.html', categoryName: 'Films (Non-English)' },
{ url: 'https://top10.netflix.com/tv.html', categoryName: 'TV (English)' },
{ url: 'https://top10.netflix.com/tv-non-english.html', categoryName: 'TV (Non-English)' },
];
const dateMatch = window.location.href.match(/\/\d{4}-\d\d-\d\d/);
const parser = new DOMParser();
const aggregatedRows = [];
Promise.all(
links.map(({ url, categoryName }) => fetch(dateMatch ? url.replace('.html', dateMatch[0]) : url)
.then((r) => r.text())
.then((text) => parser.parseFromString(text, 'text/html'))
.then((doc) => {
const tableBodyRows = doc.querySelectorAll('#maincontent + div tbody > tr');
tableBodyRows.forEach((row) => {
const categoryCell = document.createElement('td');
categoryCell.textContent = categoryName;
const secondCell = row.querySelectorAll('td')[1];
row.insertBefore(categoryCell, secondCell);
aggregatedRows.push(row);
});
})),
).then(() => {
const tableHeaderRow = document.querySelector('#maincontent + div thead > tr');
const tableHeaderCategorySelect = document.querySelectorAll(
'#maincontent + div thead > tr > th',
)[1];
tableHeaderRow.removeChild(tableHeaderCategorySelect);
const tableHeaderWeeks = document.querySelectorAll('#maincontent + div thead > tr > th')[1];
tableHeaderWeeks.insertAdjacentHTML(
'beforebegin',
'<th class="align-bottom border-bottom border-b-2 border-gray-800 pb-1 table-header-text"><span class="pageText">CATEGORY</span></th><th class="align-bottom border-bottom border-b-2 border-gray-800 pb-1 table-header-text"><span class="pageText">NAME</span></th>',
);
const body = document.querySelector('#maincontent + div tbody');
const bodyRows = document.querySelectorAll('#maincontent + div tbody > tr');
bodyRows.forEach((row) => body.removeChild(row));
const rowSorter = (row) => Number(row.querySelector('span.inline-block').textContent.replaceAll(',', ''));
aggregatedRows.sort((a, b) => rowSorter(b) - rowSorter(a));
aggregatedRows.forEach((row, i) => {
const r = row;
r.querySelector('td').textContent = i + 1;
body.appendChild(r);
});
});
const mutationObserver = new MutationObserver((mutationRecords) => {
const addedNodes = [];
mutationRecords.forEach((mutationRecord) => mutationRecord.addedNodes.forEach((node) => {
addedNodes.push(node);
}));
addedNodes.forEach((node) => {
if (node.getAttribute && node.getAttribute('id').includes('listbox')) {
node.querySelectorAll('div[id*=option]').forEach((div, i) => {
const { href } = window.location;
const hrefPattern = /(?<date>\/\d{4}-\d\d-\d\d)?\.html(?<fragment>#.*)?$/;
const hrefMatch = href.match(hrefPattern);
if (hrefMatch) {
const { date, fragment } = hrefMatch.groups;
div.addEventListener('click', () => window.location.assign(links[i].url.replace('.html', `${date || ''}.html${fragment || ''}`)));
} else {
div.addEventListener('click', () => window.location.assign(links[i].url));
}
});
}
});
});
const categorySelects = document.querySelectorAll('div[id*="category-select"]');
const observeOptions = { subtree: true, childList: true };
categorySelects.forEach((select) => mutationObserver.observe(select, observeOptions));
const addDays = function addDays(date, days) {
const calculatedDate = new Date(date);
calculatedDate.setDate(date.getDate() + days);
return calculatedDate;
};
const yyyyMmDd = (date) => date.toISOString().split('T')[0];
const nearestID = function nearestID(node) {
const nodeId = node.getAttribute('id');
if (nodeId) {
return nodeId;
}
const { parentNode } = node;
if (parentNode) {
return nearestID(node.parentNode);
}
return null;
};
const currentWeek = new Date(
document.querySelector('main #maincontent .select-week').textContent.split('-')[1].trim(),
);
const previousWeek = yyyyMmDd(addDays(currentWeek, -7));
const hrefPattern = /(\/\d{4}-\d\d-\d\d)?\.html(#.*)?$/;
const prepareClick = function prepareClick(button, dateString) {
button.addEventListener('click', () => {
const { href } = window.location;
let destination;
if (href.includes('.html')) {
destination = href.replace(hrefPattern, `/${dateString}.html`);
} else {
destination = links[0].url.replace(hrefPattern, `/${dateString}.html`);
}
const fragment = nearestID(button);
if (fragment) {
destination += `#${fragment}`;
}
window.location.assign(destination);
});
};
const prevButtons = document.querySelectorAll('button[aria-label="Previous week"]');
prevButtons.forEach((prevButton) => prepareClick(prevButton, previousWeek));
const nextWeek = yyyyMmDd(addDays(currentWeek, 7));
const nextButtons = document.querySelectorAll('button[aria-label="Next week"]');
nextButtons.forEach((nextButton) => prepareClick(nextButton, nextWeek));
}());