mirror of
https://github.com/tubearchivist/browser-extension.git
synced 2024-11-22 19:50:12 +00:00
Merge pull request #30 from bakkot/update-subscribe-button
Update subscribe button video id on hover
This commit is contained in:
commit
5987707b53
@ -18,5 +18,7 @@ module.exports = {
|
|||||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||||
curly: ['error', 'multi-line'],
|
curly: ['error', 'multi-line'],
|
||||||
'no-var': 'error',
|
'no-var': 'error',
|
||||||
|
'no-func-assign': 'off',
|
||||||
|
'no-inner-declarations': 'off',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -124,13 +124,13 @@ function isElementVisible(element) {
|
|||||||
|
|
||||||
function ensureTALinks() {
|
function ensureTALinks() {
|
||||||
let channelContainerNodes = getChannelContainers();
|
let channelContainerNodes = getChannelContainers();
|
||||||
|
|
||||||
for (let channelContainer of channelContainerNodes) {
|
for (let channelContainer of channelContainerNodes) {
|
||||||
channelContainer = adjustOwner(channelContainer);
|
channelContainer = adjustOwner(channelContainer);
|
||||||
if (channelContainer.hasTA) continue;
|
if (channelContainer.hasTA) continue;
|
||||||
channelContainer.hasTA = true;
|
let channelButton = buildChannelButton(channelContainer);
|
||||||
buildChannelButton(channelContainer).then(channelButton => {
|
|
||||||
channelContainer.appendChild(channelButton);
|
channelContainer.appendChild(channelButton);
|
||||||
});
|
channelContainer.hasTA = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleContainerNodes = getTitleContainers();
|
let titleContainerNodes = getTitleContainers();
|
||||||
@ -143,42 +143,69 @@ function ensureTALinks() {
|
|||||||
titleContainer.hasTA = true;
|
titleContainer.hasTA = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ensureTALinks = throttled(ensureTALinks, 700);
|
||||||
|
|
||||||
// fix positioning of #owner div to fit new button
|
|
||||||
function adjustOwner(channelContainer) {
|
function adjustOwner(channelContainer) {
|
||||||
return channelContainer.querySelector('#buttons') || channelContainer;
|
return channelContainer.querySelector('#buttons') || channelContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildChannelButton(channelContainer) {
|
function buildChannelButton(channelContainer) {
|
||||||
return new Promise(resolve => {
|
let channelHandle = getChannelHandle(channelContainer);
|
||||||
let buttonDiv;
|
channelContainer.taDerivedHandle = channelHandle;
|
||||||
let channelSubButton;
|
|
||||||
let spacer;
|
|
||||||
let channelDownloadButton;
|
|
||||||
|
|
||||||
// Delayed execution for interface to refresh
|
let buttonDiv = buildChannelButtonDiv();
|
||||||
setTimeout(() => {
|
|
||||||
const channelHandle = getChannelHandle(channelContainer);
|
let channelSubButton = buildChannelSubButton(channelHandle);
|
||||||
buttonDiv = buildChannelButtonDiv();
|
|
||||||
channelSubButton = buildChannelSubButton(channelHandle);
|
|
||||||
spacer = buildSpacer();
|
|
||||||
channelDownloadButton = buildChannelDownloadButton();
|
|
||||||
buttonDiv.appendChild(channelSubButton);
|
buttonDiv.appendChild(channelSubButton);
|
||||||
|
channelContainer.taSubButton = channelSubButton;
|
||||||
|
|
||||||
|
let spacer = buildSpacer();
|
||||||
buttonDiv.appendChild(spacer);
|
buttonDiv.appendChild(spacer);
|
||||||
|
|
||||||
|
let channelDownloadButton = buildChannelDownloadButton();
|
||||||
buttonDiv.appendChild(channelDownloadButton);
|
buttonDiv.appendChild(channelDownloadButton);
|
||||||
resolve(buttonDiv);
|
channelContainer.taDownloadButton = channelDownloadButton;
|
||||||
}, 2000);
|
|
||||||
|
if (!channelContainer.taObserver) {
|
||||||
|
function updateButtonsIfNecessary() {
|
||||||
|
let newHandle = getChannelHandle(channelContainer);
|
||||||
|
if (channelContainer.taDerivedHandle === newHandle) return;
|
||||||
|
console.log(`updating handle from ${channelContainer.taDerivedHandle} to ${newHandle}`);
|
||||||
|
channelContainer.taDerivedHandle = newHandle;
|
||||||
|
let channelSubButton = buildChannelSubButton(newHandle);
|
||||||
|
channelContainer.taSubButton.replaceWith(channelSubButton);
|
||||||
|
channelContainer.taSubButton = channelSubButton;
|
||||||
|
|
||||||
|
let channelDownloadButton = buildChannelDownloadButton();
|
||||||
|
channelContainer.taDownloadButton.replaceWith(channelDownloadButton);
|
||||||
|
channelContainer.taDownloadButton = channelDownloadButton;
|
||||||
|
}
|
||||||
|
channelContainer.taObserver = new MutationObserver(throttled(updateButtonsIfNecessary, 100));
|
||||||
|
channelContainer.taObserver.observe(channelContainer, {
|
||||||
|
attributes: true,
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return buttonDiv;
|
||||||
|
}
|
||||||
|
|
||||||
function getChannelHandle(channelContainer) {
|
function getChannelHandle(channelContainer) {
|
||||||
|
let channelHandle;
|
||||||
|
const videoOwnerRenderer = channelContainer.querySelector('.ytd-video-owner-renderer');
|
||||||
|
|
||||||
|
if (!videoOwnerRenderer) {
|
||||||
const channelHandleContainer = document.querySelector('#channel-handle');
|
const channelHandleContainer = document.querySelector('#channel-handle');
|
||||||
let channelHandle = channelHandleContainer ? channelHandleContainer.innerText : null;
|
channelHandle = channelHandleContainer ? channelHandleContainer.innerText : null;
|
||||||
if (!channelHandle) {
|
} else {
|
||||||
let href = channelContainer.querySelector('.ytd-video-owner-renderer').href;
|
const href = videoOwnerRenderer.href;
|
||||||
|
if (href) {
|
||||||
const urlObj = new URL(href);
|
const urlObj = new URL(href);
|
||||||
channelHandle = urlObj.pathname.split('/')[1];
|
channelHandle = urlObj.pathname.split('/')[1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return channelHandle;
|
return channelHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,10 +263,10 @@ function checkChannelSubscribed(channelSubButton) {
|
|||||||
console.log('Unknown state');
|
console.log('Unknown state');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handleError() {
|
function handleError(e) {
|
||||||
buttonError(channelSubButton);
|
buttonError(channelSubButton);
|
||||||
channelSubButton.innerText = 'Error';
|
channelSubButton.innerText = 'Error';
|
||||||
console.log('error');
|
console.error('error', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let channelHandle = channelSubButton.dataset.id;
|
let channelHandle = channelSubButton.dataset.id;
|
||||||
@ -289,16 +316,19 @@ function buildChannelDownloadButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTitleContainers() {
|
function getTitleContainers() {
|
||||||
let nodes = document.querySelectorAll('#video-title');
|
let elements = document.querySelectorAll('#video-title');
|
||||||
return nodes;
|
let videoNodes = [];
|
||||||
|
elements.forEach(element => {
|
||||||
|
if (isElementVisible(element)) {
|
||||||
|
videoNodes.push(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildVideoButton(titleContainer) {
|
function getVideoId(titleContainer) {
|
||||||
let href = getNearestLink(titleContainer);
|
let href = getNearestLink(titleContainer);
|
||||||
if (!href) return;
|
if (!href) return;
|
||||||
const dlButton = document.createElement('a');
|
|
||||||
dlButton.classList.add('ta-button');
|
|
||||||
dlButton.href = '#';
|
|
||||||
|
|
||||||
let videoId;
|
let videoId;
|
||||||
if (href.startsWith('/watch?v')) {
|
if (href.startsWith('/watch?v')) {
|
||||||
@ -307,11 +337,16 @@ function buildVideoButton(titleContainer) {
|
|||||||
} else if (href.startsWith('/shorts/')) {
|
} else if (href.startsWith('/shorts/')) {
|
||||||
videoId = href.split('/')[2];
|
videoId = href.split('/')[2];
|
||||||
}
|
}
|
||||||
|
return videoId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildVideoButton(titleContainer) {
|
||||||
|
let videoId = getVideoId(titleContainer);
|
||||||
if (!videoId) return;
|
if (!videoId) return;
|
||||||
|
|
||||||
dlButton.setAttribute('data-id', videoId);
|
const dlButton = document.createElement('a');
|
||||||
dlButton.setAttribute('data-type', 'video');
|
dlButton.classList.add('ta-button');
|
||||||
dlButton.title = `TA download video: ${titleContainer.innerText} [${videoId}]`;
|
dlButton.href = '#';
|
||||||
|
|
||||||
Object.assign(dlButton.style, {
|
Object.assign(dlButton.style, {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -395,13 +430,19 @@ function checkVideoExists(taButton) {
|
|||||||
}
|
}
|
||||||
taButton.isChecked = true;
|
taButton.isChecked = true;
|
||||||
}
|
}
|
||||||
function handleError() {
|
function handleError(e) {
|
||||||
buttonError(taButton);
|
buttonError(taButton);
|
||||||
let videoId = taButton.dataset.id;
|
let videoId = taButton.dataset.id;
|
||||||
console.log(`error: failed to get info from TA for video ${videoId}`);
|
console.log(`error: failed to get info from TA for video ${videoId}`);
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let videoId = taButton.dataset.id;
|
if (!taButton.parentElement) return;
|
||||||
|
let videoId = getVideoId(taButton.parentElement);
|
||||||
|
taButton.setAttribute('data-id', videoId);
|
||||||
|
taButton.setAttribute('data-type', 'video');
|
||||||
|
taButton.title = `TA download video: ${taButton.parentElement.innerText} [${videoId}]`;
|
||||||
|
|
||||||
let message = { type: 'videoExists', videoId };
|
let message = { type: 'videoExists', videoId };
|
||||||
let sending = sendMessage(message);
|
let sending = sendMessage(message);
|
||||||
sending.then(handleResponse, handleError);
|
sending.then(handleResponse, handleError);
|
||||||
@ -455,9 +496,8 @@ function sendUrl(url, action, button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleError(error) {
|
function handleError(e) {
|
||||||
console.log('error');
|
console.log('error', e);
|
||||||
console.log(JSON.stringify(error));
|
|
||||||
buttonError(button);
|
buttonError(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,15 +530,20 @@ function cleanButtons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let oldHref = document.location.href;
|
let oldHref = document.location.href;
|
||||||
let throttleBlock;
|
|
||||||
const throttle = (callback, time) => {
|
function throttled(callback, time) {
|
||||||
|
let throttleBlock = false;
|
||||||
|
let lastArgs;
|
||||||
|
return (...args) => {
|
||||||
|
lastArgs = args;
|
||||||
if (throttleBlock) return;
|
if (throttleBlock) return;
|
||||||
throttleBlock = true;
|
throttleBlock = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
callback();
|
|
||||||
throttleBlock = false;
|
throttleBlock = false;
|
||||||
|
callback(...lastArgs);
|
||||||
}, time);
|
}, time);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let observer = new MutationObserver(list => {
|
let observer = new MutationObserver(list => {
|
||||||
const currentHref = document.location.href;
|
const currentHref = document.location.href;
|
||||||
@ -507,7 +552,7 @@ let observer = new MutationObserver(list => {
|
|||||||
oldHref = currentHref;
|
oldHref = currentHref;
|
||||||
}
|
}
|
||||||
if (list.some(i => i.type === 'childList' && i.addedNodes.length > 0)) {
|
if (list.some(i => i.type === 'childList' && i.addedNodes.length > 0)) {
|
||||||
throttle(ensureTALinks, 700);
|
ensureTALinks();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user