diff --git a/src/modules/processing/match.js b/src/modules/processing/match.js index 267fc25..75ce5b7 100644 --- a/src/modules/processing/match.js +++ b/src/modules/processing/match.js @@ -13,6 +13,7 @@ import reddit from "./services/reddit.js"; import twitter from "./services/twitter.js"; import youtube from "./services/youtube.js"; import vk from "./services/vk.js"; +import ok from "./services/ok.js"; import tiktok from "./services/tiktok.js"; import tumblr from "./services/tumblr.js"; import vimeo from "./services/vimeo.js"; @@ -43,19 +44,25 @@ export default async function(host, patternMatch, url, lang, obj) { break; case "vk": r = await vk({ - userId: patternMatch["userId"], - videoId: patternMatch["videoId"], + userId: patternMatch.userId, + videoId: patternMatch.videoId, + quality: obj.vQuality + }); + break; + case "ok": + r = await ok({ + id: patternMatch.id, quality: obj.vQuality }); break; case "bilibili": r = await bilibili({ - id: patternMatch["id"].slice(0, 12) + id: patternMatch.id.slice(0, 12) }); break; case "youtube": let fetchInfo = { - id: patternMatch["id"].slice(0, 11), + id: patternMatch.id.slice(0, 11), quality: obj.vQuality, format: obj.vCodec, isAudioOnly: isAudioOnly, @@ -73,16 +80,16 @@ export default async function(host, patternMatch, url, lang, obj) { break; case "reddit": r = await reddit({ - sub: patternMatch["sub"], - id: patternMatch["id"] + sub: patternMatch.sub, + id: patternMatch.id }); break; case "douyin": case "tiktok": r = await tiktok({ host: host, - postId: patternMatch["postId"], - id: patternMatch["id"], + postId: patternMatch.postId, + id: patternMatch.id, noWatermark: obj.isNoTTWatermark, fullAudio: obj.isTTFullAudio, isAudioOnly: isAudioOnly @@ -97,7 +104,7 @@ export default async function(host, patternMatch, url, lang, obj) { break; case "vimeo": r = await vimeo({ - id: patternMatch["id"].slice(0, 11), + id: patternMatch.id.slice(0, 11), quality: obj.vQuality, isAudioOnly: isAudioOnly, forceDash: isAudioOnly ? true : obj.vimeoDash @@ -107,10 +114,10 @@ export default async function(host, patternMatch, url, lang, obj) { isAudioOnly = true; r = await soundcloud({ url, - author: patternMatch["author"], - song: patternMatch["song"], - shortLink: patternMatch["shortLink"] || false, - accessKey: patternMatch["accessKey"] || false + author: patternMatch.author, + song: patternMatch.song, + shortLink: patternMatch.shortLink || false, + accessKey: patternMatch.accessKey || false }); break; case "instagram": @@ -121,31 +128,31 @@ export default async function(host, patternMatch, url, lang, obj) { break; case "vine": r = await vine({ - id: patternMatch["id"] + id: patternMatch.id }); break; case "pinterest": r = await pinterest({ - id: patternMatch["id"] + id: patternMatch.id }); break; case "streamable": r = await streamable({ - id: patternMatch["id"], + id: patternMatch.id, quality: obj.vQuality, isAudioOnly: isAudioOnly, }); break; case "twitch": r = await twitch({ - clipId: patternMatch["clip"] || false, + clipId: patternMatch.clip || false, quality: obj.vQuality, isAudioOnly: obj.isAudioOnly }); break; case "rutube": r = await rutube({ - id: patternMatch["id"], + id: patternMatch.id, quality: obj.vQuality, isAudioOnly: isAudioOnly }); diff --git a/src/modules/processing/services/ok.js b/src/modules/processing/services/ok.js new file mode 100644 index 0000000..bde163f --- /dev/null +++ b/src/modules/processing/services/ok.js @@ -0,0 +1,56 @@ +import { genericUserAgent, maxVideoDuration } from "../../config.js"; +import { cleanString } from "../../sub/utils.js"; + +const resolutions = { + "ultra": "2160", + "quad": "1440", + "full": "1080", + "hd": "720", + "sd": "480", + "low": "360", + "lowest": "240", + "mobile": "144" +} + +export default async function(o) { + let quality = o.quality === "max" ? "2160" : o.quality; + + let html = await fetch(`https://ok.ru/video/${o.id}`, { + headers: { "user-agent": genericUserAgent } + }).then((r) => { return r.text() }).catch(() => { return false }); + + if (!html) return { error: 'ErrorCouldntFetch' }; + if (!html.includes(`
maxVideoDuration / 1000) return { error: ['ErrorLengthLimit', maxVideoDuration / 60000] }; + + let videos = videoData.videos.filter(v => !v.disallowed); + let bestVideo = videos.find(v => resolutions[v.name] === quality) || videos[videos.length - 1]; + + let fileMetadata = { + title: cleanString(videoData.movie.title.trim()), + author: cleanString(videoData.author.name.trim()), + } + + if (bestVideo) return { + urls: bestVideo.url, + filenameAttributes: { + service: "ok", + id: o.id, + title: fileMetadata.title, + author: fileMetadata.author, + resolution: `${resolutions[bestVideo.name]}p`, + qualityLabel: `${resolutions[bestVideo.name]}p`, + extension: "mp4" + } + } + + return { error: 'ErrorEmptyDownload' } +} diff --git a/src/modules/processing/services/vk.js b/src/modules/processing/services/vk.js index 30d05f2..d956c3b 100644 --- a/src/modules/processing/services/vk.js +++ b/src/modules/processing/services/vk.js @@ -12,7 +12,7 @@ export default async function(o) { if (!html) return { error: 'ErrorCouldntFetch' }; - // decode cyrillic from windows-1251 because vk still uses apis from prehistoring times + // decode cyrillic from windows-1251 because vk still uses apis from prehistoric times let decoder = new TextDecoder('windows-1251'); html = decoder.decode(html); @@ -35,7 +35,7 @@ export default async function(o) { let fileMetadata = { title: cleanString(js.player.params[0].md_title.trim()), - artist: cleanString(js.player.params[0].md_author.trim()), + author: cleanString(js.player.params[0].md_author.trim()), } if (url) return { @@ -44,7 +44,7 @@ export default async function(o) { service: "vk", id: `${o.userId}_${o.videoId}`, title: fileMetadata.title, - author: fileMetadata.artist, + author: fileMetadata.author, resolution: `${quality}p`, qualityLabel: `${quality}p`, extension: "mp4" diff --git a/src/modules/processing/servicesConfig.json b/src/modules/processing/servicesConfig.json index 6ecd274..a4bbf49 100644 --- a/src/modules/processing/servicesConfig.json +++ b/src/modules/processing/servicesConfig.json @@ -1,5 +1,5 @@ { - "audioIgnore": ["vk"], + "audioIgnore": ["vk", "ok"], "config": { "bilibili": { "alias": "bilibili.com videos", @@ -28,6 +28,12 @@ "patterns": ["video:userId_:videoId", "clip:userId_:videoId", "clips:duplicate?z=clip:userId_:videoId"], "enabled": true }, + "ok": { + "alias": "ok video", + "tld": "ru", + "patterns": ["video/:id"], + "enabled": true + }, "youtube": { "alias": "youtube videos, shorts & music", "patterns": ["watch?v=:id", "embed/:id", "watch/:id"], diff --git a/src/modules/processing/servicesPatternTesters.js b/src/modules/processing/servicesPatternTesters.js index e1f3d01..6bfd1d4 100644 --- a/src/modules/processing/servicesPatternTesters.js +++ b/src/modules/processing/servicesPatternTesters.js @@ -5,6 +5,9 @@ export const testers = { "instagram": (patternMatch) => patternMatch.postId?.length <= 12 || (patternMatch.username?.length <= 30 && patternMatch.storyId?.length <= 24), + + "ok": (patternMatch) => + patternMatch.id?.length <= 16, "pinterest": (patternMatch) => patternMatch.id?.length <= 128,