YouTube (New Design) | Compact Subscription Feed

Optimized YouTube Subscription feed list view with more information on less space

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name            YouTube (New Design) | Compact Subscription Feed
// @namespace       de.sidneys.userscripts
// @homepage        https://gist.githubusercontent.com/sidneys/1aec97019cde4fe37619e36eb730b216/raw/
// @version         1.0.0
// @description     Optimized YouTube Subscription feed list view with more information on less space
// @author          sidneys
// @icon            https://www.youtube.com/favicon.ico
// @include         http*://www.youtube.com/*
// @require         https://greasyfork.org/scripts/38888-greasemonkey-color-log/code/Greasemonkey%20%7C%20Color%20Log.js
// @require         https://greasyfork.org/scripts/38889-greasemonkey-waitforkeyelements-2018/code/Greasemonkey%20%7C%20waitForKeyElements%202018.js
// @run-at          document-end
// @grant           GM_addStyle
// ==/UserScript==

/**
 * @default
 * @constant
 * @global
 */
DEBUG = false;


/**
 * @default
 * @constant
 */
const urlPath = '/feed/subscriptions';


/**
 * Inject Stylesheet
 */
let injectStylesheet = () => {
    console.debug('injectStylesheet');

    GM_addStyle(`
    /* ==========================================================================
       GLOBAL
       ========================================================================== */

    .hide
    {
        opacity: 0 !important;
    }


    /* ==========================================================================
       LIST
       ========================================================================== */

    /* Container
       ========================================================================== */

    .layout-list div#content
    {
        position: relative !important;
        margin-top: 2% !important;
        width: 95% !important;
    }

    .layout-list div.branded-page-v2-primary-col > div.yt-card
    {
        margin-top: 0 !important;
    }

    /* Header
       ========================================================================== */

    .layout-list ol.section-list > li:first-child div.feed-item-container
    {
        border-top: none !important;
        background-image: linear-gradient(to bottom, rgba(0,0,0,0.25) 50%, rgba(0,0,0,0.25)) !important;
        background-repeat: no-repeat !important;
        background-size: 100% 45px !important;
    }

    .layout-list ol.section-list > li:first-child div.feed-item-container div.menu-container
    {
        margin-bottom: 20px !important;
    }

    .layout-list ol.section-list > li:first-child div.feed-item-container div.shelf-title-table
    {
        display: table !important;
        width: 100% !important;
    }

    .layout-list ol.section-list > li:first-child div.feed-item-container div.shelf-title-table h2
    {
        display: none !important;
    }

    .layout-list ol.section-list > li:first-child div.feed-item-container div.shelf-title-table .menu-container
    {
        display: block !important;
    }

    /* ==========================================================================
       ITEM
       ========================================================================== */

    /* Stripes
       ========================================================================== */

    .layout-list #contents.ytd-section-list-renderer > *.ytd-section-list-renderer:nth-child(odd)
    {
        background-color: rgba(0, 0, 0, 0.1) !important;
    }

    /* Container
       ========================================================================== */

    .layout-list ytd-shelf-renderer
    {
        border-bottom: 1px solid #5a5a5a !important;
        border-top: none !important;
        padding-bottom: 12px !important;
        padding-top: 12px !important;
    }

    .layout-list .text-wrapper.ytd-video-renderer
    {
        max-width: none !important;
    }

    .layout-list .grid-subheader.ytd-shelf-renderer
    {
        display: none !important;
    }

    .layout-list #contents.ytd-shelf-renderer
    {
        margin-top: 0 !important;
    }

    .layout-list ytd-expanded-shelf-contents-renderer
    {
        margin-bottom: 0 !important;
    }

    /* Thumbnail
       ========================================================================== */

    .layout-list ytd-thumbnail
    {
        width: 72px !important;
        height: auto !important;
        margin-left: 16px !important;
    }

    .layout-list ytd-thumbnail-overlay-time-status-renderer
    {
        color: rgb(118, 118, 118) !important;
        font-size: 12px !important;
        background-color: transparent !important;
        bottom: 15% !important;
    }

    .layout-list ytd-thumbnail-overlay-resume-playback-renderer:before
    {
        top: -37px !important;
        width: 72px !important;
        height: 41px !important;
        line-height: 36px !important;
        font-size: 1em !important;
    }

    .layout-list ytd-thumbnail-overlay-resume-playback-renderer:after
    {
        font-size: 0.75rem !important;
        font-weight: !important;
    }

    /* Title
       ========================================================================== */

    /*.layout-list #title-wrapper.ytd-video-renderer
    {
        padding: 4px 0 !important;
        display: block !important;
        white-space: nowrap !important;
        overflow: hidden !important;
        text-overflow: ellipsis !important;
        max-width: none !important;
        margin-right: 50px !important;
    }*/

    .layout-list #video-title.ytd-video-renderer
    {
        font-size: 13px !important;
        line-height: 1.3em !important;
        font-weight: 500 !important;
        display: inline !important;
        white-space: nowrap !important;
        text-overflow: ellipsis !important;
        overflow: hidden !important;
        background: none !important;
    }

    .layout-list .badge-style-type-verified.ytd-badge-supported-renderer
    {
        margin: 0 0 0 5px !important;
    }

    /* Channel
       ========================================================================== */

    .layout-list a.yt-simple-endpoint.yt-formatted-string
    {
        color: #1ea4e8 !important;
    }

    /* Description
       ========================================================================== */

    .layout-list #description-text.ytd-video-renderer
    {
        max-width: 70% !important;
        margin-top: 4px !important;
        display: none !important;
    }

    /* Badges
       ========================================================================== */

    .layout-list ytd-video-meta-block #byline-container
    {
        display: none !important;
    }

    /* Time
       ========================================================================== */

    .layout-list span.timestamp.ytd-video-meta-block
    {
        float: right !important;
        position: absolute !important;
        right: 0 !important;
        margin-right: 16px !important;
    }

    .layout-list span.timestamp.ytd-video-meta-block br
    {
        display: none !important;
    }
    `);
};

