embyToLocalPlayer

需要 Python。若用 PotPlayer mpv MPC VLC 播放,可回传播放进度。支持 Jellyfin Plex 弹弹play。

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

  1. // ==UserScript==
  2. // @name embyToLocalPlayer
  3. // @name:zh-CN embyToLocalPlayer
  4. // @name:en embyToLocalPlayer
  5. // @namespace https://github.com/kjtsune/embyToLocalPlayer
  6. // @version 1.0.8
  7. // @description 需要 Python。若用 PotPlayer mpv MPC VLC 播放,可回传播放进度。支持 Jellyfin Plex 弹弹play。
  8. // @description:zh-CN 需要 Python。若用 PotPlayer mpv MPC VLC 播放,可回传播放进度。支持 Jellyfin Plex 弹弹play。
  9. // @description:en Require Python. If you use PotPlayer mpv MPC VLC , will update watch history to emby server. Support Jellyfin Plex 弹弹play.
  10. // @author Kjtsune
  11. // @match *://*/web/index.html*
  12. // @icon https://www.google.com/s2/favicons?sz=64&domain=emby.media
  13. // @grant unsafeWindow
  14. // @grant GM_xmlhttpRequest
  15. // @grant GM_registerMenuCommand
  16. // @grant GM_unregisterMenuCommand
  17. // @run-at document-start
  18. // @license MIT
  19. // ==/UserScript==
  20. 'use strict';
  21. /*
  22. 更新的同时要去 github 下载文件,方法详见介绍里的 [更新] 部分
  23.  
  24. 2022-09-27:
  25. 1. 增加 弹弹play 支持。(动漫弹幕播放器)
  26. 2. 增加 网络模式 与 读盘模式 混合功能。
  27.  
  28. 2022-09-24:
  29. 1. 增加 Plex 支持。
  30. 2. _debug.ahk 可创建开机启动项
  31.  
  32. 2022-09-21:
  33. 1. 增加 PotPlayer 回传进度支持。
  34. 2. 增加 VLC 回传进度支持。
  35. 3. 修复首次启动时系统编码判断问题。
  36. 4. 修复 `.ini` 被记事本修改后可能编码错误
  37.  
  38. 2022-09-19:
  39. 1. 增加 Jellyfin 支持。
  40.  
  41. 2022-09-07:
  42. 1. 增加 mpc-hc mpc-be 回传进度支持。
  43. 2. 修复 mpv 窗口激活置顶可能失败,无需配置 `ontop = yes`。
  44. 3. 修复 mpc 未在前台启动,自动全屏。
  45.  
  46. 2022-09-05:
  47. 1. 修复 .vbs .ahk 文件内路径含空格问题。
  48. 2. 首次启动会自动关闭之前的进程,方便调试,减少错误。
  49. 3. 挂载盘可设优先级(一般用不到)
  50. 4. 更新 portable_config 修复一些注释有误的。
  51. */
  52.  
  53. function switchLocalStorage(key, defaultValue = 'true', trueValue = 'true', falseValue = 'false') {
  54. if (key in localStorage) {
  55. let value = (localStorage.getItem(key) === trueValue) ? falseValue : trueValue;
  56. localStorage.setItem(key, value);
  57. } else {
  58. localStorage.setItem(key, defaultValue)
  59. }
  60. console.log('switchLocalStorage ', key, ' to ', localStorage.getItem(key))
  61. }
  62.  
  63. function setModeSwitchMenu(storageKey, menuStart = '', menuEnd = '', defaultValue = '关闭', trueValue = '开启', falseValue = '关闭') {
  64. let switchNameMap = { 'true': trueValue, 'false': falseValue, null: defaultValue };
  65. let menuId = GM_registerMenuCommand(menuStart + switchNameMap[localStorage.getItem(storageKey)] + menuEnd, clickMenu);
  66.  
  67. function clickMenu() {
  68. GM_unregisterMenuCommand(menuId);
  69. switchLocalStorage(storageKey)
  70. menuId = GM_registerMenuCommand(menuStart + switchNameMap[localStorage.getItem(storageKey)] + menuEnd, clickMenu);
  71. }
  72.  
  73. }
  74.  
  75. const originFetch = fetch;
  76. unsafeWindow.fetch = async (url, request) => {
  77. // console.log('%c%o%s', 'background:yellow;', url, ' MYLOG')
  78. if (url.indexOf('/PlaybackInfo?UserId') > -1 && url.indexOf('IsPlayback=true') > -1
  79. && localStorage.getItem('webPlayerEnable') != 'true') {
  80. let response = await originFetch(url, request);
  81. let data = await response.clone().json()
  82. embyToLocalPlayer(url, request, data);
  83. } else {
  84. // console.log('%c%o%s', "color:orange;", 'url ', url)
  85. return originFetch(url, request);
  86. }
  87. }
  88.  
  89. async function getItemInfo(playbackUrl, request) {
  90. let response = await fetch(playbackUrl, request);
  91. if (response.ok) {
  92. return await response.json();
  93. } else {
  94. throw new Error(response.statusText);
  95. }
  96. }
  97.  
  98. async function embyToLocalPlayer(playbackUrl, request, response) {
  99. let data = {
  100. playbackData: response,
  101. playbackUrl: playbackUrl,
  102. request: request,
  103. mountDiskEnable: localStorage.getItem('mountDiskEnable'),
  104.  
  105. };
  106. sendDataToLocalServer(data, 'embyToLocalPlayer');
  107. }
  108.  
  109. function sendDataToLocalServer(data, path) {
  110. let url = `http://127.0.0.1:58000/${path}/`
  111. GM_xmlhttpRequest({
  112. method: "POST",
  113. url: url,
  114. data: JSON.stringify(data),
  115. headers: {
  116. "Content-Type": "application/json"
  117. },
  118. });
  119. }
  120.  
  121. function initXMLHttpRequest() {
  122. let open = XMLHttpRequest.prototype.open;
  123. XMLHttpRequest.prototype.open = function (...args) {
  124. // 正常请求不匹配的网址
  125. // console.log(args, "---all_args");
  126. let url = args[1]
  127. if (url.indexOf('playQueues?type=video') == -1 ) {
  128. return open.apply(this, args);
  129. }
  130. // 请求前拦截
  131. if (url.indexOf('playQueues?type=video') != -1
  132. && localStorage.getItem('webPlayerEnable') != 'true') {
  133. // console.log(args, "-----args");
  134. fetch(url, {
  135. method: args[0],
  136. headers: {
  137. 'Accept': 'application/json',
  138. }
  139. })
  140. .then(response => response.json())
  141. .then((res) => {
  142. let data = {
  143. playbackData: res,
  144. playbackUrl: url,
  145. mountDiskEnable: localStorage.getItem('mountDiskEnable'),
  146. };
  147. sendDataToLocalServer(data, 'plexToLocalPlayer');
  148. // console.log(data, "-----data")
  149. });
  150. return ;
  151. }
  152. return open.apply(this, args);
  153. }
  154. }
  155.  
  156. // 初始化请求并拦截 plex
  157. initXMLHttpRequest()
  158.  
  159. setModeSwitchMenu('webPlayerEnable', '网页播放模式已经 ')
  160. setModeSwitchMenu('mountDiskEnable', '读取硬盘模式已经 ')