EMBY显示EXTRAFANART剧照

EMBY显示EXTRAFANART剧照

1.前期准备

实现方式

1.使用油猴插件 + JS

2.Emby安装CustomCssJS Provider插件 + JS

CustomCssJS Provider项目地址:https://github.com/Shurelol/Emby.CustomCssJS

3.直接将JS 代码注入到 index.html (方法略)

JS代码:(来自 MICIMO 丨 主页)

// ==UserScript==
// @name         Jellyfin/Emby extrafanart 显示
// @namespace    https://www.micimo.love/
// @version      1.0.3
// @description  Jellyfin/Emby 显示剧照
// @author       MICIMO
// @updateURL    https://www.micimo.love/jellyfin/extrafanart.js
// @include      http*://*:8096/*
// ==/UserScript==

;(function () {
    'use strict';

    let startImageIndex = 0;
    let endImageIndex = 0;
    let currentZoomedImageIndex = -1;
    let itemId = null;

    const imageContainer = createImageContainer();
    const zoomedMask = createZoomedMask();

    document.body.appendChild(imageContainer);
    document.body.appendChild(zoomedMask);

    function getCurrentItemId() {
        return location.hash.match(/id\=(\w+)/)?.[1] ?? null;
    }

    function getBackgroundImageSrc(index) {
        const currentItemId = getCurrentItemId();
        return currentItemId && `${location.origin}/Items/${currentItemId}/Images/Backdrop/${index}?maxWidth=1280`;
    }

    function createImageContainer() {
        const container = document.createElement('div');
        container.id = 'jv-image-container';
        container.style.display = 'grid';
        container.style.gridTemplateColumns = 'repeat(5, 1fr)';  // 每行 5 列
        container.style.gap = '10px';  // 图片之间的间距
        return container;
    }

    function createZoomedMask() {
        const mask = document.createElement('div');
        mask.id = 'jv-zoom-mask';
        mask.style.position = 'fixed';
        mask.style.left = '0';
        mask.style.right = '0';
        mask.style.top = '0';
        mask.style.bottom = '0';
        mask.style.background = 'rgba(0, 0, 0, 0.8)';
        mask.style.display = 'none';
        mask.style.justifyContent = 'center';
        mask.style.alignItems = 'center';
        mask.style.zIndex = '1100';
        mask.style.cursor = 'zoom-out';

        const zoomedImage = document.createElement('img');
        zoomedImage.id = 'jv-zoom-img';
        zoomedImage.style.maxWidth = '90%';
        zoomedImage.style.maxHeight = '90%';
        zoomedImage.style.borderRadius = '10px';
        mask.appendChild(zoomedImage);

        mask.onclick = hideZoomedMask;

        return mask;
    }

    function showZoomedMask(imageSrc) {
        const zoomedImage = document.getElementById('jv-zoom-img');
        zoomedImage.src = imageSrc;
        const zoomedMask = document.getElementById('jv-zoom-mask');
        zoomedMask.style.display = 'flex';
        document.body.style.overflow = 'hidden'; // 防止背景滚动
    }

    function hideZoomedMask() {
        const zoomedMask = document.getElementById('jv-zoom-mask');
        zoomedMask.style.display = 'none';
        document.body.style.overflow = ''; // 恢复背景滚动
    }

    function createImageElement(index) {
        const imageSrc = getBackgroundImageSrc(index);
        const wrapper = document.createElement('div');
        wrapper.className = 'jv-image-wrapper';
        wrapper.style.width = '100%';
        wrapper.style.height = '0';
        wrapper.style.paddingBottom = '75%'; // 保持 4:3 比例框
        wrapper.style.position = 'relative';
        wrapper.style.overflow = 'hidden';
        wrapper.style.boxSizing = 'border-box';

        const imageElement = document.createElement('img');
        imageElement.src = imageSrc;
        imageElement.className = 'jv-image';
        imageElement.style.position = 'absolute';
        imageElement.style.top = '0';
        imageElement.style.left = '0';
        imageElement.style.width = '100%';
        imageElement.style.height = '100%';
        imageElement.style.objectFit = 'cover'; // 图片自适应填充网格
        imageElement.style.cursor = 'zoom-in';
        imageElement.style.userSelect = 'none';
        imageElement.style.borderRadius = '10px';
        imageElement.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.1)';

        imageElement.onclick = function () {
            showZoomedMask(imageSrc);
        };

        wrapper.appendChild(imageElement);
        return wrapper;
    }

    function appendImagesToContainer(imageCount) {
        const imageFragment = document.createDocumentFragment();
        for (let index = startImageIndex; index <= imageCount; index++) {
            const imageElement = createImageElement(index);
            imageFragment.appendChild(imageElement);
        }
        imageContainer.appendChild(imageFragment);
    }

    function showContainer(imageCount) {
        if (imageCount > 0) {
            const primaryDiv =
                document.querySelector('#itemDetailPage:not(.hide) #castCollapsible') || document.querySelector('.itemView:not(.hide) .peopleSection');
            if (primaryDiv) {
                imageContainer.style.display = 'grid';
                primaryDiv.insertAdjacentElement('afterend', imageContainer);
            }
        }
    }

    function isDetailsPage() {
        return location.hash.includes('/details?id=') || location.hash.includes('/item?id=');
    }

    async function getEndImageIndex() {
        let left = startImageIndex;
        let right = startImageIndex + 20;
        let found = false;
        while (left <= right) {
            let mid = Math.floor((left + right) / 2);
            const newSrc = getBackgroundImageSrc(mid);
            try {
                const response = await fetch(newSrc, { method: 'HEAD' });
                if (!response.ok) throw new Error('Image not found.');
                found = true;
                left = mid + 1;
            } catch (error) {
                right = mid - 1;
            }
        }
        return found ? right : 0;
    }

    async function loadImages() {
        if (!isDetailsPage()) return;
        const currentItemId = getCurrentItemId();
        if (!currentItemId) return;
        if (itemId !== currentItemId) {
            endImageIndex = await getEndImageIndex();
        }
        itemId = currentItemId;
        imageContainer.innerHTML = '';
        appendImagesToContainer(endImageIndex);
        showContainer(endImageIndex);
    }

    document.addEventListener('viewshow', () => setTimeout(loadImages));
})();
 

2.实施

1.油猴方案:

直接将代码导入到插件即可

image-20241124015745688

2.CustomCssJS Provider方案

官方安装文档:Emby.CustomCssJS/src/README.md at main · Shurelol/Emby.CustomCssJS · GitHubEasy to manage your Custom JavaScript and Css to modify Emby - Emby.CustomCssJS/src/README.md at main · Shurelol/Emby.CustomCssJSicon-default.png?t=O83Ahttps://github.com/Shurelol/Emby.CustomCssJS/blob/main/src/README.md

image-20241124020224319

Mac端在应用程序中显示包内容即可

image-20241124020014644

将JS 代码 添加到插件中

image-20241124020356397

在此处将JS 启用即可实现剧照显示

image-20241124020544946

(注:目前无法做到自适应分辨率显示图片列数,因此手机推荐4-5列,PC推荐10列)

JS 代码中在此处修改图片列数

    function createImageContainer() {
        const container = document.createElement('div');
        container.id = 'jv-image-container';
        container.style.display = 'grid';
        container.style.gridTemplateColumns = 'repeat(5, 1fr)';  // 每行 5 列
        container.style.gap = '10px';  // 图片之间的间距
        return container;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值