/**
 * Feed in list / grid layout?
 * @returns {Boolean} - Page layout
 */
let isListLayout = () => !Boolean(document.querySelector('div.multirow-shelf'));

/**
 * Adapt feed item element
 * @param {HTMLElement} element - Feed item container
 */
let adaptItemLayout = (element) => {
    console.debug('adaptItemLayout');

    // DOM
    const titleElement = element.querySelector('#video-title.ytd-video-renderer');
    const verifiedElement = element.querySelector('#byline-container.ytd-video-meta-block yt-icon.ytd-badge-supported-renderer');
    const channelElement = element.querySelector('a.yt-simple-endpoint.yt-formatted-string');
    const videoMetaDivList = element.querySelectorAll('div.yt-lockup-meta');
    const videoBadgesDiv = element.querySelector('div.yt-lockup-badges');
    const videoLiveSpan = element.querySelector('span.yt-badge-live');
    const videoReminderSpan = element.querySelector('span.yt-uix-livereminder');

    // Create Separator
    let elementSeparator = document.createElement('span');
    elementSeparator.innerText = ' | ';

    // Title
    if (titleElement) {
        titleElement.insertBefore(elementSeparator, titleElement.firstChild);
    }

    // Verified
    if (verifiedElement) {
        titleElement.insertBefore(verifiedElement, titleElement.firstChild);
        verifiedElement.style.marginLeft = '4px';
    }

    // Channel
    if (channelElement && titleElement) {
        titleElement.insertBefore(channelElement, titleElement.firstChild);
    }

    // Live Badge
    if (videoLiveSpan && videoBadgesDiv && videoMetaDivList && videoMetaDivList[0] && videoMetaDivList[0].style) {
        videoBadgesDiv.style.display = 'inline-block';
        videoMetaDivList[0].style.display = 'inline-block';
    }

    // Reminder Badge
    if (videoReminderSpan && videoBadgesDiv && videoMetaDivList && videoMetaDivList[0]) {
        videoBadgesDiv.style.display = 'inline-block';
        videoMetaDivList.forEach((videoMetaDiv) => {
            videoMetaDiv.style.display = 'inline-block';
        });
    }
};

/**
 * Adapt timestamp element
 * @param {HTMLElement} element - Timestamp element
 */
let adaptTimestampLayout = (element) => {
    console.debug('adaptTimestampLayout');

    // DOM
    const itemElement = element.closest('ytd-shelf-renderer');
    const videoMetadataLineDiv = itemElement.querySelector('#metadata-line.ytd-video-meta-block');

    // Create new timestamp element
    const timestampElement = document.createElement('span');
    timestampElement.className = 'timestamp ytd-video-meta-block';
    timestampElement.innerText = element.innerText;
    videoMetadataLineDiv.appendChild(timestampElement);

    // Remove old timestamp element
    element.closest('ytd-thumbnail-overlay-time-status-renderer').parentNode.removeChild(element.closest('ytd-thumbnail-overlay-time-status-renderer'));
};


/**
 * Init
 */
let init = () => {
    console.info('init');

    // Check URL
    if (!location.pathname.startsWith(urlPath)) { return; }

    // Add Stylesheet
    injectStylesheet();

    // Set layout helper class (document.body)
    if (isListLayout()) {
        document.body.classList.add('layout-list');
    } else {
        document.body.classList.remove('layout-list');
    }

    // Watch items
    waitForKeyElements('.layout-list ytd-shelf-renderer', (item) => {
        adaptItemLayout(item);
    });

    // Watch timestamps
    waitForKeyElements('span.ytd-thumbnail-overlay-time-status-renderer', (item) => {
        adaptTimestampLayout(item);
    });
};


/**
 * @listens window:Event#load
 */
window.addEventListener('load', () => {
    console.debug('window#load');

    init();
});

/**
 * @listens window:Event#spfdone
 */
window.addEventListener('spfdone', () => {
    console.debug('window#spfdone');

    init();
});