@sockethub/platform-metadata 1.0.1-alpha.18 → 1.0.1-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +122 -20
- package/dist/index.js.map +5 -5
- package/dist/resolvers.d.ts +45 -2
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -71661,6 +71661,11 @@ function errorMessage(value) {
|
|
|
71661
71661
|
}
|
|
71662
71662
|
return String(value);
|
|
71663
71663
|
}
|
|
71664
|
+
var EXPECTED_ERROR = Symbol.for("sockethub.expectedError");
|
|
71665
|
+
function markExpectedError(err) {
|
|
71666
|
+
err[EXPECTED_ERROR] = true;
|
|
71667
|
+
return err;
|
|
71668
|
+
}
|
|
71664
71669
|
|
|
71665
71670
|
// ../util/dist/net/index.js
|
|
71666
71671
|
var import_undici = __toESM(require_undici(), 1);
|
|
@@ -71813,7 +71818,7 @@ var import_undici2 = __toESM(require_undici(), 1);
|
|
|
71813
71818
|
// package.json
|
|
71814
71819
|
var package_default = {
|
|
71815
71820
|
name: "@sockethub/platform-metadata",
|
|
71816
|
-
version: "1.0.1-alpha.
|
|
71821
|
+
version: "1.0.1-alpha.19",
|
|
71817
71822
|
description: "Fetch metadata from a given URL",
|
|
71818
71823
|
author: "Nick Jennings <nick@silverbucket.net>",
|
|
71819
71824
|
license: "LGPL-3.0+",
|
|
@@ -71855,17 +71860,17 @@ var package_default = {
|
|
|
71855
71860
|
"clean:deps": "rm -rf node_modules"
|
|
71856
71861
|
},
|
|
71857
71862
|
dependencies: {
|
|
71858
|
-
"@sockethub/util": "^1.0.0-alpha.
|
|
71863
|
+
"@sockethub/util": "^1.0.0-alpha.12",
|
|
71859
71864
|
"open-graph-scraper": "^6.11.0",
|
|
71860
71865
|
undici: "^7.16.0"
|
|
71861
71866
|
},
|
|
71862
71867
|
devDependencies: {
|
|
71863
|
-
"@sockethub/schemas": "^3.0.0-alpha.
|
|
71868
|
+
"@sockethub/schemas": "^3.0.0-alpha.24"
|
|
71864
71869
|
},
|
|
71865
71870
|
peerDependencies: {
|
|
71866
|
-
"@sockethub/server": "^5.0.0-alpha.
|
|
71871
|
+
"@sockethub/server": "^5.0.0-alpha.24"
|
|
71867
71872
|
},
|
|
71868
|
-
gitHead: "
|
|
71873
|
+
gitHead: "e778256d7067e2743cd6807a15d39a0cc65a358d",
|
|
71869
71874
|
types: "./dist/index.d.ts"
|
|
71870
71875
|
};
|
|
71871
71876
|
|
|
@@ -71884,6 +71889,15 @@ var YOUTUBE_HOSTS = new Set([
|
|
|
71884
71889
|
"m.youtube.com",
|
|
71885
71890
|
"music.youtube.com"
|
|
71886
71891
|
]);
|
|
71892
|
+
var FACEBOOK_HOSTS = new Set([
|
|
71893
|
+
"facebook.com",
|
|
71894
|
+
"www.facebook.com",
|
|
71895
|
+
"m.facebook.com",
|
|
71896
|
+
"web.facebook.com",
|
|
71897
|
+
"mbasic.facebook.com",
|
|
71898
|
+
"fb.com",
|
|
71899
|
+
"www.fb.com"
|
|
71900
|
+
]);
|
|
71887
71901
|
var REDDIT_HOSTS = new Set([
|
|
71888
71902
|
"reddit.com",
|
|
71889
71903
|
"www.reddit.com",
|
|
@@ -71967,6 +71981,19 @@ function youtubeOEmbedImage(embed) {
|
|
|
71967
71981
|
}
|
|
71968
71982
|
] : undefined;
|
|
71969
71983
|
}
|
|
71984
|
+
function isFacebookUrl(url) {
|
|
71985
|
+
let parsed;
|
|
71986
|
+
try {
|
|
71987
|
+
parsed = new URL(url);
|
|
71988
|
+
} catch {
|
|
71989
|
+
return false;
|
|
71990
|
+
}
|
|
71991
|
+
const host = parsed.hostname.toLowerCase();
|
|
71992
|
+
return FACEBOOK_HOSTS.has(host) || host === "fb.watch";
|
|
71993
|
+
}
|
|
71994
|
+
function stripFacebookEngagement(title) {
|
|
71995
|
+
return title?.replace(/^[^|]*\p{Nd}[^|]*·[^|]*\|\s*/u, "");
|
|
71996
|
+
}
|
|
71970
71997
|
function isRedditUrl(url) {
|
|
71971
71998
|
let parsed;
|
|
71972
71999
|
try {
|
|
@@ -71993,6 +72020,19 @@ function resolveRedditJson(url) {
|
|
|
71993
72020
|
json.searchParams.set("raw_json", "1");
|
|
71994
72021
|
return json.href;
|
|
71995
72022
|
}
|
|
72023
|
+
function resolveRedditMedia(url) {
|
|
72024
|
+
let parsed;
|
|
72025
|
+
try {
|
|
72026
|
+
parsed = new URL(url);
|
|
72027
|
+
} catch {
|
|
72028
|
+
return null;
|
|
72029
|
+
}
|
|
72030
|
+
if (!REDDIT_HOSTS.has(parsed.hostname.toLowerCase()))
|
|
72031
|
+
return null;
|
|
72032
|
+
if (parsed.pathname.replace(/\/+$/, "") !== "/media")
|
|
72033
|
+
return null;
|
|
72034
|
+
return redditMediaUrl(parsed.searchParams.get("url"), new Set(["i.redd.it", "preview.redd.it", "external-preview.redd.it"]));
|
|
72035
|
+
}
|
|
71996
72036
|
function parseRedditPost(value) {
|
|
71997
72037
|
if (!Array.isArray(value))
|
|
71998
72038
|
return null;
|
|
@@ -72008,19 +72048,51 @@ function parseRedditPost(value) {
|
|
|
72008
72048
|
}
|
|
72009
72049
|
return data;
|
|
72010
72050
|
}
|
|
72051
|
+
function redditMediaUrl(value, allowedHosts) {
|
|
72052
|
+
if (typeof value !== "string")
|
|
72053
|
+
return null;
|
|
72054
|
+
try {
|
|
72055
|
+
const url = new URL(value);
|
|
72056
|
+
return url.protocol === "https:" && allowedHosts.has(url.hostname.toLowerCase()) ? url.href : null;
|
|
72057
|
+
} catch {
|
|
72058
|
+
return null;
|
|
72059
|
+
}
|
|
72060
|
+
}
|
|
72061
|
+
function finiteNonNegative(value) {
|
|
72062
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
72063
|
+
}
|
|
72011
72064
|
function redditPostImage(post) {
|
|
72012
72065
|
for (const candidate of [post.url_overridden_by_dest, post.url]) {
|
|
72013
|
-
|
|
72014
|
-
|
|
72015
|
-
|
|
72016
|
-
|
|
72017
|
-
|
|
72018
|
-
|
|
72066
|
+
const url = redditMediaUrl(candidate, new Set(["i.redd.it", "preview.redd.it"]));
|
|
72067
|
+
if (url)
|
|
72068
|
+
return [{ url }];
|
|
72069
|
+
}
|
|
72070
|
+
const source = post.preview?.images?.[0]?.source;
|
|
72071
|
+
const previewUrl = redditMediaUrl(source?.url, new Set(["preview.redd.it", "external-preview.redd.it"]));
|
|
72072
|
+
if (previewUrl) {
|
|
72073
|
+
return [
|
|
72074
|
+
{
|
|
72075
|
+
url: previewUrl,
|
|
72076
|
+
width: finiteNonNegative(source?.width),
|
|
72077
|
+
height: finiteNonNegative(source?.height)
|
|
72019
72078
|
}
|
|
72020
|
-
|
|
72079
|
+
];
|
|
72021
72080
|
}
|
|
72022
72081
|
return;
|
|
72023
72082
|
}
|
|
72083
|
+
function redditPostVideo(post) {
|
|
72084
|
+
const video = post.secure_media?.reddit_video;
|
|
72085
|
+
const url = redditMediaUrl(video?.fallback_url, new Set(["v.redd.it"]));
|
|
72086
|
+
if (!url)
|
|
72087
|
+
return;
|
|
72088
|
+
return {
|
|
72089
|
+
url,
|
|
72090
|
+
thumbnail: redditPostImage(post)?.[0]?.url,
|
|
72091
|
+
width: finiteNonNegative(video?.width),
|
|
72092
|
+
height: finiteNonNegative(video?.height),
|
|
72093
|
+
duration: finiteNonNegative(video?.duration)
|
|
72094
|
+
};
|
|
72095
|
+
}
|
|
72024
72096
|
function parseRedditOEmbed(value) {
|
|
72025
72097
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
72026
72098
|
return null;
|
|
@@ -72336,6 +72408,29 @@ class Metadata {
|
|
|
72336
72408
|
this.scrape(job, cb);
|
|
72337
72409
|
}
|
|
72338
72410
|
async fetchReddit(job, cb) {
|
|
72411
|
+
const mediaImage = resolveRedditMedia(job.actor.id);
|
|
72412
|
+
if (mediaImage) {
|
|
72413
|
+
const imagePath = new URL(mediaImage).pathname;
|
|
72414
|
+
let title;
|
|
72415
|
+
try {
|
|
72416
|
+
title = decodeURIComponent(imagePath).slice(1);
|
|
72417
|
+
} catch {
|
|
72418
|
+
title = imagePath.slice(1);
|
|
72419
|
+
}
|
|
72420
|
+
job.actor.name = "reddit";
|
|
72421
|
+
job.object = {
|
|
72422
|
+
type: "page",
|
|
72423
|
+
title,
|
|
72424
|
+
name: "reddit",
|
|
72425
|
+
description: "",
|
|
72426
|
+
image: [{ url: mediaImage }],
|
|
72427
|
+
url: job.actor.id,
|
|
72428
|
+
favicon: "/favicon.ico"
|
|
72429
|
+
};
|
|
72430
|
+
this.log.debug(`reddit media link unwrapped for ${job.actor.id}`);
|
|
72431
|
+
cb(null, job);
|
|
72432
|
+
return;
|
|
72433
|
+
}
|
|
72339
72434
|
const jsonUrl = resolveRedditJson(job.actor.id);
|
|
72340
72435
|
const embedPromise = withDeadline(this.fetchRedditEmbed(job.actor.id), REDDIT_JSON_TIMEOUT_MS).catch(() => {
|
|
72341
72436
|
return;
|
|
@@ -72353,6 +72448,7 @@ class Metadata {
|
|
|
72353
72448
|
name: "reddit",
|
|
72354
72449
|
description: normalizeDescription(post.selftext ?? ""),
|
|
72355
72450
|
image: redditPostImage(post),
|
|
72451
|
+
video: redditPostVideo(post),
|
|
72356
72452
|
url: job.actor.id,
|
|
72357
72453
|
favicon: "/favicon.ico"
|
|
72358
72454
|
};
|
|
@@ -72378,7 +72474,7 @@ class Metadata {
|
|
|
72378
72474
|
cb(null, job);
|
|
72379
72475
|
return;
|
|
72380
72476
|
}
|
|
72381
|
-
cb(new Error(`No Reddit metadata available for ${job.actor.id}`));
|
|
72477
|
+
cb(markExpectedError(new Error(`No Reddit metadata available for ${job.actor.id}`)));
|
|
72382
72478
|
}
|
|
72383
72479
|
fetchRedditJson(url) {
|
|
72384
72480
|
return new Promise((resolve, reject) => {
|
|
@@ -72441,7 +72537,7 @@ class Metadata {
|
|
|
72441
72537
|
}
|
|
72442
72538
|
}
|
|
72443
72539
|
scrape(job, cb, redditEmbed, scrapeUrl = job.actor.id, youtubeEmbed) {
|
|
72444
|
-
const useCompatUserAgent = isRedditUrl(job.actor.id) || Boolean(resolveYouTubeOEmbed(job.actor.id));
|
|
72540
|
+
const useCompatUserAgent = isRedditUrl(job.actor.id) || isFacebookUrl(job.actor.id) || Boolean(resolveYouTubeOEmbed(job.actor.id));
|
|
72445
72541
|
const userAgent = useCompatUserAgent ? this.compatUserAgent() : this.userAgent();
|
|
72446
72542
|
const dispatcher = this.getDispatcher();
|
|
72447
72543
|
this.log.debug(`scrape started for ${job.actor.id} via ${scrapeUrl}`);
|
|
@@ -72481,18 +72577,24 @@ class Metadata {
|
|
|
72481
72577
|
const { result } = data;
|
|
72482
72578
|
this.log.debug(`scrape completed for ${job.actor.id}`);
|
|
72483
72579
|
const reddit = isRedditUrl(job.actor.id);
|
|
72580
|
+
const facebook = isFacebookUrl(job.actor.id);
|
|
72484
72581
|
const embed = reddit ? await redditEmbed : undefined;
|
|
72485
72582
|
const youtube = await youtubeEmbed;
|
|
72486
72583
|
if (!reddit)
|
|
72487
72584
|
job.actor.id = result.ogUrl || job.actor.id;
|
|
72488
|
-
|
|
72585
|
+
const siteName = result.ogSiteName ?? (facebook ? "Facebook" : undefined);
|
|
72586
|
+
const scrapedImages = facebook ? result.ogImage?.map((image) => ({
|
|
72587
|
+
...image,
|
|
72588
|
+
alt: stripFacebookEngagement(image.alt)
|
|
72589
|
+
})) : result.ogImage;
|
|
72590
|
+
job.actor.name = reddit ? embed?.provider_name ?? "reddit" : siteName ?? job.actor.name ?? "";
|
|
72489
72591
|
job.object = {
|
|
72490
72592
|
type: "page",
|
|
72491
72593
|
language: result.ogLocale,
|
|
72492
|
-
title: embed?.title ?? youtube?.title ?? result.ogTitle,
|
|
72493
|
-
name: embed?.provider_name ?? youtube?.provider_name ??
|
|
72594
|
+
title: embed?.title ?? youtube?.title ?? (facebook ? stripFacebookEngagement(result.ogTitle) : result.ogTitle),
|
|
72595
|
+
name: embed?.provider_name ?? youtube?.provider_name ?? siteName,
|
|
72494
72596
|
description: normalizeDescription(result.ogDescription || ""),
|
|
72495
|
-
image: reddit ? redditPostImages(result.ogImage) ?? redditOEmbedImage(embed ?? {}) :
|
|
72597
|
+
image: reddit ? redditPostImages(result.ogImage) ?? redditOEmbedImage(embed ?? {}) : scrapedImages?.length ? scrapedImages : youtubeOEmbedImage(youtube),
|
|
72496
72598
|
url: reddit ? job.actor.id : result.ogUrl,
|
|
72497
72599
|
favicon: result.favicon || "/favicon.ico",
|
|
72498
72600
|
charset: result.charset
|
|
@@ -72535,7 +72637,7 @@ class Metadata {
|
|
|
72535
72637
|
cb(null, job);
|
|
72536
72638
|
return;
|
|
72537
72639
|
}
|
|
72538
|
-
cb(err);
|
|
72640
|
+
cb(markExpectedError(new Error(`metadata scrape failed for ${job.actor.id}: ${err.message}`)));
|
|
72539
72641
|
});
|
|
72540
72642
|
}
|
|
72541
72643
|
cleanup(cb) {
|
|
@@ -72551,4 +72653,4 @@ export {
|
|
|
72551
72653
|
withDeadline
|
|
72552
72654
|
};
|
|
72553
72655
|
|
|
72554
|
-
//# debugId=
|
|
72656
|
+
//# debugId=136FC9DCA9AFCE9364756E2164756E21
|