theYNC.com Underground bypass

Watch theYNC Underground videos without needing an account

目前为 2024-12-31 提交的版本。查看 最新版本

// ==UserScript==
// @name        theYNC.com Underground bypass
// @description Watch theYNC Underground videos without needing an account
// @require     https://cdn.jsdelivr.net/npm/@trim21/[email protected]/dist/gm_fetch.js
// @namespace   Violentmonkey Scripts
// @match       *://*.theync.com/*
// @match       *://theync.com/*
// @match       *://*.theync.net/*
// @match       *://theync.net/*
// @match       *://*.theync.org/*
// @match       *://theync.org/*
// @grant       GM.xmlHttpRequest
// @connect     media.theync.com
// @connect     archive.org
// @grant       GM_addStyle
// @grant       GM_log
// @version     4.4
// @license     MIT
// @author      -
// ==/UserScript==

'use strict'

function waitForElement (selector) {
  return new Promise(resolve => {
    {
      const element = document.querySelector(selector)
      if (element) {
        return resolve(element)
      }
    }

    const observer = new MutationObserver(() => {
      const element = document.querySelector(selector)
      if (element) {
        observer.disconnect()
        resolve(element)
      }
    })

    // If you get 'parameter 1 is not of type 'Node'' error, see https://stackoverflow.com/a/77855838/492336
    observer.observe(document.body, {
      childList: true,
      subtree: true
    })
  })
}

function fetchArchive (address) {
  try {
    const url = new URL('https://archive.org/wayback/available')
    url.searchParams.append('url', address)
    return GM_fetch(url, {
      method: 'GET'
    })
  } catch (e) {
    return Promise.reject()
  }
}

function queryArchive (url) {
  return fetchArchive(url)
    .then(archiveResponse => {
      if (!archiveResponse.ok) {
        if (archiveResponse.status === 429) {
          //Too many requests
          GM_log('Too many request, delaying fetching')
          return new Promise(resolve => {
            setTimeout(resolve, 2000)
          }).then(() => fetchArchive(url))
        }
        console.error(archiveResponse)
        return Promise.reject(archiveResponse)
      }
      return archiveResponse
    })
    .then(archiveResponse => archiveResponse.json())
    .then(({ archived_snapshots }) => {
      if (archived_snapshots.closest) {
        return archived_snapshots.closest.url
      }
      return Promise.reject(archived_snapshots.closest?.url)
    })
}

GM_addStyle(`
.loader {
  border: 0.25em solid #f3f3f3;
  border-top-width: 0.25em;
  border-top-style: solid;
  border-top-color: hsl(0, 0%, 95.3%);
  border-top: 0.25em solid rgb(0, 0, 0);
  border-radius: 50%;
  width: 1em;
  height: 1em;
  animation: spin 2s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.border-gold {
  display: flex !important;
  align-items: center;
  justify-content: center;
  gap: 1em;
}
`)

function isValidURL (address) {
  try {
    const url = new URL(address)
    return GM_fetch(url, { method: 'HEAD' }).then(response => {
      if (response.ok) {
        return address
      }
      return Promise.reject(address)
    })
  } catch (e) {
    return Promise.reject(address)
  }
}

function getTheYNCVideoURL (element) {
  const thumbnailURL = element.querySelector('.image > img').src
  if (!thumbnailURL) return
  for (const [, group_url] of thumbnailURL.matchAll(
    /^https?:\/\/theync\.(?:com|org|net)\/media\/thumbs\/(.*?)\.(?:flv|mpg|wmv|avi|3gp|qt|mp4|mov|m4v|f4v)/gim
  )) {
    if (group_url) {
      return `https://media.theync.com/videos/${group_url}.mp4`
    }
  }
}

function getVideoURLFromArchive (archiveURL) {
  return GM_fetch(archiveURL, {
    method: 'GET'
  })
    .then(response => {
      // When the page is loaded convert it to text
      return response.text()
    })
    .then(html => {
      // Initialize the DOM parser
      const parser = new DOMParser()

      // Parse the text
      const doc = parser.parseFromString(html, 'text/html')

      // You can now even select part of that html as you would in the regular DOM
      // Example:
      // const docArticle = doc.querySelector('article').innerHTML
      const archivedScript = doc.querySelector('[id=thisPlayer] + script')
      if (!archivedScript) {
        return Promise.reject()
      }
      for (const [, videoURL] of archivedScript.textContent.matchAll(
        /thisPlayer\.setup.*?file: "(?:https?\:\/\/web.archive.org\/web\/\d*?\/)?(https?\:\/\/.*?.\.(?:flv|mpg|wmv|avi|3gp|qt|mp4|mov|m4v|f4v))"/gms
      )) {
        if (videoURL) {
          return decodeURIComponent(videoURL)
        }
      }
      return Promise.reject()
    })
}

const allowedExtensions = [
  'flv',
  'mpg',
  'wmv',
  'avi',
  '3gp',
  'qt',
  'mp4',
  'mov',
  'm4v',
  'f4v'
]

waitForElement('.content-block').then(contentBlock => {
  for (const element of contentBlock.querySelectorAll(
    '.inner-block > a:has(> .item-info > .border-gold)'
  )) {
    const undergroundLogo = element.querySelector('.item-info > .border-gold')
    const loadingElement = document.createElement('div')
    loadingElement.classList.add('loader')
    undergroundLogo.appendChild(loadingElement)
    isValidURL(getTheYNCVideoURL(element))
      .then(
        url => {
          undergroundLogo.textContent = 'BYPASSED'
          undergroundLogo.style.backgroundColor = 'green'
          element.href = url
        },
        () =>
          ['com', 'org', 'net']
            .reduce(
              (accumulator, currentTLD) =>
                accumulator.catch(() =>
                  queryArchive(
                    element.href.replace(
                      /(^https?:\/\/theync\.)(com|org|net)(\/.*$)/gim,
                      `$1${currentTLD}$3`
                    )
                  )
                ),
              Promise.reject()
            )
            .then(
              url =>
                getVideoURLFromArchive(url).then(
                  videoURL => {
                    undergroundLogo.textContent = 'ARCHIVED'
                    undergroundLogo.style.backgroundColor = 'blue'
                    element.href = videoURL
                  },
                  () => {
                    undergroundLogo.textContent = 'MAYBE ARCHIVED'
                    undergroundLogo.style.backgroundColor = 'aqua'
                    element.href = url
                  }
                ),
              () => GM_log(`No bypass or archive found for ${element.href}`)
            )
      )

      .finally(() => loadingElement.remove())
  }
})

QingJ © 2025

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