Delete main.py
Browse files
main.py
DELETED
|
@@ -1,116 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
import subprocess
|
| 3 |
-
import shutil
|
| 4 |
-
import tempfile
|
| 5 |
-
from fastapi import FastAPI, UploadFile, File, Form, HTTPException, Security, Depends
|
| 6 |
-
from fastapi.responses import FileResponse
|
| 7 |
-
from fastapi.security.api_key import APIKeyHeader
|
| 8 |
-
from tempfile import NamedTemporaryFile
|
| 9 |
-
import uvicorn
|
| 10 |
-
|
| 11 |
-
app = FastAPI(title="Universal File Converter API - SECURED")
|
| 12 |
-
|
| 13 |
-
# =========================================================
|
| 14 |
-
# BRIDGE CONTROL (SECURITY)
|
| 15 |
-
# =========================================================
|
| 16 |
-
# Define the header name the backend will look for
|
| 17 |
-
API_KEY_NAME = "X-Bridge-Key"
|
| 18 |
-
api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False)
|
| 19 |
-
|
| 20 |
-
# This key must match the frontend exactly
|
| 21 |
-
API_SECRET_KEY = os.environ.get("BRIDGE_SECRET_KEY", "my_secure_bridge_token_2026")
|
| 22 |
-
|
| 23 |
-
async def get_api_key(api_key_header: str = Security(api_key_header)):
|
| 24 |
-
"""Verifies the Bridge Control badge."""
|
| 25 |
-
if api_key_header == API_SECRET_KEY:
|
| 26 |
-
return api_key_header
|
| 27 |
-
raise HTTPException(
|
| 28 |
-
status_code=403,
|
| 29 |
-
detail="Bridge Control: Access Denied. Unauthorized connection attempt."
|
| 30 |
-
)
|
| 31 |
-
|
| 32 |
-
# =========================================================
|
| 33 |
-
# THE 300+ FORMAT ROUTING DICTIONARY
|
| 34 |
-
# =========================================================
|
| 35 |
-
CONVERSION_ENGINES = {
|
| 36 |
-
**{ext: 'imagemagick' for ext in['jpg', 'jpeg', 'png', 'webp', 'gif', 'bmp', 'tiff', 'ico', 'svg', 'heic', 'eps', 'ps', 'tga', 'jp2', 'pcx', 'pnm', 'pgm', 'ppm', 'pbm', 'xbm', 'xpm', 'cr2', 'crw', 'nef', 'arw', 'dng', 'orf', 'raf', 'rw2', 'pef', 'srw', 'exr', 'hdr', 'dds', 'avif', 'jxl', 'dib', 'jpe', 'tpf', 'vtf', 'wmf', 'emf', 'cdr', 'cpt', 'svgz', 'cgm', 'djvu', 'pcd', 'pict', 'raw', 'xcf','apng', 'bpg', 'jxr', 'wdp', 'hdp', 'heif', 'fits', 'fit', 'fts', 'jbig', 'jbig2', 'pgf', 'sgi', 'ras', 'sun', 'pix', 'mrw', 'mef', 'mos', 'nrw', 'ptx', 'r3d', 'rwz', 'sr2', 'kdc', 'erf', 'fff', 'bay', 'cap', 'iiq', '3fr', 'ari', 'cine', 'kc2', 'mdc', 'pef', 'srw', 'x3f', 'yuv', 'ycbcr', 'ciff', 'drf', 'dcr', 'dcs', 'srf', 'k25', 'pxn', 'gpr', 'hif', 'avifs', 'jls', 'jng', 'mtv', 'psd', 'psb', 'ora', 'art']},
|
| 37 |
-
**{ext: 'ffmpeg' for ext in['mp4', 'avi', 'mkv','m2t', '8svx', 'aa', 'aa3', 'aacp', 'adt', 'adts', 'afc', 'aif', 'aifc', 'aifff', 'al', 'alaw', 'amrnb', 'amrwb', 'amrwb+', 'ast', 'at3', 'atrac', 'awb', 'brstm', 'bwav', 'cdda', 'cdr', 'daud', 'dfpwm', 'dsp', 'fsb', 'g721', 'g723', 'g726', 'g729', 'hcom', 'mka', 'mlp', 'mp1', 'mpa', 'mpc', 'mpga', 'mpp', 'oga', 'oma', 'sds', 'sf', 'smp', 'tak', 'ulaw', 'vag', 'vox', 'w64', 'wve', 'wv','m2t', 'm2ts', 'mts', 'm2v', 'mpv', 'h264', 'h265', 'hevc', 'vp8', 'vp9', 'ivf', 'fli', 'flc', 'roq', 'bik', 'bik2', 'smk', 'nut', 'dpg', 'evo', 'mve', 'ogm', 'ogx', 'mxg', 'mvi', 'avs', 'avs2', 'avs3', 'dvr-ms', 'idx', 'sub', 'sup', 'thp', 'pva', 'm2p', 'vivo', 'viv', 'wm', 'y4m', 'yuv4mpeg', 'webm', 'mov', 'flv', 'wmv', 'm4v', 'mpeg', '3gp', 'ogv', 'asf', 'rm', 'rmvb', 'ts', 'm2ts', 'vob', 'mxf', 'roq', 'nsv', 'f4v', 'f4p', 'f4a', 'f4b', 'drc', 'yuv', 'nut', 'amv', 'svt', 'ivf', 'mpe', 'mp2v', 'm2v', 'm4p', 'mpg', 'wtv', 'gxf', 'mjpg', 'mts', 'xvid', 'divx', 'mp3', 'wav', 'flac', 'ogg', 'aac', 'm4a', 'wma', 'aiff', 'opus', 'alac', 'amr', 'au', 'snd', 'mid', 'midi', 'kar', 'mka', 'mac', 'ape', 'spx', 'rka', 'shn', 'tta', 'smp', 'dts', 'pcm', 'gsm', 'dct', 'voc', 'aup', 'band', 'bwf', 'cda', 'ds2', 'dss', 'dvf', 'm4r', 'm4b', 'mus', 'qcp', 'ra', 'ram', 'rx2', 's3m', 'srm', 'uax', 'xm', 'it', 'ac3', 'caf']},
|
| 38 |
-
**{ext: 'libreoffice' for ext in['pdf','abw', 'ai', 'ans', '123', 'bks', 'gnm', 'gnx', 'pxl', 'sdc', 'sxc', 'uos', 'wb1', 'wb2', 'wb3', 'wks', 'wq2', 'xlk', 'xlm', 'xlt', 'xlv','asc', 'ascii', 'csvs', 'docbook', 'fods', 'markdown', 'pdb', 'pdfa', 'ps', 'text', 'tsv', 'txt2', 'docx', 'doc', 'odt', 'rtf', 'wpd', 'wps', 'sdw', 'sgl', 'lwp', 'docm', 'dot', 'dotx', 'dotm', 'pages', 'xps', 'oxps', 'abw', 'log', 'msg', 'eml', 'p7s', '1st', 'ans', 'asc', 'diz', 'err', 'faq', 'readme', 'sub', 'ltr', 'dvi', 'xlsx', 'xls', 'ods', 'csv', 'tsv', 'xlsm', 'xlsb', 'xltx', 'xltm', 'xlw', 'xlr', 'wk1', 'wk2', 'wk3', 'wk4', 'wq1', 'sd1', 'dbf', 'dif', 'slk', 'prn', 'numbers', 'fods', 'ots', 'gnumeric', 'pptx', 'ppt', 'odp', 'pptm', 'pps', 'ppsx', 'ppsm', 'pot', 'potx', 'potm', 'sda', 'sdd', 'sti', 'thmx', 'key', 'pez', 'otp']},
|
| 39 |
-
**{ext: 'calibre' for ext in['epub','asc', 'ascii', 'markdown', 'pdb', 'text', 'mobi', 'azw3', 'fb2', 'lit', 'prc', 'tcr', 'cbr', 'cbz', 'cb7', 'cbt', 'cba', 'chm', 'djv', 'ibooks', 'kfx', 'pdb', 'snb', 'tmd', 'lrf']},
|
| 40 |
-
**{ext: 'pandoc' for ext in ['html', 'md', 'rst', 'tex']},
|
| 41 |
-
**{ext: 'assimp' for ext in['stl', 'obj', 'fbx', 'dae', '3ds', 'blend', 'ply', 'gltf', 'glb', 'step', 'stp', 'iges', 'igs', 'dxf', 'dwg', 'x3d', 'wrl', 'amf']},
|
| 42 |
-
**{ext: 'fontforge' for ext in['ttf','afm', 'bdf', 'lwfn', 'mf', 'otc', 'pfm', 'pk', 'sfd', 'tfm', 'ufo', 'vfb', 'otf', 'woff', 'woff2', 'eot', 'dfont', 'fon', 'pfa', 'pfb', 'suit', 'fnt']},
|
| 43 |
-
**{ext: 'archive_engine' for ext in['zip','001', '002', '003', '004', '005', '006', '007', '008', '009', '010', 'dd', 'ear', 'part1', 'part2', 'part3', 'pax', 'rar5', 'tar.gz', 'tar.bz', 'tar.lz', 'tar.lzma', 'tar.z', 'war', 'tar', 'gz', 'bz2', '7z', 'rar', 'xz', 'lzma', 'wim', 'swm', 'cab', 'iso', 'dmg', 'img', 'vdi', 'vhd', 'vmdk', 'squashfs', 'qcow2', 'z', 'taz', 'tgz', 'tbz2', 'tz2', 'tbz', 'jar', 'apk', 'xpi', 'crx', 'nupkg', 'pak', 'lz', 'sit', 'sitx', 'pea', 'ar', 'cpio', 'shar', 'lha', 'lzh', 'alz']},
|
| 44 |
-
**{ext: 'rename' for ext in['py', 'js', 'java', 'c', 'cpp', 'cs', 'rb', 'go', 'rs', 'php', 'swift', 'kt', 'sh', 'bat', 'ps1', 'pl', 'lua', 'm', 'r', 'vbs', 'asm', 'dart', 'ts', 'css', 'scss', 'less', 'txt', 'xml', 'json', 'yaml', 'yml', 'rss', 'atom', 'rdf', 'owl', 'xsd', 'dtd', 'xslt', 'xsl', 'plist', 'ini', 'cfg', 'conf', 'toml', 'sql', 'hdf5', 'h5', 'nc', 'sqlite', 'db', 'mdb', 'accdb', 'bson', 'avro', 'parquet']}
|
| 45 |
-
}
|
| 46 |
-
|
| 47 |
-
def execute_conversion(input_path: str, output_path: str, target_ext: str):
|
| 48 |
-
engine = CONVERSION_ENGINES.get(target_ext)
|
| 49 |
-
if not engine:
|
| 50 |
-
raise ValueError(f"Target format '{target_ext}' is not mapped to an engine.")
|
| 51 |
-
|
| 52 |
-
try:
|
| 53 |
-
if engine == 'rename':
|
| 54 |
-
shutil.copy(input_path, output_path)
|
| 55 |
-
return
|
| 56 |
-
elif engine == 'libreoffice':
|
| 57 |
-
out_dir = os.path.dirname(output_path)
|
| 58 |
-
cmd =['soffice', '--headless', '--convert-to', target_ext, '--outdir', out_dir, input_path]
|
| 59 |
-
elif engine == 'imagemagick':
|
| 60 |
-
cmd =['magick', input_path, output_path]
|
| 61 |
-
elif engine == 'ffmpeg':
|
| 62 |
-
cmd =['ffmpeg', '-y', '-i', input_path, output_path]
|
| 63 |
-
elif engine == 'pandoc':
|
| 64 |
-
cmd =['pandoc', input_path, '-o', output_path]
|
| 65 |
-
elif engine == 'calibre':
|
| 66 |
-
cmd =['ebook-convert', input_path, output_path]
|
| 67 |
-
elif engine == 'assimp':
|
| 68 |
-
cmd = ['assimp', 'export', input_path, output_path]
|
| 69 |
-
elif engine == 'fontforge':
|
| 70 |
-
script = f'Open("{input_path}"); Generate("{output_path}")'
|
| 71 |
-
cmd = ['fontforge', '-lang=ff', '-c', script]
|
| 72 |
-
elif engine == 'archive_engine':
|
| 73 |
-
with tempfile.TemporaryDirectory() as temp_dir:
|
| 74 |
-
subprocess.run(['7z', 'x', f'-o{temp_dir}', input_path], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| 75 |
-
subprocess.run(['7z', 'a', output_path, f'{temp_dir}/*'], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| 76 |
-
return
|
| 77 |
-
|
| 78 |
-
subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| 79 |
-
except FileNotFoundError:
|
| 80 |
-
raise RuntimeError(f"Required server tool for engine '{engine}' is missing or not installed.")
|
| 81 |
-
except subprocess.CalledProcessError as e:
|
| 82 |
-
err_msg = e.stderr.decode('utf-8') if e.stderr else str(e)
|
| 83 |
-
raise RuntimeError(f"Engine Error ({engine}): {err_msg}")
|
| 84 |
-
|
| 85 |
-
@app.post("/convert")
|
| 86 |
-
async def convert_file(
|
| 87 |
-
file: UploadFile = File(...),
|
| 88 |
-
target_format: str = Form(...),
|
| 89 |
-
api_key: str = Depends(get_api_key) # <-- SECURITY BRIDGE CHECK HAPPENS HERE
|
| 90 |
-
):
|
| 91 |
-
target_format = target_format.lower().strip('.')
|
| 92 |
-
|
| 93 |
-
filename_parts = file.filename.rsplit('.', 1)
|
| 94 |
-
input_ext = filename_parts[-1] if len(filename_parts) > 1 else "tmp"
|
| 95 |
-
base_name = filename_parts[0] if len(filename_parts) > 1 else "file"
|
| 96 |
-
|
| 97 |
-
# Memory-safe chunked streaming (Prevents RAM explosions)
|
| 98 |
-
with NamedTemporaryFile(delete=False, suffix=f".{input_ext}") as tmp_in:
|
| 99 |
-
shutil.copyfileobj(file.file, tmp_in)
|
| 100 |
-
input_path = tmp_in.name
|
| 101 |
-
|
| 102 |
-
output_path = input_path.rsplit('.', 1)[0] + f".{target_format}"
|
| 103 |
-
|
| 104 |
-
try:
|
| 105 |
-
execute_conversion(input_path, output_path, target_format)
|
| 106 |
-
|
| 107 |
-
return FileResponse(
|
| 108 |
-
path=output_path,
|
| 109 |
-
filename=f"{base_name}_converted.{target_format}",
|
| 110 |
-
media_type='application/octet-stream'
|
| 111 |
-
)
|
| 112 |
-
except Exception as e:
|
| 113 |
-
raise HTTPException(status_code=500, detail=str(e))
|
| 114 |
-
|
| 115 |
-
if __name__ == "__main__":
|
| 116 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|