rutube: add support for shorts and yappy (#471)

* rutube: add support for shorts and yappy

* tests: add rutube yappy and shorts tests

Closes #465
Closes #466
This commit is contained in:
wukko 2024-04-29 21:36:35 +06:00 committed by GitHub
parent 8f27c86a43
commit f20f87bd1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 56 additions and 9 deletions

View file

@ -151,6 +151,7 @@ export default async function(host, patternMatch, url, lang, obj) {
case "rutube":
r = await rutube({
id: patternMatch.id,
yappyId: patternMatch.yappyId,
quality: obj.vQuality,
isAudioOnly: isAudioOnly
});

View file

@ -1,18 +1,47 @@
import HLS from 'hls-parser';
import { maxVideoDuration } from "../../config.js";
import { cleanString } from '../../sub/utils.js';
async function requestJSON(url) {
try {
const r = await fetch(url);
return await r.json();
} catch {}
}
export default async function(obj) {
if (obj.yappyId) {
let yappy = await requestJSON(
`https://rutube.ru/pangolin/api/web/yappy/yappypage/?client=wdp&videoId=${obj.yappyId}&page=1&page_size=15`
)
let yappyURL = yappy?.results?.find(r => r.id === obj.yappyId)?.link;
if (!yappyURL) return { error: 'ErrorEmptyDownload' };
return {
urls: yappyURL,
filename: `rutube_yappy_${obj.yappyId}.mp4`,
audioFilename: `rutube_yappy_${obj.yappyId}_audio`
}
}
let quality = obj.quality === "max" ? "9000" : obj.quality;
let play = await fetch(`https://rutube.ru/api/play/options/${obj.id}/?no_404=true&referer&pver=v2`).then((r) => { return r.json() }).catch(() => { return false });
let play = await requestJSON(
`https://rutube.ru/api/play/options/${obj.id}/?no_404=true&referer&pver=v2`
)
if (!play) return { error: 'ErrorCouldntFetch' };
if ("hls" in play.live_streams) return { error: 'ErrorLiveVideo' };
if (!play.video_balancer || play.detail) return { error: 'ErrorEmptyDownload' };
if (play.detail || !play.video_balancer) return { error: 'ErrorEmptyDownload' };
if (play.live_streams?.hls) return { error: 'ErrorLiveVideo' };
if (play.duration > maxVideoDuration)
return { error: ['ErrorLengthLimit', maxVideoDuration / 60000] };
let m3u8 = await fetch(play.video_balancer.m3u8)
.then(r => r.text())
.catch(() => {});
if (play.duration > maxVideoDuration) return { error: ['ErrorLengthLimit', maxVideoDuration / 60000] };
let m3u8 = await fetch(play.video_balancer.m3u8).then((r) => { return r.text() }).catch(() => { return false });
if (!m3u8) return { error: 'ErrorCouldntFetch' };
m3u8 = HLS.parse(m3u8).variants.sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
@ -21,6 +50,7 @@ export default async function(obj) {
if (Number(quality) < bestQuality.resolution.height) {
bestQuality = m3u8.find((i) => (Number(quality) === i["resolution"].height));
}
let fileMetadata = {
title: cleanString(play.title.trim()),
artist: cleanString(play.author.name.trim()),
@ -31,7 +61,7 @@ export default async function(obj) {
isM3U8: true,
filenameAttributes: {
service: "rutube",
id: play.id,
id: obj.id,
title: fileMetadata.title,
author: fileMetadata.artist,
resolution: `${bestQuality.resolution.width}x${bestQuality.resolution.height}`,

View file

@ -110,7 +110,7 @@
"rutube": {
"alias": "rutube videos",
"tld": "ru",
"patterns": ["video/:id", "play/embed/:id"],
"patterns": ["video/:id", "play/embed/:id", "shorts/:id", "yappy/:yappyId"],
"enabled": true
},
"dailymotion": {

View file

@ -19,7 +19,7 @@ export const testers = {
patternMatch.sub?.length <= 22 && patternMatch.id?.length <= 10,
"rutube": (patternMatch) =>
patternMatch.id?.length === 32,
patternMatch.id?.length === 32 || patternMatch.yappyId?.length === 32,
"soundcloud": (patternMatch) =>
(patternMatch.author?.length <= 255 && patternMatch.song?.length <= 255)

View file

@ -1061,6 +1061,22 @@
"code": 200,
"status": "stream"
}
}, {
"name": "yappy",
"url": "https://rutube.ru/yappy/f1771e86294748eea8ecb2ac88e55740/",
"params": {},
"expected": {
"code": 200,
"status": "stream"
}
}, {
"name": "shorts",
"url": "https://rutube.ru/shorts/935c1afafd0e7d52836d671967d53dac/",
"params": {},
"expected": {
"code": 200,
"status": "stream"
}
}, {
"name": "vertical video (isAudioOnly)",
"url": "https://rutube.ru/video/18a281399b96f9184c647455a86f6724/",