Greasy Fork

Greasy Fork is available in English.

Bilibili 一键截图

按 S 键一键截图,并保存成 PNG 格式

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Bilibili 一键截图
// @description  按 S 键一键截图,并保存成 PNG 格式
// @version      0.1.7
// @author       Kazurin
// @license      MIT
// @namespace    http://greasyfork.icu/users/699115
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/bangumi/play/*
// @grant        none
// ==/UserScript==

'use strict';
var video, videoTitle, bgmTitle, canvas, ctx, link;

function lazyInitialize() {
    if(!canvas) {
        video = document.querySelector('#bilibili-player video') || document.querySelector('.bilibili-player-video video');
        videoTitle = document.querySelector('h1.video-title') || document.querySelector('.video-title span');
        bgmTitle = document.querySelector('.media-title');
        canvas = document.createElement('canvas');
        ctx = canvas.getContext('2d');
        link = document.createElement('a');
        link.style.display = 'none';
        document.body.appendChild(link);
    }
}

function getVideoCurrentTime(video) {
    var time = Math.round(video.currentTime);
    var seconds = time % 60;
    var minutes = (time - seconds) / 60;
    return minutes + '-' + (seconds < 10 ? '0' : '') + seconds;
}

function startDownload(uri) {
    link.href = uri;
    if(window.location.href.indexOf('/bangumi/') >= 0) {
        // 视频类型为番剧
        var bgmEpisode = document.querySelector('#eplist_module .ep-item.cursor .ep-title') ||
            document.querySelector('.ep-section-module .ep-item.cursor .ep-title');
        if(bgmEpisode) {
            // 视频有分集
            link.download = bgmTitle.textContent + ' ' + bgmEpisode.textContent + ' ' + getVideoCurrentTime(video) + '.png';
        } else {
            // 视频无分集
            link.download = bgmTitle.textContent + ' ' + getVideoCurrentTime(video) + '.png';
        }
    } else {
        // 视频类型为普通视频
        var episode = document.querySelector('.cur-list ul.list-box li.on span.page-num');
        if(episode) {
            // 视频有分集
            link.download = videoTitle.textContent + ' ' + episode.textContent + ' ' + getVideoCurrentTime(video) + '.png';
        } else {
            // 视频无分集
            link.download = videoTitle.textContent + ' ' + getVideoCurrentTime(video) + '.png';
        }
    }
    link.click();
}

function onError(error) {
    console.error('截图失败');
    console.error(error);
    window.alert('截图失败,请重试。如果此问题反复出现,请在 F12 控制台查看错误消息,并向开发者反馈。');
}

function downloadScreenshot() {
    lazyInitialize();
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    if(typeof(canvas.toBlob) !== 'undefined') {
        // 如果浏览器支持 canvas.toBlob(),则用 blob URL 下载
        canvas.toBlob(function(blob) {
            try {
                var url = URL.createObjectURL(blob, 'image/png');
                startDownload(url);
                URL.revokeObjectURL(url);
            } catch(e) {
                onError(e);
            }
        });
    } else {
        // 否则用 data URL 下载
        startDownload(canvas.toDataURL('image/png'));
    }
}

function hasActiveInput() {
    // 检查当前焦点是否在输入框上
    const activeTag = document.activeElement.tagName;
    return activeTag == 'INPUT' || activeTag == 'TEXTAREA';
}

document.addEventListener('keydown', function(e) {
    if(e.keyCode == 83 && !hasActiveInput()) {
        e.preventDefault();
        try {
            downloadScreenshot();
        } catch(e) {
            onError(e);
        }
    }
});