File size: 7,357 Bytes
48a533f 6c4045b 52ee455 48a533f 52ee455 96b22ca 52ee455 2b31489 0333263 48a533f 96b22ca 9d6531a 2b31489 9d6531a 2b31489 9d6531a 2b31489 9d6531a 2b31489 9d6531a 2b31489 9d6531a 2b31489 9d6531a 2b31489 9d6531a 2b31489 9d6531a 48a533f 6c4045b ed44308 52ee455 058a4f4 6c4045b 058a4f4 0333263 058a4f4 0333263 48a533f 52ee455 2efdf09 48a533f 6c4045b 48a533f 7e9918d 52ee455 bc70293 7e9918d 96b22ca 6f2871e 96b22ca 7e9918d 96b22ca 7e9918d 96b22ca 52ee455 96b22ca 7e9918d 5b8911a 7e9918d 37f9d0f 7e9918d 5a90bee 48a533f 96b22ca 48a533f 96b22ca 48a533f 96b22ca 48a533f 7e9918d 48a533f ea17dd4 5a90bee 96b22ca 2b31489 52ee455 2b31489 7e9918d 2b31489 96b22ca 2b31489 96b22ca 52ee455 96b22ca |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# app.py
from fastapi import FastAPI, HTTPException, Response
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import subprocess
import os
import shutil
import logging
from datetime import datetime
import tempfile
from pathlib import Path
from dotenv import load_dotenv
from urllib.parse import quote
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def env_to_cookies(env_content: str, output_file: str) -> None:
"""Convert environment variable content to cookie file"""
try:
# Extract content from env format
if '="' not in env_content:
raise ValueError("Invalid env content format")
content = env_content.split('="', 1)[1].strip('"')
# Replace escaped newlines with actual newlines
cookie_content = content.replace('\\n', '\n')
# Write to cookie file
with open(output_file, 'w') as f:
f.write(cookie_content)
logger.info(f"Successfully created cookie file at {output_file}")
except Exception as e:
logger.error(f"Error creating cookie file: {str(e)}")
raise ValueError(f"Error converting to cookie file: {str(e)}")
def get_cookies() -> str:
"""Get cookies from environment variable"""
load_dotenv()
cookie_content = os.getenv('COOKIES')
if not cookie_content:
raise ValueError("COOKIES environment variable not set")
return cookie_content
def env_to_cookies_from_env(output_file: str) -> None:
"""Convert environment variable from .env file to cookie file"""
try:
load_dotenv()
env_content = os.getenv('COOKIES')
logger.info("Retrieved cookies from environment variable")
if not env_content:
raise ValueError("COOKIES not found in environment variables")
env_to_cookies(f'COOKIES="{env_content}"', output_file)
except Exception as e:
logger.error(f"Error creating cookie file from env: {str(e)}")
raise ValueError(f"Error converting to cookie file: {str(e)}")
app = FastAPI(
title="GAMDL API",
description="API for downloading Google Drive files using gamdl",
version="1.0.0"
)
# Create downloads directory if it doesn't exist
DOWNLOADS_DIR = "downloads"
os.makedirs(DOWNLOADS_DIR, exist_ok=True)
# Mount the downloads directory with cache control headers
class CacheControlStaticFiles(StaticFiles):
def __init__(self, directory: str):
super().__init__(directory=directory)
async def get_response(self, path: str, scope):
response = await super().get_response(path, scope)
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response
app.mount("/files", CacheControlStaticFiles(directory=DOWNLOADS_DIR), name="files")
class DownloadRequest(BaseModel):
url: str
class DownloadResponse(BaseModel):
success: bool
message: str
filename: str = None
download_url: str = None
file_size: int = None # Include file size in the response
@app.post("/download", response_model=DownloadResponse)
async def download_file(request: DownloadRequest):
try:
# Create a unique subdirectory for this download
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
download_subdir = os.path.join(DOWNLOADS_DIR, timestamp)
os.makedirs(download_subdir, exist_ok=True)
# Log the current working directory and download directory
logger.info(f"Current working directory: {os.getcwd()}")
logger.info(f"Download directory: {download_subdir}")
# Create cookies file from environment variable
cookie_path = os.path.join(download_subdir, "cookies.txt")
logger.info(f"Creating cookies file at: {cookie_path}")
env_to_cookies_from_env(cookie_path)
# Change to download directory
original_dir = os.getcwd()
os.chdir(download_subdir)
# Log the command being executed
cmd = ["votify", "--audio-quality", "vorbis-low", request.url]
logger.info(f"Executing command: {' '.join(cmd)}")
# Run gamdl command with more detailed output
process = subprocess.run(
cmd,
capture_output=True,
text=True
)
# Log the command output
logger.info(f"Command stdout: {process.stdout}")
logger.info(f"Command stderr: {process.stderr}")
# Check if the command was successful
process.check_returncode()
# Get the downloaded filename
files = [f for f in os.listdir() if f != "cookies.txt"]
logger.info(f"Files in download directory: {files}")
if not files:
raise Exception("No files found in download directory after download attempt")
downloaded_file = files[0]
logger.info(f"Downloaded file: {downloaded_file}")
# Get the file size
file_size = os.path.getsize(downloaded_file)
# Generate the download URL and URL encode the filename
space_url = os.getenv("SPACE_URL", "https://chrunos-vob.hf.space")
encoded_filename = quote(downloaded_file) # URL encode the filename
download_url = f"{space_url}/files/{timestamp}/{encoded_filename}"
logger.info(f"Generated download URL: {download_url}")
# Move back to original directory
return DownloadResponse(
success=True,
message="File downloaded successfully",
filename=downloaded_file,
download_url=download_url,
file_size=file_size # Include the file size in the response
)
except subprocess.CalledProcessError as e:
logger.error(f"Download process failed: stdout={e.stdout}, stderr={e.stderr}")
raise HTTPException(
status_code=400,
detail=f"Failed to download: {e.stderr or e.stdout or str(e)}"
)
except Exception as e:
logger.error(f"Unexpected error: {str(e)}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Error: {str(e)}"
)
finally:
# Always try to return to the original directory
if 'original_dir' in locals():
os.chdir(original_dir)
@app.get("/test")
async def test():
"""Test endpoint to verify setup"""
try:
# Test cookie creation
temp_cookie = os.path.join(DOWNLOADS_DIR, "test_cookies.txt")
env_to_cookies_from_env(temp_cookie)
# Test gamdl installation
process = subprocess.run(["votify", "--version"], capture_output=True, text=True)
return {
"gamdl_version": process.stdout.strip(),
"cookies_created": os.path.exists(temp_cookie),
"cookies_size": os.path.getsize(temp_cookie) if os.path.exists(temp_cookie) else 0,
"installed": True,
"error": process.stderr if process.stderr else None
}
except Exception as e:
return {
"installed": False,
"error": str(e)
} |