Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes Issue 294: Add Details feature for playing video #2712

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

AnhChienVu
Copy link

@AnhChienVu AnhChienVu commented Dec 5, 2024

Fixes #294:

In response to the request from issue #294, I have implemented a Details Switch within the Channel Button. This feature allows users to toggle the visibility of the details area, enabling it to be shown or hidden based on the switch's state.

For a detailed explanation of the implementation steps, you can refer to my blog post. To help you quickly understand how this functionality works, I’ve attached a video below:

Untitled.video.-.Made.with.Clipchamp.3.mp4

To address all edge cases where the details area might not appear correctly based on the switch's state, I stored the switch state in local storage. This allows the extension to track and maintain the switch state, ensuring the details are displayed correctly when users navigate back to YouTube, even if they toggled the switch from a different tab (not YouTube).

Another edge case I accounted for is when the user navigates to a new video. The extension tracks the video ID in the URL, and based on this ID, it fetches the corresponding details, removing the existing ones from the screen.

Note: This feature requires a YOUTUBE_API_KEY to fetch the video data. I just used my own API to test, after finishing test, it will be deleted and removed from the source code. If you want to test this function, you can create a new API key.

@AnhChienVu AnhChienVu marked this pull request as ready for review December 5, 2024 22:43
…ulating the UI of Details area

- Change the way of creating SVG to avoid CORS error

- Move css styles to extension/styles.css

- Use MutationObserver listens for DOM changes (e.g., when YouTube injects ytd-video-owner-renderer), ensuring the element is detected as soon as it's available.

- To manipulate the UI, it listens to message from content.js to decide whether or not to display the Details area
… area to channel.js under web-accessible folder.

- Check the switch and fetch data immediately after the DOM is loaded

- Passing video information to channel.js file by using window.PostMessage() functtion
@AnhChienVu AnhChienVu changed the title Fixes Issue 294: Fixes Issue 294: Add Details feature for playing video Dec 6, 2024
@ImprovedTube
Copy link
Member

ImprovedTube commented Dec 6, 2024

Hi @AnhChienVu thank you!!

I stored the switch state in local storage. This allows the extension to track and maintain the switch state, ensuring the details are displayed correctly when users navigate back to YouTube, even if they toggled the switch from a different tab (not YouTube).

https://github.com/code-charity/youtube/wiki/Contributing#adding-a-feature

// FEEDBACK WHEN THE USER CHANGED A SETTING


API

#1452

