diff --git a/.gitignore b/.gitignore index 96bc3ad..db033f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ venv/ -node_modules/ \ No newline at end of file +node_modules/ +media/ \ No newline at end of file diff --git a/main.py b/main.py index 74ddcc3..b8a049a 100644 --- a/main.py +++ b/main.py @@ -2,39 +2,110 @@ from fastapi import FastAPI, HTTPException from pydantic import BaseModel import yt_dlp import vlc -import threading -import time +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) -# Queue to store video URLs -video_queue = [] -current_video = None +# 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() +vlc_instance = vlc.Instance('--quiet') player = vlc_instance.media_player_new() -player.set_fullscreen(True) +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 -# Add video URL to the queue +# 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): - video_queue.append(video_link.url) - return {"message": "Video added to the queue"} + 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") -# Get current queue -@app.get("/queue") -def get_queue(): - return {"queue": video_queue} +# 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}") @@ -47,11 +118,6 @@ def control_playback(action: str): player.stop() elif action == "mute": player.audio_toggle_mute() - elif action == "fullscreen": - if player.get_fullscreen(): - player.set_fullscreen(False) - else: - player.set_fullscreen(True) else: raise HTTPException(status_code=400, detail="Invalid action") return {"message": f"Player action {action} executed"} @@ -62,29 +128,7 @@ def seek(seconds: int): player.set_time(seconds * 1000) return {"message": f"Seeked to {seconds} seconds"} - -# Function to play videos from the queue -def play_videos(): - global current_video - while True: - if video_queue and player.get_state() not in [vlc.State.Playing, vlc.State.Paused]: - current_video = video_queue.pop(0) - ydl_opts = {'format': 'best', 'quiet': True} - with yt_dlp.YoutubeDL(ydl_opts) as ydl: - info_dict = ydl.extract_info(current_video, download=False) - video_url = info_dict.get("url", None) - media = vlc_instance.media_new(video_url) - player.set_media(media) - player.play() - time.sleep(1) # Give some time for the player to start - time.sleep(1) - - -# Start the video playing thread -video_thread = threading.Thread(target=play_videos, daemon=True) -video_thread.start() - # Run FastAPI if __name__ == "__main__": import uvicorn - uvicorn.run(app, host="127.0.0.1", port=1337) + uvicorn.run(app, host="0.0.0.0", port=1337) diff --git a/readme.md b/readme.md index 4475908..c3c9eed 100644 --- a/readme.md +++ b/readme.md @@ -35,9 +35,9 @@ Your SpaceInvaderz API should now be running on `http://0.0.0.0:1337`. ## 🌌 API Endpoints -### 1. Add Video to Queue +### 1. Add Video to playlist -**Description:** Adds a video to the playback queue. +**Description:** Adds a video to the playback playlist. - **URL:** `/add` - **Method:** `POST` @@ -59,21 +59,21 @@ Invoke-RestMethod -Uri http://localhost:1337/add -Method Post -Body (@{url = $vi curl -X POST "http://localhost:1337/add" -H "Content-Type: application/json" -d "{\"url\":\"YOUR_VIDEO_URL\"}" ``` -### 2. Get Current Queue +### 2. Get Current playlist -**Description:** Retrieves the current queue of videos. +**Description:** Retrieves the current playlist of videos. -- **URL:** `/queue` +- **URL:** `/playlist` - **Method:** `GET` #### PowerShell: ```powershell -Invoke-RestMethod -Uri http://localhost:1337/queue -Method Get +Invoke-RestMethod -Uri http://localhost:1337/playlist -Method Get ``` #### cURL: ```sh -curl -X GET "http://localhost:1337/queue" +curl -X GET "http://localhost:1337/playlist" ``` ### 3. Control Playback