Sprints AI - Auto Mark Episodes as Watched

Marks Sprints AI episodes as watched, updates UI, and moves to the next episode automatically.

目前為 2025-02-16 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Sprints AI - Auto Mark Episodes as Watched
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Marks Sprints AI episodes as watched, updates UI, and moves to the next episode automatically.
// @author       You
// @match        https://sprints.ai/journeys/learning/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    function markAsWatched(episode, checkmark) {
        const itemId = episode.getAttribute("data-id");
        const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';

        if (!itemId) {
            alert("Error: No Item ID found.");
            return;
        }

        console.log(`Marking episode ${itemId} as watched...`);

        GM_xmlhttpRequest({
            method: "POST",
            url: "https://sprints.ai/course/1999481/learningStatus",
            headers: {
                "User-Agent": navigator.userAgent,
                "Accept": "*/*",
                "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                "X-CSRF-TOKEN": csrfToken,
                "X-Requested-With": "XMLHttpRequest",
            },
            data: `item=file_id&item_id=${itemId}&status=true`,
            onload: function (response) {
                if (response.status === 200) {
                    console.log(`Episode ${itemId} marked as watched!`);
                    updateEpisodeUI(episode, checkmark);
                    moveToNextEpisode(episode);
                } else {
                    alert("Failed to mark as watched.");
                }
            },
            onerror: function () {
                alert("Network error.");
            }
        });
    }

    function updateEpisodeUI(episode, checkmark) {
        episode.setAttribute("data-progress-status", "done");

        let iconDiv = episode.querySelector(".item-icon img");
        if (iconDiv) {
            iconDiv.src = "/assets/default/img/learning/watched.svg";
        }

        checkmark.innerHTML = "✔️";  // Update checkmark to indicate it's marked
        checkmark.style.color = "gray"; // Dim the color to indicate completion
        checkmark.style.pointerEvents = "none"; // Prevent further clicks
    }

    function moveToNextEpisode(currentEpisode) {
        let episodes = document.querySelectorAll(".content-item-link[data-file-type='video']");
        let currentIndex = Array.from(episodes).indexOf(currentEpisode);

        if (currentIndex >= 0 && currentIndex < episodes.length - 1) {
            let nextEpisode = episodes[currentIndex + 1];
            console.log(`Switching to next episode: ${nextEpisode.getAttribute("data-id")}`);
            nextEpisode.click();
        }
    }

    function addCheckmarksToEpisodes() {
        document.querySelectorAll(".content-item-link[data-file-type='video']").forEach(episode => {
            if (episode.querySelector(".checkmark")) return; // Avoid duplicate checkmarks

            let checkmark = document.createElement("span");
            checkmark.innerHTML = "✔️";
            checkmark.className = "checkmark";
            checkmark.style.position = "absolute";
            checkmark.style.top = "5px";
            checkmark.style.right = "5px";
            checkmark.style.fontSize = "16px";
            checkmark.style.cursor = "pointer";
            checkmark.style.color = "green";
            checkmark.style.fontWeight = "bold";
            checkmark.style.background = "white";
            checkmark.style.borderRadius = "50%";
            checkmark.style.padding = "2px 5px";
            checkmark.title = "Mark as Watched";

            checkmark.onclick = function (event) {
                event.stopPropagation();
                markAsWatched(episode, checkmark);
            };

            let iconDiv = episode.querySelector(".item-icon");
            if (iconDiv) {
                iconDiv.style.position = "relative";
                iconDiv.appendChild(checkmark);
            }

            console.log(`Checkmark added to episode: ${episode.getAttribute("data-id")}`);
        });
    }

    // Wait for page load
    setTimeout(addCheckmarksToEpisodes, 3000);
})();