Greasy Fork镜像 支持简体中文。

pls.watch

Adds a button on YouTube, Imgur and SoundCloud to open current resource in pls.watch looper

  1. // ==UserScript==
  2. // @name pls.watch
  3. // @description Adds a button on YouTube, Imgur and SoundCloud to open current resource in pls.watch looper
  4. // @version 1.9.2
  5. // @namespace https://pls.watch
  6. // @icon https://ipfs.io/ipfs/QmZFXPq9xMJY3Z8q2fq4wfsU93uTpVfjbiaYzwFmfnkCfM
  7. // @match https://www.youtube.com/*
  8. // @match https://youtube.com/*
  9. // @match http://www.youtube.com/*
  10. // @match http://youtube.com/*
  11. // @match https://imgur.com/*
  12. // @match http://imgur.com/*
  13. // @match http://soundcloud.com/*
  14. // @match https://soundcloud.com/*
  15. // @license CC0; https://creativecommons.org/publicdomain/zero/1.0/
  16. // @homepageURL https://github.com/lidel/pls.watch/#companion-userscript
  17. // @supportURL https://github.com/lidel/pls.watch/issues
  18. // @require https://cdn.jsdelivr.net/jquery/3.2.1/jquery.slim.min.js
  19. // @grant none
  20. // @run-at document-end
  21. // @noframes
  22. // ==/UserScript==
  23. 'use strict';
  24. (function ($, undefined) { // eslint-disable-line no-unused-vars
  25. const youtubeHandler = function () {
  26. const atWatchPage = window.location.pathname.startsWith('/watch');
  27. if (atWatchPage && $('#pls-watch').length === 0) {
  28. const getYtPlayer = function () {
  29. return window.document.getElementById('movie_player');
  30. };
  31. const renderLooperActions = function() {
  32. console.log('renderLooperActions()');
  33. $('#pls-watch').remove();
  34.  
  35. // new layout (https://www.youtube.com/new)
  36. const $secondaryActions = $('#info #top-level-buttons');
  37. const $button = $('<button id="pls-watch" style="cursor:pointer;background:none;border:none;vertical-align:middle;" title="Open in pls.watch"><span style="margin:0 0.1rem;vertical-align: middle;font-size:2em;" class="yt-view-count-renderer"> &#x21BB; </span></button>');
  38. $secondaryActions.append($button);
  39.  
  40. $button.show();
  41. $button.click(function () {
  42. let url = window.location.href;
  43. url = url.replace(/.*youtube.com\/watch\?/, 'https://pls.watch/#');
  44. url = url.replace(/[&#]t=[^&#]*/g, '');
  45. window.open(url);
  46. });
  47. };
  48.  
  49. const initButton = function() {
  50. console.log('initButton()');
  51. renderLooperActions();
  52.  
  53. window.ytLooperStateChanged = function(state) {
  54. console.log('ytLooperStateChanged().state', state);
  55. if (state === 1) {
  56. // youtube redraws div.watch-action-buttons AFTER 5 and -1 events
  57. // and 1 is the only one we have after GUI stabilizes.
  58. // ANGST.
  59. renderLooperActions();
  60. }
  61. };
  62. getYtPlayer().addEventListener('onStateChange', window.ytLooperStateChanged);
  63. };
  64.  
  65. initButton();
  66. }
  67. };
  68. const imgurHandlerRenderButton = function(ids) {
  69. const id = ids[0];
  70. if (/[a-zA-Z0-9]+/.test(id) && ($('div.post-image img').length > 0 || $('div.post-image video').length > 0)) {
  71. console.log('pls.watch → renderButton for ' + ids.join(', '));
  72. const url = 'https://pls.watch/#i=' + ids.join('&i=');
  73. const html = '<a style="pointer:cursor;text-decoration:none;color:#ccc" title="Open in pls.watch"><span style="font-size:1.5em">&#x21BB;</span><br>yt.looper</a>';
  74. const $a = $(html).click(function () {
  75. window.open(url);
  76. });
  77. $('<div class="post-account" id="pls-watch">')
  78. .data('imgurId', id)
  79. .css('margin-left','1em')
  80. .css('float', 'right')
  81. .css('text-align', 'center')
  82. .append($a)
  83. .hide()
  84. .prependTo($('div.post-header'))
  85. .show();
  86.  
  87. }
  88. };
  89. const imgurHandler = function () {
  90. const $oldButton = $('#pls-watch');
  91. const imgurIds = $('div.post-image-container').map(function() { return $(this).attr('id'); }).get();
  92. if (imgurIds.length > 0 && $oldButton.data('imgurId') != imgurIds[0]) {
  93. $oldButton.remove();
  94. imgurHandlerRenderButton(imgurIds);
  95. }
  96. };
  97. const soundCloudHandler = function () {
  98. if ($('#pls-watch').length === 0) {
  99. const $soundActions = $('div.l-about-top div.soundActions');
  100. if ($soundActions.length === 1) {
  101. console.log('soundCloudHandler(): adding pls.watch button..');
  102. const scId = window.location.pathname.replace(/^\//, '');
  103. const url = 'https://pls.watch/#s=' + scId;
  104. const $button = $('<button id="pls-watch" class="sc-button sc-button-medium" title="Open in pls.watch"><span style="font-weight: 900;">&#x21BB;</span>&nbsp;pls.watch</button>');
  105. $button.click(function () {
  106. window.open(url);
  107. });
  108. $('div.sc-button-group', $soundActions).first().append($button);
  109. }
  110. }
  111. };
  112. // since everyone does reactive gui, we just poll to see if elements are present/gone
  113. console.log('pls.watch userscript loaded');
  114. switch (window.location.hostname.replace('www.', '')) {
  115. case 'youtube.com':
  116. window.setInterval(youtubeHandler, 1000);
  117. break;
  118. case 'imgur.com':
  119. window.setInterval(imgurHandler, 1000);
  120. break;
  121. case 'soundcloud.com':
  122. window.setInterval(soundCloudHandler, 1000);
  123. break;
  124. }
  125. }(window.jQuery.noConflict(true)));
  126. // vim:ts=2:sw=2:et:

QingJ © 2025

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