embyToLocalPlayer

需要python。若用 PotPlayer VLC mpv MPC 播放,可更新服务器观看进度。支持 Jellyfin。

当前为 2022-09-21 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         embyToLocalPlayer
// @name:zh-CN   embyToLocalPlayer
// @name:en      embyToLocalPlayer
// @namespace    https://github.com/kjtsune/embyToLocalPlayer
// @version      1.0.6
// @description  需要python。若用 PotPlayer VLC  mpv MPC 播放,可更新服务器观看进度。支持 Jellyfin。
// @description:zh-CN 需要python。若用 PotPlayer VLC  mpv MPC 播放,可更新服务器观看进度。支持 Jellyfin。
// @description:en  Require python. If you use PotPlayer or VLC or mpv or MPC , will update watch history to emby server. Support Jellyfin.
// @author       Kjtsune
// @match        *://*/web/index.html*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=emby.media
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @run-at       document-start
// @license MIT
// ==/UserScript==
'use strict';
/*
更新的同时要去 github 下载文件,方法详见介绍里的 [更新] 部分

2022-09-21:
1. 增加 PotPlayer 回传进度支持。
2. 增加 VLC 回传进度支持。
3. 修复首次启动时系统编码判断问题。

2022-09-19:
1. 增加 Jellyfin 支持。

2022-09-07:
1. 增加 mpc-hc mpc-be 回传进度支持。
2. 修复 mpv 窗口激活置顶可能失败,无需配置 `ontop = yes`。
3. 修复 mpc 未在前台启动,自动全屏。

2022-09-05:
1. 修复 .vbs .ahk 文件内路径含空格问题。
2. 首次启动会自动关闭之前的进程,方便调试,减少错误。
3. 挂载盘可设优先级(一般用不到)
4. 更新 portable_config 修复一些注释有误的。
*/


function switchLocalStorage(key, defaultValue = 'true', trueValue = 'true', falseValue = 'false') {
    if (key in localStorage) {
        let value = (localStorage.getItem(key) === trueValue) ? falseValue : trueValue;
        localStorage.setItem(key, value);
    } else {
        localStorage.setItem(key, defaultValue)
    }
    console.log('switchLocalStorage ', key, ' to ', localStorage.getItem(key))
}

function setModeSwitchMenu(storageKey, menuStart = '', menuEnd = '', defaultValue = '关闭', trueValue = '开启', falseValue = '关闭') {
    let switchNameMap = { 'true': trueValue, 'false': falseValue, null: defaultValue };
    let menuId = GM_registerMenuCommand(menuStart + switchNameMap[localStorage.getItem(storageKey)] + menuEnd, clickMenu);

    function clickMenu() {
        GM_unregisterMenuCommand(menuId);
        switchLocalStorage(storageKey)
        menuId = GM_registerMenuCommand(menuStart + switchNameMap[localStorage.getItem(storageKey)] + menuEnd, clickMenu);
    }

}

const originFetch = fetch;
unsafeWindow.fetch = async (url, request) => {
    if (url.indexOf('/PlaybackInfo?UserId') > -1 && url.indexOf('IsPlayback=true') > -1
        && localStorage.getItem('webPlayerEnable') != 'true') {
        let response = await originFetch(url, request);
        let data = await response.clone().json()
        embyToLocalPlayer(url, request, data);
        console.log('%c%o%s', "color:orange;", 'headers ', response, typeof (response))

        // // 不知道回传什么数据 jellyfin 才不会网页播放,且不转圈。emby 会弹无兼容数据流
        // if (url.indexOf('Emby-Token') != -1) { return '' }
        // data.MediaSources[0].SupportsTranscoding = false;
        // data.MediaSources[0].SupportsDirectPlay = false;
        // data.MediaSources[0].SupportsProbing = false;
        // data.MediaSources[0].Container = 'mkv';
        // console.log('%c%o%s', "color:orange;", 'data ', JSON.stringify(data), typeof (data))
        // var myBlob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
        // var init = { "status" : 200 , "statusText" : "SuperSmashingGreat!" };
        // var myResponse = new Response(myBlob, init);
        // return myResponse

    }
    // else if (localStorage.getItem('webPlayerEnable') != 'true' && url.indexOf('/stream') != -1) {
    //     console.log('%c%o%s', "color:orange;", 'url', url)
    //     return
    // }
    else {
        return originFetch(url, request);
    }
}

async function getItemInfo(playbackUrl, request) {
    let response = await fetch(playbackUrl, request);
    if (response.ok) {
        return await response.json();
    } else {
        throw new Error(response.statusText);
    }
}

async function embyToLocalPlayer(playbackUrl, request, response) {
    let data = {
        playbackData: response,
        playbackUrl: playbackUrl,
        request: request,
        mountDiskEnable: localStorage.getItem('mountDiskEnable'),

    };
    sendDataToLocalServer(data, 'embyToLocalPlayer');
}

function sendDataToLocalServer(data, path) {
    let url = `http://127.0.0.1:58000/${path}/`
    GM_xmlhttpRequest({
        method: "POST",
        url: url,
        data: JSON.stringify(data),
        headers: {
            "Content-Type": "application/json"
        },
    });
}

setModeSwitchMenu('webPlayerEnable', '网页播放模式已经')
setModeSwitchMenu('mountDiskEnable', '读取硬盘模式已经')