Odysee Auto-Liker

Automatically likes Odysee videos

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name           Odysee Auto-Liker
// @namespace      https://github.com/Kite8409/odysee-auto-liker
// @version        1.0.4
// @description    Automatically likes Odysee videos
// @author         Kite8409 (fork from https://github.com/HatScripts/youtube-auto-liker)
// @license        MIT
// @icon           https://raw.githubusercontent.com/Kite8409/odysee-auto-liker/master/logo.svg
// @match          http*://odysee.com/*
// @require        https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_registerMenuCommand
// @run-at         document-idle
// @noframes
// @supportURL     https://github.com/Kite8409/odysee-auto-liker/issues/
// ==/UserScript==

/* global GM_config, GM_info, GM_registerMenuCommand */

(() => {
  'use strict'

  GM_config.init({
    id: 'ytal_config',
    title: GM_info.script.name + ' Settings',
    fields: {
      DEBUG_MODE: {
        label: 'Debug mode',
        type: 'checkbox',
        default: false,
        title: 'Log debug messages to the console'
      },
      CHECK_FREQUENCY: {
        label: 'Check frequency (ms)',
        type: 'number',
        min: 1,
        default: 5000,
        title: 'The number of milliseconds to wait between checking if video should be liked'
      },
      WATCH_THRESHOLD: {
        label: 'Watch threshold %',
        type: 'number',
        min: 0,
        max: 100,
        default: 50,
        title: 'The percentage watched to like the video at'
      },
      LIKE_IF_NOT_SUBSCRIBED: {
        label: 'Like if not following',
        type: 'checkbox',
        default: true,
        title: 'Like videos from channels you are not following'
      }
    }
  })

  GM_registerMenuCommand('Settings', () => {
    GM_config.open()
  })

  function Debugger (name, enabled) {
    this.debug = {}
    if (!window.console) {
      return () => {}
    }
    for (const m in console) {
      if (typeof console[m] === 'function') {
        if (enabled) {
          this.debug[m] = console[m].bind(window.console, name + ': ')
        } else {
          this.debug[m] = () => {}
        }
      }
    }
    return this.debug
  }

  const DEBUG = new Debugger(GM_info.script.name, GM_config.get('DEBUG_MODE'))
  // Define CSS selectors
  const SELECTORS = {
    PLAYER: 'video',
    FIRE_BUTTON: 'button.button-like:nth-child(1)',
    FIRE_BUTTON_CLICKED_CLASS: 'button--fire',
    FOLLOW_BUTTON: '.button-group > button:nth-child(1)',
    FOLLOW_BUTTON_CLICKED_CLASS: 'button-following',
  }

  const autoLikedVideoIds = []

  setTimeout(wait, GM_config.get('CHECK_FREQUENCY'))

  function getVideoId () {
    return location.pathname
  }

  function watchThresholdReached () {
    const player = document.querySelector(SELECTORS.PLAYER)
    if (!player || player.clientHeight <= 288) { // Check if player is not a mini player
      return false
    }
    return player.currentTime / player.duration >= (GM_config.get('WATCH_THRESHOLD') / 100)
  }

  function isSubscribed () {
    return document.querySelector(SELECTORS.FOLLOW_BUTTON).classList.contains(SELECTORS.FOLLOW_BUTTON_CLICKED_CLASS)
  }

  function isLiked(likeButton) {
    return likeButton.classList.contains(SELECTORS.FIRE_BUTTON_CLICKED_CLASS)
  }

  function wait () {
    if (!watchThresholdReached()) {
      setTimeout(wait, GM_config.get('CHECK_FREQUENCY'))
      return
    }

    try {
      if (GM_config.get('LIKE_IF_NOT_SUBSCRIBED') || isSubscribed()) {
        like()
      }
    } catch (e) {
      DEBUG.info(`Failed to like video: ${e}. Will try again in ${GM_config.get('CHECK_FREQUENCY')} ms...`)
    }

    setTimeout(wait, GM_config.get('CHECK_FREQUENCY'))
  }

  function like () {
    DEBUG.info('Trying to like video...')

    const likeButton =  document.querySelector(SELECTORS.FIRE_BUTTON)
    if (!likeButton) {
      throw Error('Couldn\'t find like button')
    }

    const videoId = getVideoId()

    if (isLiked(likeButton)) {
      DEBUG.info('Like button has already been clicked')
      autoLikedVideoIds.push(videoId)
    }
    else if (autoLikedVideoIds.includes(videoId)) {
      DEBUG.info('Video has already been auto-liked. User must have un-liked it, so we won\'t like it again')
    }
    else {
      DEBUG.info('Found like button')
      DEBUG.info('It\'s unclicked. Clicking it...')
      likeButton.click()
      autoLikedVideoIds.push(videoId)
      DEBUG.info('Successfully liked video')
    }
  }
})()