youtube HTML5 Auto Loop

youtube再生時に自動ループする

2023-04-29 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name           youtube HTML5 Auto Loop
// @namespace      youtube HTML5 Auto Loop
// @grant          none
// @description    youtube再生時に自動ループする
// @author         TNB
// @match          https://www.youtube.com/*
// @version        1.5.3
// @run-at         document-start
// ==/UserScript==


/********************  SETTING **************************/
const loop_off = {
  when_enable_next_video_autoplay: false,
  when_playlist: false,
  with_embedded_video: false
};
/********************************************************/

'use strict';

const YoutubeHTML5AutoLoop = {
  loop: true,
  playercontainer: null,
  video: null,
  prevSrc: null,
  button: null,
  eventcache: {},
  cancelInit: false,
  ele: {
    when_enable_next_video_autoplay: '.ytp-right-controls > button[style]:not([style *= "display: none"]) .ytp-autonav-toggle-button[aria-checked="true"]',
    when_playlist: '#secondary-inner > #playlist:not([hidden])',
    with_embedded_video: 'html[data-cast-api-enabled="true"]'
  },
  init: function() {
    this.addListener();
  },
  isLoop: function() {
    return !Object.keys(loop_off).some(a => loop_off[a] && document.querySelector(this.ele[a]));
  },
  goLoop: function() {
    this.video.currentTime = 0;
    this.video.play;
  },
  enableLoop: function() {
    if (this.loop) this.video.setAttribute('loop', this.loop);
    else this.video.removeAttribute('loop');
  },
  initLoop: function() {
    this.loop = this.isLoop();
    this.enableLoop();
  },
  loopToggle: function() {
    this.loop = !this.loop;
    this.enableLoop();
  },
  displayLoopStatus: function() {
    const video = document.querySelector('video:hover');
    if (!video) return;
    const checkBox = document.querySelector('.ytp-contextmenu [aria-checked]');
    checkBox.setAttribute('aria-checked', this.loop);
    if (!this.eventcache.checkBox) {
      checkBox.addEventListener('click', this, true);
      this.eventcache.checkBox = true;
    }
  },
  isEnded: function(m) {
    return m.classList.contains('ended-mode') || m.querySelector('.ytp-autonav-endscreen-button-container:not([style*="display"]),.html5-endscreen:not([style*="display"])');
  },
  toggleNextVideoAutoplay: function() {
    if ((!loop_off.when_enable_next_video_autoplay && this.loop) || loop_off.when_enable_next_video_autoplay) {
      setTimeout(() => {
          if (document.querySelector(`.ytp-right-controls > button[style]:not([style *= "display: none"]) .ytp-autonav-toggle-button[aria-checked="${this.loop}"]`)) this.button.click();
      }, 1000);
    }
  },
  observeVideo: function() {
    const mo = new MutationObserver(() => {
      if (this.video.src != this.prevSrc) this.cancelInit = false;
      if (!this.cancelInit) this.initLoop();
      if (this.loop && this.isEnded(this.playercontainer)) this.goLoop();
      if (!this.eventcache.toggleAutoPlay) this.addToggleEvent();
      this.toggleNextVideoAutoplay();
      this.prevSrc = this.video.src;
      this.video = this.playercontainer.querySelector('video');
    });
    mo.observe(this.playercontainer, {attributes: true, attributeFilter: ['class']});
  },
  findPlayercontainer: function() {
    if (window != window.parent && document.getElementById('chat')) return;
    const mm = new MutationObserver(() => {
      this.playercontainer = document.getElementById('movie_player');
      if (!this.playercontainer) return;
      this.video = this.playercontainer.querySelector('video');
      this.observeVideo();
      this.initLoop();
      this.addToggleEvent();
      this.toggleNextVideoAutoplay();
      mm.disconnect();
    });
    mm.observe(document.body, {childList: true, subtree: true});
  },
  addToggleEvent: function() {
    this.button = document.querySelector('.ytp-right-controls > button[style]:not([style *= "display: none"]) .ytp-autonav-toggle-button');
    if (!loop_off.when_enable_next_video_autoplay || !this.button) return;
    this.button.addEventListener('click', () => {
      this.loop = JSON.parse(this.button.getAttribute('aria-checked'));
      this.enableLoop();
      this.cancelInit = true;
      this.eventcache.toggleAutoPlay = true;
    });
  },
  addListener: function() {
    window.addEventListener('DOMContentLoaded', this);
    window.addEventListener('contextmenu', this);
  },
  handleEvent: function(e) {
    switch (e.type) {
      case 'DOMContentLoaded':
        this.findPlayercontainer();
        break;
      case 'contextmenu':
        this.displayLoopStatus();
        break;
      case 'click':
        this.loopToggle();
        document.body.click();
        this.toggleNextVideoAutoplay();
        this.cancelInit = true;
        e.stopPropagation();
        break;
    }
  }
};

YoutubeHTML5AutoLoop.init();