// ==UserScript==
// @name Forza图库图片批量下载
// @namespace https://space.bilibili.com/68391#!/
// @version 1.0
// @description 批量下载Forza玩家图库的图片
// @author 剧情帝
// @match https://www.forzamotorsport.net/*/gallery/*
// @grant GM_registerMenuCommand
// @grant GM_download
// @grant GM_addStyle
// @grant GM_notification
// ==/UserScript==
(function() {
'use strict';
let $photoArr, $photos, $selectModeBtn, $selectAllBtn, $downloadBtn, $resetBtn;
let selectMode = false, downloading = false;
let total_selected = 0;
GM_registerMenuCommand('选择并下载图片', InitSelect);
function InitSelect(){
$photos = $("#photos").addClass('select_mode');
$photoArr = $(".photo", $photos);
if($photoArr.length === 0){
alert('请在图片列表加载完毕后重试');
return;
}
selectMode = true;
GM_addStyle((`
.photo .media_element {
display: flex;
}
.photos.select_mode .photo .media_element a {
/*pointer-events: none;*/
}
.photo .image {
position: relative;
}
.photo .selectbox{
display: none;
}
.photos.select_mode .photo .selectbox {
display: flex;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
font-size: 20px;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.3);
color: #fff;
}
.photos.select_mode .photo .selectbox:hover{
background-color: unset;
font-size: 0;
}
.photos.select_mode .photo .selectbox.selected{
font-size: 0;
background-color: unset;
border: 5px solid #00a1d6;
}
.photos.select_mode .photo .selectbox.downloading{
font-size: 20px;
background-color: rgba(0, 0, 0, 0.3);
border: 5px solid #ff0;
}
.photos.select_mode .photo .selectbox.downloaded{
font-size: 20px;
background-color: rgba(0, 0, 0, 0.3);
border: 5px solid #0f0;
}
.photos.select_mode .photo .selectbox.failed{
font-size: 20px;
background-color: rgba(0, 0, 0, 0.3);
border: 5px solid #f00;
}
.tool_box{
position:fixed;
right: 10px;
top:40%;
background-color: #cf4335;
padding: 10px;
border-radius: 3px;
max-width: 100px;
}
.tool_box #mode, .tool_box label{
vertical-align: middle;
}
.tool_box input[type="button"]{
display: block;
width: 70px;
margin: 10px auto auto auto;
}
.tool_box p{
width: 100%;
text-align: center;
margin-top: 10px;
}
`));
let $toolBox = $(`<div class="tool_box">
<input id="mode" type="checkbox" checked="checked"><label for="mode">选择模式</label>
<input id="select_all" type="button" value="选择全部">
<input id="download" type="button" value="下载">
<input id="reset" type="button" value="重置" disabled="disabled">
<p>在选择模式下,直接左键点击图片来选择,中键单击可以在新标签页查看图像</p>
</div>
`);
$selectModeBtn = $("#mode", $toolBox);
$selectAllBtn = $("#select_all", $toolBox);
$downloadBtn = $("#download", $toolBox);
$resetBtn = $("#reset", $toolBox);
$("body").append($toolBox);
$photoArr.each((index, photo)=>{
let $photo = $(photo);
let $select = $('<div class="selectbox">未选择</div>');
$("a", $photo).click(()=>{
return !selectMode; //图片选择模式下阻止点击图片的默认行为
});
$select.click( SelectPic);
$('.image', $photo).append($select);
});
//“选择模式”按钮功能
$selectModeBtn.change(()=>{
selectMode = !selectMode;
if(selectMode){
$photos.addClass('select_mode');
$selectAllBtn.prop('disabled', false);
$downloadBtn.prop('disabled', false);
}
else{
$photos.removeClass('select_mode');
$selectAllBtn.prop('disabled', true);
$downloadBtn.prop('disabled', true);
}
});
//全选按钮功能
$selectAllBtn.click(()=>{
if($selectAllBtn.val() === '选择全部'){
$(".selectbox", $photoArr).addClass('selected');
total_selected = $photoArr.length;
}
else if($selectAllBtn.val() === '取消全选'){
$(".selectbox", $photoArr).removeClass('selected');
total_selected = 0;
}
AlterSelectAllButton();
});
//下载按钮功能
$downloadBtn.click(DownloadImgs);
//重置按钮功能
$resetBtn.click(()=>{
downloading = false;
$selectModeBtn.prop('disabled', false);
$selectAllBtn.prop('disabled', false).val('选择全部');
$downloadBtn.prop('disabled', false);
$resetBtn.prop('disabled', true);
total_selected = 0;
$(".selectbox.selected", $photos).removeClass('selected downloading downloaded failed').text('未选择');
});
}
function SelectPic() {
if(downloading)
return;
let $selectBox = $(this);
// $selectBox.toggleClass('selected');
if(!$selectBox.hasClass('selected')){
$selectBox.addClass('selected');
total_selected++;
}
else{
$selectBox.removeClass('selected');
total_selected--;
}
AlterSelectAllButton();
}
function AlterSelectAllButton() {
$selectAllBtn.val( (total_selected === $photoArr.length) ? '取消全选' : '选择全部' );
}
function DownloadImgs() {
if(total_selected === 0){
alert('您没有选中任何图片!');
return;
}
let choose = confirm(`注意:请不要在浏览器下载设置中选中 “下载前询问每个文件的保存位置” !!!否则会弹出多个对话框。\n\n已选中 ${total_selected} 张图片,点击“是”开始下载`);
if(choose === false)
return;
$selectModeBtn.prop('disabled', true);
$selectAllBtn.prop('disabled', true);
$downloadBtn.prop('disabled', true);
downloading = true;
let index = 0;
let $selectedBoxs = $(".selectbox.selected", $photos);
let total_downloaded = 0, total_failed = 0;
DownloadImg( index);
//递归下载
function DownloadImg( index) {
if(index >= total_selected){
//下载全部结束
GM_notification( (total_downloaded === total_selected) ? '所有图片下载成功!' : `下载结束,成功下载${total_downloaded}张图片,${total_failed}张失败` );
console.log( (total_downloaded === total_selected) ? '所有图片下载成功!' : `下载结束,成功下载${total_downloaded}张图片,${total_failed}张失败` );
$resetBtn.prop('disabled', false);
return;
}
let $selectedBox = $selectedBoxs.eq(index);
let $img = $selectedBox.prev('img');
let imgSrc = $img.attr('src').replace('/thumbnail', '');
let imgName = `${$img.attr('title')} ${imgSrc.split('/').pop()}.jpg`;
console.log(`第${index+1}张图片${imgName}开始下载`);
$selectedBox.addClass('downloading').text('正在下载');
GM_download({
url: imgSrc,
name: imgName,
onload: () => {
console.info(`第${index+1}张图片${imgName}下载成功`);
$selectedBox.removeClass('downloading').addClass('downloaded').text('下载完成');
total_downloaded++;
setTimeout(() => {
DownloadImg(index + 1);
}, 3000);
},
onerror: () => {
console.error(`第${index+1}张图片${imgName}下载失败`);
$selectedBox.removeClass('downloading').addClass('failed').text('下载失败');
total_failed++;
setTimeout(() => {
DownloadImg(index + 1);
}, 3000);
},
ontimeout: () => {
console.error(`第${index+1}张图片${imgName}下载超时`);
$selectedBox.removeClass('downloading').addClass('failed').text('下载超时');
total_failed++;
setTimeout(() => {
DownloadImg(index + 1);
}, 3000);
}
});
}
}
})();