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)
        }