From 47d15c2592c1127b0cc25c3017061d9b5cfd2453 Mon Sep 17 00:00:00 2001 From: vectflow Date: Sat, 29 Jun 2024 00:47:33 -0400 Subject: [PATCH] feat(linkedin): service to scrape linkedin video post for cdn urls serving the video --- src/modules/processing/services/linkedin.js | 62 +++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/modules/processing/services/linkedin.js diff --git a/src/modules/processing/services/linkedin.js b/src/modules/processing/services/linkedin.js new file mode 100644 index 00000000..71acefd8 --- /dev/null +++ b/src/modules/processing/services/linkedin.js @@ -0,0 +1,62 @@ +import { genericUserAgent } from "../../config.js"; + +const qualityMatch = { + "mp4-640p-30fp-crf28": 640, + "mp4-720p-30fp-crf28": 720 +}; + +export default async function (obj) { + const html = await fetch( + `https://www.linkedin.com/feed/update/urn:li:activity:${obj.postId}`, + { headers: { "user-agent": genericUserAgent } } + ) + .then((res) => res.text()) + .catch(() => {}); + + if (!html) { + return { error: "ErrorCouldntFetch" }; + } + + let data; + try { + const json = html + .split('data-sources="')[1] + .split('" data-poster-url="')[0] + .replaceAll(""", '"') + .replaceAll("&", "&"); + data = JSON.parse(json); + } catch (error) { + return { error: "ErrorCouldntFetch" }; + } + + let fallbackUrl; + const quality = obj.quality === "max" || obj.quality >= 720 ? 720 : 640; + const filenameBase = `linkedin_${obj.postId}`; + + for (const source of data) { + const videoQuality = qualityMatch[source.src.split("/")[6]]; + + if (videoQuality === quality) { + return { + urls: source.src, + filename: `${filenameBase}.mp4`, + audioFilename: `${filenameBase}_audio` + }; + // will prioritize using known quality over unknown quality if no matching quality + } else if (!videoQuality && !fallbackUrl) { + fallbackUrl = source.src; + } else { + fallbackUrl = source.src; + } + } + + if (fallbackUrl) { + return { + urls: fallbackUrl, + filename: `${filenameBase}.mp4`, + audioFilename: `${filenameBase}_audio` + }; + } + + return { error: "ErrorEmptyDownload" }; +}