mirror of
https://github.com/imputnet/cobalt.git
synced 2025-07-13 08:48:26 +00:00
api/ntv: initial support
This commit is contained in:
parent
e4b53880af
commit
6f9e4bc911
@ -191,6 +191,7 @@ export default function({
|
||||
case "streamable":
|
||||
case "snapchat":
|
||||
case "twitch":
|
||||
case "ntv":
|
||||
responseType = "redirect";
|
||||
break;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import facebook from "./services/facebook.js";
|
||||
import bluesky from "./services/bluesky.js";
|
||||
import xiaohongshu from "./services/xiaohongshu.js";
|
||||
import newgrounds from "./services/newgrounds.js";
|
||||
import ntv from "./services/ntv.js";
|
||||
|
||||
let freebind;
|
||||
|
||||
@ -231,6 +232,15 @@ export default async function({ host, patternMatch, params, authType }) {
|
||||
r = await dailymotion(patternMatch);
|
||||
break;
|
||||
|
||||
case "ntv":
|
||||
r = await ntv({
|
||||
name: patternMatch.name ?? null,
|
||||
showid: patternMatch.showid ?? null,
|
||||
videoid: patternMatch.videoid,
|
||||
quality: params.videoQuality
|
||||
});
|
||||
break;
|
||||
|
||||
case "snapchat":
|
||||
r = await snapchat({
|
||||
...patternMatch,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import UrlPattern from "url-pattern";
|
||||
|
||||
export const audioIgnore = new Set(["vk", "ok", "loom"]);
|
||||
export const audioIgnore = new Set(["vk", "ok", "loom", "ntv"]);
|
||||
export const hlsExceptions = new Set(["dailymotion", "vimeo", "rutube", "bsky", "youtube"]);
|
||||
|
||||
export const services = {
|
||||
@ -219,6 +219,13 @@ export const services = {
|
||||
"v/:id"
|
||||
],
|
||||
subdomains: ["music", "m"],
|
||||
},
|
||||
ntv: {
|
||||
patterns: [
|
||||
"peredacha/:name/m:showid/o:videoid",
|
||||
"video/:videoid",
|
||||
],
|
||||
tld: "ru"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,4 +82,8 @@ export const testers = {
|
||||
|
||||
"newgrounds": pattern =>
|
||||
pattern.id?.length <= 12 || pattern.audioId?.length <= 12,
|
||||
|
||||
"ntv": pattern =>
|
||||
pattern.videoid.length <= 32 ||
|
||||
(pattern.name.length <= 64 && pattern.showid.length <= 32 && pattern.videoid.length <= 32),
|
||||
}
|
||||
|
101
api/src/processing/services/ntv.js
Normal file
101
api/src/processing/services/ntv.js
Normal file
@ -0,0 +1,101 @@
|
||||
import { env } from "../../config.js";
|
||||
|
||||
const ntvApi = 'https://www.ntv.ru/api/player/?id=';
|
||||
|
||||
// the most generic user agent
|
||||
export const clientAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0";
|
||||
|
||||
const getVideo = async (videoID) => {
|
||||
const video = await fetch(`${ntvApi}${videoID}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"user-agent": clientAgent,
|
||||
}
|
||||
})
|
||||
.then(r => {
|
||||
if (r.status === 200) {
|
||||
return r.json();
|
||||
}
|
||||
});
|
||||
|
||||
return video;
|
||||
}
|
||||
|
||||
export default async function (obj) {
|
||||
let video = null;
|
||||
|
||||
if (obj.name && obj.name.length > 0) {
|
||||
const fetchID = await fetch(`https://www.ntv.ru/peredacha/${obj.name}/m${obj.showid}/o${obj.videoid}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"user-agent": clientAgent,
|
||||
}
|
||||
})
|
||||
.then(r => {
|
||||
if (r.status === 200) {
|
||||
return r.text();
|
||||
}
|
||||
});
|
||||
|
||||
let figuredVideoId = null;
|
||||
const match = String(fetchID).match(/<meta\s+property="og:video:url"\s+content="https:\/\/www\.ntv\.ru\/embed\/(\d+)\/?"/i);
|
||||
if (match && match[1]) {
|
||||
figuredVideoId = match[1];
|
||||
} else {
|
||||
return { error: "fetch.fail" };
|
||||
}
|
||||
|
||||
video = await getVideo(figuredVideoId);
|
||||
} else {
|
||||
video = await getVideo(obj.videoid);
|
||||
}
|
||||
|
||||
if (!video) {
|
||||
return { error: "fetch.empty" };
|
||||
}
|
||||
|
||||
if (!video.playback || !video.totaltime) {
|
||||
return { error: "fetch.fail" };
|
||||
}
|
||||
|
||||
if (video.totaltime > env.durationLimit) {
|
||||
return { error: "content.too_long" };
|
||||
}
|
||||
|
||||
const userQuality = obj.quality === "max" ? "1080" : obj.quality;
|
||||
let url = null;
|
||||
|
||||
// for hls there's 144p, 360p, 720p and 1080p available, but for mp4 only 360p and 1080p
|
||||
// we'll use mp4 to simplify things
|
||||
switch (userQuality) {
|
||||
case "1080":
|
||||
url = video.playback.hd_video;
|
||||
break;
|
||||
case "720":
|
||||
case "480":
|
||||
case "360":
|
||||
url = video.playback.video;
|
||||
break;
|
||||
default:
|
||||
// 360 by default
|
||||
url = video.playback.video;
|
||||
}
|
||||
|
||||
if (!url) return { error: "fetch.fail" };
|
||||
|
||||
const fileMetadata = {
|
||||
title: video.description.trim(),
|
||||
// despite the param name, it actually contains the video title with the name of the show
|
||||
}
|
||||
|
||||
return {
|
||||
urls: url,
|
||||
fileMetadata,
|
||||
filenameAttributes: {
|
||||
service: "ntv",
|
||||
id: `${obj.videoid}`,
|
||||
title: fileMetadata.title,
|
||||
extension: "mp4"
|
||||
}
|
||||
}
|
||||
}
|
20
api/src/util/tests/ntv.json
Normal file
20
api/src/util/tests/ntv.json
Normal file
@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"name": "tv show video",
|
||||
"url": "https://www.ntv.ru/peredacha/dacha_otvet/m18960/o806491",
|
||||
"params": {},
|
||||
"expected": {
|
||||
"code": 200,
|
||||
"status": "redirect"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newsfeed video",
|
||||
"url": "https://www.ntv.ru/video/2483380",
|
||||
"params": {},
|
||||
"expected": {
|
||||
"code": 200,
|
||||
"status": "redirect"
|
||||
}
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user