from fastapi import FastAPI, HTTPException from pydantic import BaseModel import yt_dlp import vlc import os import json app = FastAPI() # Define a data model for the queue item class VideoLink(BaseModel): url: str # Create media directory if it doesn't exist MEDIA_DIR = 'media' if not os.path.exists(MEDIA_DIR): os.makedirs(MEDIA_DIR) # File to store video info dictionaries INFO_FILE = os.path.join(MEDIA_DIR, 'downloaded_info.json') try: if os.path.exists(INFO_FILE) and os.path.getsize(INFO_FILE) > 0: with open(INFO_FILE, 'r') as f: downloaded_info = json.load(f) else: downloaded_info = {} except (json.JSONDecodeError, IOError) as e: downloaded_info = {} # VLC player instance vlc_instance = vlc.Instance('--quiet') player = vlc_instance.media_player_new() playlist = [] # Function to download video or use existing file def get_media_file(url): ydl_opts = { 'format': 'best', 'quiet': True, 'outtmpl': os.path.join(MEDIA_DIR, '%(title)s.%(ext)s'), 'overwrites': False, # 'verbose': True } with yt_dlp.YoutubeDL(ydl_opts) as ydl: info_dict = ydl.extract_info(url, download=False) video_id = info_dict['id'] # Check if video ID already exists in downloaded info if video_id in downloaded_info: print(f"\nVideo {video_id} already downloaded\n\n") video_file = downloaded_info[video_id]['filepath'] else: print(f"\nDownloading video {video_id}\n\n") video_file = ydl.prepare_filename(info_dict) # Fixed line ydl.download([url]) minimal_info_dict = { 'id': video_id, 'title': info_dict['title'], # 'release_date': info_dict.get('release_date'), 'filepath': video_file } downloaded_info[video_id] = minimal_info_dict with open(INFO_FILE, 'w') as f: json.dump(downloaded_info, f, indent=4) return video_file # Function to add video to VLC playlist def add_to_playlist(url): video_file = get_media_file(url) media = vlc_instance.media_new_path(video_file) playlist.append(media) # Function to play the next video in the playlist def play_next(): if playlist: media = playlist.pop(0) player.set_media(media) player.play() # Add video URL to the playlist @app.post("/add") def add_video(video_link: VideoLink): add_to_playlist(video_link.url) if player.get_state() not in [vlc.State.Playing, vlc.State.Paused]: play_next() return {"message": "Video added to the playlist"} # Remove video URL from the playlist @app.delete("/remove/{index}") def remove_video(index: int): if 0 <= index < len(playlist): removed_video = playlist.pop(index) return {"message": "Video removed from the playlist", "url": removed_video.get_mrl()} else: raise HTTPException(status_code=404, detail="Index out of range") # Skip current video and play next @app.post("/skip") def skip_video(): player.stop() play_next() return {"message": "Skipped to the next video"} # Get current playlist @app.get("/playlist") def get_playlist(): return {"playlist": [media.get_mrl() for media in playlist]} # Control playback: play, pause, stop @app.post("/control/{action}") def control_playback(action: str): if action == "play": player.play() elif action == "pause": player.pause() elif action == "stop": player.stop() elif action == "mute": player.audio_toggle_mute() else: raise HTTPException(status_code=400, detail="Invalid action") return {"message": f"Player action {action} executed"} # Seek video to a specific time in seconds @app.post("/seek/{seconds}") def seek(seconds: int): player.set_time(seconds * 1000) return {"message": f"Seeked to {seconds} seconds"} # Run FastAPI if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=1337)