Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/1.19.0 #68

Merged
merged 7 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/imageresizer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ app.get("/cdn/:dir/:filename", async (req: Request<{ dir: string; filename: stri
}

// Validate parameters
const validFormats = ["avif", "webp", "jpg"];
const validFormats = ["avif", "jpg"];
const validWidths = ["150", "300", "768", "1024", "original"];

if (width && !validWidths.includes(width.toString())) {
Expand All @@ -57,11 +57,11 @@ app.get("/cdn/:dir/:filename", async (req: Request<{ dir: string; filename: stri

if (format && !validFormats.includes(format.toString())) {
logger.error(`Invalid format parameter: "${format}"`);
res.status(400).send("Invalid format parameter, must be one of: avif, webp, jpg");
res.status(400).send("Invalid format parameter, must be one of: avif, jpg");
return;
}

const targetFormat = (format as "avif" | "webp" | "jpg") || "jpg";
const targetFormat = (format as "avif" | "jpg") || "jpg";
const targetWidth = width ? (width === "original" ? undefined : parseInt(width.toString())) : undefined;

const originalFilePath = path.join(cdnFiles, filename);
Expand Down
50 changes: 42 additions & 8 deletions src/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ events { worker_connections 1024; }

http {
include mime.types;

gzip on;
gzip_disable "msie6";

gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types
application/atom+xml
application/geo+json
application/javascript
application/x-javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/xhtml+xml
application/xml
font/eot
font/otf
font/ttf
image/svg+xml
text/css
text/javascript
text/plain
text/xml;

limit_req_zone $http_x_forwarded_for zone=myhigherlimit:10m rate=10r/s;
limit_req_zone $http_x_forwarded_for zone=mylimit:10m rate=3r/s;

Expand All @@ -17,16 +48,9 @@ http {
listen 80;
listen [::]:80;

root /var/www/data;
index index.html;

access_log /var/log/nginx/access_custom.log compression;
access_log /dev/stdout compression;

location ~ /\.ht {
deny all;
}

location ^~ /cdn/ {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
Expand All @@ -43,6 +67,16 @@ http {
proxy_pass http://frontend:3000;
}

location ~ /(brammen\.jpg|chris\.jpg|jay\.jpg|peter\.jpg|sep\.jpg|ps\.png|reddit\-logo\.svg|threads\-logo\.svg|twitch\-logo\.svg)$ {
limit_req zone=mylimit burst=50 nodelay;

proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
proxy_pass http://frontend:3000;

expires 365d;
}

location / {
limit_req zone=mylimit burst=50 nodelay;

Expand All @@ -51,4 +85,4 @@ http {
proxy_pass http://frontend:3000;
}
}
}
}
23 changes: 11 additions & 12 deletions src/psaggregator/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/psaggregator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "psaggregator",
"version": "1.18.0",
"version": "1.19.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",
Expand Down
7 changes: 6 additions & 1 deletion src/psaggregator/src/lib/components/BigHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
<div class="flex items-center gap-x-4 border-b p-4">
<div>
<a href="/">
<img src="/ps.png" alt="psaggregator logo, pietsmiet logo turned upside down, green game controller" class="h-8 w-8" />
<img
src="/ps.png"
alt="psaggregator logo, pietsmiet logo turned upside down, green game controller"
class="h-8 w-8"
height="100"
width="100" />
</a>
</div>
<div class="flex grow flex-nowrap items-center justify-between">
Expand Down
30 changes: 23 additions & 7 deletions src/psaggregator/src/lib/components/CDNImage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,28 @@
let classes = "";
export { classes as class };

function getPreferredImageFormat() {
let imageSrc = "";

function supportsAVIF() {
return new Promise((resolve) => {
const avifImage =
"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
const img = new Image();
img.onload = () => resolve(true);
img.onerror = () => resolve(false);
img.src = avifImage;
});
}

async function getPreferredImageFormat() {
if (!browser || !window || !window.matchMedia) {
return "jpg";
}

if (window.matchMedia && window.matchMedia("(image-avif)").matches) {
if (await supportsAVIF()) {
return "avif";
} else if (window.matchMedia && window.matchMedia("(image-webp)").matches) {
return "webp";
}

return "jpg"; // fallback
}

Expand Down Expand Up @@ -50,9 +62,13 @@
return "300"; // fallback
}

$: imageSrc = `${src}?format=${getPreferredImageFormat()}&width=${getPreferredImageSize()}`;
async function calculateImageSrc(src: string | null | undefined) {
imageSrc = `${src}?format=${await getPreferredImageFormat()}&width=${getPreferredImageSize()}`;
}

$: browser && calculateImageSrc(src);
</script>

{#if browser}
<img src={imageSrc} alt={alt ?? "unknown"} title={title ?? alt ?? "unknown"} {loading} class={style} />
{#if imageSrc}
<img src={imageSrc} alt={alt ?? "unknown"} title={title ?? alt ?? "unknown"} {loading} class={classes} {style} />
{/if}
9 changes: 8 additions & 1 deletion src/psaggregator/src/lib/components/InstagramPost.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import CdnImage from "./CDNImage.svelte";

export let post: Information & { InformationResource: InformationResource[] };
export let loading: "lazy" | "eager" = "lazy";

let video: HTMLVideoElement;
$: isVideoOnly =
Expand Down Expand Up @@ -59,7 +60,13 @@
{/each}
</div>
{:else if post.imageUri}
<CdnImage size="large" class="m-4 rounded-xl md:m-8" src={post.imageUri} alt={"community post attachment"} title={post.text} />
<CdnImage
size="large"
class="m-4 rounded-xl md:m-8"
src={post.imageUri}
alt={"community post attachment"}
title={post.text}
{loading} />
{/if}
</div>
</Card.Root>
104 changes: 56 additions & 48 deletions src/psaggregator/src/lib/components/InstagramStoriesContainer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -184,62 +184,70 @@

<MediaQuery query="(min-width: 768px)" let:matches>
{#if active}
<div class="absolute left-0 top-0 z-10 flex h-full w-full flex-col bg-black">
<div
class="max-w-screen absolute left-0 top-0 z-10 flex h-screen max-h-screen w-screen flex-col overflow-hidden bg-black pt-12 lg:pt-12">
<div
class="story-container flex h-full w-full flex-col overflow-hidden lg:mx-auto lg:w-1/2"
class="story-container max-w-screen flex h-screen max-h-screen w-screen flex-col overflow-hidden lg:mx-auto lg:w-1/2"
class:pause={touchStartX}
on:touchstart={touchStartHandler}
on:touchend={touchEndHandler}>
<div class="progress-container flex w-full px-2 pt-4" bind:this={progressContainer}>
{#each stories as story, index}
{@const duration =
story.InformationResource?.length && story.InformationResource[0].videoDuration
? story.InformationResource[0].videoDuration
: 15}
<div
style="animation-duration: {duration}s"
class:active={currentIndex === index}
class:passed={currentIndex > index}
class="progress"
on:animationend={playNext}
on:click={() => {
playSpecific(index);
}}
on:keydown={void 0}
role="button"
tabindex="0">
</div>
{/each}
</div>
<div class="mt-2 flex w-full items-center justify-between px-2">
<div class="flex items-center gap-x-2">
<img src="{filterKey}.jpg" alt={filterKey} class="h-12 w-12 rounded-full object-cover" />
<span class="text-sm font-bold text-white">{titleCase(filterKey)}</span>
<div class="max-w-screen lg:max-w-1/2 absolute top-12 z-10 w-screen lg:top-0 lg:w-1/2">
<div class="progress-container flex w-full max-w-full px-2 pt-4" bind:this={progressContainer}>
{#each stories as story, index}
{@const duration =
story.InformationResource?.length && story.InformationResource[0].videoDuration
? story.InformationResource[0].videoDuration
: 15}
<div
style="animation-duration: {duration}s"
class:active={currentIndex === index}
class:passed={currentIndex > index}
class="progress"
on:animationend={playNext}
on:click={() => {
playSpecific(index);
}}
on:keydown={void 0}
role="button"
tabindex="0">
</div>
{/each}
</div>
<div class="flex items-center gap-x-2">
{#if selectedStory && selectedStory.InformationResource?.length && selectedStory.InformationResource[0].videoUri}
<button
on:click={(e) => {
video.muted = !video.muted;
e.stopPropagation();
}}>
{#if video}
{#if video.muted}
<VolumeMute class="h-8 w-8" />
{:else}
<VolumeUp class="h-8 w-8" />
<div class="mt-2 flex w-full items-center justify-between px-2">
<div class="flex items-center gap-x-2">
<img
src="{filterKey}.jpg"
alt={filterKey}
class="aspect-square h-12 w-12 rounded-full object-cover"
width="64"
height="64" />
<span class="text-sm font-bold text-white">{titleCase(filterKey)}</span>
</div>
<div class="flex items-center gap-x-2">
{#if selectedStory && selectedStory.InformationResource?.length && selectedStory.InformationResource[0].videoUri}
<button
on:click={(e) => {
video.muted = !video.muted;
e.stopPropagation();
}}>
{#if video}
{#if video.muted}
<VolumeMute class="h-8 w-8" />
{:else}
<VolumeUp class="h-8 w-8" />
{/if}
{/if}
{/if}
</button>
{/if}
<button on:click={() => (active = false)}>
<CloseLarge class="h-8 w-8" />
</button>
{/if}
<button on:click={() => (active = false)}>
<CloseLarge class="h-8 w-8" />
</button>
</div>
</div>
</div>
<div
bind:this={storyView}
class="flex h-full w-full items-center justify-center overflow-y-auto py-2 md:py-8"
class="flex w-full justify-center overflow-hidden"
on:click={clickImageHandler}
on:keydown={void 0}
role="button"
Expand All @@ -253,14 +261,14 @@
loop
muted
playsinline
class="h-full w-full object-contain"></video>
class="rounded-[20px] object-contain"></video>
{:else}
<CdnImage
size="full"
src={selectedStory.imageUri}
alt={selectedStory.text}
title={selectedStory.text}
class="h-full w-full object-contain" />
class="rounded-[20px] object-contain" />
{/if}
{/if}
</div>
Expand All @@ -278,7 +286,7 @@
on:keydown={void 0}
role="button"
tabindex="0">
<img class="h-full w-full rounded-full object-cover" src="{filterKey}.jpg" alt={filterKey} />
<img class="h-full w-full rounded-full object-cover" src="{filterKey}.jpg" alt={filterKey} width="64" height="64" />
</div>
{/if}
</MediaQuery>
Loading