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 "streamable":
|
||||||
case "snapchat":
|
case "snapchat":
|
||||||
case "twitch":
|
case "twitch":
|
||||||
|
case "ntv":
|
||||||
responseType = "redirect";
|
responseType = "redirect";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import facebook from "./services/facebook.js";
|
|||||||
import bluesky from "./services/bluesky.js";
|
import bluesky from "./services/bluesky.js";
|
||||||
import xiaohongshu from "./services/xiaohongshu.js";
|
import xiaohongshu from "./services/xiaohongshu.js";
|
||||||
import newgrounds from "./services/newgrounds.js";
|
import newgrounds from "./services/newgrounds.js";
|
||||||
|
import ntv from "./services/ntv.js";
|
||||||
|
|
||||||
let freebind;
|
let freebind;
|
||||||
|
|
||||||
@ -231,6 +232,15 @@ export default async function({ host, patternMatch, params, authType }) {
|
|||||||
r = await dailymotion(patternMatch);
|
r = await dailymotion(patternMatch);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "ntv":
|
||||||
|
r = await ntv({
|
||||||
|
name: patternMatch.name ?? null,
|
||||||
|
showid: patternMatch.showid ?? null,
|
||||||
|
videoid: patternMatch.videoid,
|
||||||
|
quality: params.videoQuality
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
case "snapchat":
|
case "snapchat":
|
||||||
r = await snapchat({
|
r = await snapchat({
|
||||||
...patternMatch,
|
...patternMatch,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import UrlPattern from "url-pattern";
|
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 hlsExceptions = new Set(["dailymotion", "vimeo", "rutube", "bsky", "youtube"]);
|
||||||
|
|
||||||
export const services = {
|
export const services = {
|
||||||
@ -219,6 +219,13 @@ export const services = {
|
|||||||
"v/:id"
|
"v/:id"
|
||||||
],
|
],
|
||||||
subdomains: ["music", "m"],
|
subdomains: ["music", "m"],
|
||||||
|
},
|
||||||
|
ntv: {
|
||||||
|
patterns: [
|
||||||
|
"peredacha/:name/m:showid/o:videoid",
|
||||||
|
"video/:videoid",
|
||||||
|
],
|
||||||
|
tld: "ru"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,4 +82,8 @@ export const testers = {
|
|||||||
|
|
||||||
"newgrounds": pattern =>
|
"newgrounds": pattern =>
|
||||||
pattern.id?.length <= 12 || pattern.audioId?.length <= 12,
|
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