arca.live enhancements

Adds: list previews, post visit history

目前为 2024-01-08 提交的版本。查看 最新版本

// ==UserScript==
// @author      jvlflame
// @name        arca.live enhancements
// @version     0.0.1
// @license MIT
// @include     https://arca.live/*

// @description Adds: list previews, post visit history

// @namespace https://greasyfork.org/users/63118
// ==/UserScript==


let GLOBAL_STYLES = `
    .vrow.column.head {
        height: initial !important;
    }

    .vrow.column {
        height: 135px !important;
    }

    .vrow.column.visited {
        opacity: 0.4;
    }

    .vrow-inner {
        padding-left: 115px;
    }

    .vrow-preview {
        display: block !important;
        top: 10px !important;
    }

    .notice.column {
        height: 2.4rem !important;
    }

    .sidebar-item {
        display: none;
    }
`;


const CURRENT_PAGE = window.location.pathname;
const IS_POST_PAGE = CURRENT_PAGE.match(/\/b\/.*\/\d+/g);
const IS_LIST_PAGE = !IS_POST_PAGE;
const CATEGORY = CURRENT_PAGE.match(/\/b\/(\w+)/g);
const VISITED_POSTS = getPostsFromLocalStorage(CATEGORY);

const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.innerText = GLOBAL_STYLES;
document.head.appendChild(styleSheet);

function getPost(id, title, unixTimestamp) {
    const dateTimeString = unixTimestamp ? new Date(unixTimestamp * 1000).toISOString() : new Date().toISOString();

    const post = {
        t: title,
        v: dateTimeString
    }

    return {
        id: id,
        post: post
    };
}

function getPostsFromLocalStorage(category) {
    const posts = JSON.parse(localStorage.getItem(`visited-posts-${category}`));
    return posts ? posts : {};
}

function isPostVisited(visitedPosts, id) {
    return visitedPosts[id];
}

function appendPostToLocalStorage(post, category) {
    const posts = getPostsFromLocalStorage(category);

    if (isPostVisited(posts, post.id)) {
        return;
    }

    posts[post.id] = post.post;
    localStorage.setItem(`visited-posts-${category}`, JSON.stringify(posts));
}

function migrateRecentArticles() {
    /* recent_articles
        {
           boardName: string;
           slug: string;
           articleId: number;
           title: string;
           regdateAt: number
        }[]
    */

    const isMigrated = localStorage.getItem('migrated-timestamp');

    if (isMigrated) {
        return;
    }

    const nativeVisitedPosts = localStorage.getItem('recent_articles');

    if (!nativeVisitedPosts) {
        return;
    }

    for (const visitedPost of JSON.parse(nativeVisitedPosts)) {
        const post = getPost(visitedPost.articleId, visitedPost.title, visitedPost.regdateAt);
        const category = `/b/${visitedPost.slug}`;
        appendPostToLocalStorage(post, category);
    }

    localStorage.setItem('migrated-timestamp', new Date().toISOString());
}


// Get the list table element
const table = document.getElementsByClassName("list-table table");

// Get the list table row elements
const rows = table[0].querySelectorAll("a.vrow.column");

for (const row of rows) {
    if (row.classList.contains("notice")) {
        continue;
    };


    const previewElement = row.querySelectorAll('.vrow-preview');
    const hasPreview = Boolean(previewElement[0])

    if (!hasPreview) {
        const dummyPreviewElement = document.createElement('div');
        dummyPreviewElement.classList.add('vrow-preview');
        row.appendChild(dummyPreviewElement);
    }

    const href = row.href;

    // Remove the query string so it's easier to copy article id when archiving
    const hrefWithoutQuery = href.split('?')[0];
    row.setAttribute("href", hrefWithoutQuery);

    const id = href.split(/\/b\/\w+\//)[1].split(/\?/)[0];
    const titleElement = row.querySelectorAll(".title")[0];
    const title = titleElement ? titleElement.outerText : '';

    const isVisited = isPostVisited(VISITED_POSTS, id);

    if (isVisited) {
        row.classList.add("visited");
    } else {
        row.addEventListener("click", () => {
            const post = getPost(id, title);
            appendPostToLocalStorage(post, CATEGORY);
        });

        row.addEventListener("auxclick", () => {
            const post = getPost(id, title);
            appendPostToLocalStorage(post, CATEGORY);
        });
    }
}

if (IS_POST_PAGE) {
    const title = document.querySelectorAll(".title-row .title")[0].outerText;
    const id = CURRENT_PAGE.split(/\/b\/\w+\//)[1].split(/\?/)[0];
    const post = getPost(id, title);

    if (isPostVisited(VISITED_POSTS, id)) {
        return;
    };

    appendPostToLocalStorage(post, CATEGORY);
}

migrateRecentArticles();