YouTube Shorts URL 转换按钮

将 YouTube Shorts 网址转换为常规的 YouTube 视频网址。

  1. // ==UserScript==
  2. // @name YouTube Shorts URL Conversion Button
  3. // @name:zh-TW YouTube Shorts URL 轉換按鈕
  4. // @name:zh-HK YouTube Shorts URL 轉換按鈕
  5. // @name:ja YouTube Shorts URL コンバーター
  6. // @name:zh-CN YouTube Shorts URL 转换按钮
  7. // @name:ko YouTube Shorts URL 변환 버튼
  8. // @name:ru Кнопка преобразования URL YouTube Shorts
  9. // @name:de YouTube Shorts URL Konvertierungstaste
  10. // @name:es Botón de conversión de URL de YouTube Shorts
  11. // @name:fr Bouton de conversion d'URL YouTube Shorts
  12. // @name:it Pulsante di conversione URL YouTube Shorts
  13. // @name:pt Botão de conversão de URL do YouTube Shorts
  14. // @name:ar زر تحويل URL من YouTube Shorts
  15. // @name:nl YouTube Shorts URL Conversieknop
  16. // @name:tr YouTube Shorts URL Dönüştürme Butonu
  17. // @name:pl Przycisk konwersji URL YouTube Shorts
  18. // @namespace http://tampermonkey.net/
  19. // @version 1.13
  20. // @description Convert YouTube Shorts URL to regular YouTube video URL.
  21. // @description:zh-TW 將 YouTube Shorts 網址轉換為常規的 YouTube 影片網址。
  22. // @description:zh-HK 將 YouTube Shorts 網址轉換為常規的 YouTube 影片網址。
  23. // @description:ja YouTube Shorts URLを通常のYouTubeビデオURLに変換します。
  24. // @description:zh-CN 将 YouTube Shorts 网址转换为常规的 YouTube 视频网址。
  25. // @description:ko YouTube Shorts URL을 일반 YouTube 비디오 URL로 변환합니다.
  26. // @description:ru Преобразование URL YouTube Shorts в обычный URL видео YouTube.
  27. // @description:de Konvertiere YouTube Shorts URL in reguläre YouTube Video URL.
  28. // @description:es Convierte la URL de YouTube Shorts en una URL de video de YouTube normal.
  29. // @description:fr Convertir l'URL YouTube Shorts en URL vidéo YouTube classique.
  30. // @description:it Converti l'URL YouTube Shorts in URL video YouTube normale.
  31. // @description:pt Converte a URL do YouTube Shorts para URL normal do YouTube.
  32. // @description:ar تحويل رابط YouTube Shorts إلى رابط فيديو YouTube عادي.
  33. // @description:nl Converteer YouTube Shorts URL naar reguliere YouTube video URL.
  34. // @description:tr YouTube Shorts URL'sini normal YouTube video URL'sine dönüştür.
  35. // @description:pl Konwertuj URL YouTube Shorts na regularny URL wideo YouTube.
  36. // @author 鮪魚大師
  37. // @match https://www.youtube.com/*
  38. // @grant none
  39. // @license MIT
  40. // ==/UserScript==
  41.  
  42. (function() {
  43. 'use strict';
  44.  
  45. const debug = false;
  46.  
  47. let convertButton;
  48. let resizeButton;
  49. let isButtonDown = false;
  50. let buttonSize = "medium"; // 預設大小 目前只有"medium"跟"small"
  51.  
  52. const lang = document.documentElement.lang || navigator.language;
  53. const langData = [
  54. {
  55. name: "English",
  56. match: ["en", "en-US", "en-GB", "en-CA", "en-AU"],
  57. lang: {
  58. buttonText: "Convert Shorts",
  59. buttonTitle: "Convert Shorts URL to regular video URL",
  60. resizeButtonTitle: "Resize the buttons",
  61. },
  62. },
  63. {
  64. name: "Chinese (Traditional)",
  65. match: ["zh-TW", "zh-HK", "zh-Hant", "zh-Hant-TW"],
  66. lang: {
  67. buttonText: "Shorts轉換",
  68. buttonTitle: "將Shorts網址轉換成一般影片網址",
  69. resizeButtonTitle: "調整按鈕大小",
  70. },
  71. },
  72. {
  73. name: "Japanese",
  74. match: ["ja"],
  75. lang: {
  76. buttonText: "Shorts変換",
  77. buttonTitle: "YouTube Shorts URLを通常のYouTubeビデオURLに変換します",
  78. resizeButtonTitle: "ボタンサイズを変更する",
  79. },
  80. },
  81. {
  82. name: "Chinese (Simplified)",
  83. match: ["zh-CN", "zh-SG", "zh-Hans", "zh-Hans_CN"],
  84. lang: {
  85. buttonText: "Shorts转换",
  86. buttonTitle: "将 YouTube Shorts 网址转换为常规的 YouTube 视频网址",
  87. resizeButtonTitle: "调整按钮大小",
  88. },
  89. },
  90. {
  91. name: "Korean",
  92. match: ["ko"],
  93. lang: {
  94. buttonText: "Shorts변환",
  95. buttonTitle: "YouTube Shorts URL을 일반 YouTube 비디오 URL로 변환합니다",
  96. resizeButtonTitle: "버튼 크기 조정",
  97. },
  98. },
  99. {
  100. name: "Russian",
  101. match: ["ru"],
  102. lang: {
  103. buttonText: "Shorts конвертация",
  104. buttonTitle: "Преобразование URL YouTube Shorts в обычный URL видео YouTube",
  105. resizeButtonTitle: "Изменить размер кнопок",
  106. },
  107. },
  108. {
  109. name: "German",
  110. match: ["de"],
  111. lang: {
  112. buttonText: "Shorts konvertieren",
  113. buttonTitle: "Konvertiere YouTube Shorts URL in reguläre YouTube Video URL",
  114. resizeButtonTitle: "Größe der Schaltflächen ändern",
  115. },
  116. },
  117. {
  118. name: "Spanish",
  119. match: ["es", "es-ES", "es-MX", "es-AR", "es-CO"],
  120. lang: {
  121. buttonText: "Convertir Shorts",
  122. buttonTitle: "Convierte la URL de YouTube Shorts en una URL de video de YouTube normal",
  123. resizeButtonTitle: "Cambiar el tamaño de los botones",
  124. },
  125. },
  126. {
  127. name: "French",
  128. match: ["fr", "fr-FR", "fr-CA", "fr-BE", "fr-CH"],
  129. lang: {
  130. buttonText: "Convertir Shorts",
  131. buttonTitle: "Convertir l'URL YouTube Shorts en URL vidéo YouTube classique",
  132. resizeButtonTitle: "Redimensionner les boutons",
  133. },
  134. },
  135. {
  136. name: "Italian",
  137. match: ["it"],
  138. lang: {
  139. buttonText: "Converti Shorts",
  140. buttonTitle: "Converti l'URL YouTube Shorts in URL video YouTube normale",
  141. resizeButtonTitle: "Ridimensiona i pulsanti",
  142. },
  143. },
  144. {
  145. name: "Portuguese",
  146. match: ["pt", "pt-PT", "pt-BR"],
  147. lang: {
  148. buttonText: "Converter Shorts",
  149. buttonTitle: "Converter a URL do YouTube Shorts para a URL normal do vídeo do YouTube",
  150. resizeButtonTitle: "Alterar o tamanho dos botões",
  151. },
  152. },
  153. {
  154. name: "Arabic",
  155. match: ["ar"],
  156. lang: {
  157. buttonText: "تحويل Shorts",
  158. buttonTitle: "تحويل رابط YouTube Shorts إلى رابط فيديو YouTube عادي",
  159. resizeButtonTitle: "تغيير حجم الأزرار",
  160. },
  161. },
  162. {
  163. name: "Dutch",
  164. match: ["nl", "nl-NL", "nl-BE"],
  165. lang: {
  166. buttonText: "Shorts converteren",
  167. buttonTitle: "Converteer YouTube Shorts URL naar reguliere YouTube video URL",
  168. resizeButtonTitle: "Verander de grootte van de knoppen",
  169. },
  170. },
  171. {
  172. name: "Turkish",
  173. match: ["tr"],
  174. lang: {
  175. buttonText: "Shorts dönüştür",
  176. buttonTitle: "YouTube Shorts URL'sini normal YouTube video URL'sine dönüştür",
  177. resizeButtonTitle: "Düğme boyutunu değiştir",
  178. },
  179. },
  180. {
  181. name: "Polish",
  182. match: ["pl"],
  183. lang: {
  184. buttonText: "Konwertuj Shorts",
  185. buttonTitle: "Konwertuj URL YouTube Shorts na regularny URL wideo YouTube",
  186. resizeButtonTitle: "Zmień rozmiar przycisków",
  187. },
  188. },
  189. {
  190. name: "Hebrew",
  191. match: ["he"],
  192. lang: {
  193. buttonText: "המיר Shorts",
  194. buttonTitle: "המיר את כתובת ה-URL של YouTube Shorts לכתובת URL רגילה של סרטון YouTube",
  195. resizeButtonTitle: "שנה את גודל הכפתורים",
  196. },
  197. },
  198. {
  199. name: "Vietnamese",
  200. match: ["vi"],
  201. lang: {
  202. buttonText: "Chuyển đổi Shorts",
  203. buttonTitle: "Chuyển đổi URL YouTube Shorts thành URL video YouTube thông thường",
  204. resizeButtonTitle: "Thay đổi kích thước các nút",
  205. },
  206. },
  207. ];
  208.  
  209. function debugLog(message) {
  210. if (debug) {
  211. console.log("[DEBUG] " + message);
  212. }
  213. }
  214.  
  215. function getLanguageData() {
  216. if (debug) {
  217. debugLog("偵測到的語言: " + lang);
  218. }
  219. for (const data of langData) {
  220. if (data.match.some(match => lang.startsWith(match))) {
  221. if (debug) {
  222. debugLog(`匹配到語言: ${data.name}`);
  223. }
  224. return data.lang;
  225. }
  226. }
  227.  
  228. if (debug) {
  229. debugLog(`找不到匹配的語言,使用預設語言: ${langData[0].name}`);
  230. }
  231. return langData[0].lang;
  232. }
  233.  
  234. const languageData = getLanguageData();
  235.  
  236. // 根據 'buttonSize' 變數更新按鈕大小
  237. function updateButtonSize() {
  238. if (convertButton) {
  239. convertButton.style.fontSize = buttonSize === "small" ? "14px" : "24px";
  240. convertButton.style.padding = buttonSize === "small" ? "5px 10px" : "10px 20px";
  241. }
  242. }
  243.  
  244. // 建立 Convert Button 和 Resize Button
  245. function createButtons() {
  246. // Convert 按鈕
  247. if (!convertButton) {
  248. debugLog("正在創建 Convert 按鈕...");
  249. convertButton = document.createElement('button');
  250. convertButton.textContent = languageData.buttonText;
  251. convertButton.style.position = 'fixed';
  252. convertButton.style.top = '150px';
  253. convertButton.style.right = '10px';
  254. convertButton.style.zIndex = '9999';
  255. convertButton.style.backgroundColor = '#FF0000';
  256. convertButton.style.color = '#FFFFFF';
  257. convertButton.style.fontSize = '24px';
  258. convertButton.style.padding = '10px 20px';
  259. convertButton.style.border = 'none';
  260. convertButton.style.borderRadius = '5px';
  261. convertButton.title = languageData.buttonTitle;
  262. document.body.appendChild(convertButton);
  263. updateButtonSize();
  264.  
  265. convertButton.addEventListener('click', convertURL);
  266. convertButton.addEventListener('auxclick', convertURL);
  267.  
  268. convertButton.addEventListener('mousedown', function() {
  269. convertButton.style.backgroundColor = '#D80000';
  270. isButtonDown = true;
  271. });
  272.  
  273. convertButton.addEventListener('mouseup', function() {
  274. convertButton.style.backgroundColor = '#FF0000';
  275. isButtonDown = false;
  276. });
  277.  
  278. convertButton.addEventListener('mouseout', function() {
  279. if (!isButtonDown) {
  280. convertButton.style.backgroundColor = '#FF0000';
  281. }
  282. });
  283.  
  284. convertButton.addEventListener('mouseenter', function() {
  285. convertButton.style.backgroundColor = '#FF3333';
  286. });
  287.  
  288. convertButton.addEventListener('mouseleave', function() {
  289. convertButton.style.backgroundColor = '#FF0000';
  290. });
  291.  
  292. debugLog("按鈕創建成功");
  293. }
  294.  
  295. // Resize 按鈕
  296. if (!resizeButton) {
  297. debugLog("正在創建 Resize 按鈕...");
  298. resizeButton = document.createElement('button');
  299. resizeButton.textContent = "◱";
  300. resizeButton.style.position = 'fixed';
  301. resizeButton.style.right = '10px';
  302. resizeButton.style.top = (convertButton.getBoundingClientRect().bottom + 5) + 'px';
  303. resizeButton.style.zIndex = '9999';
  304. resizeButton.style.backgroundColor = '#008CBA';
  305. resizeButton.style.color = '#FFFFFF';
  306. resizeButton.style.fontSize = '18px';
  307. resizeButton.style.width = '25px';
  308. resizeButton.style.height = '25px';
  309. resizeButton.style.display = 'flex';
  310. resizeButton.style.justifyContent = 'center';
  311. resizeButton.style.alignItems = 'center';
  312. resizeButton.style.border = 'none';
  313. resizeButton.style.borderRadius = '5px';
  314. resizeButton.title = languageData.resizeButtonTitle;
  315. document.body.appendChild(resizeButton);
  316.  
  317. resizeButton.addEventListener('click', () => {
  318. buttonSize = buttonSize === "small" ? "medium" : "small";
  319. updateButtonSize();
  320. resizeButton.style.top = (convertButton.getBoundingClientRect().bottom + 5) + 'px';
  321. });
  322.  
  323. resizeButton.addEventListener('mouseenter', function() {
  324. resizeButton.style.backgroundColor = '#00bcd4';
  325. });
  326.  
  327. resizeButton.addEventListener('mouseleave', function() {
  328. resizeButton.style.backgroundColor = '#008CBA';
  329. });
  330. }
  331. }
  332.  
  333. //主要功能
  334. function convertURL(event) {
  335. const currentURL = window.location.href;
  336. debugLog("當前網址: " + currentURL);
  337.  
  338. if (currentURL.includes("youtube.com/shorts/")) {
  339. const match = currentURL.match(/https:\/\/www\.youtube\.com\/shorts\/([A-Za-z0-9_-]+)/);
  340. if (match) {
  341. const videoID = match[1];
  342. const videoURL = `https://www.youtube.com/watch?v=${videoID}`;
  343. debugLog(`匹配到的影片ID: ${videoID}`);
  344. debugLog(`轉換後的網址: ${videoURL}`);
  345.  
  346. if (event && event.button === 2) {
  347. debugLog("檢測到右鍵點擊(未執行任何操作)");
  348. } else if (event && event.button === 1) {
  349. debugLog("檢測到中鍵點擊(開啟新標籤)");
  350. window.open(videoURL, '_blank');
  351. } else {
  352. debugLog("正在導航至轉換後的網址");
  353. window.location.href = videoURL;
  354. }
  355. } else {
  356. debugLog("網址中沒有匹配到影片ID");
  357. }
  358. } else {
  359. debugLog("不是 YouTube Shorts 網址");
  360. }
  361. }
  362.  
  363. function removeConvertButton() {
  364. if (convertButton) {
  365. debugLog("正在移除 Convert 按鈕...");
  366. convertButton.remove();
  367. convertButton = null;
  368. debugLog("Convert 按鈕已移除");
  369. }
  370.  
  371. if (resizeButton) {
  372. debugLog("正在移除 Resize 按鈕...");
  373. resizeButton.remove();
  374. resizeButton = null;
  375. debugLog("Resize 按鈕已移除");
  376. }
  377. }
  378.  
  379. function debounce(func, wait) {
  380. let timeout;
  381. return function executedFunction(...args) {
  382. const later = () => {
  383. timeout = null;
  384. func(...args);
  385. };
  386. clearTimeout(timeout);
  387. timeout = setTimeout(later, wait);
  388. };
  389. }
  390.  
  391. const checkAndCreateButton = debounce(function() {
  392. debugLog("檢查是否應該創建/移除按鈕...");
  393. if (window.location.href.includes("youtube.com/shorts/")) {
  394. createButtons();
  395. } else {
  396. removeConvertButton();
  397. }
  398. }, 200); // 防抖200ms
  399.  
  400. window.addEventListener('popstate', checkAndCreateButton);
  401.  
  402. const observer = new MutationObserver(function(mutationsList) {
  403. for (const mutation of mutationsList) {
  404. if (mutation.type === 'childList') {
  405. checkAndCreateButton();
  406. break;
  407. }
  408. }
  409. });
  410.  
  411. observer.observe(document.documentElement, { childList: true, subtree: true });
  412. checkAndCreateButton();
  413.  
  414. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址