diff --git a/fix_ts.js b/fix_ts.js
new file mode 100644
index 0000000..4dc145e
--- /dev/null
+++ b/fix_ts.js
@@ -0,0 +1,20 @@
+const fs = require('fs');
+
+// Fix route.ts
+let route = fs.readFileSync('src/app/api/media/[...path]/route.ts', 'utf8');
+route = route.replace(
+ "fileStream.on('data', (chunk) => controller.enqueue(new Uint8Array(chunk)));",
+ "fileStream.on('data', (chunk) => controller.enqueue(new Uint8Array(chunk as Buffer)));"
+);
+fs.writeFileSync('src/app/api/media/[...path]/route.ts', route, 'utf8');
+
+// Fix MediaTile.tsx
+let tile = fs.readFileSync('src/components/MediaTile.tsx', 'utf8');
+tile = tile.replace(
+ "const target = e.target;",
+ "const target = e.target as HTMLVideoElement;"
+).replace(
+ "const target = e.target;",
+ "const target = e.target as HTMLImageElement;"
+);
+fs.writeFileSync('src/components/MediaTile.tsx', tile, 'utf8');
diff --git a/patch_range.js b/patch_range.js
new file mode 100644
index 0000000..a933a38
--- /dev/null
+++ b/patch_range.js
@@ -0,0 +1,73 @@
+const fs = require('fs');
+
+let route = fs.readFileSync('src/app/api/media/[...path]/route.ts', 'utf8');
+
+const rangeLogic = `
+ // Get file stats for Content-Length
+ const stat = await fs.promises.stat(filePath);
+ const fileSize = stat.size;
+
+ // Handle Range Requests (CRITICAL for video streaming in Safari/Chrome)
+ const rangeHeader = request.headers.get('range');
+ let start = 0;
+ let end = fileSize - 1;
+ let isPartial = false;
+
+ if (rangeHeader) {
+ const parts = rangeHeader.replace(/bytes=/, '').split('-');
+ const partialStart = parts[0];
+ const partialEnd = parts[1];
+
+ start = parseInt(partialStart, 10);
+ end = partialEnd ? parseInt(partialEnd, 10) : fileSize - 1;
+
+ if (start >= fileSize) {
+ return new NextResponse('Requested range not satisfiable', { status: 416 });
+ }
+ isPartial = true;
+ }
+
+ const contentLength = (end - start) + 1;
+
+ // Build response headers
+ const contentType = getSafeContentType(contentTypeExt);
+ const headers = new Headers();
+ headers.set('Content-Type', contentType);
+ headers.set('Content-Length', contentLength.toString());
+ headers.set('Cache-Control', 'public, max-age=3600, stale-while-revalidate=86400');
+ headers.set('Accept-Ranges', 'bytes');
+
+ if (isPartial) {
+ headers.set('Content-Range', \`bytes \${start}-\${end}/\${fileSize}\`);
+ }
+
+ // SVG: force download to prevent XSS
+ if (contentType === 'image/svg+xml') {
+ headers.set('Content-Disposition', \`attachment; filename="\${path.basename(relativePath)}"\`);
+ }
+
+ // Stream the file chunk
+ const fileStream = fs.createReadStream(filePath, { start, end });
+ const webStream = new ReadableStream({
+ start(controller) {
+ fileStream.on('data', (chunk) => controller.enqueue(new Uint8Array(chunk)));
+ fileStream.on('end', () => controller.close());
+ fileStream.on('error', (err) => controller.error(err));
+ },
+ cancel() {
+ fileStream.destroy();
+ },
+ });
+
+ return new NextResponse(webStream, {
+ status: isPartial ? 206 : 200,
+ headers
+ });
+`;
+
+route = route.replace(
+ /\/\/ Get file stats for Content-Length[\s\S]+return new NextResponse\(webStream, \{ headers \}\);/,
+ rangeLogic.trim()
+);
+
+fs.writeFileSync('src/app/api/media/[...path]/route.ts', route, 'utf8');
diff --git a/patch_tile.js b/patch_tile.js
new file mode 100644
index 0000000..089eebd
--- /dev/null
+++ b/patch_tile.js
@@ -0,0 +1,50 @@
+const fs = require('fs');
+let tile = fs.readFileSync('src/components/MediaTile.tsx', 'utf8');
+
+const oldRender = `{isVisible && (
+ <>
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+
{
+ const target = e.target as HTMLImageElement;
+ target.parentElement?.classList.remove('loading-skeleton');
+ }}
+ />
+ {isVideo && (
+
`;
+
+const newRender = `{isVisible && (
+ <>
+ {isVideo ? (
+