Greasy Fork is available in English.

Netflix Mark Watched

Mark Netflix shows as watched.

// ==UserScript==
// @name Netflix Mark Watched
// @author SirGrypin
// @version 1.6
// @namespace watched_netflix
// @description Mark Netflix shows as watched.
// @include https://www.netflix.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @grant GM_registerMenuCommand
// @license MIT
// ==/UserScript==

function addWatchedButton(element) {
    var id = JSON.parse(decodeURI(element.data('ui-tracking-context'))).video_id;
    var watched = localStorage.getItem("watched_" + id);

    if (watched === 'true') {
        element.closest('.title-card-container').addClass('g_watched');
    }

    var watchedEye = $('<div class="watched_eye">&#128065;</div>');

    watchedEye.click(function () {
        var cardContainer = $(this).closest('.title-card-container');
        var isWatched = cardContainer.hasClass('g_watched');

        if (isWatched) {
            cardContainer.removeClass('g_watched');
            markAsUnwatched(id);
        } else {
            cardContainer.addClass('g_watched');
            markAsWatched(id);
        }
    });

    element.closest('.title-card-container').append(watchedEye);
}

// Function to mark a show as watched
function markAsWatched(videoId) {
    // Prefix the key with "watched_"
    localStorage.setItem("watched_" + videoId, "true");
}

// Function to mark a show as unwatched
function markAsUnwatched(videoId) {
    // Prefix the key with "watched_"
    localStorage.setItem("watched_" + videoId, "false");
}

// Backup data related to watched shows to a JSON file
function backupWatchedShows() {
    var watchedData = {};
    for (var key in localStorage) {
        if (key.startsWith("watched_")) {
            watchedData[key] = localStorage[key];
        }
    }

    var data = JSON.stringify(watchedData);
    var blob = new Blob([data], { type: "application/json" });
    var url = URL.createObjectURL(blob);

    var a = document.createElement("a");
    a.href = url;
    a.download = "watchedShowsBackup.json";
    a.style.display = "none";
    document.body.appendChild(a);
    a.click();

    document.body.removeChild(a);
    URL.revokeObjectURL(url);
}

// Restore data related to watched shows from a JSON file
function restoreWatchedShows() {
    var input = document.createElement("input");
    input.type = "file";
    input.accept = ".json";

    input.click();

    input.addEventListener("change", function () {
        var file = input.files[0];
        var reader = new FileReader();

        reader.onload = function () {
            try {
                var data = JSON.parse(reader.result);
                for (var key in data) {
                    localStorage.setItem(key, data[key]);
                }
                alert("Watched shows data restored successfully.");
            } catch (e) {
                alert("Error restoring data: " + e);
            }
        };

        if (file) {
            reader.readAsText(file);
        }
    });
}

$(document).ready(function () {
    // Initial execution for the elements present on the page load
    $('[data-ui-tracking-context]').each(function () {
        addWatchedButton($(this));
    });

    // Add a MutationObserver to detect when new elements are added
    var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            if (mutation.addedNodes) {
                $(mutation.addedNodes).find('[data-ui-tracking-context]').each(function () {
                    addWatchedButton($(this));
                });
            }
        });
    });

    // Observe changes in the DOM, including dynamically loaded content
    observer.observe(document.body, { childList: true, subtree: true });

    GM_registerMenuCommand("Backup Watched Shows", backupWatchedShows);
    GM_registerMenuCommand("Restore Watched Shows", restoreWatchedShows);

    $('head').append(`
    <style>
    .watched_eye {
      font-size: 57px;
      padding: 10px;
      position: absolute;
      bottom: -40px;
      left: 0;
      background: gray;
      border-radius: 6px;
      height: 30px;
      line-height: 30px;
    }
    .watched_eye:hover {
      opacity: 0.3;
      cursor: pointer;
    }
    .title-card-container.g_watched {
      opacity: 0.3;
    }
    </style>
  `);
});