( for users: https://github.com/code-charity/youtube/wiki/%F0%9F%9B%88-YouTube-API:--How-to-generate-your-Youtube-API-key )


and this is the first feature loading the video URL again, as if it was a new tab (to make sure if the video is music), or querying independent API server (these might not offers channel video count):

//DATA (TO-DO: make the Data available to more/all features? #1452 #1763 (Then can replace ImprovedTube.elements.category === 'music', VideoID is also used elsewhere)
DATA = {};
defaultKeywords = "video,sharing,camera,phone,video phone,free,upload";
DATA.keywords = false; keywords = false; amountOfSongs = false;
DATA.videoID = ImprovedTube.videoId() || false;
ImprovedTube.fetchDOMData = function () {
// if (history.length > 1 && history.state.endpoint.watchEndpoint) {
try { DATA = JSON.parse(document.querySelector('#microformat script')?.textContent) ?? false; DATA.title = DATA.name;}
catch { DATA.genre = false; DATA.keywords = false; DATA.lengthSeconds = false;
try {
DATA.title = document.getElementsByTagName('meta')?.title?.content || false;
DATA.genre = document.querySelector('meta[itemprop=genre]')?.content || false;
DATA.duration = document.querySelector('meta[itemprop=duration]')?.content || false;
} catch {}} if ( DATA.title === ImprovedTube.videoTitle() )
{ keywords = document.getElementsByTagName('meta')?.keywords?.content || false; if (!keywords) {keyword=''} ImprovedTube.speedException(); }
else { keywords = ''; (async function () { try { const response = await fetch(`https://www.youtube.com/watch?v=${DATA.videoID}`);
const htmlContent = await response.text();
const metaRegex = /<meta[^>]+name=["'](keywords|genre|duration)["'][^>]+content=["']([^"']+)["'][^>]*>/gi;
let match; while ((match = metaRegex.exec(htmlContent)) !== null) {
const [, property, value] = match;
if (property === 'keywords') { keywords = value;} else {DATA[property] = value;}
}
amountOfSongs = (htmlContent.slice(-80000).match(/},"subtitle":{"simpleText":"(\d*)\s/) || [])[1] || false;
if (keywords) { ImprovedTube.speedException(); }
} catch (error) { console.error('Error: fetching from https://Youtube.com/watch?v=${DATA.videoID}', error); keywords = ''; }
})();
}
};
if ( (history && history.length === 1) || !history?.state?.endpoint?.watchEndpoint) { ImprovedTube.fetchDOMData();}
else {
//Invidious instances. Should be updated automatically!...
const invidiousInstances = ['invidious.fdn.fr', 'inv.tux.pizza', 'invidious.flokinet.to', 'invidious.protokolla.fi', 'invidious.private.coffee', 'yt.artemislena.eu', 'invidious.materialio.us', 'iv.datura.network'];
function getRandomInvidiousInstance () { return invidiousInstances[Math.floor(Math.random() * invidiousInstances.length)];}
(async function () { let retries = 4; let invidiousFetched = false;
async function fetchInvidiousData () {
try {const response = await fetch(`https://${getRandomInvidiousInstance()}/api/v1/videos/${DATA.videoID}?fields=genre,title,lengthSeconds,keywords`);
DATA = await response.json();
if (DATA.genre && DATA.title && DATA.keywords && DATA.lengthSeconds) { if (DATA.keywords.toString() === defaultKeywords ) {DATA.keywords = ''}
ImprovedTube.speedException(); invidiousFetched = true; }
} catch (error) { console.error('Error: Invidious API: ', error); }
}
while (retries > 0 && !invidiousFetched) { await fetchInvidiousData();
if (!invidiousFetched) { await new Promise(resolve => setTimeout(resolve, retries === 4 ? 1500 : 876)); retries--; } }
if (!invidiousFetched) { if (document.readyState === 'loading') {document.addEventListener('DOMContentLoaded', ImprovedTube.fetchDOMData())}
else { ImprovedTube.fetchDOMData();} }
})();
}
} // else { }
}


i think we don't need to edit background.js or add a content script.
(the code can become shorter using existing functions)


what improves for package.json package-lock.json

@AnhChienVu
Copy link
Author

Hi @ImprovedTube, actually, I want to make it separate and clear of code that makes it easier to debug as well as understand the code that I was writing. That's why I explicitly add more cases in background.js. And the content.js will take care of handling message from background then send request to change UI. Because it also makes the feature work well, so to integrate with the existing codes, it should take longer time to deep dive into it.

For the package.json and package-lock.json, I was thinking to add .env to secure the YOUTUBE_API_KEY when I publish the PR, but it seems to be not worked when the Chrome Extension is not built in Node.js. So For these files, I can remove these packages

@ImprovedTube ImprovedTube marked this pull request as draft December 7, 2024 01:53
@ImprovedTube ImprovedTube marked this pull request as draft December 7, 2024 01:53
@ImprovedTube
Copy link
Member

ImprovedTube commented Dec 7, 2024

hi! @AnhChienVu

actually, I want to make it separate and clear of code that makes it easier to debug as well as understand the code that I was writing.

good! some of it will / should be similar for most extensions
so i assume you, or i, or somebody might enjoy to quickly integrate it to optimize CPU and amount of lines

did you see?:

https://github.com/code-charity/youtube/wiki/Contributing#adding-a-feature

// FEEDBACK WHEN THE USER CHANGED A SETTING


localstorage

#1408 (comment)

@AnhChienVu
Copy link
Author

Thanks @ImprovedTube for your feedback, I am trying to integrate with the existing codes by taking a look at the reaction when user changes setting based on localStorage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

always show "all videos"
2 participants