From 26ea2b12c0aec31a11f73eab29531afccf2ed32e Mon Sep 17 00:00:00 2001 From: Steve Berdy <86739818+steveberdy@users.noreply.github.com> Date: Wed, 17 Jan 2024 16:25:59 -0500 Subject: [PATCH] support for linkedin videos --- README.md | 1 + package.json | 1 + src/modules/processing/match.js | 7 +++++ src/modules/processing/services/linkedin.js | 27 +++++++++++++++++++ src/modules/processing/servicesConfig.json | 6 +++++ .../processing/servicesPatternTesters.js | 9 ++++--- src/test/tests.json | 9 +++++++ 7 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/modules/processing/services/linkedin.js diff --git a/README.md b/README.md index 16998478..b101f94d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ this list is not final and keeps expanding over time. if support for a service y | bilibili.com | ✅ | ✅ | ✅ | ➖ | ➖ | | instagram posts & stories | ✅ | ✅ | ✅ | ➖ | ➖ | | instagram reels | ✅ | ✅ | ✅ | ➖ | ➖ | +| linkedin videos | ✅ | ❌ | ❌ | ✅ | ✅ | | pinterest | ✅ | ✅ | ✅ | ➖ | ➖ | | reddit | ✅ | ✅ | ✅ | ❌ | ❌ | | rutube | ✅ | ✅ | ✅ | ✅ | ✅ | diff --git a/package.json b/package.json index c5bb65d3..0b3fc694 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "express-rate-limit": "^6.3.0", "ffmpeg-static": "^5.1.0", "hls-parser": "^0.10.7", + "libxmljs": "^1.0.11", "nanoid": "^4.0.2", "node-cache": "^5.1.2", "psl": "1.9.0", diff --git a/src/modules/processing/match.js b/src/modules/processing/match.js index 0d5980ca..69fe6cec 100644 --- a/src/modules/processing/match.js +++ b/src/modules/processing/match.js @@ -24,6 +24,7 @@ import pinterest from "./services/pinterest.js"; import streamable from "./services/streamable.js"; import twitch from "./services/twitch.js"; import rutube from "./services/rutube.js"; +import linkedin from "./services/linkedin.js"; export default async function(host, patternMatch, url, lang, obj) { assert(url instanceof URL); @@ -158,6 +159,12 @@ export default async function(host, patternMatch, url, lang, obj) { isAudioOnly: isAudioOnly }); break; + case "linkedin": + r = await linkedin({ + url, + id: patternMatch.id + }); + break; default: return apiJSON(0, { t: errorUnsupported(lang) }); } diff --git a/src/modules/processing/services/linkedin.js b/src/modules/processing/services/linkedin.js new file mode 100644 index 00000000..934fbf4d --- /dev/null +++ b/src/modules/processing/services/linkedin.js @@ -0,0 +1,27 @@ +import libxmljs from "libxmljs"; + +export default async function(obj) { + const htmlContent = await fetch(obj.url.href).then((r) => { + return r.status === 200 ? r.text() : false + }).catch(() => { return false }); + const htmlDoc = await libxmljs.parseHtmlAsync(htmlContent) + .then((d) => { return d }); + const rawData = htmlDoc.find("//script[@type='application/ld+json']")[0]; + const json = JSON.parse(rawData.text()); + + let fileMetadata = { + title: json.video.name, + author: json.author.name + } + + return { + urls: json.video.contentUrl, + filenameAttributes: { + service: "linkedin", + id: obj.id, + title: fileMetadata.title, + author: fileMetadata.author, + extension: "mp4" + } + } +} diff --git a/src/modules/processing/servicesConfig.json b/src/modules/processing/servicesConfig.json index 9d903fcb..426b6684 100644 --- a/src/modules/processing/servicesConfig.json +++ b/src/modules/processing/servicesConfig.json @@ -106,6 +106,12 @@ "tld": "ru", "patterns": ["video/:id", "play/embed/:id"], "enabled": true + }, + "linkedin": { + "alias": "linkedin posts", + "subdomains": ["m"], + "patterns": ["posts/:id"], + "enabled": true } } } diff --git a/src/modules/processing/servicesPatternTesters.js b/src/modules/processing/servicesPatternTesters.js index 970e8f40..c5240db3 100644 --- a/src/modules/processing/servicesPatternTesters.js +++ b/src/modules/processing/servicesPatternTesters.js @@ -5,7 +5,10 @@ export const testers = { "instagram": (patternMatch) => patternMatch.postId?.length <= 12 || (patternMatch.username?.length <= 30 && patternMatch.storyId?.length <= 24), - + + "linkedin": (patternMatch) => + patternMatch.id?.length >= 0, + "ok": (patternMatch) => patternMatch.id?.length <= 16, @@ -19,12 +22,12 @@ export const testers = { patternMatch.id?.length === 32, "soundcloud": (patternMatch) => - (patternMatch.author?.length <= 255 && patternMatch.song?.length <= 255) + (patternMatch.author?.length <= 255 && patternMatch.song?.length <= 255) || patternMatch.shortLink?.length <= 32, "streamable": (patternMatch) => patternMatch.id?.length === 6, - + "tiktok": (patternMatch) => patternMatch.postId?.length <= 21 || patternMatch.id?.length <= 13, diff --git a/src/test/tests.json b/src/test/tests.json index d3170858..e564afd4 100644 --- a/src/test/tests.json +++ b/src/test/tests.json @@ -1171,5 +1171,14 @@ "code": 200, "status": "stream" } + }], + "linkedin": [{ + "name": "video post", + "url": "https://www.linkedin.com/posts/hadiyarajesh_kotlin-android-coroutines-activity-7144537175857037312-JKmR", + "params": {}, + "expected": { + "code": 200, + "status": "stream" + } }] }