remove vods

there's no point in downloading entire streams. people can clip what they need and download that instead!
This commit is contained in:
wukko 2023-09-16 17:58:43 +06:00
parent f7247b87f0
commit ad8a9c454d
5 changed files with 5 additions and 110 deletions

View file

@ -24,7 +24,7 @@ Paste the link, get the video, move on. It's that simple. Just how it should be.
| Streamable | ✅ | ✅ | ✅ | | | Streamable | ✅ | ✅ | ✅ | |
| TikTok | ✅ | ✅ | ✅ | Supports downloads of: videos with or without watermark, images from slideshow without watermark, full (original) audios. | | TikTok | ✅ | ✅ | ✅ | Supports downloads of: videos with or without watermark, images from slideshow without watermark, full (original) audios. |
| Tumblr | ✅ | ✅ | ✅ | Support for audio file downloads. | | Tumblr | ✅ | ✅ | ✅ | Support for audio file downloads. |
| Twitch Clips & Videos | ✅ | ✅ | ✅ | | | Twitch Clips | ✅ | ✅ | ✅ | |
| Twitter/X * | ✅ | ✅ | ✅ | Ability to pick what to save from multi-media tweets. | | Twitter/X * | ✅ | ✅ | ✅ | Ability to pick what to save from multi-media tweets. |
| Vimeo | ✅ | ✅ | ✅ | Audio downloads are only available for dash files. | | Vimeo | ✅ | ✅ | ✅ | Audio downloads are only available for dash files. |
| Vine Archive | ✅ | ✅ | ✅ | | | Vine Archive | ✅ | ✅ | ✅ | |

View file

@ -125,7 +125,6 @@ export default async function (host, patternMatch, url, lang, obj) {
break; break;
case "twitch": case "twitch":
r = await twitch({ r = await twitch({
vodId: patternMatch["video"] ? patternMatch["video"] : false,
clipId: patternMatch["clip"] ? patternMatch["clip"] : false, clipId: patternMatch["clip"] ? patternMatch["clip"] : false,
quality: obj.vQuality, quality: obj.vQuality,
isAudioOnly: obj.isAudioOnly isAudioOnly: obj.isAudioOnly

View file

@ -1,11 +1,9 @@
import { maxVideoDuration } from "../../config.js"; import { maxVideoDuration } from "../../config.js";
import { getM3U8Formats } from "../../sub/utils.js";
const gqlURL = "https://gql.twitch.tv/gql"; const gqlURL = "https://gql.twitch.tv/gql";
const m3u8URL = "https://usher.ttvnw.net";
const clientIdHead = { "client-id": "kimne78kx3ncx6brgo4mv6wki5h1ko" }; const clientIdHead = { "client-id": "kimne78kx3ncx6brgo4mv6wki5h1ko" };
async function getClip(obj) { export default async function (obj) {
let req_metadata = await fetch(gqlURL, { let req_metadata = await fetch(gqlURL, {
method: "POST", method: "POST",
headers: clientIdHead, headers: clientIdHead,
@ -76,105 +74,3 @@ async function getClip(obj) {
audioFilename: `twitchclip_${clipMetadata.id}_audio` audioFilename: `twitchclip_${clipMetadata.id}_audio`
} }
} }
async function getVideo(obj) {
let req_metadata = await fetch(gqlURL, {
method: "POST",
headers: clientIdHead,
body: JSON.stringify([
{
"operationName": "VideoMetadata",
"variables": {
"channelLogin": "",
"videoID": obj.vodId
},
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "226edb3e692509f727fd56821f5653c05740242c82b0388883e0c0e75dcbf687"
}
}
}
])
}).then((r) => { return r.status === 200 ? r.json() : false; }).catch(() => { return false });
if (!req_metadata) return { error: 'ErrorCouldntFetch' };
let vodMetadata = req_metadata[0].data.video;
if (vodMetadata.previewThumbnailURL.endsWith('/404_processing_{width}x{height}.png')) return { error: 'ErrorLiveVideo' };
if (vodMetadata.lengthSeconds > maxVideoDuration / 1000) return { error: ['ErrorLengthLimit', maxVideoDuration / 60000] };
if (!vodMetadata.owner) return { error: 'ErrorEmptyDownload' };
let req_token = await fetch(gqlURL, {
method: "POST",
headers: clientIdHead,
body: JSON.stringify({
query: `{
videoPlaybackAccessToken(
id: "${obj.vodId}",
params: {
platform: "web",
playerBackend: "mediaplayer",
playerType: "site"
}
)
{
value
signature
}
}`
})
}).then((r) => { return r.status === 200 ? r.json() : false; }).catch(() => { return false });
if (!req_token) return { error: 'ErrorCouldntFetch' };
let req_m3u8 = await fetch(
`${m3u8URL}/vod/${obj.vodId}.m3u8?${
new URLSearchParams({
allow_source: 'true',
allow_audio_only: 'true',
allow_spectre: 'true',
player: 'twitchweb',
playlist_include_framerate: 'true',
nauth: req_token.data.videoPlaybackAccessToken.value,
nauthsig: req_token.data.videoPlaybackAccessToken.signature
}
)}`, {
headers: clientIdHead
}
).then((r) => { return r.status === 200 ? r.text() : false; }).catch(() => { return false });
if (!req_m3u8) return { error: 'ErrorCouldntFetch' };
let formats = getM3U8Formats(req_m3u8);
let generalMeta = {
title: vodMetadata.title,
artist: `Twitch Broadcast by @${vodMetadata.owner.login}`,
}
if (obj.isAudioOnly) {
return {
type: "render",
isM3U8: true,
time: vodMetadata.lengthSeconds * 1000,
urls: formats.find(f => f.id === 'audio_only').url,
audioFilename: `twitchvod_${obj.vodId}_audio`,
fileMetadata: generalMeta
}
} else {
let format = formats.find(f => f.resolution && f.resolution[1] === obj.quality) || formats[0];
return {
urls: format.url,
isM3U8: true,
time: vodMetadata.lengthSeconds * 1000,
filename: `twitchvod_${obj.vodId}_${format.resolution[0]}x${format.resolution[1]}.mp4`,
fileMetadata: generalMeta
}
}
}
export default async function (obj) {
let response = { error: 'ErrorEmptyDownload' };
if (obj.clipId) {
response = await getClip(obj)
} else if (obj.vodId) {
response = await getVideo(obj)
}
return response
}

View file

@ -74,9 +74,9 @@
"enabled": true "enabled": true
}, },
"twitch": { "twitch": {
"alias": "twitch clips & videos", "alias": "twitch clips",
"tld": "tv", "tld": "tv",
"patterns": ["videos/:video", ":channel/clip/:clip"], "patterns": [":channel/clip/:clip"],
"enabled": true "enabled": true
} }
} }

View file

@ -34,5 +34,5 @@ export const testers = {
"streamable": (patternMatch) => (patternMatch["id"] && patternMatch["id"].length === 6), "streamable": (patternMatch) => (patternMatch["id"] && patternMatch["id"].length === 6),
"twitch": (patternMatch) => ((patternMatch["channel"] && patternMatch["clip"] && patternMatch["clip"].length <= 100 || patternMatch["video"] && patternMatch["video"].length <= 10)), "twitch": (patternMatch) => ((patternMatch["channel"] && patternMatch["clip"] && patternMatch["clip"].length <= 100)),
} }