Skip to content

ytTracker

YT Stats Tracker est une extension de navigateur couplée à une application web qui permet de suivre et analyser ses habitudes de visionnage sur YouTube. L’extension enregistre les vidéos regardées et envoie les données vers un serveur, ce qui permet à l’utilisateur d’accéder ensuite à un tableau de bord complet depuis le site.

Concrètement, l’application fonctionne comme les outils en ligne de statistiques pour Spotify : elle offre une vision claire de son activité YouTube, avec des données sur les vidéos les plus regardées, le temps passé, la fréquence de visionnage d’une chaîne ou encore l’évolution des vues au fil du temps.

Le projet a été développé en TypeScript, avec ElysiaJS comme framework back-end et Bun comme runtime pour garantir rapidité et légèreté. L’ensemble est open-source, ce qui le rend librement modifiable et réutilisable par la communauté.

Ce projet m’a permis de travailler sur l’intégration entre une extension navigateur et une application web, tout en expérimentant de nouvelles technologies modernes comme Bun et ElysiaJS.

Code observant l'URL permettant d'envoyé l'url au serveur

js
let currentUrl = window.location.href;

function checkVideoChange() {
    if (window.location.href.includes('/watch') && currentUrl !== window.location.href) {
        currentUrl = window.location.href;
        const videoId = new URLSearchParams(window.location.search).get('v');
        const channelId = new URLSearchParams(window.location.search).get('ab_channel');

        if (videoId && !channelId) {
            console.log(`Detected video change, Video ID: ${videoId}`);
            chrome.runtime.sendMessage({ action: "sendVideoId", videoId }, (response) => {
                if (chrome.runtime.lastError) {
                    console.error("Runtime error:", chrome.runtime.lastError.message);
                } else {
                    console.log("Background response:", response);
                    handleVideoIdMessage(videoId);
                }
            });
        }
    }
}

const observer = new MutationObserver(checkVideoChange);
observer.observe(document.body, { childList: true, subtree: true });

window.addEventListener('popstate', checkVideoChange);


chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    console.log(message)

    if (message.action === "saveToken") {
        saveTokenCookie();
    }

    if (message.action === "sendVideoId") {
        handleVideoIdMessage(message.videoId);
    }
});

function saveTokenCookie() {
    chrome.cookies.get({ url: "http://localhost:3000", name: "token" }, (cookie) => {
        if (cookie) {
            chrome.storage.local.set({ token: cookie.value }, () => {
                console.log("Token saved successfully.");
            });
        } else {
            console.error("No token cookie found after login.");
        }
    });
}

function handleVideoIdMessage(videoId) {
    console.log(videoId)
            sendVideoIdToServer(videoId);
}

function sendVideoIdToServer(videoId) {
    fetch("http://localhost:3000/videos/add", {
        method: "PUT",
        headers: {
            "Content-Type": "application/json",
        },
        credentials: "include",
        body: JSON.stringify({ videoId })
    })
        .then((response) => {
            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }
            return response.text();
        })
        .then((result) => {
            console.log(result)
         console.log("Video ID sent successfully:", result)
        })
        .catch((error) => console.error("Failed to send video ID:", error));
}