Odysee Auto-Liker

Automatically likes Odysee videos

  1. // ==UserScript==
  2. // @name Odysee Auto-Liker
  3. // @namespace https://github.com/Kite8409/odysee-auto-liker
  4. // @version 1.0.4
  5. // @description Automatically likes Odysee videos
  6. // @author Kite8409 (fork from https://github.com/HatScripts/youtube-auto-liker)
  7. // @license MIT
  8. // @icon https://raw.githubusercontent.com/Kite8409/odysee-auto-liker/master/logo.svg
  9. // @match http*://odysee.com/*
  10. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @grant GM_registerMenuCommand
  14. // @run-at document-idle
  15. // @noframes
  16. // @supportURL https://github.com/Kite8409/odysee-auto-liker/issues/
  17. // ==/UserScript==
  18.  
  19. /* global GM_config, GM_info, GM_registerMenuCommand */
  20.  
  21. (() => {
  22. 'use strict'
  23.  
  24. GM_config.init({
  25. id: 'ytal_config',
  26. title: GM_info.script.name + ' Settings',
  27. fields: {
  28. DEBUG_MODE: {
  29. label: 'Debug mode',
  30. type: 'checkbox',
  31. default: false,
  32. title: 'Log debug messages to the console'
  33. },
  34. CHECK_FREQUENCY: {
  35. label: 'Check frequency (ms)',
  36. type: 'number',
  37. min: 1,
  38. default: 5000,
  39. title: 'The number of milliseconds to wait between checking if video should be liked'
  40. },
  41. WATCH_THRESHOLD: {
  42. label: 'Watch threshold %',
  43. type: 'number',
  44. min: 0,
  45. max: 100,
  46. default: 50,
  47. title: 'The percentage watched to like the video at'
  48. },
  49. LIKE_IF_NOT_SUBSCRIBED: {
  50. label: 'Like if not following',
  51. type: 'checkbox',
  52. default: true,
  53. title: 'Like videos from channels you are not following'
  54. }
  55. }
  56. })
  57.  
  58. GM_registerMenuCommand('Settings', () => {
  59. GM_config.open()
  60. })
  61.  
  62. function Debugger (name, enabled) {
  63. this.debug = {}
  64. if (!window.console) {
  65. return () => {}
  66. }
  67. for (const m in console) {
  68. if (typeof console[m] === 'function') {
  69. if (enabled) {
  70. this.debug[m] = console[m].bind(window.console, name + ': ')
  71. } else {
  72. this.debug[m] = () => {}
  73. }
  74. }
  75. }
  76. return this.debug
  77. }
  78.  
  79. const DEBUG = new Debugger(GM_info.script.name, GM_config.get('DEBUG_MODE'))
  80. // Define CSS selectors
  81. const SELECTORS = {
  82. PLAYER: 'video',
  83. FIRE_BUTTON: 'button.button-like:nth-child(1)',
  84. FIRE_BUTTON_CLICKED_CLASS: 'button--fire',
  85. FOLLOW_BUTTON: '.button-group > button:nth-child(1)',
  86. FOLLOW_BUTTON_CLICKED_CLASS: 'button-following',
  87. }
  88.  
  89. const autoLikedVideoIds = []
  90.  
  91. setTimeout(wait, GM_config.get('CHECK_FREQUENCY'))
  92.  
  93. function getVideoId () {
  94. return location.pathname
  95. }
  96.  
  97. function watchThresholdReached () {
  98. const player = document.querySelector(SELECTORS.PLAYER)
  99. if (!player || player.clientHeight <= 288) { // Check if player is not a mini player
  100. return false
  101. }
  102. return player.currentTime / player.duration >= (GM_config.get('WATCH_THRESHOLD') / 100)
  103. }
  104.  
  105. function isSubscribed () {
  106. return document.querySelector(SELECTORS.FOLLOW_BUTTON).classList.contains(SELECTORS.FOLLOW_BUTTON_CLICKED_CLASS)
  107. }
  108.  
  109. function isLiked(likeButton) {
  110. return likeButton.classList.contains(SELECTORS.FIRE_BUTTON_CLICKED_CLASS)
  111. }
  112.  
  113. function wait () {
  114. if (!watchThresholdReached()) {
  115. setTimeout(wait, GM_config.get('CHECK_FREQUENCY'))
  116. return
  117. }
  118.  
  119. try {
  120. if (GM_config.get('LIKE_IF_NOT_SUBSCRIBED') || isSubscribed()) {
  121. like()
  122. }
  123. } catch (e) {
  124. DEBUG.info(`Failed to like video: ${e}. Will try again in ${GM_config.get('CHECK_FREQUENCY')} ms...`)
  125. }
  126.  
  127. setTimeout(wait, GM_config.get('CHECK_FREQUENCY'))
  128. }
  129.  
  130. function like () {
  131. DEBUG.info('Trying to like video...')
  132.  
  133. const likeButton = document.querySelector(SELECTORS.FIRE_BUTTON)
  134. if (!likeButton) {
  135. throw Error('Couldn\'t find like button')
  136. }
  137.  
  138. const videoId = getVideoId()
  139.  
  140. if (isLiked(likeButton)) {
  141. DEBUG.info('Like button has already been clicked')
  142. autoLikedVideoIds.push(videoId)
  143. }
  144. else if (autoLikedVideoIds.includes(videoId)) {
  145. DEBUG.info('Video has already been auto-liked. User must have un-liked it, so we won\'t like it again')
  146. }
  147. else {
  148. DEBUG.info('Found like button')
  149. DEBUG.info('It\'s unclicked. Clicking it...')
  150. likeButton.click()
  151. autoLikedVideoIds.push(videoId)
  152. DEBUG.info('Successfully liked video')
  153. }
  154. }
  155. })()

QingJ © 2025

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