您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show played status on playlist when using Plex
- // ==UserScript==
- // @name Plex playlist played status
- // @description Show played status on playlist when using Plex
- // @version 1.1
- // @namespace cybolic.me
- // @author Christian Dannie Storgaard
- // @include https://app.plex.tv/desktop
- // @include https://app.plex.tv/desktop/*
- // @include https://app.plex.tv/desktop#*
- // @include http://localhost:32400/web/*
- // @include http://127.0.0.1:32400/web/*
- // @include https://localhost:32400/web/*
- // @include https://127.0.0.1:32400/web/*
- // @grant none
- // @license GNU GPLv3
- // ==/UserScript==
- var info = {
- serverId: '',
- playlistId: '',
- playlistDOM: undefined
- };
- var logMessage = function (msg) {
- console.info(`[Plex Playlist Played] ${msg}`);
- };
- var getCurrentUsersData = function () {
- return JSON.parse(localStorage.users)?.users || [];
- };
- var getCurrentServerId = function () {
- return window.location.hash
- .split('/server/').pop()
- .split?.('/').shift();
- };
- var getCurrentPlaylistId = function () {
- return decodeURIComponent(window.location.hash)
- .split('key=/playlists/').pop()
- .split?.('&').shift();
- };
- var getServerDetailsForAll = function () {
- return Object.fromEntries(
- getCurrentUsersData()
- .filter(user => user.servers.length)
- .map(userWithServers => userWithServers.servers)
- .flat()
- .map(server => [ server.machineIdentifier, server ])
- );
- }
- var getServerDetailsForId = function (serverId) {
- return getServerDetailsForAll()[serverId];
- };
- var getPlaylist = function (serverId, playlistId) {
- const serverDetails = getServerDetailsForId(serverId);
- const url = `${serverDetails.connections.shift()?.uri || 'https://localhost:32400'}/playlists/${playlistId}/items?includeExternalMedia=1&X-Plex-Token=${serverDetails.accessToken}`;
- logMessage(`looking up ${url}`);
- return fetch(url)
- .then(response => response.text())
- .then(responseText => (new DOMParser()).parseFromString(responseText, 'application/xml'));
- };
- var getPlaylistElementFromKey = function (serverId, key) {
- return document.querySelectorAll(`a[data-testid="metadataTitleLink"][href*="/server/${serverId}"][href*="${encodeURIComponent(key)}"]`).shift();
- };
- var addStyle = function (css) {
- let shouldAddToHead = false;
- let style = document.querySelector('#plex-playlist-played-css');
- if (style == null) {
- style = document.createElement('style');
- style.id = 'plex-playlist-played-css';
- shouldAddToHead = true;
- }
- style.textContent = css;
- if (shouldAddToHead) {
- document.head.append(style);
- }
- };
- var getCssForPlaylist = function (serverId, dom) {
- logMessage("creating css");
- const videosNotPlayed = Array.from(dom.querySelectorAll('Video:not([viewCount])'));
- const css = videosNotPlayed
- // get the library key for these items
- .map(video => ({
- key: video.attributes['key'].value,
- type: video.attributes['type'].value,
- }))
- // generate a CSS rule for each playlist item that targets the only element we can track, the link to the item
- .map(attrs => {
- const selector = `a[data-testid="metadataTitleLink"][href*="/server/${serverId}"][href*="${encodeURIComponent(attrs.key)}&"]`;
- return `${selector}::after {
- content: '';
- position: absolute;
- ${attrs.type === 'episode'
- ? `left: 155px; top: 16px;`
- : `left: 141px; top: 7px;`
- }
- width: 0px;
- height: 0px;
- border: 8px solid #e5a00d;
- border-color: #e5a00d #e5a00d transparent transparent;
- filter: drop-shadow(0px 1px 0px rgba(0,0,0,0.5));
- pointer-events: none;
- }`;
- })
- .join('\n');
- return css;
- };
- var checkCurrentPage = function () {
- logMessage("checking if current location is playlist");
- if (window.location.hash.includes(`key=${encodeURIComponent('/playlists/')}`)) {
- logMessage("current page is playlist; fetching playlist data");
- info.serverId = getCurrentServerId();
- info.playlistId = getCurrentPlaylistId();
- getPlaylist(info.serverId, info.playlistId).then(dom => {
- logMessage("playlist data fetched, creating CSS");
- info.playlistDOM = dom;
- const css = getCssForPlaylist(info.serverId, info.playlistDOM);
- addStyle(css);
- logMessage('play status added');
- });
- }
- };
- window.addEventListener('hashchange', checkCurrentPage);
- logMessage("added event handler");
- checkCurrentPage();