- // ==UserScript==
- // @name Bilibili Download Pictures
- // @name:zh-CN 下载Bilibili动态页面图片
- // @version 0.9.9
- // @description Download pictures from bilibili timeline and 720P videos.
- // @description:zh-CN 下载“Bilibili动态”时间线页面的图片,也可下载视频(720P单文件)
- // @author OWENDSWANG
- // @icon https://avatars.githubusercontent.com/u/9076865?s=40&v=4
- // @license MIT
- // @homepage https://gf.qytechs.cn/scripts/421885
- // @supportURL https://github.com/owendswang/Download-Pictures-from-Bilibili-Timeline/issues
- // @match https://t.bilibili.com/*
- // @match https://space.bilibili.com/*/dynamic*
- // @match https://www.bilibili.com/opus/*
- // @match https://www.bilibili.com/video/*
- // @match https://www.bilibili.com/v/topic/detail/?*
- // @connect bilibili.com
- // @connect bilivideo.com
- // @connect bilivideo.cn
- // @connect hdslb.com
- // @connect biliimg.com
- // @grant GM_download
- // @grant GM_xmlhttpRequest
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_cookie
- // @grant GM_registerMenuCommand
- // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
- // @namespace https://gf.qytechs.cn/users/738244
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- // Your code here...
- const settingVersion = 1;
- const downloadIcon = 'url(\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAHpSURBVDiNndS7a1RREMfxz9XVrI8UIkjwLxCipYVp9A+wEQsV8dFksLCwUATxAYqNIAhWO4UPsAqCCGqTQkRQULEMgojYCSK+X4nhWty7uCZ3k5gfnObMOd8zM2dmirIs9SozV+IxNmCJZk3jObZGxFSvodVweD024TMm+wDb2Iy1eDsfcCkKHMSdPsB9uFKf/UdNwK4mI+J3kyEzp5r26Z8jTa8v5N5cwEWpCdgYZh/NOtuCzGyrQiwx+B/Awcz8ovrE6Yj42crMcYyoSqRdr/nULd6X+IFfWJaZYy1cwhA24j5u1t4+mAN4D0cwhb21Q89wtSjLUmauxm1sw56IGFtIvJm5H9dxFzsj4lfR23qZeQ0HcDEijs4Du4zD6ETEoe5+0el0zuNnURTnRkdHZeYpnMUt7JrZq5k5oErLdhyPiAuZuQyn8XEJTuBMWZbLISLOqVprB55k5roe2BCe1rDdEXGhNq3CSRxrqX73U68XEXEjM99gHBOZuUVVs4+wAiMR8bjnSolv+NC3UyLiIYZVU+cFJvARwzNg/6gLLDVUfUS8UpXTw3ptjIjXDZzpmlF2p02BdmbOmn8R8V1VTiAzmybUQM0oik6n81WVl/f9wvC3M4o+9kI1bD+08A5r6rVYlapcf/0DW06ifC1dVCUAAAAASUVORK5CYII=\')';
- let notLoaded = true;
- let cardsTotal = 0;
- let skeletonsTotal = 0;
- let downloadQueueCard = document.createElement('div');
- downloadQueueCard.style.position = 'fixed';
- downloadQueueCard.style.bottom = '0.5rem';
- downloadQueueCard.style.left = '0.5rem';
- downloadQueueCard.style.maxHeight = '50vh';
- downloadQueueCard.style.overflowY = 'auto';
- downloadQueueCard.style.overflowX = 'hidden';
- downloadQueueCard.style.zIndex = '10';
- let downloadQueueTitle = document.createElement('div');
- downloadQueueTitle.textContent = '下载队列';
- downloadQueueTitle.style.fontSize = '0.8rem';
- downloadQueueTitle.style.color = 'gray';
- downloadQueueTitle.style.display = 'none';
- downloadQueueCard.appendChild(downloadQueueTitle);
- document.body.appendChild(downloadQueueCard);
- let progressBar = document.createElement('div');
- progressBar.style.height = '1.4rem';
- progressBar.style.width = '17rem';
- // progressBar.style.background = 'linear-gradient(to right, red 100%, transparent 100%)';
- progressBar.style.borderStyle = 'solid';
- progressBar.style.borderWidth = '0.1rem';
- progressBar.style.borderColor = 'grey';
- progressBar.style.borderRadius = '0.5rem';
- progressBar.style.boxSizing = 'content-box';
- progressBar.style.marginTop = '0.5rem';
- progressBar.style.marginRight = '1rem';
- progressBar.style.position = 'relative';
- let progressText = document.createElement('div');
- // progressText.textContent = 'test.test';
- progressText.style.mixBlendMode = 'screen';
- progressText.style.width = '100%';
- progressText.style.textAlign = 'center';
- progressText.style.color = 'orange';
- progressText.style.fontSize = '0.7rem';
- progressText.style.lineHeight = '1.4rem';
- progressText.style.overflow = 'hidden';
- progressBar.appendChild(progressText);
- let progressCloseBtn = document.createElement('button');
- progressCloseBtn.style.border = 'unset';
- progressCloseBtn.style.background = 'unset';
- progressCloseBtn.style.color = 'orange';
- progressCloseBtn.style.position = 'absolute';
- progressCloseBtn.style.right = '0.3rem';
- progressCloseBtn.style.top = '0.2rem';
- progressCloseBtn.style.fontSize = '1rem';
- progressCloseBtn.style.lineHeight = '1rem';
- progressCloseBtn.style.cursor = 'pointer';
- progressCloseBtn.textContent = '×';
- progressCloseBtn.title = '取消';
- progressCloseBtn.onmouseover = function(e){
- this.style.color = 'red';
- }
- progressCloseBtn.onmouseout = function(e){
- this.style.color = 'orange';
- }
- progressBar.appendChild(progressCloseBtn);
- // downloadQueueCard.appendChild(progressBar);
- function oXMLHttpRequest(url, type) {
- return new Promise(function(resolve, reject) {
- let oReq = new XMLHttpRequest();
- oReq.open("GET", url);
- oReq.withCredentials = true;
- oReq.responseType = type;
- oReq.onload = (e) => {
- // console.log(e);
- // console.log(oReq.response);
- resolve(oReq.response);
- };
- oReq.onerror = (e) => { console.log(e); alert('请求失败!'); resolve(null); };
- oReq.onabort = (e) => { console.log(e); alert('请求被中断!'); resolve(null); };
- oReq.ontimeout = (e) => { console.log(e); alert('请求超时!'); resolve(null); };
- oReq.send(null);
- });
- }
- /*function saveAs(blob, name) {
- const link = document.createElement("a");
- link.style.display = "none";
- link.href = URL.createObjectURL(blob);
- link.download = name;
- link.target = '_blank';
- document.body.appendChild(link);
- // console.log(link);
- link.click();
- const timeout = setTimeout(() => {
- URL.revokeObjectURL(link.href);
- link.parentNode.removeChild(link);
- }, 1000);
- }*/
- function downloadError(e, url, name, progress) {
- // console.log(e, url);
- /*GM_notification({
- title: 'Download error',
- text: 'Error: ' + e.error + '\nUrl: ' + url,
- silent: true,
- timeout: 3,
- });*/
- progress.style.background = 'red';
- progress.firstChild.textContent = (name.length > 10 ? (name.substring(0,10) + '...') : name) + ' [' + (e.error || 'Unknown') + ']';
- progress.firstChild.style.color = 'yellow';
- progress.firstChild.style.mixBlendMode = 'unset';
- let progressRetryBtn = document.createElement('button');
- progressRetryBtn.style.border = 'unset';
- progressRetryBtn.style.background = 'unset';
- progressRetryBtn.style.color = 'yellow';
- progressRetryBtn.style.position = 'absolute';
- progressRetryBtn.style.right = '1.2rem';
- progressRetryBtn.style.top = '0.05rem';
- progressRetryBtn.style.fontSize = '1rem';
- progressRetryBtn.style.lineHeight = '1rem';
- progressRetryBtn.style.cursor = 'pointer';
- progressRetryBtn.style.letterSpacing = '-0.2rem';
- progressRetryBtn.textContent = '⤤⤦';
- progressRetryBtn.title = '重试';
- progressRetryBtn.onmouseover = function(e){
- this.style.color = 'white';
- }
- progressRetryBtn.onmouseout = function(e){
- this.style.color = 'yellow';
- }
- progressRetryBtn.onclick = function(e) {
- this.parentNode.remove();
- downloadWrapper(url, name);
- }
- progress.insertBefore(progressRetryBtn, progress.lastChild);
- progress.lastChild.title = '关闭';
- progress.lastChild.style.color = 'yellow';
- progress.lastChild.onmouseover = function(e){
- this.style.color = 'white';
- };
- progress.lastChild.onmouseout = function(e){
- this.style.color = 'yellow';
- };
- progress.lastChild.onclick = function(e) {
- this.parentNode.remove();
- if(progress.parent.childElementCount == 1) progress.parent.firstChild.style.display = 'none';
- };
- // setTimeout(() => { progress.remove(); if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none'; }, 1000);
- }
- function downloadWrapper(url, name) {
- // console.log('downloadWrapper: ', url, name);
- downloadQueueTitle.style.display = 'block';
- let progress = downloadQueueCard.appendChild(progressBar.cloneNode(true));
- progress.firstChild.textContent = (name.length > 10 ? (name.substring(0,10) + '...') : name) + ' [0%]';
- return new Promise(function(resolve, reject) {
- const download = GM_xmlhttpRequest({
- method: 'GET',
- url,
- responseType: 'blob',
- headers: {
- Referer: location.protocol + '//' + location.hostname,
- Origin: location.protocol + '//' + location.hostname,
- },
- onprogress: (e) => {
- // e = { int done, finalUrl, bool lengthComputable, int loaded, int position, int readyState, response, str responseHeaders, responseText, responseXML, int status, statusText, int total, int totalSize }
- const percent = e.done / e.total * 100;
- progress.style.background = 'linear-gradient(to right, green ' + percent + '%, transparent ' + percent + '%)';
- progress.firstChild.textContent = (name.length > 10 ? (name.substring(0,10) + '...') : name) + ' [' + percent.toFixed(0) + '%]';
- },
- onload: function({ response }) {
- // console.log(response);
- const timeout = setTimeout(() => {
- progress.remove();
- if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
- }, 1000);
- progress.lastChild.onclick = function(e) {
- clearTimeout(timeout);
- this.parentNode.remove();
- if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
- };
- saveAs(response, name);
- resolve(null);
- },
- onabort: function(e) { console.log(e); resolve(null); },
- onerror: function(e) { downloadError(e, url, name, progress); console.log(e); resolve(null); },
- ontimeout: function(e) { downloadError(e, url, name, progress); console.log(e); resolve(null); },
- });
- progress.lastChild.onclick = function(e) {
- download.abort();
- this.parentNode.remove();
- if(downloadQueueCard.childElementCount == 1) downloadQueueTitle.style.display = 'none';
- };
- });
- }
- /*function getCookie(name) {
- return new Promise(function(resolve, reject) {
- GM_cookie.list({ name: name }, function(cookies, error) {
- if (!error) {
- // console.log(cookies);
- resolve(cookies[0].value);
- } else {
- console.error(error);
- }
- });
- });
- }
- function getAllCookies() {
- return new Promise(function(resolve, reject) {
- GM_cookie.list({}, function(cookies, error) {
- if (!error) {
- // console.log(cookies);
- const cookiesStr = cookies.map((ele) => { return ele.name + '=' + ele.value }).join('; ');
- // console.log(cookiesStr);
- resolve(cookiesStr);
- } else {
- console.error(error);
- resolve(null);
- }
- });
- });
- }
- function download2Blob(url) {
- // console.log('download2Blob: ', url);
- return new Promise(function(resolve, reject) {
- GM_xmlhttpRequest({
- method: 'GET',
- url,
- responseType: 'blob',
- headers: {
- Referer: location.protocol + '//' + location.hostname,
- Origin: location.protocol + '//' + location.hostname,
- },
- onload: function({ response }) {
- // console.log(response);
- // saveAs(response, name);
- resolve(response);
- },
- onabort: function(e) { console.log(e); alert('请求被中断!'); resolve(null); },
- onerror: function(e) { console.log(e); alert('请求失败!'); resolve(null); },
- ontimeout: function(e) { console.log(e); alert('下载超时!'); resolve(null); },
- });
- });
- }*/
- function getPicName(nameSetting, originalName, index, data) {
- const card = JSON.parse(data.card.card);
- let setName = nameSetting;
- setName = setName.replace('{original}', originalName.split('.')[0]);
- setName = setName.replace('{ext}', originalName.split('.')[1]);
- const userName = card.user?.name || data.card.desc.user_profile.info.uname;
- const userId = card.user?.uid || data.card.desc.user_profile.info.uid;
- const dynamicId = data.card.desc.dynamic_id;
- const content = card.item?.description || card.title;
- setName = setName.replace('{username}', userName);
- setName = setName.replace('{userid}', userId);
- setName = setName.replace('{dynamicid}', dynamicId);
- setName = setName.replace('{index}', index);
- setName = setName.replace('{content}', content.substring(0, 25));
- let YYYY, MM, DD, HH, mm, ss;
- const postAt = new Date((card.item?.upload_time || data.card.desc.timestamp) * 1000);
- YYYY = postAt.getFullYear().toString();
- MM = (postAt.getMonth() + 1).toString().padStart(2, '0');
- DD = postAt.getDate().toString().padStart(2, '0');
- HH = postAt.getHours().toString().padStart(2, '0');
- mm = postAt.getMinutes().toString().padStart(2, '0');
- ss = postAt.getSeconds().toString().padStart(2, '0');
- setName = setName.replace('{YYYY}', YYYY);
- setName = setName.replace('{MM}', MM);
- setName = setName.replace('{DD}', DD);
- setName = setName.replace('{HH}', HH);
- setName = setName.replace('{mm}', mm);
- setName = setName.replace('{ss}', ss);
- /*if (retweetPostId && GM_getValue('retweetMode', false)) {
- setName = setName.replace('{re.mblogid}', retweetPostId);
- setName = setName.replace('{re.username}', retweetUserName);
- setName = setName.replace('{re.userid}', retweetUserId);
- setName = setName.replace('{re.uid}', retweetPostUid);
- setName = setName.replace('{re.content}', retweetContent.substring(0, 25));
- let reYYYY, reMM, reDD, reHH, remm, ress;
- const retweetPostAt = new Date(retweetPostTime);
- if (retweetPostTime) {
- reYYYY = retweetPostAt.getFullYear().toString();
- reMM = (retweetPostAt.getMonth() + 1).toString().padStart(2, '0');
- reDD = retweetPostAt.getDate().toString().padStart(2, '0');
- reHH = retweetPostAt.getHours().toString().padStart(2, '0');
- remm = retweetPostAt.getMinutes().toString().padStart(2, '0');
- ress = retweetPostAt.getSeconds().toString().padStart(2, '0');
- }
- setName = setName.replace('{re.YYYY}', reYYYY);
- setName = setName.replace('{re.MM}', reMM);
- setName = setName.replace('{re.DD}', reDD);
- setName = setName.replace('{re.HH}', reHH);
- setName = setName.replace('{re.mm}', remm);
- setName = setName.replace('{re.ss}', ress);
- }*/
- return setName.replace(/[<|>|*|"|\/|\\|\||:|?|\n]/g, '_');
- }
- function getVidName(nameSetting, originalName, data) {
- let setName = nameSetting;
- setName = setName.replace('{original}', originalName.split('.')[0]);
- setName = setName.replace('{ext}', originalName.split('.')[1]);
- const bvid = data.bvid;
- const aid = data.aid;
- const cid = data.cid;
- const title = data.title;
- const content = data.desc;
- const userName = data.owner.name;
- const userId = data.owner.mid;
- setName = setName.replace('{bvid}', bvid);
- setName = setName.replace('{aid}', aid);
- setName = setName.replace('{cid}', cid);
- setName = setName.replace('{title}', title);
- setName = setName.replace('{content}', content.substring(0, 25));
- setName = setName.replace('{username}', userName);
- setName = setName.replace('{userid}', userId);
- let YYYY, MM, DD, HH, mm, ss;
- const postAt = new Date(data.ctime * 1000);
- YYYY = postAt.getFullYear().toString();
- MM = (postAt.getMonth() + 1).toString().padStart(2, '0');
- DD = postAt.getDate().toString().padStart(2, '0');
- HH = postAt.getHours().toString().padStart(2, '0');
- mm = postAt.getMinutes().toString().padStart(2, '0');
- ss = postAt.getSeconds().toString().padStart(2, '0');
- setName = setName.replace('{YYYY}', YYYY);
- setName = setName.replace('{MM}', MM);
- setName = setName.replace('{DD}', DD);
- setName = setName.replace('{HH}', HH);
- setName = setName.replace('{mm}', mm);
- setName = setName.replace('{ss}', ss);
- return setName.replace(/[<|>|*|"|\/|\\|\||:|?|\n]/g, '_');
- }
- function handleImageDynamic(data) {
- const card = JSON.parse(data.card.card);
- const pictures = card.item.pictures;
- // console.log(pictures);
- for (const [ index, picture ] of pictures.entries()) {
- // console.log(picture);
- const pictureUrl = picture.img_src;
- const originalName = pictureUrl.split('/')[pictureUrl.split('/').length - 1];
- const pictureName = getPicName(GM_getValue('dlPicName', '{original}.{ext}'), originalName, index + 1, data);
- /*GM_download({
- url: pictureUrl,
- name: pictureName,
- onerror: function(e) { console.log(e); alert('下载失败!'); },
- ontimeout: function(e) { console.log(e); alert('下载超时!'); },
- });*/
- downloadWrapper(pictureUrl, pictureName);
- }
- }
- async function handleArticleDynamic(data) {
- const card = JSON.parse(data.card.card);
- const pictures = card.image_urls;
- // console.log(pictures);
- for (const [ index, picture ] of pictures.entries()) {
- // console.log(picture);
- const pictureUrl = picture;
- const originalName = pictureUrl.split('/')[pictureUrl.split('/').length - 1];
- const pictureName = getPicName(GM_getValue('dlPicName', '{original}.{ext}'), originalName, index + 1, data);
- /*GM_download({
- url: pictureUrl,
- name: pictureName,
- onerror: function(e) { console.log(e); alert('下载失败!'); },
- ontimeout: function(e) { console.log(e); alert('下载超时!'); },
- });*/
- downloadWrapper(pictureUrl, pictureName);
- }
- }
- function getVideoInfo(bvid) {
- // console.log('getVideoInfo');
- return oXMLHttpRequest('https://api.bilibili.com/x/web-interface/view?bvid=' + bvid, 'json');
- }
- function getVideoDetail(aid, cid/*, cookies*/) {
- /*return new Promise(function(resolve, reject) {
- // console.log(aid, cid, cookies);
- GM_xmlhttpRequest({
- method: 'GET',
- // 1080p dash --> https://api.bilibili.com/x/player/playurl?avid=1551880723&cid=1473551215&qn=80&fnval=4048
- // 720p mp4 --> https://api.bilibili.com/x/player/playurl?avid=1551880723&cid=1473551215&qn=64
- url: 'https://api.bilibili.com/x/player/wbi/playurl?avid=' + aid.toString() + '&cid=' + cid.toString() + '&fnval=64',
- responseType: 'json',
- anonymous: true,
- cookie: cookies,
- onload: function({ response }) {
- // console.log(response);
- resolve(response);
- },
- onabort: function(e) { resolve(null); },
- onerror: function(e) { resolve(null); },
- ontimeout: function(e) { resolve(null); },
- });
- });*/
- return oXMLHttpRequest('https://api.bilibili.com/x/player/wbi/playurl?avid=' + aid.toString() + '&cid=' + cid.toString() + '&fnval=64', 'json');
- }
- async function downloadVideo(data) {
- const vidRes = await getVideoDetail(data.aid, data.cid/*, cookies*/);
- // console.log(vidRes);
- const vidUrl = vidRes.data.durl[0].url;
- // console.log(vidUrl);
- const originalName = vidUrl.split('?')[0].split('/')[vidUrl.split('?')[0].split('/').length - 1];
- const vidName = getVidName(GM_getValue('dlVidName', '{original}.{ext}'), originalName, data);
- // console.log(vidName);
- /*GM_download({
- url: vidUrl,
- name: vidName,
- headers: {
- Referer: 'https://www.bilibili.com',
- Origin: 'https://www.bilibili.com',
- },
- onerror: function(e) { console.log(e); },
- ontimeout: function(e) { console.log(e); },
- });
- const blob = await download2Blob(vidUrl);
- const url = URL.createObjectURL(blob);
- // console.log(url);
- GM_download({
- url: url,
- name: vidName,
- onerror: function(e) { console.log(e); alert('下载失败!'); },
- ontimeout: function(e) { console.log(e); alert('下载超时!'); },
- });
- saveAs(blob, vidName);*/
- downloadWrapper(vidUrl, vidName);
- }
- async function handleVideoDownload(bvid) {
- const vidInfoRes = await getVideoInfo(bvid);
- // console.log(vidInfoRes);
- await downloadVideo(vidInfoRes.data);
- }
- async function handleVideoDynamic(data) {
- // console.log('handleVideoDynamic');
- // console.log(data);
- // const card = JSON.parse(data.card.card);
- // const aid = card.aid;
- // const cid = card.cid;
- // console.log(aid, cid);
- // const cookies = await getAllCookies();
- // const cookies = 'SESSDATA=' + await getCookie('SESSDATA');
- // console.log(cookies);
- // await downloadVideo(aid, cid);
- const bvid = data.card.desc.bvid;
- await handleVideoDownload(bvid);
- }
- function getDynamicDetail(dynId) {
- /*return new Promise(function(resolve, reject) {
- GM_xmlhttpRequest({
- method: 'GET',
- url: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=' + dynId,
- responseType: 'json',
- onload: function({ response }) {
- // console.log(response);
- resolve(response);
- },
- onabort: function(e) { resolve(null); },
- onerror: function(e) { resolve(null); },
- ontimeout: function(e) { resolve(null); },
- });
- });*/
- return oXMLHttpRequest('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=' + dynId, 'json');
- // return oXMLHttpRequest('https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?id=' + dynId, 'json');
- }
- async function handleDynamicDownload(dynId) {
- // console.log('handleDynamicDownload: ' + dynId);
- const dynRes = await getDynamicDetail(dynId);
- // console.log(dynRes.data);
- if (dynRes.data.card.card) {
- const card = JSON.parse(dynRes.data.card.card);
- switch(dynRes.data.card.desc.type) {
- case 1:
- // 转发
- break;
- case 2:
- // 图片
- // console.log('picture');
- handleImageDynamic(dynRes.data);
- break;
- case 4:
- // 文字
- break;
- case 8:
- // 视频
- // console.log('video');
- handleVideoDynamic(dynRes.data);
- break;
- case 64:
- // 专栏
- handleArticleDynamic(dynRes.data);
- break;
- case 256:
- // 音频
- break;
- default:
- break;
- }
- } else {
- console.log('no content found!', dynRes);
- alert('无法下载!');
- }
- }
- function addOpusDownloadButton(card) {
- if(card.getElementsByClassName('download-button').length == 0) {
- // console.log(card);
- const buttonBar = card.getElementsByClassName('bili-tabs__nav__items')[0];
- let downloadButton = document.createElement('div');
- downloadButton.textContent = '下载';
- downloadButton.classList.add('bili-tabs__nav__item');
- downloadButton.addEventListener('click', function(event) {
- const dynId = window.location.pathname.split('/')[window.location.pathname.split('/').length - 1];
- // console.log(dynId);
- handleDynamicDownload(dynId);
- /*const content = document.body.querySelector('div.opus-module-content');
- const list = content.querySelectorAll('div.bili-album__preview__picture__img');
- // console.log(list);
- for (const item of list) {
- let imgUrl = item.style.backgroundImage.split(/"|@/)[1] || item.querySelector('img').src.split('@')[0];
- if (imgUrl.startsWith('//')) {
- imgUrl = 'https:' + imgUrl;
- }
- const imgName = imgUrl.split('/')[imgUrl.split('/').length - 1];
- // console.log(imgUrl);
- // console.log(imgName);
- GM_download(imgUrl, imgName);
- }
- const topAlbum = document.body.querySelector('div.opus-module-top__album');
- if (topAlbum) {
- const topAlbumIndicatorList = topAlbum.querySelectorAll('div.horizontal-scroll-album__indicator > div > img');
- const topAlbumList = topAlbum.querySelectorAll('div.horizontal-scroll-album__pic__img > img');
- let topList = topAlbumList;
- if (topAlbumIndicatorList.length > 0) topList = topAlbumIndicatorList;
- for (const item of topList) {
- let imgUrl = item.src.split(/@/)[0];
- if (imgUrl.startsWith('//')) {
- imgUrl = 'https:' + imgUrl;
- }
- const imgName = imgUrl.split('/')[imgUrl.split('/').length - 1];
- // console.log(imgUrl);
- // console.log(imgName);
- GM_download(imgUrl, imgName);
- }
- }*/
- });
- buttonBar.appendChild(downloadButton);
- }
- }
- function addDownloadButton(card) {
- // console.log('addDownloadButton');
- if(card.getElementsByClassName('download-button').length == 0) {
- if(card.getElementsByClassName('bili-dyn-item__footer').length > 0) {
- card.querySelectorAll('div.bili-dyn-item__footer > div.bili-dyn-item__action').forEach((ele) => { ele.style.marginRight = '48px'; });
- let buttonBar = card.getElementsByClassName('bili-dyn-item__footer')[0];
- let downloadButton = document.createElement('div');
- downloadButton.classList.add('bili-dyn-item__action');
- downloadButton.classList.add('download-button');
- let span = document.createElement('div');
- span.classList.add('bili-dyn-action');
- let icon = document.createElement('i');
- icon.style.width = '20px';
- icon.style.height = '20px';
- icon.style.transform = 'scale(0.8)';
- icon.style.backgroundImage = downloadIcon;
- icon.style.backgroundRepeat = 'no-repeat';
- icon.style.backgroundSize = '100% 100%';
- icon.style.backgroundPosition = 'center';
- let text = document.createElement('span');
- text.textContent = '下载';
- span.appendChild(icon);
- span.appendChild(text);
- downloadButton.appendChild(span);
- buttonBar.appendChild(downloadButton);
- downloadButton = buttonBar.getElementsByClassName('download-button')[0];
- downloadButton.addEventListener('mouseover', function(event) {
- this.querySelector('i').style.backgroundImage = downloadIcon;
- // console.log('over');
- });
- downloadButton.addEventListener('mouseout', function(event) {
- this.querySelector('i').style.backgroundImage = downloadIcon;
- // console.log('out');
- });
- downloadButton.addEventListener('click', async function(event) {
- // console.log('click');
- event.preventDefault();
- const content = this.closest('div.bili-dyn-item__main');
- // console.log(content);
- const opusCard = content.querySelector('[dyn-id]');
- // console.log(opusCard.getAttribute('dyn-id'));
- const dynId = opusCard.getAttribute('dyn-id');
- handleDynamicDownload(dynId);
- /*const list = content.querySelectorAll('div.bili-album__preview__picture,div.preview__picture__img.b-img');
- // console.log(list);
- if (list.length > 0) {
- for (let j = 0; j < list.length; j++) {
- let imgUrl;
- if (list[j].querySelector('img')) {
- imgUrl = list[j].querySelector('img').src.split(/@/)[0];
- } else {
- imgUrl = list[j].style.backgroundImage.split(/"|@/)[1];
- }
- // console.log(imgUrl);
- if (imgUrl.startsWith('//')) {
- imgUrl = 'https:' + imgUrl;
- }
- const imgName = imgUrl.split('/')[imgUrl.split('/').length - 1];
- // console.log(imgName);
- GM_download(imgUrl, imgName);
- }
- }*/
- });
- } else if(GM_getValue('enableVideoDownload', false) && card.getElementsByClassName('bili-tabs__nav__items').length > 0) {
- // console.log('add video dynamic download button');
- const buttonBar = card.getElementsByClassName('bili-tabs__nav__items')[0];
- let downloadButton = document.createElement('div');
- downloadButton.textContent = '下载';
- downloadButton.classList.add('bili-tabs__nav__item');
- downloadButton.addEventListener('click', function(event) {
- // console.log('click');
- event.preventDefault();
- const content = this.closest('div.card');
- // console.log(content);
- const opusCard = content.querySelector('[dyn-id]');
- // console.log(opusCard.getAttribute('dyn-id'));
- const dynId = opusCard.getAttribute('dyn-id');
- handleDynamicDownload(dynId);
- /*const list = content.querySelectorAll('div.bili-album__preview__picture,div.preview__picture__img.b-img');
- // console.log(list);
- if (list.length > 0) {
- for (let j = 0; j < list.length; j++) {
- let imgUrl;
- if (list[j].querySelector('img')) {
- imgUrl = list[j].querySelector('img').src.split(/@/)[0];
- } else {
- imgUrl = list[j].style.backgroundImage.split(/"|@/)[1];
- }
- // console.log(imgUrl);
- if (imgUrl.startsWith('//')) {
- imgUrl = 'https:' + imgUrl;
- }
- const imgName = imgUrl.split('/')[imgUrl.split('/').length - 1];
- // console.log(imgName);
- GM_download(imgUrl, imgName);
- }
- }*/
- });
- buttonBar.appendChild(downloadButton);
- }
- }
- }
- function addPlayPageDownloadButton(buttonBar) {
- let buttonWrap = document.createElement('div');
- buttonWrap.className = 'toolbar-left-item-wrap';
- let button = document.createElement('div');
- button.className = 'video-toolbar-left-item download-button';
- let icon = document.createElement('i');
- icon.className = 'video-toolbar-item-icon';
- icon.style.width = '36px';
- icon.style.height = '36px';
- icon.style.backgroundImage = downloadIcon;
- icon.style.backgroundRepeat = 'no-repeat';
- icon.style.backgroundSize = '100% 100%';
- icon.style.backgroundPosition = 'center';
- let text = document.createElement('span');
- text.textContent = '下载';
- button.appendChild(icon);
- button.appendChild(text);
- buttonWrap.appendChild(button);
- buttonBar.appendChild(buttonWrap);
- button.addEventListener('click', async function(event) {
- // console.log('click');
- event.preventDefault();
- const bvid = window.location.pathname.match(/BV[a-z|A-Z|0-9]{10}/g)[0];
- // console.log(bvid);
- handleVideoDownload(bvid);
- });
- }
- function handleOpusCard(card) {
- // console.log('handleOpusCard');
- if (card.getElementsByClassName('bili-album').length > 0 || card.getElementsByClassName('horizontal-scroll-album').length > 0 || (GM_getValue('enableVideoDownload', false) && card.getElementsByClassName('bili-dyn-card-video').length > 0)) {
- addOpusDownloadButton(card);
- }
- }
- function handleCard(card) {
- // console.log('handleCard');
- if (card.getElementsByClassName('bili-album').length > 0 || card.getElementsByClassName('bili-dyn-gallery').length > 0) {
- // console.log('add download button');
- card.getElementsByClassName('bili-album__preview__picture__img').forEach((img) => {
- img.addEventListener('click', function(event) {
- addDownloadButton(card);
- });
- });
- addDownloadButton(card);
- } else if (GM_getValue('enableVideoDownload', false) && card.getElementsByClassName('bili-dyn-card-video').length > 0 && card.getElementsByClassName('bili-dyn-action like disabled').length === 0) {
- addDownloadButton(card);
- }
- }
- function bodyMouseOver(event) {
- // console.log('bodyMouseOver');
- if (notLoaded) {
- // console.log('not loaded');
- if (document.body.querySelector('div.bili-dyn-list')) {
- // console.log('feed');
- const cards = document.body.querySelectorAll('div.bili-dyn-list div.bili-dyn-item');
- // console.log(cards.length);
- if (cards.length > cardsTotal) {
- // console.log('cards');
- cardsTotal = cards.length;
- // console.log(cardsTotal);
- for (let i = 0; i < cardsTotal; i++) {
- // console.log('card');
- handleCard(cards[i])
- // startIndex += 1;
- }
- if (cardsTotal > 0) {
- notLoaded = false;
- }
- // document.body.removeEventListener('mouseover', bodyMouseOver);
- }
- } else if (location.pathname.startsWith('/v/topic/detail') && document.body.querySelector('div.list-view.topic-list__flow-list')) {
- const cards = document.body.querySelectorAll('div.list-view.topic-list__flow-list div.bili-dyn-item');
- console.log(cards.length);
- if (cards.length > cardsTotal) {
- // console.log('cards');
- cardsTotal = cards.length;
- // console.log(cardsTotal);
- for (let i = 0; i < cardsTotal; i++) {
- // console.log('card');
- handleCard(cards[i])
- // startIndex += 1;
- }
- if (cardsTotal > 0) {
- notLoaded = false;
- }
- document.body.removeEventListener('mouseover', bodyMouseOver);
- }
- } else if(document.body.querySelector('div.bili-dyn-item')) {
- // console.log('found single card');
- const card = document.body.querySelector('div.bili-dyn-item');
- if (card) {
- handleCard(card);
- notLoaded = false;
- // document.body.removeEventListener('mouseover', bodyMouseOver);
- }
- } else if (document.body.querySelector('div.opus-detail')) {
- // console.log('found single opus card');
- const card = document.body.querySelector('div.opus-detail');
- if (card) {
- handleOpusCard(card);
- notLoaded = false;
- // document.body.removeEventListener('mouseover', bodyMouseOver);
- }
- } /* else if (GM_getValue('enableVideoDownload', false) && document.body.querySelector('div.video-toolbar-left-main')) {
- const buttonBar = document.body.querySelector('div.video-toolbar-left-main');
- if (buttonBar) {
- addPlayPageDownloadButton(buttonBar);
- notLoaded = false;
- }
- }*/
- }
- }
- if (location.pathname.startsWith('/v/topic/detail')) document.body.addEventListener('mouseover', bodyMouseOver);
- function showModal(event) {
- // console.log(addDlBtnMode);
- let bg = document.createElement('div');
- bg.style.position = 'fixed';
- bg.style.top = 0;
- bg.style.left = 0;
- bg.style.zIndex = 500;
- bg.style.backgroundColor = 'black';
- bg.style.opacity = 0.5;
- let modal = document.createElement('div');
- document.body.appendChild(bg);
- modal.style.position = 'fixed';
- modal.style.width = '25rem';
- modal.style.height = 'auto';
- modal.style.maxHeight = '80vh';
- modal.style.zIndex = 600;
- modal.style.backgroundColor = 'white';
- modal.style.borderStyle = 'solid';
- modal.style.borderWidth = '0.2rem';
- modal.style.borderRadius = '0.5rem';
- modal.style.borderColor = 'black';
- modal.style.overflowX = 'hidden';
- modal.style.overflowY = 'auto';
- modal.style.fontSize = '1rem';
- let titleBar = document.createElement('div');
- titleBar.textContent = '欢迎使用“下载Bilibili动态页面图片”脚本';
- titleBar.style.width = '100%';
- titleBar.style.textAlign = 'center';
- titleBar.style.backgroundColor = 'black';
- titleBar.style.color = 'white';
- titleBar.style.fontSize = '1rem';
- titleBar.style.fontWeight = 'bold';
- titleBar.style.paddingTop = '0.5rem';
- titleBar.style.paddingBottom = '0.5rem';
- titleBar.style.borderTopLeftRadius = '0.3rem';
- titleBar.style.borderTopRightRadius = '0.3rem';
- modal.appendChild(titleBar);
- let question1 = document.createElement('p');
- question1.style.paddingLeft = '2rem';
- question1.style.paddingRight = '2rem';
- question1.style.marginTop = '1rem';
- question1.style.marginBottom = '1rem';
- let labelPicName = document.createElement('label');
- labelPicName.textContent = '下载图片文件名';
- labelPicName.setAttribute('for', 'dlPicName');
- question1.appendChild(labelPicName);
- let inputPicName = document.createElement('input');
- inputPicName.type = 'text';
- inputPicName.id = 'dlPicName';
- inputPicName.name = 'dlPicName';
- inputPicName.style.marginTop = '0.5rem';
- inputPicName.style.width = 'calc(100% - 1rem)';
- inputPicName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
- inputPicName.style.borderStyle = 'solid';
- inputPicName.style.borderColor = 'gray';
- inputPicName.style.borderWidth = '0.14rem';
- inputPicName.style.borderRadius = '0.2rem';
- inputPicName.defaultValue = GM_getValue('dlPicName', '{original}.{ext}');
- question1.appendChild(inputPicName);
- let PicNameExplain1 = document.createElement('p');
- PicNameExplain1.innerHTML = '{original} - 原文件名\n{username} - UP主名称\n{userid} - UP主ID\n{dynamicid} - 动态id\n{ext} - 文件后缀\n{index} - 图片序号\n{YYYY} {MM} {DD} {HH} {mm} {ss} - 原博发布时\n间的年份、月份、日期、小时、分钟、秒,可\n分开独立使用\n{content} - 动态文字内容(最多前25个字符)';
- PicNameExplain1.style.marginTop = '0.5rem';
- PicNameExplain1.style.marginBottom = '0';
- PicNameExplain1.style.whiteSpace = 'pre';
- PicNameExplain1.style.color = 'gray';
- question1.appendChild(PicNameExplain1);
- /*let PicNameExplain2 = document.createElement('p');
- PicNameExplain2.innerHTML = '<b>注意</b>:启用“打包下载”时,需区分多文件名称,\n避免重复而导致打包后只有一个文件,文件命\n名时,必须包含{original}、{index}中至少一个\n标签。';
- PicNameExplain2.style.marginTop = '0.5rem';
- PicNameExplain2.style.whiteSpace = 'pre';
- PicNameExplain2.style.color = 'gray';
- question1.appendChild(PicNameExplain2);*/
- modal.appendChild(question1);
- let question2 = document.createElement('p');
- question2.style.paddingLeft = '2rem';
- question2.style.paddingRight = '2rem';
- question2.style.marginTop = '1rem';
- question2.style.marginBottom = '0';
- let labelVideoDownload = document.createElement('label');
- labelVideoDownload.setAttribute('for', 'enableVideoDownload');
- labelVideoDownload.textContent = '开启视频下载';
- labelVideoDownload.style.display = 'inline-block';
- labelVideoDownload.style.paddingRight = '0.2rem';
- question2.appendChild(labelVideoDownload);
- let inputVideoDownload = document.createElement('input');
- inputVideoDownload.type = 'checkbox';
- inputVideoDownload.id = 'enableVideoDownload';
- inputVideoDownload.checked = GM_getValue('enableVideoDownload', false);
- question2.appendChild(inputVideoDownload);
- let videoDownloadExplain = document.createElement('p');
- videoDownloadExplain.textContent = '目前Bilibili视频单文件下载最高只支持720P MP4格式。';
- videoDownloadExplain.style.marginTop = '0.5rem';
- videoDownloadExplain.style.marginBottom = '0';
- videoDownloadExplain.style.color = 'gray';
- question2.appendChild(videoDownloadExplain);
- let labelVidName = document.createElement('label');
- labelVidName.textContent = '下载图片文件名';
- labelVidName.setAttribute('for', 'dlVidName');
- labelVidName.style.display = 'block';
- labelVidName.style.marginTop = '0.5rem';
- labelVidName.style.color = GM_getValue('enableVideoDownload', false) ? null : 'gray';
- question2.appendChild(labelVidName);
- let inputVidName = document.createElement('input');
- inputVidName.type = 'text';
- inputVidName.id = 'dlVidName';
- inputVidName.name = 'dlVidName';
- inputVidName.style.marginTop = '0.5rem';
- inputVidName.style.width = 'calc(100% - 1rem)';
- inputVidName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
- inputVidName.style.borderStyle = 'solid';
- inputVidName.style.borderWidth = '0.14rem';
- inputVidName.style.borderRadius = '0.2rem';
- inputVidName.disabled = GM_getValue('enableVideoDownload', false) ? false : true;
- inputVidName.style.borderColor = GM_getValue('enableVideoDownload', false) ? 'gray' : 'lightgray';
- inputVidName.defaultValue = GM_getValue('dlVidName', '{original}.{ext}');
- question2.appendChild(inputVidName);
- let vidNameExplain1 = document.createElement('p');
- vidNameExplain1.innerHTML = '{original} - 原文件名\n{username} - UP主名称\n{userid} - UP主ID\n{bvid} - 视频BVID\n{aid} - 视频AID\n{cid} - 视频CID\n{title} - 视频标题\n{ext} - 文件后缀\n{YYYY} {MM} {DD} {HH} {mm} {ss} - 原博发布时\n间的年份、月份、日期、小时、分钟、秒,可\n分开独立使用\n{content} - 视频简介(最多前25个字符)';
- vidNameExplain1.style.marginTop = '0.5rem';
- vidNameExplain1.style.marginBottom = '0';
- vidNameExplain1.style.whiteSpace = 'pre';
- vidNameExplain1.style.color = 'gray';
- question2.appendChild(vidNameExplain1);
- modal.appendChild(question2);
- /*let question3 = document.createElement('p');
- question3.style.paddingLeft = '2rem';
- question3.style.paddingRight = '2rem';
- question3.style.marginTop = '1rem';
- question3.style.marginBottom = '0';
- let labelZipMode = document.createElement('label');
- labelZipMode.setAttribute('for', 'zipMode');
- labelZipMode.textContent = '打包下载';
- labelZipMode.style.display = 'inline-block';
- labelZipMode.style.paddingRight = '0.2rem';
- labelZipMode.style.color = GM_getValue('ariaMode', false) ? 'gray' : null;
- question3.appendChild(labelZipMode);
- let inputZipMode = document.createElement('input');
- inputZipMode.type = 'checkbox';
- inputZipMode.id = 'zipMode';
- inputZipMode.checked = GM_getValue('zipMode', false);
- inputZipMode.disabled = GM_getValue('ariaMode', false);
- question3.appendChild(inputZipMode);
- let labelPackName = document.createElement('label');
- labelPackName.textContent = '打包文件名';
- labelPackName.setAttribute('for', 'packFileName');
- labelPackName.style.display = 'block';
- labelPackName.style.marginTop = '0.5rem';
- labelPackName.style.color = (GM_getValue('zipMode', false) && !GM_getValue('ariaMode', false)) ? null : 'gray';
- // labelPackName.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
- question3.appendChild(labelPackName);
- let inputPackName = document.createElement('input');
- inputPackName.type = 'text';
- inputPackName.id = 'packFileName';
- inputPackName.name = 'packFileName';
- inputPackName.style.marginTop = '0.5rem';
- inputPackName.style.width = 'calc(100% - 1rem)';
- inputPackName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
- inputPackName.style.borderStyle = 'solid';
- inputPackName.style.borderColor = (GM_getValue('zipMode', false) && !GM_getValue('ariaMode', false)) ? 'gray' : 'lightgray';
- inputPackName.style.borderWidth = '0.14rem';
- inputPackName.style.borderRadius = '0.2rem';
- inputPackName.defaultValue = GM_getValue('packFileName', '{mblogid}.zip');
- // inputPackName.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
- inputPackName.disabled = (GM_getValue('zipMode', false) && !GM_getValue('ariaMode', false)) ? false : true;
- question3.appendChild(inputPackName);
- let filePackExplain = document.createElement('p');
- filePackExplain.textContent = '与“下载文件名称”规则相同,但{original}、{ext}、{index}除外';
- filePackExplain.style.marginTop = '0.5rem';
- filePackExplain.style.marginBottom = '0';
- filePackExplain.style.color = 'gray';
- // filePackExplain.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
- question3.appendChild(filePackExplain);
- modal.appendChild(question3);
- let question4 = document.createElement('p');
- question4.style.paddingLeft = '2rem';
- question4.style.paddingRight = '2rem';
- question4.style.marginTop = '1rem';
- question4.style.marginBottom = '0';
- let labelRetweetMode = document.createElement('label');
- labelRetweetMode.setAttribute('for', 'retweetMode');
- labelRetweetMode.textContent = '单独设置转发微博下载文件名称';
- labelRetweetMode.style.display = 'inline-block';
- labelRetweetMode.style.paddingRight = '0.2rem';
- question4.appendChild(labelRetweetMode);
- let inputRetweetMode = document.createElement('input');
- inputRetweetMode.type = 'checkbox';
- inputRetweetMode.id = 'retweetMode';
- inputRetweetMode.checked = GM_getValue('retweetMode', false);
- question4.appendChild(inputRetweetMode);
- let labelRetweetFileName = document.createElement('label');
- labelRetweetFileName.textContent = '转发微博下载文件名称';
- labelRetweetFileName.setAttribute('for', 'retweetFileName');
- labelRetweetFileName.style.display = 'block';
- labelRetweetFileName.style.marginTop = '0.5rem';
- labelRetweetFileName.style.color = GM_getValue('retweetMode', false) ? null : 'gray';
- // labelPackName.style.display = GM_getValue('retweetMode', false) ? 'block' : 'none';
- question4.appendChild(labelRetweetFileName);
- let inputRetweetFileName = document.createElement('input');
- inputRetweetFileName.type = 'text';
- inputRetweetFileName.id = 'retweetFileName';
- inputRetweetFileName.name = 'retweetFileName';
- inputRetweetFileName.style.marginTop = '0.5rem';
- inputRetweetFileName.style.width = 'calc(100% - 1rem)';
- inputRetweetFileName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
- inputRetweetFileName.style.borderStyle = 'solid';
- inputRetweetFileName.style.borderColor = 'lightgray';
- inputRetweetFileName.style.borderWidth = '0.14rem';
- inputRetweetFileName.style.borderRadius = '0.2rem';
- inputRetweetFileName.defaultValue = GM_getValue('retweetFileName', '{original}.{ext}');
- // inputRetweetFileName.style.display = GM_getValue('retweetMode', false) ? 'block' : 'none';
- inputRetweetFileName.disabled = GM_getValue('retweetMode', false) ? false : true;
- question4.appendChild(inputRetweetFileName);
- let retweetFileNameExplain = document.createElement('p');
- retweetFileNameExplain.textContent = '除“下载文件名”规则外,额外标签如下:\n{re.mblogid} - 转博mblogid\n{re.username} - 转发博主名称\n{re.userid} - 转发博主ID\n{re.uid} - 转博uid\n{re.content} - 转发博文内容(最多前25个字符)\n{re.YYYY} {re.MM} {re.DD} {re.HH} {re.mm} {re.ss}\n - 原博发布时间的年份、月份、日期、小时、\n分钟、秒,可分开独立使用';
- retweetFileNameExplain.style.marginTop = '0.5rem';
- retweetFileNameExplain.style.whiteSpace = 'pre';
- retweetFileNameExplain.style.marginBottom = '0';
- retweetFileNameExplain.style.color = 'gray';
- // retweetFileNameExplain.style.display = GM_getValue('retweetMode', false) ? 'block' : 'none';
- question4.appendChild(retweetFileNameExplain);
- let labelRetweetPackName = document.createElement('label');
- labelRetweetPackName.textContent = '转发微博打包文件名';
- labelRetweetPackName.setAttribute('for', 'retweetPackFileName');
- labelRetweetPackName.style.display = 'block';
- labelRetweetPackName.style.marginTop = '0.5rem';
- labelRetweetPackName.style.color = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? null : 'gray';
- // labelRetweetPackName.style.display = GM_getValue('zipMode', false) ? 'block' : 'none';
- question4.appendChild(labelRetweetPackName);
- let inputRetweetPackName = document.createElement('input');
- inputRetweetPackName.type = 'text';
- inputRetweetPackName.id = 'retweetPackFileName';
- inputRetweetPackName.name = 'retweetPackFileName';
- inputRetweetPackName.style.marginTop = '0.5rem';
- inputRetweetPackName.style.width = 'calc(100% - 1rem)';
- inputRetweetPackName.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
- inputRetweetPackName.style.borderStyle = 'solid';
- inputRetweetPackName.style.borderColor = 'lightgray';
- inputRetweetPackName.style.borderWidth = '0.14rem';
- inputRetweetPackName.style.borderRadius = '0.2rem';
- inputRetweetPackName.defaultValue = GM_getValue('retweetPackFileName', '{mblogid}.zip');
- // inputRetweetPackName.style.display = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? 'block' : 'none';
- inputRetweetPackName.disabled = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? false : true;
- question4.appendChild(inputRetweetPackName);
- let retweetPackExplain = document.createElement('p');
- retweetPackExplain.textContent = '与“转发微博下载文件名称”规则相同,但{original}、{ext}、{index}除外';
- retweetPackExplain.style.marginTop = '0.5rem';
- retweetPackExplain.style.marginBottom = '0';
- retweetPackExplain.style.color = 'gray';
- // retweetPackExplain.style.display = (GM_getValue('zipMode', false) && GM_getValue('retweetMode', false) && !GM_getValue('ariaMode', false)) ? 'block' : 'none';
- question4.appendChild(retweetPackExplain);
- modal.appendChild(question4);
- let question5 = document.createElement('p');
- question5.style.paddingLeft = '2rem';
- question5.style.paddingRight = '2rem';
- question5.style.marginTop = '1rem';
- question5.style.marginBottom = '0';
- let labelAriaMode = document.createElement('label');
- labelAriaMode.setAttribute('for', 'ariaMode');
- labelAriaMode.textContent = '使用Aria2c远程下载';
- labelAriaMode.style.display = 'inline-block';
- labelAriaMode.style.paddingRight = '0.2rem';
- question5.appendChild(labelAriaMode);
- let inputAriaMode = document.createElement('input');
- inputAriaMode.type = 'checkbox';
- inputAriaMode.id = 'ariaMode';
- inputAriaMode.checked = GM_getValue('ariaMode', false);
- question5.appendChild(inputAriaMode);
- let ariaModeExplain = document.createElement('p');
- ariaModeExplain.textContent = '使用此方式下载,无法使用打包功能,无法在页面右下角显示下载进度和结果。';
- ariaModeExplain.style.marginTop = '0.5rem';
- ariaModeExplain.style.marginBottom = '0';
- ariaModeExplain.style.color = 'gray';
- question5.appendChild(ariaModeExplain);
- let labelAriaRpcUrl = document.createElement('label');
- labelAriaRpcUrl.textContent = 'RPC接口地址';
- labelAriaRpcUrl.setAttribute('for', 'ariaRpcUrl');
- labelAriaRpcUrl.style.display = 'block';
- labelAriaRpcUrl.style.marginTop = '0.5rem';
- labelAriaRpcUrl.style.color = GM_getValue('ariaMode', false) ? null : 'gray';
- question5.appendChild(labelAriaRpcUrl);
- let inputAriaRpcUrl = document.createElement('input');
- inputAriaRpcUrl.type = 'text';
- inputAriaRpcUrl.id = 'ariaRpcUrl';
- inputAriaRpcUrl.name = 'ariaRpcUrl';
- inputAriaRpcUrl.style.marginTop = '0.5rem';
- inputAriaRpcUrl.style.width = 'calc(100% - 1rem)';
- inputAriaRpcUrl.style.padding = '0.1rem 0.2rem 0.1rem 0.2rem';
- inputAriaRpcUrl.style.borderStyle = 'solid';
- inputAriaRpcUrl.style.borderColor = 'lightgray';
- inputAriaRpcUrl.style.borderWidth = '0.14rem';
- inputAriaRpcUrl.style.borderRadius = '0.2rem';
- inputAriaRpcUrl.defaultValue = GM_getValue('ariaRpcUrl', 'http://localhost:6800/jsonrpc');
- // inputAriaRpcUrl.style.display = GM_getValue('ariaMode', false) ? 'block' : 'none';
- inputAriaRpcUrl.disabled = GM_getValue('ariaMode', false) ? false : true;
- question5.appendChild(inputAriaRpcUrl);
- let inputAriaExplain = document.createElement('p');
- inputAriaExplain.textContent = '如果接口地址不是localhost,需手动将地址添加到XHR白名单。';
- inputAriaExplain.style.marginTop = '0.5rem';
- inputAriaExplain.style.marginBottom = '0';
- inputAriaExplain.style.color = 'gray';
- question5.appendChild(inputAriaExplain);
- modal.appendChild(question5);
- inputRetweetMode.addEventListener('change', function(event) {
- if (event.currentTarget.checked) {
- // labelRetweetFileName.style.display = 'block';
- // inputRetweetFileName.style.display = 'block';
- // retweetFileNameExplain.style.display = 'block';
- inputRetweetFileName.disabled = false;
- labelRetweetFileName.style.color = null;
- inputRetweetFileName.style.borderColor = 'gray';
- } else {
- // labelRetweetFileName.style.display = 'none';
- // inputRetweetFileName.style.display = 'none';
- // retweetFileNameExplain.style.display = 'none';
- inputRetweetFileName.disabled = true;
- labelRetweetFileName.style.color = 'gray';
- inputRetweetFileName.style.borderColor = 'lightgray';
- }
- if (event.currentTarget.checked && inputZipMode.checked && !inputAriaMode.checked) {
- inputRetweetPackName.disabled = false;
- labelRetweetPackName.style.color = null;
- inputRetweetPackName.style.borderColor = 'gray';
- } else {
- inputRetweetPackName.disabled = true;
- labelRetweetPackName.style.color = 'gray';
- inputRetweetPackName.style.borderColor = 'lightgray';
- }
- });
- inputZipMode.addEventListener('change', function(event) {
- if (event.currentTarget.checked) {
- // labelPackName.style.display = 'block';
- // inputPackName.style.display = 'block';
- // filePackExplain.style.display = 'block';
- inputPackName.disabled = false;
- labelPackName.style.color = null;
- inputPackName.style.borderColor = 'gray';
- } else {
- // labelPackName.style.display = 'none';
- // inputPackName.style.display = 'none';
- // filePackExplain.style.display = 'none';
- inputPackName.disabled = true;
- labelPackName.style.color = 'gray';
- inputPackName.style.borderColor = 'lightgray';
- }
- if (event.currentTarget.checked && inputRetweetMode.checked) {
- inputRetweetPackName.disabled = false;
- labelRetweetPackName.style.color = null;
- inputRetweetPackName.style.borderColor = 'gray';
- } else {
- inputRetweetPackName.disabled = true;
- labelRetweetPackName.style.color = 'gray';
- inputRetweetPackName.style.borderColor = 'lightgray';
- }
- });
- inputAriaMode.addEventListener('change', function(event) {
- if (event.currentTarget.checked) {
- // labelAriaRpcUrl.style.display = 'block';
- // inputAriaRpcUrl.style.display = 'block';
- inputAriaRpcUrl.disabled = false;
- labelAriaRpcUrl.style.color = null;
- inputAriaRpcUrl.style.borderColor = 'gray';
- inputZipMode.disabled = true;
- labelZipMode.style.color = 'gray';
- } else {
- // labelAriaRpcUrl.style.display = 'none';
- // inputAriaRpcUrl.style.display = 'none';
- inputAriaRpcUrl.disabled = true;
- labelAriaRpcUrl.style.color = 'gray';
- inputAriaRpcUrl.style.borderColor = 'lightgray';
- inputZipMode.disabled = false;
- labelZipMode.style.color = null;
- }
- if (!event.currentTarget.checked && inputZipMode.checked) {
- inputPackName.disabled = false;
- labelPackName.style.color = null;
- inputPackName.style.borderColor = 'gray';
- } else {
- inputPackName.disabled = true;
- labelPackName.style.color = 'gray';
- inputPackName.style.borderColor = 'lightgray';
- }
- if (!event.currentTarget.checked && inputZipMode.checked && inputRetweetMode.checked) {
- inputRetweetPackName.disabled = false;
- labelRetweetPackName.style.color = null;
- inputRetweetPackName.style.borderColor = 'gray';
- } else {
- inputRetweetPackName.disabled = true;
- labelRetweetPackName.style.color = 'gray';
- inputRetweetPackName.style.borderColor = 'lightgray';
- }
- });*/
- inputVideoDownload.addEventListener('change', function(event) {
- if (event.currentTarget.checked) {
- // labelRetweetFileName.style.display = 'block';
- // inputRetweetFileName.style.display = 'block';
- // retweetFileNameExplain.style.display = 'block';
- inputVidName.disabled = false;
- labelVidName.style.color = null;
- inputVidName.style.borderColor = 'gray';
- } else {
- // labelRetweetFileName.style.display = 'none';
- // inputRetweetFileName.style.display = 'none';
- // retweetFileNameExplain.style.display = 'none';
- inputVidName.disabled = true;
- labelVidName.style.color = 'gray';
- inputVidName.style.borderColor = 'lightgray';
- }
- });
- let okButton = document.createElement('button');
- okButton.textContent = '确定';
- okButton.style.paddingTop = '0.5rem';
- okButton.style.paddingBottom = '0.5rem';
- okButton.style.margin = '2rem';
- okButton.style.backgroundColor = 'darkblue';
- okButton.style.color = 'white';
- okButton.style.fontSize = '1.5rem';
- okButton.style.fontWeight = 'bold';
- okButton.style.width = '21rem';
- okButton.style.borderStyle = 'solid';
- okButton.style.borderRadius = '0.5rem';
- okButton.style.borderColor = 'black';
- okButton.style.borderWidth = '0.2rem';
- okButton.addEventListener('mouseover', function(event) {
- okButton.style.backgroundColor = 'blue';
- });
- okButton.addEventListener('mouseout', function(event) {
- okButton.style.backgroundColor = 'darkblue';
- });
- okButton.addEventListener('mousedown', function(event) {
- okButton.style.backgroundColor = 'darkblue';
- });
- okButton.addEventListener('mouseover', function(event) {
- okButton.style.backgroundColor = 'blue';
- });
- function resizeWindow(event) {
- // console.log('resize');
- bg.style.width = document.documentElement.clientWidth.toString() + 'px';
- bg.style.height = document.documentElement.clientHeight.toString() + 'px';
- modal.style.top = (( document.documentElement.clientHeight - modal.offsetHeight ) / 2).toString() + 'px';
- modal.style.left = (( document.documentElement.clientWidth - modal.offsetWidth ) / 2).toString() + 'px';
- }
- okButton.addEventListener('click', function(event) {
- /*if (document.getElementById('zipMode').checked && !document.getElementById('dlPicName').value.includes('{original}') && !document.getElementById('dlPicName').value.includes('{index}')) {
- alert('启用“打包下载”时,需区分多文件名称,避免重复而导致打包后只有一个文件,文件命名时,必须包含{original}、{index}中至少一个标签。');
- document.getElementById('dlPicName').focus();
- return;
- }*/
- let refreshFlag = false;
- if (document.getElementById('enableVideoDownload').checked !== GM_getValue('enableVideoDownload', false)) {
- refreshFlag = true;
- }
- GM_setValue('dlPicName', document.getElementById('dlPicName').value);
- GM_setValue('enableVideoDownload', document.getElementById('enableVideoDownload').checked);
- GM_setValue('dlVidName', document.getElementById('dlVidName').value);
- // GM_setValue('retweetMode', document.getElementById('retweetMode').checked);
- // GM_setValue('retweetFileName', document.getElementById('retweetFileName').value);
- // GM_setValue('zipMode', document.getElementById('zipMode').checked);
- // GM_setValue('packFileName', document.getElementById('packFileName').value);
- // GM_setValue('retweetPackFileName', document.getElementById('retweetPackFileName').value);
- // GM_setValue('ariaMode', document.getElementById('ariaMode').checked);
- // GM_setValue('ariaRpcUrl', document.getElementById('ariaRpcUrl').value);
- GM_setValue('isSet', settingVersion);
- if (refreshFlag) {
- alert('已' + (document.getElementById('enableVideoDownload').checked ? '开启' : '关闭') + '视频下载功能,将在页面刷新后生效。');
- location.reload();
- }
- window.removeEventListener('resize', resizeWindow);
- document.body.removeChild(modal);
- document.body.removeChild(bg);
- });
- modal.appendChild(okButton);
- document.body.appendChild(modal);
- /*bg.addEventListener('click', function(event) {
- document.body.removeChild(modal);
- document.body.removeChild(bg);
- window.removeEventListener('resize', resizeWindow);
- });*/
- resizeWindow();
- window.addEventListener('resize', resizeWindow);
- }
-
- if(GM_getValue('isSet', null) !== settingVersion) {
- showModal();
- }
- bodyMouseOver();
- new MutationObserver((mutationList, observer) => {
- for (const mutation of mutationList) {
- // console.log(mutation);
- if (mutation.type === 'childList') {
- // if (!['svg'].includes(mutation.target.tagName)) console.log(mutation.target);
- /*for (const node of mutation.addedNodes) {
- // console.log(node.nodeType, node);
- if (node.nodeType === 1 && Object.keys(mutation.target.getElementsByClassName('video-like')).length > 0) {
- console.log(mutation.target, node);
- }
- }*/
- if (mutation.target.tagName === 'DIV' && ['bili-dyn-list__items', 'content'].includes(mutation.target.className)) {
- // console.log(mutation.addedNodes);
- for (const node of mutation.addedNodes) {
- // console.log(node);
- handleCard(node);
- }
- } else if (mutation.target.tagName === 'DIV' && mutation.target.parentNode.className === 'list-view topic-list__flow-list') {
- // vconsole.log(mutation.addedNodes);
- for (const node of mutation.addedNodes) {
- // console.log(node);
- handleCard(node);
- }
- } else if (GM_getValue('enableVideoDownload', false) && mutation.target.tagName === 'BODY') {
- for (const node of mutation.addedNodes) {
- if (node.nodeType === 1 && node.tagName === 'DIV' && node.classList.contains('lt-row')) {
- // console.log(mutation);
- const buttonBar = document.body.querySelector('div.video-toolbar-left-main');
- if (buttonBar && !buttonBar.querySelector('div.download-button')) {
- // console.log(mutation);
- addPlayPageDownloadButton(buttonBar);
- }
- }
- }
- }
- }
- }
- }).observe(document.body, { attributes: false, childList: true, subtree: true });
-
- let settingButton = document.createElement('button');
- settingButton.textContent = '设置';
- settingButton.style.position = 'fixed';
- settingButton.style.top = '4rem';
- settingButton.style.left = '0rem';
- settingButton.style.fontSize = '0.7rem';
- settingButton.style.backgroundColor = 'gray';
- settingButton.style.color = 'white';
- settingButton.style.borderWidth = '0.2rem';
- settingButton.style.borderStyle = 'solid';
- settingButton.style.borderRadius = '0.5rem';
- settingButton.style.borderColor = 'lightgrey';
- settingButton.style.zIndex = 400;
- settingButton.style.paddingLeft = '1rem';
- settingButton.style.paddingRight = '1rem';
- settingButton.style.paddingTop = '0.2rem';
- settingButton.style.paddingBottom = '0.2rem';
- settingButton.addEventListener('mouseover', function(event) {
- settingButton.style.backgroundColor = 'darkgray';
- settingButton.style.color = 'black';
- });
- settingButton.addEventListener('mouseout', function(event) {
- settingButton.style.backgroundColor = 'gray';
- settingButton.style.color = 'white';
- });
- settingButton.addEventListener('mousedown', function(event) {
- settingButton.style.backgroundColor = 'gray';
- settingButton.style.color = 'white';
- });
- settingButton.addEventListener('mouseup', function(event) {
- settingButton.style.backgroundColor = 'darkgray';
- settingButton.style.color = 'black';
- });
- settingButton.addEventListener('click', showModal);
- document.body.appendChild(settingButton);
- GM_registerMenuCommand('设置', showModal, "0");
- })();