Xmillsa's Youtube Downloader

Download Youtube Videos

目前为 2018-12-22 提交的版本。查看 最新版本

// ==UserScript==
// @name        Xmillsa's Youtube Downloader
// @version     0.0.6
// @namespace   https://andys-net.co.uk/
// @author      Xmillsa
// @grant       none
// @match       https://www.youtube.com/*
// @homepageURL https://andys-net.co.uk/
// @description Download Youtube Videos
// ==/UserScript==

(function(){
    "use strict";

    const ytDownloader = {};
    
    let ytd = {
        videoID: '',
        videoObj: {},
        formats: [],
        adaptive: [],
        container: null,

        // Gets the current videos ID.
        getVideoID: function(){
            return new Promise(function(resolve, reject){
                if (document.querySelector('[video-id]') === null){
                    // Doesn't exist yet...
                    reject('Can\'t find a video, trying again in .5 seconds.');
                }else{
                    // Store the video ID.
                    // this.videoID = document.querySelector('[video-id]').getAttribute('video-id');
                    this.videoID = /(?![\?v=]).*?(?=&|$)/i.exec(window.location.search);
                    resolve();
                }
            }.bind(this));
        },

        // Let's get some details!
        getVideoDetails: function(){
            console.log('Get video details');
            return new Promise(function(resolve, reject){
                fetch('https://www.youtube.com/get_video_info?video_id='+ this.videoID +'&el=detailpage', {method: 'GET'})
                .then(r => r.text())
                .then(r => {
                    // Store some info.
                    this.videoObj = JSON.parse(decodeURIComponent(String(/player_response=[^&]*/i.exec(r)).replace('player_response=', '')));
                    this.formats = this.videoObj.streamingData.formats;
                    this.adaptive = this.videoObj.streamingData.adaptiveFormats;
                    // Carry on.
                    resolve();
                })
                .catch(e => {
                    console.error(e);
                    console.error('https://www.youtube.com/get_video_info?video_id='+ this.videoID +'&el=detailpage');
                    reject('There was an error with the fetch request... trying again.');
                });
            }.bind(this));
        },

        makeButtons: function(){
            // Check we have a container to put our links.
            if (this.container === null){
                console.log('Container Missing, Creating...');
                this.createContainer();
                return;
            }
            
            this.formats.sort((a, b) => {
                return parseInt(b.contentLength) - parseInt(a.contentLength);
            });
            this.adaptive.sort((a, b) => {
                return parseInt(b.contentLength) - parseInt(a.contentLength);
            });
            
            let i = 0;
            for(; i < this.formats.length; i++){
                let a = this.createALink( this.formats[ i ] );

                document.getElementById('andyLeft').appendChild(a);
                document.getElementById('andyLeft').appendChild(document.createElement('br'));
            }
            
            i = 0;
            for(; i < this.adaptive.length; i++){
                let a = this.createALink( this.adaptive[ i ] );

                document.getElementById('andyRight').appendChild(a);
                document.getElementById('andyRight').appendChild(document.createElement('br'));
            }
        },

        // This creates a container for our buttons.
        createContainer: function(){
            // Check it doesn't already exist.
            if (document.getElementById('andysContainer') === null){
                const div = document.createElement('div'),
                      target = document.querySelector('#primary #player');

                // Check our target exists.
                if (target !== null){
                    const insertTarget = target.querySelector
                    div.className = 'style-scope ytd-watch-flexy';
                    div.id = 'andysContainer';
                    
                    div.innerHTML = '<div id="andyLeft"></div><div id="andyRight"></div>';
                    
                    target.parentNode.insertBefore(div, target.parentNode.querySelector('#meta'));
                    this.container = div;
                }
            }
            this.makeButtons();
        },

        /*
            Creates our <a> links ready to be put into the page!
        */
        createALink: function( format ){
            // Create a button for each format.
            let a = document.createElement('a'),
                mime = format['mimeType'].split(';')[0],
                qual = format['qualityLabel'],
                size = Number(format['contentLength'] / 1024 / 1024).toFixed(2);
            
            a.title = format['mimeType'];
            
            switch (mime){
                case 'video/3gpp':
                    a.innerText = qual +' .3gp';
                break;
                case 'video/mp4':
                    a.innerText = qual +' .mp4';
                break;
                case 'video/webm':
                    a.innerText = qual +' .webm';
                break;
                case 'audio/mp4':
                    a.innerText = 'Audio Only .m4a';
                break;
                case 'audio/webm':
                    a.innerText = 'Audio Only .webm';
                break;
                default:
                    a.innerText = qual +' Unknown Type?!';
            }
            
            a.innerText += ', Size: '+ size +'MB';
            a.target = '_blank';
            a.download = document.title.replace(' - YouTube', '').replace('(', '').replace(')', '');
            a.href = format['url'];
            
            return a;
        },
        
        reset: function(){
            if (this.container !== null){
                this.container.remove();
            }
            // Reset vars.
            this.videoID = '';
            this.videoObj = {};
            this.formats = [];
            this.adaptive = [];
            this.container = null;
        },

        // The PROCESS
        process: function(){
            
            // Reset.
            this.reset();
            
            // Check we're on a watch?v= page.
            if (/watch\?v/.test(window.location.href)){
                this.getVideoID()
                .then(() => {
                    // We have an ID, lets fetch it's info!
                    console.log('Found the video!');
                    this.getVideoDetails()
                    .then(() => {
                        console.log('Make buttons.');
                        this.makeButtons();
                    })
                    .catch(e => {
                        console.log(e);
                        // Try again?
                        setTimeout(this.process.bind(this), 500);
                    });
                })
                .catch(e => {
                    console.error(e);
                    // Try again?
                    setTimeout(this.process.bind(this), 500);
                });
            }
        }

    };

    /*
      Let's look for some page changes.
    */
    let oldURL = '',
        newURL = window.location.href;

    setInterval(loopyLoops, 100);
    // Check for changes.
    function loopyLoops(){
        newURL = window.location.href;
        // We've moved pages, start the PROCESS.
        if (oldURL !== newURL){
            console.log('New page!');
            oldURL = window.location.href;
            ytd.process();
        }
    }
    
    const css = `
    #andysContainer{
        margin-top:26px;
        font-size:1.3em;
        display:flex;
        justify-content:space-evenly;
        width:100%;
    }
    #andysContainer a{
        color: #a92;
    }`;
    
    const style = document.createElement('style');
    style.innerText = css;
    document.head.appendChild(style);
}());

QingJ © 2025

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