theYNC.com Underground bypass

Watch theYNC Underground videos without needing an account

2025-01-12 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        theYNC.com Underground bypass
// @description Watch theYNC Underground videos without needing an account
// @require     https://cdn.jsdelivr.net/npm/@trim21/[email protected]
// @namespace   Violentmonkey Scripts
// @match       *://*.theync.com/*
// @match       *://theync.com/*
// @match       *://*.theync.net/*
// @match       *://theync.net/*
// @match       *://*.theync.org/*
// @match       *://theync.org/*
// @match       *://archive.ph/*
// @match       *://archive.today/*
// @include     /https?:\/\/web\.archive\.org\/web\/\d+?\/https?:\/\/theync\.(?:com|org|net)/
// @require     https://update.greasyfork.org/scripts/523012/1519437/WaitForKeyElement.js
// @grant       GM.xmlHttpRequest
// @connect     media.theync.com
// @connect     archive.org
// @grant       GM_addStyle
// @grant       GM_log
// @grant       GM_addElement
// @version     7.6
// @supportURL  https://greasyfork.org/en/scripts/520352-theync-com-underground-bypass/feedback
// @license     MIT
// @author      https://greasyfork.org/en/users/1409235-paywalldespiser
// ==/UserScript==

/**
 * Fetches available archives of a given address.
 *
 * @param {string} address
 * @returns {Promise<Response>}
 */
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();
    }
}

/**
 * Fetches available archives of a given address and retrieves their URLs.
 *
 * @param {string} address
 * @returns {Promise<string>}
 */
function queryArchive(address) {
    return fetchArchive(address)
        .then((archiveResponse) => {
            if (!archiveResponse.ok) {
                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);
        })
        .then((url) => {
            // Avoid "Mixed content"
            if (location.protocol === 'https:') {
                return url.replace(/^http:\/\//i, 'https://');
            }
            return url;
        });
}

/**
 * Checks whether a URL is valid and accessible.
 *
 * @param {string} address
 * @returns {Promise<string>}
 */
function isValidURL(address) {
    if (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 {
            return Promise.reject(address);
        }
    }
    return Promise.reject(address);
}

/**
 * Tries to guess the video URL of a given theYNC video via the thumbnail URL.
 * Only works on videos published before around May 2023.
 *
 * @param {Element} element
 * @returns {string | undefined}
 */
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`;
        }
    }
}

/**
 * Retrieves the video URL from a theYNC video page
 *
 * @param {Element} element
 * @returns {string | undefined}
 */
function retrieveVideoURL(element = document) {
    if (location.host === 'archive.ph' || location.host === 'archive.today') {
        const videoElement = element.querySelector(
            '[id="thisPlayer"] video[old-src]'
        );
        if (videoElement) {
            return videoElement.getAttribute('old-src');
        }
    }
    const videoSrc = element.querySelector(
        '.stage-video > .inner-stage video[src]'
    )?.src;
    if (videoSrc) {
        return videoSrc;
    }
    const playerSetupScript = element.querySelector(
        '[id=thisPlayer] + script'
    )?.textContent;
    if (playerSetupScript) {
        // TODO: Find a non-regex solution to this that doesn't involve eval
        for (const [, videoURL] of playerSetupScript.matchAll(
            /(?<=thisPlayer\.setup\(\{).*?file:\ *"(https?\:\/\/.+?.\.(?:flv|mpg|wmv|avi|3gp|qt|mp4|mov|m4v|f4v))"/gms
        )) {
            if (videoURL) {
                return videoURL;
            }
        }
    }
}

/**
 * Retrieves the video URL from an archived YNC URL
 *
 * @param {string} archiveURL
 * @returns {Promise<string>}
 */
function getVideoURLFromArchive(archiveURL) {
    return GM_fetch(archiveURL, {
        method: 'GET',
    })
        .then((response) => {
            if (!response.ok) {
                console.error(response);
                return Promise.reject(response);
            }
            // When the page is loaded convert it to text
            return response;
        })
        .then((response) => 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 videoURL = retrieveVideoURL(doc);
            if (videoURL) {
                return videoURL;
            }
            return Promise.reject();
        });
}

/**
 * set Link of element
 *
 * @param {HTMLLinkElement} element
 * @param {string} url
 */
function setElementLink(element, url) {
    element.href = url;
    element.target = '_blank';
    element.rel = 'noopener noreferrer';
}

(function () {
    'use strict';

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

    GM_addStyle(`
    .loader {
        border: 0.25em solid #f3f3f3;
        border-top: 0.25em solid rgba(0, 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;
    }
    `);

    waitForKeyElement(
        '[id="content"],[id="related-videos"] .content-block'
    ).then((contentBlock) => {
        for (const element of contentBlock.querySelectorAll(
            '.upgrade-profile > .upgrade-info-block > .image-block'
        )) {
            isValidURL(getTheYNCVideoURL(element)).then(
                (url) => (location.href = url)
            );
        }
        for (const element of contentBlock.querySelectorAll(
            '.inner-block > a'
        )) {
            const undergroundLogo = element.querySelector(
                '.item-info > .border-gold'
            );
            if (!undergroundLogo) {
                continue;
            }
            const loadingElement = document.createElement('div');
            loadingElement.classList.add('loader');
            undergroundLogo.appendChild(loadingElement);
            isValidURL(getTheYNCVideoURL(element))
                .then((url) => {
                    undergroundLogo.textContent = 'BYPASSED';
                    undergroundLogo.style.backgroundColor = 'green';
                    setElementLink(element, url);
                })
                .catch(() =>
                    ['com', 'org', 'net']
                        .reduce(
                            (accumulator, currentTLD) =>
                                accumulator.catch(() =>
                                    queryArchive(
                                        element.href.replace(
                                            /(^https?:\/\/theync\.)(com|org|net)(\/.*$)/gim,
                                            `$1${currentTLD}$3`
                                        )
                                    )
                                ),
                            Promise.reject()
                        )
                        .then((archiveURL) =>
                            getVideoURLFromArchive(archiveURL)
                                .then((videoURL) => {
                                    undergroundLogo.textContent = 'ARCHIVED';
                                    undergroundLogo.style.backgroundColor =
                                        'blue';
                                    setElementLink(element, videoURL);
                                })
                                .catch(() => {
                                    undergroundLogo.textContent =
                                        'MAYBE ARCHIVED';
                                    undergroundLogo.style.backgroundColor =
                                        'aqua';
                                    setElementLink(element, archiveURL);
                                })
                        )
                        .catch(() => {
                            undergroundLogo.textContent = 'Try archive.today';
                            undergroundLogo.style.backgroundColor = 'red';
                            setElementLink(
                                element,
                                `https://archive.ph/${element.href}`
                            );

                            GM_log(
                                `No bypass or archive found for ${element.href}`
                            );
                        })
                )

                .finally(() => loadingElement.remove());
        }
    });
    waitForKeyElement('[id="stage"]:has([id="thisPlayer"])').then((stage) => {
        const videoURL = retrieveVideoURL();
        if (videoURL) {
            stage.innerHTML = '';
            stage.style.textAlign = 'center';

            const video = GM_addElement(stage, 'video', {
                controls: 'controls',
            });
            video.style.width = 'auto';
            video.style.height = '100%';
            const source = GM_addElement(video, 'source');
            source.src = videoURL;
            source.type = 'video/mp4';
        }
    });
})();