使用 mpv 播放

通过 mpv 和 youtube-dl 播放网页上的视频和歌曲

当前为 2020-12-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Play with mpv
  3. // @name:en-US Play with mpv
  4. // @name:zh-CN 使用 mpv 播放
  5. // @name:zh-TW 使用 mpv 播放
  6. // @description Play website videos and songs with mpv & youtube-dl
  7. // @description:en-US Play website videos and songs with mpv & youtube-dl
  8. // @description:zh-CN 通过 mpv 和 youtube-dl 播放网页上的视频和歌曲
  9. // @description:zh-TW 通過 mpv 和 youtube-dl 播放網頁上的視頻和歌曲
  10. // @namespace play-with-mpv-handler
  11. // @version 2020.12.27.2
  12. // @author Akatsuki Rui
  13. // @license MIT License
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @grant GM_notification
  17. // @grant GM_openInTab
  18. // @run-at document-idle
  19. // @noframes
  20. // @match *://www.youtube.com/*
  21. // @match *://www.bilibili.com/video/*
  22. // ==/UserScript==
  23.  
  24. "use strict";
  25.  
  26. const MPV_HANDLER_VERSION = "v0.1.1";
  27. const MPV_ICON =
  28. "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCIgdmVyc2lvbj0iMSI+CiA8Y2lyY2xlIHN0eWxlPSJvcGFjaXR5Oi4yIiBjeD0iMzIiIGN5PSIzMyIgcj0iMjgiLz4KIDxjaXJjbGUgc3R5bGU9ImZpbGw6IzhkMzQ4ZSIgY3g9IjMyIiBjeT0iMzIiIHI9IjI4Ii8+CiA8Y2lyY2xlIHN0eWxlPSJvcGFjaXR5Oi4zIiBjeD0iMzQuNSIgY3k9IjI5LjUiIHI9IjIwLjUiLz4KIDxjaXJjbGUgc3R5bGU9Im9wYWNpdHk6LjIiIGN4PSIzMiIgY3k9IjMzIiByPSIxNCIvPgogPGNpcmNsZSBzdHlsZT0iZmlsbDojZmZmZmZmIiBjeD0iMzIiIGN5PSIzMiIgcj0iMTQiLz4KIDxwYXRoIHN0eWxlPSJmaWxsOiM2OTFmNjkiIHRyYW5zZm9ybT0ibWF0cml4KDEuNTE1NTQ0NSwwLDAsMS41LC0zLjY1Mzg3OSwtNC45ODczODQ4KSIgZD0ibTI3LjE1NDUxNyAyNC42NTgyNTctMy40NjQxMDEgMi0zLjQ2NDEwMiAxLjk5OTk5OXYtNC0zLjk5OTk5OWwzLjQ2NDEwMiAyeiIvPgogPHBhdGggc3R5bGU9ImZpbGw6I2ZmZmZmZjtvcGFjaXR5Oi4xIiBkPSJNIDMyIDQgQSAyOCAyOCAwIDAgMCA0IDMyIEEgMjggMjggMCAwIDAgNC4wMjE0ODQ0IDMyLjU4NTkzOCBBIDI4IDI4IDAgMCAxIDMyIDUgQSAyOCAyOCAwIDAgMSA1OS45Nzg1MTYgMzIuNDE0MDYyIEEgMjggMjggMCAwIDAgNjAgMzIgQSAyOCAyOCAwIDAgMCAzMiA0IHoiLz4KPC9zdmc+Cgo=";
  29. const MATCH_URLS = ["www.youtube.com/watch", "www.bilibili.com/video/"];
  30.  
  31. function notifyHandlerUpdate() {
  32. const NOTIFICATION = {
  33. title: "Play with mpv",
  34. text: `mpv-handler is upgraded to ${MPV_HANDLER_VERSION}
  35.  
  36. Click to check updates`,
  37. onclick: () => {
  38. GM_openInTab("https://github.com/akiirui/mpv-handler/releases/latest");
  39. GM_setValue("mpvHandlerVersion", MPV_HANDLER_VERSION);
  40. },
  41. };
  42.  
  43. let version = GM_getValue("mpvHandlerVersion", null);
  44. if (version !== MPV_HANDLER_VERSION) {
  45. GM_notification(NOTIFICATION);
  46. }
  47. }
  48.  
  49. function appendButton() {
  50. let head = document.getElementsByTagName("head")[0];
  51. let body = document.getElementsByTagName("body")[0];
  52. let style = document.createElement("style");
  53. let buttonIframe = document.createElement("iframe");
  54. let button = document.createElement("a");
  55.  
  56. if (head) {
  57. style.innerHTML = `.play-with-mpv {
  58. position: fixed;
  59. left: 12px;
  60. bottom: 12px;
  61. width: 48px;
  62. height: 48px;
  63. border: 0;
  64. border-radius: 50%;
  65. background-size: 100%;
  66. background-image: url(${MPV_ICON});
  67. background-repeat: no-repeat;
  68. }`;
  69. head.appendChild(style);
  70. }
  71.  
  72. if (body) {
  73. buttonIframe.name = "play-with-mpv";
  74. buttonIframe.style = "display: none";
  75. body.appendChild(buttonIframe);
  76.  
  77. button.className = "play-with-mpv";
  78. button.style = "display: none";
  79. button.target = "play-with-mpv";
  80. button.addEventListener("click", () => {
  81. let videoElement = document.getElementsByTagName("video")[0];
  82. if (videoElement) videoElement.pause();
  83. });
  84. body.appendChild(button);
  85.  
  86. updateButton(location.href);
  87. }
  88. }
  89.  
  90. function updateButton(currentUrl) {
  91. let isMatch = false;
  92. let button = document.getElementsByClassName("play-with-mpv")[0];
  93.  
  94. for (const element of MATCH_URLS) {
  95. if ((isMatch = currentUrl.includes(element))) break;
  96. }
  97.  
  98. if (button) {
  99. button.style = isMatch ? "display: inline-block" : "display: none";
  100. button.href = isMatch ? "mpv://" + btoa(currentUrl) : "";
  101. }
  102. }
  103.  
  104. function detectPJAX() {
  105. let previousUrl = null;
  106.  
  107. setInterval(() => {
  108. let currentUrl = location.href;
  109.  
  110. if (currentUrl && previousUrl !== currentUrl) {
  111. updateButton(currentUrl);
  112. previousUrl = currentUrl;
  113. }
  114. }, 500);
  115. }
  116.  
  117. notifyHandlerUpdate();
  118. appendButton();
  119. detectPJAX();