3* controlling multiple Chromecast devices simultaneously.
4* The application logic is entirely on the client-side, interacting with a
5* user-provided backend REST API. This val only serves the static HTML, CSS,
6* and JavaScript files.
7*/
304// --- STATE ---
305const PORT = 8081;
306let apiBase = "";
307let services = [];
308let list = []; // Array of host strings
333const allControlButtons = [sendMediaBtn, playBtn, pauseBtn, stopBtn, closeBtn, addAllBtn, removeAllBtn];
334335// --- API HELPERS ---
336const apiCall = (endpoint, options = {}) => {
337if (!apiBase) return Promise.reject("API base not set");
338return fetch(`${apiBase}${endpoint}`, options);
339};
340341const getStatus = () => apiCall("/status");
342const getServices = () => apiCall("/services").then(res => res.ok ? res.json() : Promise.reject(res));
343const getList = () => apiCall("/list").then(res => res.ok ? res.json() : Promise.reject(res));
344const updateList = (hosts) => apiCall("/list", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(hosts) });
345const deleteFromList = (hosts) => apiCall("/list", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify(hosts) });
346347const postCommand = (endpoint, body = {}) => apiCall(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
348const sendMedia = (contentId, contentType) => postCommand("/media", { contentId, contentType });
349const stopPlayback = () => postCommand("/stop");
428if(servicesInterval) clearInterval(servicesInterval);
429430apiBase = `http://${host}:${PORT}`;
431hostInput.disabled = true;
432connectBtn.disabled = true;
YoutubeDownloaderyoutube.ts6 matches
23// In a real implementation, you would either:
24// 1. Use a separate service that has yt-dlp installed
25// 2. Use YouTube API + other tools for downloading
26// 3. Use a third-party service
27
7273/**
74* Gets video information (simulated - in real implementation would use YouTube API)
75*/
76private static async getVideoInfo(url: string): Promise<VideoInfo> {
77const videoId = this.extractVideoId(url);
78
79// In a real implementation, you would use YouTube Data API v3
80// For demo purposes, we'll return mock data
81return {
103message: "Video downloaded successfully",
104filename: `${videoInfo.title}.mp4`,
105downloadUrl: `/api/download/video/${this.extractVideoId(url)}`
106};
107}
125message: "Audio extracted successfully",
126filename: `${videoInfo.title}.mp3`,
127downloadUrl: `/api/download/audio/${this.extractVideoId(url)}`
128};
129}
140// 1. A server with yt-dlp installed (Python environment)
141// 2. File storage system (local filesystem, cloud storage, etc.)
142// 3. YouTube Data API key for video metadata
143// 4. Proper error handling and rate limiting
144// 5. Cleanup of temporary files
YoutubeDownloaderREADME.md1 match
17โ โโโ index.ts # Main Hono server
18โ โโโ routes/
19โ โ โโโ download.ts # Download API endpoints
20โ โ โโโ static.ts # Static file serving
21โ โโโ services/
YoutubeDownloaderindex.ts3 matches
10});
1112// API routes
13app.route("/api/download", downloadRoutes);
1415// Static file serving and main routes
21status: "healthy",
22timestamp: new Date().toISOString(),
23service: "YouTube Downloader API"
24});
25});
YoutubeDownloaderdownload.ts4 matches
5const download = new Hono();
67// POST /api/download - Start a download
8download.post("/", async (c) => {
9try {
44});
4546// GET /api/download/video/:videoId - Download video file
47download.get("/video/:videoId", async (c) => {
48const videoId = c.req.param("videoId");
61});
6263// GET /api/download/audio/:videoId - Download audio file
64download.get("/audio/:videoId", async (c) => {
65const videoId = c.req.param("videoId");
78});
7980// GET /api/download/status/:videoId - Check download status
81download.get("/status/:videoId", async (c) => {
82const videoId = c.req.param("videoId");
28};
2930const response = await fetch("/api/download", {
31method: "POST",
32headers: {
9192// Register
93app.post("/api/auth/register", async c => {
94try {
95const { username, email, password, display_name } = await c.req.json();
151152// Login
153app.post("/api/auth/login", async c => {
154try {
155const { username, password } = await c.req.json();
194195// Logout
196app.post("/api/auth/logout", async c => {
197try {
198const sessionId = getSessionFromCookie(c.req.header('cookie'));
210211// Get current user
212app.get("/api/auth/me", async c => {
213try {
214const user = await getCurrentUser(c);
235236// Create artwork
237app.post("/api/artworks", async c => {
238try {
239const user = await getCurrentUser(c);
266267// Get user's artworks
268app.get("/api/artworks/my", async c => {
269try {
270const user = await getCurrentUser(c);
287288// Get public artworks
289app.get("/api/artworks/public", async c => {
290try {
291const limit = parseInt(c.req.query('limit') || '50');
301302// Get artwork by ID
303app.get("/api/artworks/:id", async c => {
304try {
305const id = parseInt(c.req.param('id'));
324325// Update artwork
326app.put("/api/artworks/:id", async c => {
327try {
328const user = await getCurrentUser(c);
347348// Delete artwork
349app.delete("/api/artworks/:id", async c => {
350try {
351const user = await getCurrentUser(c);
369370// Search artworks
371app.get("/api/artworks/search", async c => {
372try {
373const query = c.req.query('q');
1// Simple password hashing using Web Crypto API
2export async function hashPassword(password: string): Promise<string> {
3const encoder = new TextEncoder();
ai_comments_to_tasksindex.ts2 matches
245}
246247// API endpoint to analyze PR messages
248app.post("/api/analyze", async c => {
249try {
250const body: AnalysisRequest = await c.req.json();
309310try {
311const response = await fetch("/api/analyze", {
312method: "POST",
313headers: {