diff --git a/src/modules/processing/match.js b/src/modules/processing/match.js index 70a31a21..0552f2da 100644 --- a/src/modules/processing/match.js +++ b/src/modules/processing/match.js @@ -18,6 +18,7 @@ import soundcloud from "./services/soundcloud.js"; import instagram from "./services/instagram.js"; import vine from "./services/vine.js"; import pinterest from "./services/pinterest.js"; +import streamable from "./services/streamable.js"; export default async function (host, patternMatch, url, lang, obj) { try { @@ -114,6 +115,13 @@ export default async function (host, patternMatch, url, lang, obj) { case "pinterest": r = await pinterest({ id: patternMatch["id"] }); break; + case "streamable": + r = await streamable({ + id: patternMatch["id"], + quality: obj.vQuality, + isAudioOnly: isAudioOnly, + }); + break; default: return apiJSON(0, { t: errorUnsupported(lang) }); } diff --git a/src/modules/processing/matchActionDecider.js b/src/modules/processing/matchActionDecider.js index 6d1b46b5..e46991fa 100644 --- a/src/modules/processing/matchActionDecider.js +++ b/src/modules/processing/matchActionDecider.js @@ -56,6 +56,7 @@ export default function(r, host, audioFormat, isAudioOnly, lang, isAudioMuted) { case "tumblr": case "twitter": case "pinterest": + case "streamable": responseType = 1; break; } diff --git a/src/modules/processing/services/streamable.js b/src/modules/processing/services/streamable.js new file mode 100644 index 00000000..29b6dece --- /dev/null +++ b/src/modules/processing/services/streamable.js @@ -0,0 +1,19 @@ +export default async function(obj) { + let video = await fetch(`https://api.streamable.com/videos/${obj.id}`).then((r) => { return r.status === 200 ? r.json() : false }).catch(() => { return false }); + if (!video) return { error: 'ErrorEmptyDownload' }; + + let best = video.files['mp4-mobile']; + if (video.files.mp4 && (obj.isAudioOnly || obj.quality === "max" || obj.quality >= Number("720"))) { + best = video.files.mp4; + } + + if (best) return { + urls: best.url, + filename: `streamable_${obj.id}_${best.width}x${best.height}.mp4`, + audioFilename: `streamable_${obj.id}_audio`, + metadata: { + title: video.title + } + } + return { error: 'ErrorEmptyDownload' } +} diff --git a/src/modules/processing/servicesConfig.json b/src/modules/processing/servicesConfig.json index a9219354..aadc3926 100644 --- a/src/modules/processing/servicesConfig.json +++ b/src/modules/processing/servicesConfig.json @@ -2,7 +2,7 @@ "audioIgnore": ["vk"], "config": { "bilibili": { - "alias": "bilibili (.com only)", + "alias": "bilibili.com videos", "patterns": ["video/:id"], "enabled": true }, @@ -67,6 +67,11 @@ "alias": "pinterest videos & stories", "patterns": ["pin/:id"], "enabled": true + }, + "streamable": { + "alias": "streamable videos", + "patterns": [":id", "o/:id", "e/:id", "s/:id"], + "enabled": true } } } diff --git a/src/modules/processing/servicesPatternTesters.js b/src/modules/processing/servicesPatternTesters.js index c336afcc..cd4d4d61 100644 --- a/src/modules/processing/servicesPatternTesters.js +++ b/src/modules/processing/servicesPatternTesters.js @@ -30,5 +30,7 @@ export const testers = { "vine": (patternMatch) => (patternMatch["id"] && patternMatch["id"].length <= 12), - "pinterest": (patternMatch) => (patternMatch["id"] && patternMatch["id"].length <= 128) + "pinterest": (patternMatch) => (patternMatch["id"] && patternMatch["id"].length <= 128), + + "streamable": (patternMatch) => (patternMatch["id"] && patternMatch["id"].length === 6) } diff --git a/src/test/tests.json b/src/test/tests.json index bfac3bec..e72421df 100644 --- a/src/test/tests.json +++ b/src/test/tests.json @@ -983,5 +983,50 @@ "code": 200, "status": "redirect" } + }], + "streamable": [{ + "name": "regular video", + "url": "https://streamable.com/03r3c2", + "params": {}, + "expected": { + "code": 200, + "status": "redirect" + } + }, { + "name": "embedded link", + "url": "https://streamable.com/e/rsmo56", + "params": {}, + "expected": { + "code": 200, + "status": "redirect" + } + }, { + "name": "regular video (isAudioOnly)", + "url": "https://streamable.com/03r3c2", + "params": { + "isAudioOnly": true + }, + "expected": { + "code": 200, + "status": "stream" + } + }, { + "name": "regular video (isAudioMuted)", + "url": "https://streamable.com/03r3c2", + "params": { + "isAudioMuted": true + }, + "expected": { + "code": 200, + "status": "stream" + } + }, { + "name": "inexistent video", + "url": "https://streamable.com/XXXXXX", + "params": {}, + "expected": { + "code": 400, + "status": "error" + } }] } \ No newline at end of file