|
// ==UserScript== |
|
// @name Coub Likes Downloader |
|
// @version 0.1 |
|
// @description try to take over the world! |
|
// @author Grishka |
|
// @match https://coub.com/* |
|
// @grant none |
|
// ==/UserScript== |
|
|
|
// Добавляем кнопку в шапку |
|
var hnav=document.querySelector(".header__nav .inline--container"); |
|
if(!hnav){ |
|
console.log("no button!"); |
|
return; |
|
} |
|
var jsZipEl; |
|
var dlButtonLi=document.createElement("li"); |
|
dlButtonLi.className="nav__item"; |
|
var dlButtonA=document.createElement("a"); |
|
dlButtonA.className="nav__item__inner"; |
|
dlButtonA.innerText="Скачать лайки!"; |
|
dlButtonA.onclick=function(){startLikesDownload(event.altKey);}; |
|
dlButtonLi.appendChild(dlButtonA); |
|
hnav.appendChild(dlButtonLi); |
|
|
|
var dirHandle; |
|
var totalPages; |
|
var downloadedCount=0; |
|
var errorCount=0; |
|
var dlStatus; |
|
var currentPage; |
|
var askedPermission=false; |
|
|
|
// Мякотка |
|
async function startLikesDownload(askForPage){ |
|
ModalPopup.show({content: '<div id="dlStatus"></div><hr/><div>Не закрывайте эту валкдку!</div>', type: 'simple', classes: ''}); |
|
dlStatus=$("#dlStatus"); |
|
dlStatus.text("Инициализация..."); |
|
if(!jsZipEl){ |
|
jsZipEl=document.createElement("script"); |
|
jsZipEl.src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"; |
|
jsZipEl.onload=async function(){actuallyStartDownload(askForPage);}; |
|
document.body.appendChild(jsZipEl); |
|
}else{ |
|
actuallyStartDownload(askForPage); |
|
} |
|
} |
|
|
|
async function actuallyStartDownload(askForPage){ |
|
dirHandle=await window.showDirectoryPicker(); |
|
dirHandle.requestPermission({writable: true}); |
|
|
|
downloadLikesPage(askForPage ? parseInt(window.prompt("Начать со страницы")) : 1); |
|
} |
|
|
|
async function downloadLikesPage(page){ |
|
currentPage=page; |
|
var _resp=await fetch("https://coub.com/api/v2/timeline/likes?all=true&order_by=date&page="+page); |
|
var resp=await _resp.json(); |
|
if(!totalPages){ |
|
totalPages=resp.total_pages; |
|
} |
|
var promises=[]; |
|
for(var i=0;i<resp.coubs.length;i++){ |
|
var coub=resp.coubs[i]; |
|
if(!askedPermission){ // при первой записи файла вылезет окно с запросом на доступ, без await будет ошибка |
|
await downloadOneCoub(coub); |
|
askedPermission=true; |
|
}else{ |
|
promises.push(downloadOneCoub(coub)); |
|
} |
|
} |
|
await Promise.all(promises); |
|
if(page<totalPages){ |
|
downloadLikesPage(page+1); |
|
}else{ |
|
dlStatus.text("Скачивание завершено. Всего скачано: "+downloadedCount+", ошибок: "+errorCount); |
|
} |
|
} |
|
|
|
async function downloadOneCoub(coub){ |
|
try{ |
|
var zip=new JSZip(); |
|
zip.file("coub.json", JSON.stringify(coub)); |
|
var files=coub.file_versions.html5; |
|
var videoUrl=(files.video.higher || files.video.high || files.video.med).url; |
|
var audioUrl=files.audio ? (files.audio.high || files.audio.med).url : null; |
|
|
|
var videoResp=await fetch(videoUrl); |
|
if(audioUrl){ // у некоторых коубов нет звука, копирасты-с |
|
var audioResp=await fetch(audioUrl); |
|
zip.file(fileNameFromURL(audioUrl), await audioResp.blob()); |
|
} |
|
zip.file(fileNameFromURL(videoUrl), await videoResp.blob()); |
|
|
|
var zipData=await zip.generateAsync({type: "blob"}); |
|
var handle=await dirHandle.getFileHandle(((currentPage-1)*10+coub.position_on_page-1)+"_"+coub.permalink+".coub.zip", {create: true}); |
|
var stream=await handle.createWritable(); |
|
var writer=await stream.getWriter(); |
|
await writer.write(zipData); |
|
await writer.close(); |
|
downloadedCount++; |
|
}catch(e){ |
|
console.log(e); |
|
errorCount++; |
|
} |
|
dlStatus.html("Скачано "+downloadedCount+" из примерно "+(totalPages*10)+"<br/>Ошибок: "+errorCount); |
|
} |
|
|
|
function fileNameFromURL(url){ |
|
var parts=url.split("/"); |
|
return parts[parts.length-1]; |
|
} |
Не могли бы вы сделать версию для скачки одиночного (просматриваемого) куба?