16 };
17 } else {
18 const client = new Cerebras({ apiKey: Deno.env.get("CEREBRAS_API_KEY") });
19 const completion = await client.chat.completions.create({
20 messages: [
13 });
14
15 // Fetch weather data for Madrid using Open-Meteo API
16 const weatherResponse = await fetch(
17 'https://api.open-meteo.com/v1/forecast?latitude=40.4168&longitude=-3.7038¤t=temperature_2m,weather_code,wind_speed_10m&timezone=Europe%2FMadrid'
18 );
19
35 JSON.stringify({
36 iss: serviceAccount.client_email,
37 scope: "https://www.googleapis.com/auth/datastore",
38 aud: "https://oauth2.googleapis.com/token",
39 exp: now + 3600,
40 iat: now,
71
72 // ---- Exchange JWT for access token ----
73 const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
74 method: "POST",
75 headers: { "Content-Type": "application/x-www-form-urlencoded" },
90 // ---- Query Firestore publicLenses ----
91 const pubDocRes = await fetch(
92 `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/publicLenses/${id}`,
93 { headers: { Authorization: `Bearer ${access_token}` } },
94 );
106 // ---- Query Firestore private user doc ----
107 const privDocRes = await fetch(
108 `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/users/${owner}/lenses/${id}`,
109 { headers: { Authorization: `Bearer ${access_token}` } },
110 );
116 }
117 const privDoc = await privDocRes.json();
118 const apiToken = privDoc.fields.apiToken.stringValue;
119
120 // ---- Success ----
121 return new Response(JSON.stringify({ apiToken, groupId, lensId }), {
122 headers: corsHeaders(),
123 });
15 // mp4s (AVC)
16 // "http://ftp.nluug.nl/pub/graphics/blender/demo/movies/ToS/tears_of_steel_720p.mov", // 355MB
17 "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4", // 2MB
18 "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4", // 2MB
19 // from https://test-videos.co.uk/bigbuckbunny/mp4-h264
20 "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_5MB.mp4", // 5MB, 720p
21 "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_5MB.mp4", // 5MB, 1080p
22 //"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/WhatCarCanYouGetForAGrand.mp4", // 43MB
23
24 // webm (vp8)
6
7import Parser from "https://esm.sh/rss-parser@3.13.0";
8import { BskyAgent } from "https://esm.sh/@atproto/api@0.13.17";
9
10const RSS_URL = "https://letterboxd.com/petezarustica/rss/";
56 // 4) Deduplicate by checking your recent posts for the same link
57 // (avoids needing KV on Val Town)
58 const feedResp = await agent.api.app.bsky.feed.getAuthorFeed({
59 actor: did,
60 limit: 30,
77 };
78
79 await agent.api.com.atproto.repo.createRecord({
80 repo: did,
81 collection: "app.bsky.feed.post",
1005 "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
1006 "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
1007 "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
1008 "engines": {
1009 "node": ">=0.4.x"
1005 "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
1006 "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
1007 "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
1008 "engines": {
1009 "node": ">=0.4.x"
8}
9
10// Helper: zlib decompress using CompressionStream API (available in Val Town)
11async function inflateUint8Array(uint8array) {
12 const cs = new DecompressionStream("deflate");
356 try {
357 // Pass password as query parameter for authentication
358 const response = await fetch(`/api/posts/${encodeURIComponent(slug)}?password=${encodeURIComponent(password)}`);
359
360 if (!response.ok) {
518
519 try {
520 const response = await fetch(`/api/posts/${encodeURIComponent(currentPost.slug)}`, {
521 method: 'PUT',
522 headers: {
564
565 try {
566 const response = await fetch(`/api/posts/${encodeURIComponent(currentPost.slug)}?password=${encodeURIComponent(currentPassword)}`, {
567 method: 'DELETE'
568 });
625
626 try {
627 const response = await fetch(`/api/posts/${encodeURIComponent(currentPost.slug)}/images`);
628
629 if (!response.ok) {
711 }
712
713 const response = await fetch('/api/images/upload', {
714 method: 'POST',
715 body: formData
39 id: "absolute_regression",
40 name: "Absolute Regression",
41 rssUrl: "https://api.mangaupdates.com/v1/series/73697803962/rss",
42 sourceFilter: "Asura",
43 color: 0x00ff00 // Green
46 id: "eternally_regressing_knight",
47 name: "Eternally Regressing Knight",
48 rssUrl: "https://api.mangaupdates.com/v1/series/35590700362/rss",
49 sourceFilter: "Asura",
50 color: 0x0099ff // Blue