DTF Enhancer

Выводит список подписок в сайдбаре и раскрывает список комментов

目前為 2024-03-14 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         DTF Enhancer
// @namespace    http://tampermonkey.net/
// @version      0.0.2
// @description  Выводит список подписок в сайдбаре и раскрывает список комментов
// @author       You
// @match        *://dtf.ru/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=dtf.ru
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
  const cn = (tagName, attrs = {}, childrenList = [], parentNode = null) => {
    const node = document.createElement(tagName);

    if (typeof attrs === 'object') {
        for (const attrsKey in attrs) node.setAttribute(attrsKey, attrs[attrsKey]);
    }

    if (Array.isArray(childrenList)) {
        childrenList.forEach(child => {
            node.appendChild(typeof child === 'string' ? document.createTextNode(child) : child);
        });
    }

    if (parentNode) {
        parentNode.appendChild(node);
    }

    return node;
  };

  const getDomElementAsync = (selector, timerLimit = 10000) => {
    return new Promise((resolve, reject) => {
        try {
            setTimeout(() => {
                console.log(`Время ожидания DOM элемента ${selector} истекло (${timerLimit / 1000}s)`);
                resolve(null);
            }, timerLimit);

            let timerId;

            const tick = () => {
                const element = document.querySelector(selector);

                if (element) {
                    clearTimeout(timerId);
                    resolve(element);
                } else {
                    timerId = setTimeout(tick, 100);
                }
            };

            tick();
        } catch (e) {
            reject(e);
        }
    });
};

  const injectStyles = () => {
    const styles = `
      .sidebar-subs {
        display: flex;
        flex-direction: column;
        overflow: auto;
        margin: 24px 0;
      }

      .sidebar-sibs__title {
        margin-bottom: 16px;
        padding: 0 8px;
        font-weight: 500;
        font-size: 18px;
      }

      .sidebar-sibs__list {
        padding: 0;
      }

      .sidebar-item._sub img.icon {
        width: 24px;
        border-radius: 50%;
      }

      .sidebar-item._sub span {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        min-width: 1px;
      }

      /* перебиваем стили DTF */
      .sidebar__main {
        display: flex;
        flex-direction: column;
        flex-shrink: 0;
        min-width: 1px;
        overflow: auto;
      }

      .sidebar-item {
        flex-shrink: 0;
      }

      .sidebar-editor-button {
        margin-top: 24px;
      }

      .sidebar-editor-buttons {
        margin-top: auto;
        margin-bottom: 16px;
      }

      .account-menu {
        visibility: hidden;
      }

      body.dtf-subs-script-inited .account-menu {
        visibility: visible;
      }
    `;

    document.head.insertAdjacentHTML("beforeend", `<style type="text/css" id="dtfSubsStyles">${styles}</style>`)
  };

  const fetchSubs = async (userId) => {
    const resp = await fetch(`https://api.dtf.ru/v2.5/subsite/subscriptions?subsiteId=${userId}`);
    const { result } = await resp.json();

    return result.items;
  }

  const getImageUrl = (uuid) => `https://leonardo.osnova.io/${uuid}/-/scale_crop/32x32/`;

  const createSidebarItem = (name, imageId, href) => {
    const imgEl = cn('img', { class: 'icon', src: getImageUrl(imageId) });
    const nameEl = cn('span', {}, [name]);
    const result = cn('a', { class: 'sidebar-item _sub', href: href, alt: name }, [imgEl, nameEl]);

    return result;
  };

  const createSidebarList = (items) => {
    const sidebarItems = items.map((item) => {
      return createSidebarItem(item.name, item.avatar.data.uuid, item.uri);
    });

    const title = cn('div', { class: 'sidebar-sibs__title' }, ['Подписки:']);
    const listWrapper = cn('div', { class: 'sidebar-sibs__list modal-window__content' }, sidebarItems);

    return cn('div', { class: 'sidebar-subs' }, [title, listWrapper]);
  };

  const getProfileUrl = async () => {
    const userButton = await getDomElementAsync('.user');
    userButton.click();

    const profileMenuItem = await getDomElementAsync('.account-menu__user-card');
    userButton.click();

    return profileMenuItem.href;
  }

  const getUserId = async () => {
    const profileUrl = await getProfileUrl();
    const userId = profileUrl.split('/u/')[1].split('-')[0];

    return userId || null;
  };

  const injectSubscriptions = async () => {
    const userId = await getUserId();

    document.body.classList.add('dtf-subs-script-inited');

    if (!userId) {
      return;
    }

    const subs = await fetchSubs(userId);
    const list = createSidebarList(subs);

    const sidebarButton = await getDomElementAsync('.sidebar-editor-button');
    sidebarButton.after(list);
  };

  const init = async () => {
    injectStyles();

    injectSubscriptions();

    const expandCommentsButton = await getDomElementAsync('.comments-limit__expand');
    expandCommentsButton.click();
  };


  init();
})();