Nicovideo Fast Downloader

Download your nicovideos with one simple click

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Nicovideo Fast Downloader
// @namespace    https://greasyfork.org/en/users/86284-benjababe
// @version      1.0
// @description  Download your nicovideos with one simple click
// @author       Benjababe
// @license      MIT

// @match        https://www.nicovideo.jp/watch/*
// @icon         https://www.google.com/s2/favicons?domain=nicovideo.jp

// @grant        GM_download
// ==/UserScript==

// jshint esversion: 6

(function () {
    'use strict';

    const HOTKEY = "Pause";
    const DOC_TITLE = document.title;
    const TITLE = document.querySelector(".VideoTitle");
    const DL_IMG = "https://i.imgur.com/CqerSAu.png";

    // appends download icon to menu on page load
    window.onload = () => {
        let menuContainer = document.querySelector(".VideoMenuContainer-areaLeft");

        let btn = document.createElement("button");
        btn.type = "Button";
        btn.onclick = downloadVideo;
        btn.classList.add("ActionButton");
        btn.classList.add("UadButton");
        btn.classList.add("VideoMenuContainer-button");

        let img = document.createElement("img");
        img.src = DL_IMG;
        img.height = 24;
        img.width = 24;
        btn.appendChild(img);

        menuContainer.appendChild(btn);
    }

    // use hotkey to download video instead of icon
    document.onkeydown = (e) => {
        if (e.code === HOTKEY) {
            downloadVideo();
        }
    }

    let downloadVideo = () => {
        let mainVideoPlayer = document.querySelector("#MainVideoPlayer");

        // cycle through child of player until a <video> is reached
        for (let i = 0; i < mainVideoPlayer.childElementCount; i++) {
            let child = mainVideoPlayer.childNodes[i];
            if (child.tagName.toLowerCase() == "video") {
                let progressTxt = document.querySelector("#progressTxt");

                // in case it was created already
                if (progressTxt == undefined) {
                    // update download text next to video title and tab title
                    progressTxt = document.createElement("h2");
                    progressTxt.id = "progressTxt";
                    progressTxt.innerText = "Downloading: 0%";
                    TITLE.parentNode.appendChild(progressTxt);
                }

                let titleTxt = TITLE.innerText;

                // get video id (sm[0-9]{1,})
                let id = location.pathname.split("/");
                id = id[id.length - 1].split("?")[0];

                // initiate download with proper start, progress and end callback functions
                GM_download({
                    "url": child.src,
                    "name": `${titleTxt}-${id}.mp4`,
                    "saveAs": true,
                    "onerror": errorCB,
                    "ontimeout": errorCB,
                    "onprogress": progress,
                    "onload": completeCB
                });
                console.log(`Downloading: ${child.src} as ${titleTxt}-${id}.mp4`);
            }
        }
    }

    // callback function for progress update
    let progress = (progress) => {
        let downloaded = parseInt(progress.done / progress.total * 100);
        // updates progress text
        document.querySelector("#progressTxt").innerText = `Downloading: ${downloaded}%`;
        // updates tab title
        document.title = `Downloading: ${downloaded}%`;
    }

    // callback function on download complete
    let completeCB = () => {
        // changes tab title back to original
        document.title = DOC_TITLE;
    }

    // callback function on error
    let errorCB = (error) => {
        console.error(error);
    }
})();