feat: migrate to bun runtime and update dependencies

This commit is contained in:
2025-06-04 08:41:53 +09:00
committed by Satsuki Akiba (aider)
parent bfb6367a56
commit 4db363068d
7 changed files with 61 additions and 32 deletions

View File

@ -14,6 +14,10 @@
"typescript": "^4.0.0", "typescript": "^4.0.0",
"@types/react": "^18.0.0", "@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0", "@types/react-dom": "^18.0.0",
"bun-types": "^0.1.0" "bun-types": "^0.1.0",
} "@types/bun": "latest"
},
"module": "src/index.tsx",
"type": "module",
"private": true
} }

View File

@ -5,11 +5,16 @@
"start": "bun run server.ts" "start": "bun run server.ts"
}, },
"dependencies": { "dependencies": {
"rss-parser": "^3.12.0", "@aws-sdk/client-polly": "^3.823.0",
"openai": "^4.0.0", "openai": "^4.104.0",
"@aws-sdk/client-polly": "^3.0.0", "rss-parser": "^3.13.0"
"better-sqlite3": "^8.0.0",
"bun-router": "^0.1.0"
}, },
"type": "module" "type": "module",
"devDependencies": {
"@types/bun": "latest"
},
"private": true,
"peerDependencies": {
"typescript": "^5"
}
} }

View File

@ -14,9 +14,7 @@ interface FeedItem {
async function main() { async function main() {
const parser = new Parser<FeedItem>(); const parser = new Parser<FeedItem>();
const feedUrls = [ const feedUrls = ["https://example.com/feed1.rss"];
"https://example.com/feed1.rss",
];
for (const url of feedUrls) { for (const url of feedUrls) {
const feed = await parser.parseURL(url); const feed = await parser.parseURL(url);

View File

@ -1,4 +1,4 @@
import Database from "better-sqlite3"; import { Database } from "bun:sqlite";
import path from "path"; import path from "path";
const dbPath = path.join(__dirname, "../data/podcast.db"); const dbPath = path.join(__dirname, "../data/podcast.db");
@ -28,17 +28,26 @@ export interface Episode {
sourceLink: string; sourceLink: string;
} }
export async function markAsProcessed(feedUrl: string, itemId: string): Promise<boolean> { export async function markAsProcessed(
const stmt = db.prepare("SELECT 1 FROM processed_feed_items WHERE feed_url = ? AND item_id = ?"); feedUrl: string,
itemId: string,
): Promise<boolean> {
const stmt = db.prepare(
"SELECT 1 FROM processed_feed_items WHERE feed_url = ? AND item_id = ?",
);
const row = stmt.get(feedUrl, itemId); const row = stmt.get(feedUrl, itemId);
if (row) return true; if (row) return true;
const insert = db.prepare("INSERT INTO processed_feed_items (feed_url, item_id, processed_at) VALUES (?, ?, ?)"); const insert = db.prepare(
"INSERT INTO processed_feed_items (feed_url, item_id, processed_at) VALUES (?, ?, ?)",
);
insert.run(feedUrl, itemId, new Date().toISOString()); insert.run(feedUrl, itemId, new Date().toISOString());
return false; return false;
} }
export async function saveEpisode(ep: Episode): Promise<void> { export async function saveEpisode(ep: Episode): Promise<void> {
const stmt = db.prepare("INSERT OR IGNORE INTO episodes (id, title, pubDate, audioPath, sourceLink) VALUES (?, ?, ?, ?, ?)"); const stmt = db.prepare(
"INSERT OR IGNORE INTO episodes (id, title, pubDate, audioPath, sourceLink) VALUES (?, ?, ?, ?, ?)",
);
stmt.run(ep.id, ep.title, ep.pubDate, ep.audioPath, ep.sourceLink); stmt.run(ep.id, ep.title, ep.pubDate, ep.audioPath, ep.sourceLink);
} }

View File

@ -7,13 +7,14 @@ export async function updatePodcastRSS() {
const channelTitle = "自動生成ポッドキャスト"; const channelTitle = "自動生成ポッドキャスト";
const channelLink = "https://your-domain.com/podcast"; const channelLink = "https://your-domain.com/podcast";
const channelDescription = "RSSフィードから自動生成されたポッドキャストです。"; const channelDescription =
"RSSフィードから自動生成されたポッドキャストです。";
const lastBuildDate = new Date().toUTCString(); const lastBuildDate = new Date().toUTCString();
let itemsXml = ""; let itemsXml = "";
for (const ep of episodes) { for (const ep of episodes) {
const fileUrl = `https://your-domain.com/podcast_audio/${path.basename( const fileUrl = `https://your-domain.com/podcast_audio/${path.basename(
ep.audioPath ep.audioPath,
)}`; )}`;
const pubDate = new Date(ep.pubDate).toUTCString(); const pubDate = new Date(ep.pubDate).toUTCString();
itemsXml += ` itemsXml += `

View File

@ -1,15 +1,12 @@
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { import { PollyClient, SynthesizeSpeechCommand } from "@aws-sdk/client-polly";
PollyClient,
SynthesizeSpeechCommand,
} from "@aws-sdk/client-polly";
const polly = new PollyClient({ region: "ap-northeast-1" }); const polly = new PollyClient({ region: "ap-northeast-1" });
export async function generateTTS( export async function generateTTS(
itemId: string, itemId: string,
scriptText: string scriptText: string,
): Promise<string> { ): Promise<string> {
const params = { const params = {
OutputFormat: "mp3", OutputFormat: "mp3",

View File

@ -1,14 +1,29 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", // Environment setup & latest features
"module": "ESNext", "lib": ["ESNext"],
"moduleResolution": "Node", "target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true, "strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"outDir": "dist" "noFallthroughCasesInSwitch": true,
}, "noUncheckedIndexedAccess": true,
"include": ["scripts", "services", "server.ts"] "noImplicitOverride": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
} }