🏠 Home 

YouTube Auto-Liker

Automatically likes videos of channels you're subscribed to


Installer dette script?
Skaberens foreslåede script

Du vil måske også kunne lide Google Translate: Filter & Flags


Installer dette script
  1. // ==UserScript==
  2. // @name YouTube Auto-Liker
  3. // @name:zh YouTube自動點讚
  4. // @name:ja YouTubeのような自動
  5. // @namespace https://github.com/HatScripts/youtube-auto-liker
  6. // @version 1.3.25
  7. // @description Automatically likes videos of channels you're subscribed to
  8. // @description:zh 對您訂閲的頻道視頻自動點讚
  9. // @description:ja 購読しているチャンネルの動画が自動的に好きです
  10. // @description:ru Автоматически нравится видео каналов, на которые вы подписаны
  11. // @description:es Le gustan automáticamente los videos de los canales a los que está suscrito
  12. // @description:pt Gosta automaticamente de vídeos de canais nos quais você está inscrito
  13. // @author HatScripts
  14. // @license MIT
  15. // @icon https://raw.githubusercontent.com/HatScripts/youtube-auto-liker/master/logo.svg
  16. // @downloadurl https://github.com/HatScripts/youtube-auto-liker/raw/master/youtube-auto-liker.user.js
  17. // @updateurl https://github.com/HatScripts/youtube-auto-liker/raw/master/youtube-auto-liker.user.js
  18. // @match http://*.youtube.com/*
  19. // @match https://*.youtube.com/*
  20. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  21. // @grant GM_getValue
  22. // @grant GM_setValue
  23. // @grant GM_registerMenuCommand
  24. // @run-at document-idle
  25. // @noframes
  26. // ==/UserScript==
  27. /* global GM_config, GM_info, GM_registerMenuCommand */
  28. (() => {
  29. 'use strict'
  30. GM_config.init({
  31. id: 'ytal_config',
  32. title: GM_info.script.name + ' Settings',
  33. fields: {
  34. DEBUG_MODE: {
  35. label: 'Debug mode',
  36. type: 'checkbox',
  37. default: false,
  38. title: 'Log debug messages to the console'
  39. },
  40. CHECK_FREQUENCY: {
  41. label: 'Check frequency (ms)',
  42. type: 'number',
  43. min: 1,
  44. default: 5000,
  45. title: 'The number of milliseconds to wait between checking if video should be liked'
  46. },
  47. WATCH_THRESHOLD: {
  48. label: 'Watch threshold %',
  49. type: 'number',
  50. min: 0,
  51. max: 100,
  52. default: 50,
  53. title: 'The percentage watched to like the video at'
  54. },
  55. LIKE_IF_NOT_SUBSCRIBED: {
  56. label: 'Like if not subscribed',
  57. type: 'checkbox',
  58. default: false,
  59. title: 'Like videos from channels you are not subscribed to'
  60. },
  61. AUTO_LIKE_LIVE_STREAMS: {
  62. label: 'Auto-like live streams',
  63. type: 'checkbox',
  64. default: false,
  65. title: 'Automatically like live streams'
  66. }
  67. },
  68. events: {
  69. init: onInit
  70. }
  71. })
  72. GM_registerMenuCommand('Settings', () => {
  73. GM_config.open()
  74. })
  75. class Debugger {
  76. constructor (name, enabled) {
  77. this.debug = {}
  78. if (!window.console) {
  79. return () => { }
  80. }
  81. Object.getOwnPropertyNames(window.console).forEach(key => {
  82. if (typeof window.console[key] === 'function') {
  83. if (enabled) {
  84. this.debug[key] = window.console[key].bind(window.console, name + ': ')
  85. } else {
  86. this.debug[key] = () => { }
  87. }
  88. }
  89. })
  90. return this.debug
  91. }
  92. }
  93. var DEBUG
  94. const SELECTORS = {
  95. PLAYER: '#movie_player',
  96. SUBSCRIBE_BUTTON: '#subscribe-button > ytd-subscribe-button-renderer',
  97. LIKE_BUTTON: '#menu #top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(1), #segmented-like-button button',
  98. DISLIKE_BUTTON: '#menu #top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(2), #segmented-dislike-button button'
  99. }
  100. const autoLikedVideoIds = []
  101. function onInit() {
  102. DEBUG = new Debugger(GM_info.script.name, GM_config.get('DEBUG_MODE'))
  103. setInterval(wait, GM_config.get('CHECK_FREQUENCY'))
  104. }
  105. function getVideoId () {
  106. const elem = document.querySelector('#page-manager > ytd-watch-flexy')
  107. if (elem && elem.hasAttribute('video-id')) {
  108. return elem.getAttribute('video-id')
  109. } else {
  110. return new URLSearchParams(window.location.search).get('v')
  111. }
  112. }
  113. function watchThresholdReached () {
  114. const player = document.querySelector(SELECTORS.PLAYER)
  115. if (player) {
  116. const watched = player.getCurrentTime() / player.getDuration()
  117. const watchedTarget = GM_config.get('WATCH_THRESHOLD') / 100
  118. if (watched < watchedTarget) {
  119. DEBUG.info(`Waiting until watch threshold reached (${watched.toFixed(2)}/${watchedTarget})...`)
  120. return false
  121. }
  122. }
  123. return true
  124. }
  125. function isSubscribed () {
  126. DEBUG.info('Checking whether subscribed...')
  127. const subscribeButton = document.querySelector(SELECTORS.SUBSCRIBE_BUTTON)
  128. if (!subscribeButton) {
  129. throw Error('Couldn\'t find sub button')
  130. }
  131. const subscribed = subscribeButton.hasAttribute('subscribe-button-invisible')
  132. DEBUG.info(subscribed ? 'We are subscribed' : 'We are not subscribed')
  133. return subscribed
  134. }
  135. function wait () {
  136. if (watchThresholdReached()) {
  137. try {
  138. if (GM_config.get('LIKE_IF_NOT_SUBSCRIBED') || isSubscribed()) {
  139. if (GM_config.get('AUTO_LIKE_LIVE_STREAMS') ||
  140. window.getComputedStyle(document.querySelector('.ytp-live-badge')).display === 'none') {
  141. like()
  142. }
  143. }
  144. } catch (e) {
  145. DEBUG.info(`Failed to like video: ${e}. Will try again in ${GM_config.get('CHECK_FREQUENCY')} ms...`)
  146. }
  147. }
  148. }
  149. function isButtonPressed (button) {
  150. return button.classList.contains('style-default-active') ||
  151. button.getAttribute('aria-pressed') === 'true'
  152. }
  153. function like () {
  154. DEBUG.info('Trying to like video...')
  155. const likeButton = document.querySelector(SELECTORS.LIKE_BUTTON)
  156. const dislikeButton = document.querySelector(SELECTORS.DISLIKE_BUTTON)
  157. if (!likeButton) {
  158. throw Error('Couldn\'t find like button')
  159. }
  160. if (!dislikeButton) {
  161. throw Error('Couldn\'t find dislike button')
  162. }
  163. const videoId = getVideoId()
  164. if (isButtonPressed(likeButton)) {
  165. DEBUG.info('Like button has already been clicked')
  166. autoLikedVideoIds.push(videoId)
  167. } else if (isButtonPressed(dislikeButton)) {
  168. DEBUG.info('Dislike button has already been clicked')
  169. } else if (autoLikedVideoIds.includes(videoId)) {
  170. DEBUG.info('Video has already been auto-liked. User must ' +
  171. 'have un-liked it, so we won\'t like it again')
  172. } else {
  173. DEBUG.info('Found like button. It\'s unclicked. Clicking it...')
  174. likeButton.click()
  175. if (isButtonPressed(likeButton)) {
  176. autoLikedVideoIds.push(videoId)
  177. DEBUG.info('Successfully liked video')
  178. } else {
  179. DEBUG.info('Failed to like video')
  180. }
  181. }
  182. }
  183. })()