Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
Simon | 1d27545409 | |
Simon | 7b40dc44c2 | |
Simon | 9ba90e4e45 | |
Simon | 0d58ddaaa2 | |
Vladimir Pouzanov | c82e493628 | |
Simon | ca15cc9c0b | |
Simon | 190f545ef2 | |
Ritiek Malhotra | 761030ca55 | |
Simon | 82a64ff4ba |
|
@ -77,6 +77,7 @@ Symlink/copy the correct manifest file for your browser to the expected location
|
|||
## Roadmap
|
||||
Join us on [Discord](https://www.tubearchivist.com/discord) and help us improve and extend this project. This is a list of planned features, in no particular order:
|
||||
- [ ] Implement download/subscribe button for playlists
|
||||
- [ ] Add download buttons to the `/shorts/` pages
|
||||
- [X] Get download and subscribe status from TA to show on the injected buttons
|
||||
- [X] Implement download button for videos on the YouTube homepage over inline preview
|
||||
- [X] Implement download button for videos on playlist
|
||||
|
|
|
@ -208,6 +208,7 @@ function buildCookieLine(cookie) {
|
|||
|
||||
async function sendCookies() {
|
||||
console.log('function sendCookies');
|
||||
const acceptableDomains = ['.youtube.com', 'youtube.com', 'www.youtube.com'];
|
||||
|
||||
let cookieStores = await browserType.cookies.getAllCookieStores();
|
||||
let cookieLines = [
|
||||
|
@ -223,7 +224,9 @@ async function sendCookies() {
|
|||
});
|
||||
for (let j = 0; j < allCookiesStore.length; j++) {
|
||||
const cookie = allCookiesStore[j];
|
||||
cookieLines.push(buildCookieLine(cookie));
|
||||
if (acceptableDomains.includes(cookie.domain)) {
|
||||
cookieLines.push(buildCookieLine(cookie));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<a href="#" id="ta-url" target="_blank">
|
||||
<img src="/images/logo.png" alt="ta-logo">
|
||||
</a>
|
||||
<span>v0.2.2</span>
|
||||
<span>v0.3.1</span>
|
||||
</div>
|
||||
<hr>
|
||||
<form class="login-form">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 3,
|
||||
"name": "TubeArchivist Companion",
|
||||
"description": "Interact with your selfhosted TA server.",
|
||||
"version": "0.2.2",
|
||||
"version": "0.3.1",
|
||||
"icons": {
|
||||
"48": "/images/icon.png",
|
||||
"128": "/images/icon128.png"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "TubeArchivist Companion",
|
||||
"description": "Interact with your selfhosted TA server.",
|
||||
"version": "0.2.2",
|
||||
"version": "0.3.1",
|
||||
"icons": {
|
||||
"128": "/images/icon128.png"
|
||||
},
|
||||
|
|
|
@ -83,7 +83,6 @@ document.getElementById('autostart').addEventListener('click', function () {
|
|||
toggleAutostart();
|
||||
});
|
||||
|
||||
|
||||
let fullUrlInput = document.getElementById('full-url');
|
||||
fullUrlInput.addEventListener('change', () => {
|
||||
browserType.storage.local.set({
|
||||
|
@ -200,7 +199,6 @@ function setStatusIcon(connected) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// fill in form
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
function onGot(item) {
|
||||
|
|
|
@ -106,7 +106,7 @@ function getBrowser() {
|
|||
}
|
||||
|
||||
function getChannelContainers() {
|
||||
const elements = document.querySelectorAll('#inner-header-container, #owner');
|
||||
const elements = document.querySelectorAll('.yt-flexible-actions-view-model-wiz, #owner');
|
||||
const channelContainerNodes = [];
|
||||
|
||||
elements.forEach(element => {
|
||||
|
@ -135,12 +135,14 @@ function ensureTALinks() {
|
|||
|
||||
let titleContainerNodes = getTitleContainers();
|
||||
for (let titleContainer of titleContainerNodes) {
|
||||
if (titleContainer.hasTA) continue;
|
||||
let parent = getNearestH3(titleContainer);
|
||||
if (!parent) continue;
|
||||
if (parent.hasTA) continue;
|
||||
let videoButton = buildVideoButton(titleContainer);
|
||||
if (videoButton == null) continue;
|
||||
processTitle(titleContainer);
|
||||
titleContainer.appendChild(videoButton);
|
||||
titleContainer.hasTA = true;
|
||||
processTitle(parent);
|
||||
parent.appendChild(videoButton);
|
||||
parent.hasTA = true;
|
||||
}
|
||||
}
|
||||
ensureTALinks = throttled(ensureTALinks, 700);
|
||||
|
@ -196,7 +198,9 @@ function getChannelHandle(channelContainer) {
|
|||
const videoOwnerRenderer = channelContainer.querySelector('.ytd-video-owner-renderer');
|
||||
|
||||
if (!videoOwnerRenderer) {
|
||||
const channelHandleContainer = document.querySelector('#channel-handle');
|
||||
const channelHandleContainer = document.querySelector(
|
||||
'.yt-content-metadata-view-model-wiz__metadata-text'
|
||||
);
|
||||
channelHandle = channelHandleContainer ? channelHandleContainer.innerText : null;
|
||||
} else {
|
||||
const href = videoOwnerRenderer.href;
|
||||
|
@ -327,6 +331,8 @@ function getTitleContainers() {
|
|||
}
|
||||
|
||||
function getVideoId(titleContainer) {
|
||||
if (!titleContainer) return undefined;
|
||||
|
||||
let href = getNearestLink(titleContainer);
|
||||
if (!href) return;
|
||||
|
||||
|
@ -383,6 +389,24 @@ function buildVideoButton(titleContainer) {
|
|||
}
|
||||
|
||||
function getNearestLink(element) {
|
||||
// Check siblings
|
||||
let sibling = element;
|
||||
while (sibling) {
|
||||
sibling = sibling.previousElementSibling;
|
||||
if (sibling && sibling.tagName === 'A' && sibling.getAttribute('href') !== '#') {
|
||||
return sibling.getAttribute('href');
|
||||
}
|
||||
}
|
||||
|
||||
sibling = element;
|
||||
while (sibling) {
|
||||
sibling = sibling.nextElementSibling;
|
||||
if (sibling && sibling.tagName === 'A' && sibling.getAttribute('href') !== '#') {
|
||||
return sibling.getAttribute('href');
|
||||
}
|
||||
}
|
||||
|
||||
// Check parent elements
|
||||
for (let i = 0; i < 5 && element && element !== document; i++) {
|
||||
if (element.tagName === 'A' && element.getAttribute('href') !== '#') {
|
||||
return element.getAttribute('href');
|
||||
|
@ -392,6 +416,16 @@ function getNearestLink(element) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getNearestH3(element) {
|
||||
for (let i = 0; i < 5 && element && element !== document; i++) {
|
||||
if (element.tagName === 'H3') {
|
||||
return element;
|
||||
}
|
||||
element = element.parentNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function processTitle(titleContainer) {
|
||||
if (titleContainer.hasListener) return;
|
||||
Object.assign(titleContainer.style, {
|
||||
|
@ -437,11 +471,15 @@ function checkVideoExists(taButton) {
|
|||
console.error(e);
|
||||
}
|
||||
|
||||
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 videoId = taButton.dataset.id;
|
||||
if (!videoId) {
|
||||
videoId = getVideoId(taButton);
|
||||
if (videoId) {
|
||||
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 sending = sendMessage(message);
|
||||
|
|
Loading…
Reference in New Issue