This commit is contained in:
vectflow 2024-07-20 23:44:19 +03:00 committed by GitHub
commit c864081d3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 122 additions and 1 deletions

View File

@ -19,6 +19,7 @@ this list is not final and keeps expanding over time. if support for a service y
| bilibili.com & bilibili.tv | ✅ | ✅ | ✅ | | |
| dailymotion | ✅ | ✅ | ✅ | ✅ | ✅ |
| instagram posts & reels | ✅ | ✅ | ✅ | | |
| linkedin | ✅ | ✅ | ✅ | ❌ | ❌ |
| loom | ✅ | ❌ | ✅ | ✅ | |
| ok video | ✅ | ❌ | ✅ | ✅ | ✅ |
| pinterest | ✅ | ✅ | ✅ | | |
@ -45,6 +46,7 @@ this list is not final and keeps expanding over time. if support for a service y
| service | notes or features |
| :-------- | :----- |
| instagram | supports reels, photos, and videos. lets you pick what to save from multi-media posts. |
| linkedin | supports post and feed links. |
| pinterest | supports photos, gifs, videos and stories. |
| reddit | supports gifs and videos. |
| rutube | supports yappy & private links. |

View File

@ -25,6 +25,7 @@ import twitch from "./services/twitch.js";
import rutube from "./services/rutube.js";
import dailymotion from "./services/dailymotion.js";
import loom from "./services/loom.js";
import linkedin from "./services/linkedin.js";
let freebind;
@ -193,6 +194,12 @@ export default async function(host, patternMatch, lang, obj) {
id: patternMatch.id
});
break;
case "linkedin":
r = await linkedin({
postId: patternMatch.id,
quality: obj.vQuality
});
break;
default:
return createResponse("error", {
t: loc(lang, 'ErrorUnsupported')

View File

@ -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" };
}

View File

@ -33,7 +33,6 @@
"vk": {
"alias": "vk video & clips",
"patterns": ["video:userId_:videoId", "clip:userId_:videoId", "clips:duplicate?z=clip:userId_:videoId"],
"subdomains": ["m"],
"enabled": true
},
"ok": {
@ -118,6 +117,11 @@
"alias": "loom videos",
"patterns": ["share/:id"],
"enabled": true
},
"linkedin": {
"alias": "linkedin videos",
"patterns": ["feed/update/urn\\:li\\:activity\\:(:id)"],
"enabled": true
}
}
}

View File

@ -9,6 +9,9 @@ export const testers = {
patternMatch.postId?.length <= 12
|| (patternMatch.username?.length <= 30 && patternMatch.storyId?.length <= 24),
"linkedin": (patternMatch) =>
patternMatch.id?.length === 19,
"loom": (patternMatch) =>
patternMatch.id?.length <= 32,

View File

@ -70,6 +70,12 @@ function aliasURL(url) {
url.hostname = 'instagram.com';
}
break;
case "linkedin":
if (parts[1] === "posts") {
const postId = parts.pop().split("-").at(-2)
url = new URL(`https://linkedin.com/feed/update/urn:li:activity:${postId}`)
}
break;
}
return url

View File

@ -1160,5 +1160,42 @@
"code": 400,
"status": "error"
}
}],
"linkedin": [{
"name": "regular video (share link)",
"url": "https://www.linkedin.com/posts/jasonyoong_in-the-early-days-of-a-startup-sam-altman-activity-7211912701411827712-oR9m?utm_source=share",
"params": {},
"expected": {
"code": 200,
"status": "stream"
}
}, {
"name": "regular video (feed link)",
"url": "https://www.linkedin.com/feed/update/urn:li:activity:7211912701411827712/",
"params": {},
"expected": {
"code": 200,
"status": "stream"
}
}, {
"name": "regular video (isAudioMuted)",
"url": "https://www.linkedin.com/feed/update/urn:li:activity:7211912701411827712/",
"params": {
"isAudioMuted": true
},
"expected": {
"code": 200,
"status": "stream"
}
}, {
"name": "regular video (isAudioOnly)",
"url": "https://www.linkedin.com/feed/update/urn:li:activity:7211912701411827712/",
"params": {
"isAudioOnly": true
},
"expected": {
"code": 200,
"status": "stream"
}
}]
}