Facebook - Video Resume

When playing a Facebook video, this script stores the current time (minus ten seconds) so that when the page is refreshed (be-it after reopening the browser or manual refresh) or after it gets reset due to bad internet connection, the video resumes from where it stopped.

目前為 2021-05-02 提交的版本,檢視 最新版本

// ==UserScript==
// @description     When playing a Facebook video, this script stores the current time (minus ten seconds) so that when the page is refreshed (be-it after reopening the browser or manual refresh) or after it gets reset due to bad internet connection, the video resumes from where it stopped.
// @name            Facebook - Video Resume
// @namespace       https://www.facebook.com
// @include         https://www.facebook.com/*
// @version         2
// @grant    				GM.getValue
// @grant    				GM.setValue
// @grant    				GM.notification
// @run-at document-idle
// ==/UserScript==

const {max, floor} = Math;

const interval = 2e3;
var intervalId;
const rewind = 10;

window.eval(`const _wr = (type) => {
    const orig = history[type];
    return function() {
        const rv = orig.apply(this, arguments);
        const e = new Event(type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return rv;
    };
};
history.pushState = _wr('pushState'), history.replaceState = _wr('replaceState');
`);

String.prototype.firstMatch = function(regexp) {
  const match = this.match(regexp);
  return match && match[1];
}

const isVideoPath = (location) => /\/.*\/videos(\/.*)?\/\d+/.test(location.pathname) || /v=\d+/.test(location.search);
var location = window.location;

const getVideoId = () => location.pathname.firstMatch(/\/.*\/videos(?:\/.*)?\/(\d+)/) || location.search.firstMatch(/v=(\d+)/);
const getTimeKey = () => `${getVideoId()}fb-video`;
const setTime = (time) => GM.setValue(getTimeKey(), time);
const getTime = () => GM.getValue(getTimeKey());


const initialize = (video) => {
  console.log(video);
  console.log(getTimeKey());
  if (video) {
    getTime().then(time => {
      video.currentTime = time;
    });


    intervalId = setInterval(() => {
      const time = max(0, floor(video.currentTime) - rewind);
      //console.log(time);
      setTime(time);
    }, interval);



    video.addEventListener('error', (e) => {
      clearInterval(intervalId);
      setTimeout(() => initialize(), 1e3);
    });

    video.addEventListener('ended', (e) => {
      setTime(0);
    });
  }
}

if (isVideoPath(location)) {
	initialize(document.querySelector('video'));
}

const pathChanged = (e) => {
  location = window.location;
  clearInterval(intervalId);
}

new MutationObserver(ms => ms.forEach(m => Array.from(m.addedNodes).filter(n => n.querySelector).forEach(n => {
  const video = n.querySelector('video');
  //console.log(m, video);
  //if (video) console.log(n);
  const isCorrectVideoParent = n.classList[0] == '__fb-light-mode' ||
      n.nextSibling && n.nextSibling.matches && n.nextSibling.matches('[data-instancekey]') ||
      n.parentNode && n.parentNode.id == 'permalink_video_pagelet' ||
      n.previousSibling && n.previousSibling.matches && n.previousSibling.matches('span');
  if (isVideoPath(location) && video && isCorrectVideoParent) {
    console.log(n, video);
    clearInterval(intervalId);
		initialize(video);
  }
}))).observe(document.body, {childList: true, subtree: true});

window.addEventListener('pushState', pathChanged);
window.addEventListener('replaceState', pathChanged);
window.addEventListener('popstate', pathChanged);

window.addEventListener('beforeunload', (e) => clearInterval(intervalId));

QingJ © 2025

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