diff --git a/src/imageresizer/src/index.ts b/src/imageresizer/src/index.ts
index 569b242..f58ccd3 100644
--- a/src/imageresizer/src/index.ts
+++ b/src/imageresizer/src/index.ts
@@ -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())) {
@@ -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);
diff --git a/src/nginx/nginx.conf b/src/nginx/nginx.conf
index 4a17fb8..b6f056c 100644
--- a/src/nginx/nginx.conf
+++ b/src/nginx/nginx.conf
@@ -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;
@@ -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;
@@ -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;
@@ -51,4 +85,4 @@ http {
proxy_pass http://frontend:3000;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/psaggregator/package-lock.json b/src/psaggregator/package-lock.json
index 77dc4da..62dd91c 100644
--- a/src/psaggregator/package-lock.json
+++ b/src/psaggregator/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "psaggregator",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "psaggregator",
- "version": "1.18.0",
+ "version": "1.19.0",
"dependencies": {
"@internationalized/date": "^3.5.5",
"@sentry/sveltekit": "^8.41.0",
@@ -2843,16 +2843,15 @@
}
},
"node_modules/@sveltejs/kit": {
- "version": "2.8.5",
- "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.5.tgz",
- "integrity": "sha512-5ry1jPd4r9knsphDK2eTYUFPhFZMqF0PHFfa8MdMQCqWaKwLSXdFMU/Vevih1I7C1/VNB5MvTuFl1kXu5vx8UA==",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.9.0.tgz",
+ "integrity": "sha512-W3E7ed3ChB6kPqRs2H7tcHp+Z7oiTFC6m+lLyAQQuyXeqw6LdNuuwEUla+5VM0OGgqQD+cYD6+7Xq80vVm17Vg==",
"hasInstallScript": true,
- "license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
"cookie": "^0.6.0",
"devalue": "^5.1.0",
- "esm-env": "^1.0.0",
+ "esm-env": "^1.2.1",
"import-meta-resolve": "^4.1.0",
"kleur": "^4.1.5",
"magic-string": "^0.30.5",
@@ -2869,9 +2868,9 @@
"node": ">=18.13"
},
"peerDependencies": {
- "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1",
+ "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0",
"svelte": "^4.0.0 || ^5.0.0-next.0",
- "vite": "^5.0.3"
+ "vite": "^5.0.3 || ^6.0.0"
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
@@ -4339,9 +4338,9 @@
}
},
"node_modules/esm-env": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
- "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA=="
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.1.tgz",
+ "integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng=="
},
"node_modules/espree": {
"version": "9.6.1",
diff --git a/src/psaggregator/package.json b/src/psaggregator/package.json
index a08c459..c65c790 100644
--- a/src/psaggregator/package.json
+++ b/src/psaggregator/package.json
@@ -1,6 +1,6 @@
{
"name": "psaggregator",
- "version": "1.18.0",
+ "version": "1.19.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",
diff --git a/src/psaggregator/src/lib/components/BigHeader.svelte b/src/psaggregator/src/lib/components/BigHeader.svelte
index 038aa2c..e003845 100644
--- a/src/psaggregator/src/lib/components/BigHeader.svelte
+++ b/src/psaggregator/src/lib/components/BigHeader.svelte
@@ -8,7 +8,12 @@
diff --git a/src/psaggregator/src/lib/components/CDNImage.svelte b/src/psaggregator/src/lib/components/CDNImage.svelte
index 201cd15..e18f883 100644
--- a/src/psaggregator/src/lib/components/CDNImage.svelte
+++ b/src/psaggregator/src/lib/components/CDNImage.svelte
@@ -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
}
@@ -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);
-{#if browser}
-
+{#if imageSrc}
+
{/if}
diff --git a/src/psaggregator/src/lib/components/InstagramPost.svelte b/src/psaggregator/src/lib/components/InstagramPost.svelte
index e256c13..26ff395 100644
--- a/src/psaggregator/src/lib/components/InstagramPost.svelte
+++ b/src/psaggregator/src/lib/components/InstagramPost.svelte
@@ -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 =
@@ -59,7 +60,13 @@
{/each}
{:else if post.imageUri}
-
+
{/if}
diff --git a/src/psaggregator/src/lib/components/InstagramStoriesContainer.svelte b/src/psaggregator/src/lib/components/InstagramStoriesContainer.svelte
index 30cc5ff..bb398ed 100644
--- a/src/psaggregator/src/lib/components/InstagramStoriesContainer.svelte
+++ b/src/psaggregator/src/lib/components/InstagramStoriesContainer.svelte
@@ -184,62 +184,70 @@
{#if active}
-
+
-
- {#each stories as story, index}
- {@const duration =
- story.InformationResource?.length && story.InformationResource[0].videoDuration
- ? story.InformationResource[0].videoDuration
- : 15}
-
index}
- class="progress"
- on:animationend={playNext}
- on:click={() => {
- playSpecific(index);
- }}
- on:keydown={void 0}
- role="button"
- tabindex="0">
-
- {/each}
-
-
-
-
-
{titleCase(filterKey)}
+
+
+ {#each stories as story, index}
+ {@const duration =
+ story.InformationResource?.length && story.InformationResource[0].videoDuration
+ ? story.InformationResource[0].videoDuration
+ : 15}
+
index}
+ class="progress"
+ on:animationend={playNext}
+ on:click={() => {
+ playSpecific(index);
+ }}
+ on:keydown={void 0}
+ role="button"
+ tabindex="0">
+
+ {/each}
-
- {#if selectedStory && selectedStory.InformationResource?.length && selectedStory.InformationResource[0].videoUri}
-
+ class="rounded-[20px] object-contain">
{:else}
+ class="rounded-[20px] object-contain" />
{/if}
{/if}
@@ -278,7 +286,7 @@
on:keydown={void 0}
role="button"
tabindex="0">
-
+
{/if}
diff --git a/src/psaggregator/src/lib/components/NewsBig.svelte b/src/psaggregator/src/lib/components/NewsBig.svelte
index 052e751..b5ab50c 100644
--- a/src/psaggregator/src/lib/components/NewsBig.svelte
+++ b/src/psaggregator/src/lib/components/NewsBig.svelte
@@ -88,15 +88,15 @@
});
-
+
YouTube
- {#each youtubeCommunityPosts as youtube}
-
+ {#each youtubeCommunityPosts as youtube, index}
+
{/each}
{#if loading[ImportType.YouTube]}
@@ -109,8 +109,8 @@
Instagram
- {#each instagramPosts as instagram}
-
+ {#each instagramPosts as instagram, index}
+
{/each}
{#if loading[ImportType.Instagram]}
@@ -123,8 +123,8 @@
Twitter
- {#each twitterPosts as twitter}
-
+ {#each twitterPosts as twitter, index}
+
{/each}
{#if loading[ImportType.Twitter]}
diff --git a/src/psaggregator/src/lib/components/NewsSmall.svelte b/src/psaggregator/src/lib/components/NewsSmall.svelte
index 50e3497..2b7b5d0 100644
--- a/src/psaggregator/src/lib/components/NewsSmall.svelte
+++ b/src/psaggregator/src/lib/components/NewsSmall.svelte
@@ -1,8 +1,7 @@
@@ -20,7 +21,7 @@
{#if entry.imageUri}
-
+
{/if}
diff --git a/src/psaggregator/src/lib/components/TwitterPost.svelte b/src/psaggregator/src/lib/components/TwitterPost.svelte
index c0e0731..d03a080 100644
--- a/src/psaggregator/src/lib/components/TwitterPost.svelte
+++ b/src/psaggregator/src/lib/components/TwitterPost.svelte
@@ -6,6 +6,7 @@
import CdnImage from "./CDNImage.svelte";
export let post: Information & { InformationResource: InformationResource[] };
+ export let loading: "lazy" | "eager" = "lazy";
function titleCase(str: string | null) {
if (!str) return "";
@@ -42,7 +43,7 @@
src={resource.imageUri}
alt={resource.remoteId}
title={resource.id}
- loading="lazy" />
+ {loading} />
{/if}
{/each}
diff --git a/src/psaggregator/src/lib/components/YouTubeCommunityPost.svelte b/src/psaggregator/src/lib/components/YouTubeCommunityPost.svelte
index b5a5ba7..f6d63c0 100644
--- a/src/psaggregator/src/lib/components/YouTubeCommunityPost.svelte
+++ b/src/psaggregator/src/lib/components/YouTubeCommunityPost.svelte
@@ -6,6 +6,7 @@
import CdnImage from "./CDNImage.svelte";
export let post: Information;
+ export let loading: "lazy" | "eager" = "lazy";
@@ -15,7 +16,13 @@
{/if}
{post.text}
{#if post.imageUri}
-
+
{/if}
diff --git a/src/psaggregator/src/routes/+page.svelte b/src/psaggregator/src/routes/+page.svelte
index 0c633a1..54ac575 100644
--- a/src/psaggregator/src/routes/+page.svelte
+++ b/src/psaggregator/src/routes/+page.svelte
@@ -9,11 +9,105 @@
import MediaQuery from "$lib/utils/MediaQuery.svelte";
import InstagramPost from "$lib/components/InstagramPost.svelte";
import TwitchEntry from "$lib/components/TwitchEntry.svelte";
- import { version } from "$app/environment";
+ import { browser, version } from "$app/environment";
import TwitterPost from "$lib/components/TwitterPost.svelte";
- import { GITHUB_URL, MAIL_TO_URL } from "../config/config";
+ import { GITHUB_URL, LOW_DATA_MODE, MAIL_TO_URL } from "../config/config";
+ import { invalidateAll } from "$app/navigation";
+ import { onDestroy, onMount } from "svelte";
+ import FaviconNotification from "favicon-notification";
+ import type { ContentPiece, Information, ScheduledContentPiece } from "@prisma/client";
+ import moment from "moment";
export let data: PageServerData;
+
+ let reloadInterval: number | NodeJS.Timeout | undefined = undefined;
+ let isNotificationVisible = false;
+
+ function findNewestDate() {
+ const dates = [
+ ...(data.today?.map((entry: ScheduledContentPiece) => moment(entry.startDate)) ?? []),
+ ...(data.youtubeCommunityPosts?.map((entry: Information) => moment(entry.date)) ?? []),
+ ...(data.instagramPosts?.map((entry: Information) => moment(entry.date)) ?? []),
+ ...(data.twitterPosts?.map((entry: Information) => moment(entry.date)) ?? []),
+ ...(data.redditPosts?.map((entry: RedditPost) => moment(entry.date)) ?? []),
+ ...(data.videos?.map((entry: ContentPiece) => moment(entry.startDate)) ?? []),
+ ...(data.upcomingStreams?.map((entry: ScheduledContentPiece) => moment(entry.startDate)) ?? []),
+ moment((data.twitchStatus as TwitchStatus)?.startedAt ?? 0)
+ ];
+
+ return Math.max(...dates);
+ }
+
+ async function reload() {
+ if ($LOW_DATA_MODE) return;
+
+ const currentLastDate = findNewestDate();
+ const currentLastUploadPlanEntriesWithLink = data.today.filter((entry: ScheduledContentPiece) => entry.href).length;
+
+ await invalidateAll();
+
+ const newLastDate = findNewestDate();
+ const newUploadPlanEntriesWithLink = data.today.filter((entry: ScheduledContentPiece) => entry.href).length;
+
+ if (
+ (currentLastDate !== newLastDate && currentLastDate && newLastDate) ||
+ currentLastUploadPlanEntriesWithLink !== newUploadPlanEntriesWithLink
+ ) {
+ isNotificationVisible = true;
+ try {
+ FaviconNotification.add();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+
+ function onUserActive() {
+ if (!isNotificationVisible) return;
+
+ isNotificationVisible = false;
+ try {
+ FaviconNotification.remove();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+
+ function handleVisibilityChange() {
+ if (document.visibilityState === "visible") {
+ onUserActive();
+ }
+ }
+
+ function handleUserInteraction() {
+ onUserActive();
+ }
+
+ onMount(() => {
+ if (browser) {
+ reloadInterval = setInterval(reload, 1000 * 60 * 5);
+
+ FaviconNotification.init({
+ color: "#ff0000",
+ lineColor: "#000000",
+ url: "/favicon.png"
+ });
+
+ document.addEventListener("visibilitychange", handleVisibilityChange);
+ window.addEventListener("mousemove", handleUserInteraction);
+ window.addEventListener("focus", handleUserInteraction);
+ }
+ });
+
+ onDestroy(() => {
+ if (browser) {
+ if (reloadInterval) clearInterval(reloadInterval);
+
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
+ window.removeEventListener("mousemove", handleUserInteraction);
+ window.removeEventListener("focus", handleUserInteraction);
+ }
+ });
+
Version 1.19.0
+
+
Neue Features
+
+ Automatisches Neuladen
+ Die Startseite lädt nun alle fünf Minuten automatisch neu, um neue Inhalte anzuzeigen.
+
+
Überarbeitungen
+
+ Verbesserte Ladezeiten
+ Weitere Optimierungen wurden vorgenommen, um die Ladezeiten zu verbessern.
+
+
+
Version 1.18.0
Überarbeitungen
@@ -58,15 +72,15 @@
Nach oben scrollen
Wenn auf mobilen Endgeräten nun auf den oberen Bildschirmrand getippt wird, wird die Seite nach oben gescrollt.
-
-
Überarbeitungen
-
- Einheitlichere Überschriften
- Die Überschriften wurden einheitlicher gestaltet.
-
-
-
Mehr Footer-Informationen
-
Auf mobilen Endgeräten wird nun mehr Information im Footer angezeigt.
+
Überarbeitungen
+
+ Einheitlichere Überschriften
+ Die Überschriften wurden einheitlicher gestaltet.
+
+
+ Mehr Footer-Informationen
+ Auf mobilen Endgeräten wird nun mehr Information im Footer angezeigt.
+
Version 1.15.0
diff --git a/src/psaggregator/src/routes/news/+page.svelte b/src/psaggregator/src/routes/news/+page.svelte
index ba8cfa0..12f2123 100644
--- a/src/psaggregator/src/routes/news/+page.svelte
+++ b/src/psaggregator/src/routes/news/+page.svelte
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/src/psaggregator/src/routes/randomvideo/+page.svelte b/src/psaggregator/src/routes/randomvideo/+page.svelte
index c61cf4c..098ea3e 100644
--- a/src/psaggregator/src/routes/randomvideo/+page.svelte
+++ b/src/psaggregator/src/routes/randomvideo/+page.svelte
@@ -11,7 +11,7 @@
- {#each data.videos as video}
+ {#each data.videos as video, index}
{#if video.startDate}
{@const newMonth = checkMonth(video.startDate)}
{#if newMonth}
@@ -228,7 +228,10 @@
{/if}
{/if}
{#if $VIDEO_COMPLEXE_VIEW}
-
+
{:else}
+ title={video.title}
+ loading={index < 10 ? "eager" : "lazy"} />
{/if}
{/each}