Skip to content

Instantly share code, notes, and snippets.

@grishka
Last active March 18, 2024 23:20
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save grishka/2efec8715ebf3c0aca2d0dbf9b703769 to your computer and use it in GitHub Desktop.
Save grishka/2efec8715ebf3c0aca2d0dbf9b703769 to your computer and use it in GitHub Desktop.

Юзерскрипт для скачивания лайкнутых коубов с coub.com

Работает только в браузерах на основе Chromium: Chrome, Vivaldi, Opera, Brave... В Safari и Firefox не работает (там нет API для доступа к локальным файлам).

В отличие от других скачивалок, скачиваются оригинальные данные без конвертации: отдельно видео и отдельно звук.

Как этим пользоваться:

  1. Установите через расширение для юзерскриптов, например, Tampermonkey.
  2. Зайдите на coub.com
  3. В шапке появится ссылка "Скачать лайки", нажмите её
  4. Откроется окно выбора папки. Создайте новую папку, куда будут скачаны коубы, и выберите её.
  5. Будет два запроса на доступ к файловой системе, сначала на получение списка файлов в папке, затем на запись в неё. Разрешите оба.
  6. И в общем-то всё, дальше оно само

Формат .coub.zip

Zip-архив. Внутри 3 файла:

  • coub.json - оригинальный объект коуба со всеми метаданными, как пришёл с сервера
  • *.mp3 - звуковая дорожка (может отсутствовать по причине копирастии)
  • *.mp4 - видео без звука, предполагается проигрывать зацикленным

И чем это смотреть?

¯\_(ツ)_/¯

Пока нечем. У этого скрипта цель скачать всё как есть, без конвертации, пока скачать ещё можно. Плеер будет когда-нибудь потом.

Вот этим плеером. Им не обязательно пользоваться с моего сайта, можно сохранить страницу средствами браузера и открывать в оффлайне.

// ==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];
}
@iav
Copy link

iav commented Mar 18, 2024

Не могли бы вы сделать версию для скачки одиночного (просматриваемого) куба?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment