Skip to content

Commit e190295

Browse files
committed
fix: migrate media location and thumbnails to agnostic space provider
1 parent dae86c9 commit e190295

35 files changed

+140
-62
lines changed

packages/@liexp/backend/src/flows/event/createEventFromURL.flow.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as TE from "fp-ts/lib/TaskEither.js";
77
import { Equal } from "typeorm";
88
import { type ConfigContext } from "../../context/config.context.js";
99
import { type DatabaseContext } from "../../context/db.context.js";
10+
import { type ENVContext } from "../../context/env.context.js";
1011
import { type FSClientContext } from "../../context/fs.context.js";
1112
import { type NERProviderContext } from "../../context/index.js";
1213
import { type LoggerContext } from "../../context/logger.context.js";
@@ -24,7 +25,8 @@ export type CreateEventFromURLContext = LoggerContext &
2425
NERProviderContext &
2526
DatabaseContext &
2627
URLMetadataContext &
27-
PuppeteerProviderContext;
28+
PuppeteerProviderContext &
29+
ENVContext;
2830

2931
export const createEventFromURL = <C extends CreateEventFromURLContext>(
3032
user: UserEntity,

packages/@liexp/backend/src/flows/event/extractEventFromURL.flow.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { type Metadata } from "page-metadata-parser";
1717
import type * as puppeteer from "puppeteer-core";
1818
import { type ConfigContext } from "../../context/config.context.js";
1919
import { type DatabaseContext } from "../../context/db.context.js";
20+
import { type ENVContext } from "../../context/env.context.js";
2021
import { type FSClientContext } from "../../context/fs.context.js";
2122
import { type NERProviderContext } from "../../context/index.js";
2223
import { type LoggerContext } from "../../context/logger.context.js";
@@ -166,7 +167,8 @@ const extractByProvider =
166167
ConfigContext &
167168
FSClientContext &
168169
NERProviderContext &
169-
DatabaseContext,
170+
DatabaseContext &
171+
ENVContext,
170172
>(
171173
p: puppeteer.Page,
172174
host: string,
@@ -201,7 +203,7 @@ const extractByProvider =
201203
TE.Do,
202204
TE.bind("link", () => {
203205
return pipe(
204-
LinkIO.decodeSingle(l),
206+
LinkIO.decodeSingle(l, ctx.env.SPACE_ENDPOINT),
205207
fp.E.fold(() => fp.O.none, fp.O.some),
206208
fp.TE.right,
207209
);
@@ -276,7 +278,8 @@ export const extractEventFromURL =
276278
FSClientContext &
277279
NERProviderContext &
278280
DatabaseContext &
279-
URLMetadataContext,
281+
URLMetadataContext &
282+
ENVContext,
280283
>(
281284
p: puppeteer.Page,
282285
user: UserEntity,

packages/@liexp/backend/src/flows/tg/parseVideo.flow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const parseVideo =
7373
TE.mapLeft(ServerError.fromUnknown),
7474
);
7575
}),
76-
TE.map((r) => ensureHTTPS(r.Location)),
76+
TE.map((r) => ensureHTTPS(ctx.env.SPACE_ENDPOINT, r.Location)),
7777
),
7878
),
7979
);

packages/@liexp/backend/src/io/link.io.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
MediaExtraMonoid,
1010
} from "@liexp/shared/lib/io/http/Media/MediaExtra.js";
1111
import * as io from "@liexp/shared/lib/io/index.js";
12+
import { ensureHTTPS } from "@liexp/shared/lib/utils/url.utils.js";
1213
import { IOError } from "@ts-endpoint/core";
1314
import { Schema } from "effect";
1415
import * as E from "fp-ts/lib/Either.js";
@@ -17,6 +18,7 @@ import { IOCodec } from "./DomainCodec.js";
1718

1819
const toLinkIO = (
1920
link: LinkEntity,
21+
spaceEndpoint: string,
2022
): E.Either<_DecodeError, io.http.Link.Link> => {
2123
return pipe(
2224
{
@@ -36,7 +38,12 @@ const toLinkIO = (
3638
link.image.extra,
3739
)
3840
: undefined,
39-
thumbnail: link.image.thumbnail ?? undefined,
41+
location: link.image.location
42+
? ensureHTTPS(spaceEndpoint, link.image.location)
43+
: undefined,
44+
thumbnail: link.image.thumbnail
45+
? ensureHTTPS(spaceEndpoint, link.image.thumbnail)
46+
: undefined,
4047
links: link.image.links ?? [],
4148
events: (link.image.events ?? []).map((e) =>
4249
Schema.is(UUID)(e) ? e : e.id,

packages/@liexp/backend/src/io/media.io.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ const encodeMedia = (
3030
return pipe(
3131
Schema.encodeEither(io.http.Media.AdminMedia)({
3232
...media,
33+
location: ensureHTTPS(spaceEndpoint, media.location),
3334
label: media.label ?? media.location,
3435
description: media.description ?? undefined,
35-
thumbnail: media.thumbnail ? ensureHTTPS(media.thumbnail) : undefined,
36+
thumbnail: media.thumbnail
37+
? ensureHTTPS(spaceEndpoint, media.thumbnail)
38+
: undefined,
3639
transferable: !media.location.includes(spaceEndpoint),
3740
creator: Schema.is(UUID)(media.creator)
3841
? media.creator
@@ -65,7 +68,7 @@ const decodeMedia = (
6568
...media,
6669
label: media.label ?? media.location,
6770
description: media.description ?? undefined,
68-
location: ensureHTTPS(media.location),
71+
location: ensureHTTPS(spaceEndpoint, media.location),
6972
creator: Schema.is(UUID)(media.creator)
7073
? media.creator
7174
: media.creator?.id,
@@ -76,8 +79,10 @@ const decodeMedia = (
7679
areas: (media.areas ?? []).map((a) => (Schema.is(UUID)(a) ? a : a.id)),
7780
featuredInStories: media.featuredInStories ?? [],
7881
socialPosts: media.socialPosts ?? [],
79-
thumbnail: media.thumbnail ? ensureHTTPS(media.thumbnail) : undefined,
80-
transferable: !media.location.includes(spaceEndpoint),
82+
thumbnail: media.thumbnail
83+
? ensureHTTPS(spaceEndpoint, media.thumbnail)
84+
: undefined,
85+
transferable: !media.location.startsWith("/"),
8186
createdAt: media.createdAt.toISOString(),
8287
updatedAt: media.updatedAt.toISOString(),
8388
deletedAt: media.deletedAt?.toISOString() ?? undefined,

packages/@liexp/backend/src/providers/puppeteer.provider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,11 @@ export const GetPuppeteerProvider = (
172172
});
173173
b.on("disconnected", (e) => {
174174
puppeteerLogger.debug.log(
175-
"browser disconnected %ds",
175+
"browser disconnected %ds: %O",
176176
differenceInSeconds(new Date(), connectedAt, {
177177
roundingMethod: "ceil",
178178
}),
179+
e,
179180
);
180181
});
181182
return b;

packages/@liexp/backend/src/providers/wikipedia/wikipedia.provider.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ interface WikipediaProviderOpts {
5252
logger: Logger;
5353
client: Bot;
5454
restClient: AxiosInstance;
55+
spaceEndpoint: string;
5556
}
5657

5758
const toMWError = (e: unknown): Error => {
@@ -62,6 +63,7 @@ export const WikipediaProvider = ({
6263
logger,
6364
client,
6465
restClient,
66+
spaceEndpoint,
6567
}: WikipediaProviderOpts): WikipediaProvider => {
6668
logger.debug.log("Wikipedia provider created");
6769

@@ -127,7 +129,7 @@ export const WikipediaProvider = ({
127129
items.filter((i) => i.type === "image"),
128130
fp.A.head,
129131
fp.O.chainNullableK((r) => r.srcset?.[0]?.src),
130-
fp.O.map((url) => ensureHTTPS(url)),
132+
fp.O.map((url) => ensureHTTPS(spaceEndpoint, url)),
131133
fp.O.toUndefined,
132134
);
133135
}),
Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { Schema } from "effect/index";
12
import * as R from "fp-ts/lib/Record.js";
23
import { pipe } from "fp-ts/lib/function.js";
34
import qs from "query-string";
4-
import { type URL } from "../io/http/Common/URL.js";
5+
import { URL } from "../io/http/Common/URL.js";
56

67
export const sanitizeURL = (url: URL): URL => {
78
const [cleanURL, query] = url.split("?");
@@ -14,20 +15,28 @@ export const sanitizeURL = (url: URL): URL => {
1415
);
1516

1617
if (!R.isEmpty(cleanQuery)) {
17-
return `${cleanURL}?${qs.stringify(cleanQuery)}` as URL;
18+
return Schema.decodeSync(URL)(`${cleanURL}?${qs.stringify(cleanQuery)}`);
1819
}
1920

20-
return cleanURL as URL;
21+
return Schema.decodeSync(URL)(cleanURL);
2122
};
2223

23-
export const ensureHTTPS = (url: string): URL => {
24-
if (url.startsWith("https://") || url.startsWith("http://")) {
25-
return url as URL;
24+
const encodeWithSpaceEndpoint = (spaceHost: string, url: string): string => {
25+
if (url.startsWith("//")) {
26+
return `https:${url}`;
2627
}
2728

28-
if (url.startsWith("//")) {
29-
return `https:${url}` as URL;
29+
if (url.startsWith("/")) {
30+
return `https://${spaceHost}${url}`;
31+
}
32+
33+
if (url.startsWith("https://") || url.startsWith("http://")) {
34+
return url;
3035
}
3136

32-
return `https://${url}` as URL;
37+
return `https://${url}`;
38+
};
39+
40+
export const ensureHTTPS = (spaceHost: string, url: string): URL => {
41+
return pipe(encodeWithSpaceEndpoint(spaceHost, url), Schema.decodeSync(URL));
3342
};

packages/@liexp/ui/src/components/Cards/Events/EventCard.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ const EventCard = <E extends SearchEvent.SearchEvent>({
8787
height: props.style?.maxHeight ?? 150,
8888
width: isVertical ? "100%" : 150,
8989
}}
90+
onError={(e) => {
91+
if (defaultImage && e.currentTarget.src !== defaultImage) {
92+
e.currentTarget.src = defaultImage;
93+
}
94+
}}
9095
/>
9196
</Stack>
9297
) : null}

packages/@liexp/ui/src/components/Media/ExpandableImageElement.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ interface ExpandableImageElementProps {
6464
onLoad?: (rect: DOMRect) => void;
6565
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
6666
disableZoom?: boolean;
67+
fallbackImage?: string;
6768
}
6869

6970
const ExpandableImageElement: React.FC<ExpandableImageElementProps> = ({
@@ -73,6 +74,7 @@ const ExpandableImageElement: React.FC<ExpandableImageElementProps> = ({
7374
onLoad,
7475
onClick,
7576
disableZoom = false,
77+
fallbackImage,
7678
}) => {
7779
const [modal, showModal] = useModal({ disablePortal: false });
7880

@@ -135,6 +137,11 @@ const ExpandableImageElement: React.FC<ExpandableImageElementProps> = ({
135137
const rect = e.currentTarget.getBoundingClientRect();
136138
onLoad?.(rect);
137139
}}
140+
onError={(e) => {
141+
if (fallbackImage) {
142+
e.currentTarget.src = fallbackImage;
143+
}
144+
}}
138145
loading="lazy"
139146
/>
140147
{!disableZoom ? (

0 commit comments

Comments
 (0)