Commit
·
228a3b1
1
Parent(s):
6d792ca
MAJOR CHANGE: drop srt files, using only srt strings (wip); added moviepy font and color dropdowns + loading spinner (wip)
Browse files- main.py +20 -38
- static/colors.txt +678 -0
- static/fonts.txt +141 -0
- static/submit_video.html +97 -44
- utils/get_moviepy_configs.py +8 -0
- utils/process_video.py +4 -10
- utils/subtitler.py +6 -8
- utils/transcriber.py +9 -7
main.py
CHANGED
|
@@ -6,13 +6,22 @@ from utils.zip_response import zip_response
|
|
| 6 |
from utils.read_html import read_html
|
| 7 |
|
| 8 |
from fastapi import FastAPI, UploadFile, HTTPException, Form, Depends
|
|
|
|
| 9 |
from fastapi.responses import HTMLResponse, Response
|
| 10 |
from fastapi.security import HTTPBasic
|
| 11 |
from pydantic import BaseModel, field_validator
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
app = FastAPI()
|
| 14 |
security = HTTPBasic()
|
| 15 |
api_configs_file = os.path.abspath("api_config.yml")
|
|
|
|
|
|
|
| 16 |
|
| 17 |
class MP4Video(BaseModel):
|
| 18 |
video_file: UploadFile
|
|
@@ -30,25 +39,6 @@ class MP4Video(BaseModel):
|
|
| 30 |
raise HTTPException(status_code=500, detail='Invalid video file type. Please upload an MP4 file.')
|
| 31 |
return v
|
| 32 |
|
| 33 |
-
class SRTFile(BaseModel):
|
| 34 |
-
srt_file: Optional[UploadFile] = None
|
| 35 |
-
|
| 36 |
-
@property
|
| 37 |
-
def filename(self):
|
| 38 |
-
return self.srt_file.filename
|
| 39 |
-
@property
|
| 40 |
-
def file(self):
|
| 41 |
-
return self.srt_file.file
|
| 42 |
-
@property
|
| 43 |
-
def size(self):
|
| 44 |
-
return self.srt_file.size
|
| 45 |
-
|
| 46 |
-
@field_validator('srt_file')
|
| 47 |
-
def validate_srt_file(cls, v):
|
| 48 |
-
if v.size > 0 and not v.filename.endswith('.srt'):
|
| 49 |
-
raise HTTPException(status_code=422, detail='Invalid subtitle file type. Please upload an SRT file.')
|
| 50 |
-
return v
|
| 51 |
-
|
| 52 |
@app.get("/")
|
| 53 |
async def root():
|
| 54 |
html_content = f"""
|
|
@@ -73,7 +63,6 @@ async def get_temp_dir():
|
|
| 73 |
|
| 74 |
@app.post("/process_video/")
|
| 75 |
async def process_video_api(video_file: MP4Video = Depends(),
|
| 76 |
-
srt_file: SRTFile = Depends(),
|
| 77 |
task: Optional[str] = Form("transcribe"),
|
| 78 |
model_version: Optional[str] = Form("deepdml/faster-whisper-large-v3-turbo-ct2"),
|
| 79 |
max_words_per_line: Optional[int] = Form(6),
|
|
@@ -93,25 +82,18 @@ async def process_video_api(video_file: MP4Video = Depends(),
|
|
| 93 |
finally:
|
| 94 |
video_file.file.close()
|
| 95 |
logging.info("Copying SRT UploadFile to the temp_input_path")
|
| 96 |
-
|
| 97 |
-
with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.srt"), 'w+b') as temp_srt_file:
|
| 98 |
-
try:
|
| 99 |
-
shutil.copyfileobj(srt_file.file, temp_srt_file)
|
| 100 |
-
finally:
|
| 101 |
-
srt_file.file.close()
|
| 102 |
-
logging.info("Processing the video...")
|
| 103 |
-
output_path, _ = process_video(temp_file.name, temp_srt_file.name, task, model_version, max_words_per_line, fontsize, font, bg_color, text_color, caption_mode)
|
| 104 |
-
logging.info("Zipping response...")
|
| 105 |
-
with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.zip"), 'w+b') as temp_zip_file:
|
| 106 |
-
zip_file = zip_response(temp_zip_file.name, [output_path, srt_path])
|
| 107 |
-
return Response(content = zip_file)
|
| 108 |
-
with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.srt"), 'w+b') as temp_srt_file:
|
| 109 |
logging.info("Processing the video...")
|
| 110 |
-
output_path,
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
except Exception as e:
|
| 116 |
raise HTTPException(status_code=500, detail=str(e))
|
| 117 |
|
|
|
|
| 6 |
from utils.read_html import read_html
|
| 7 |
|
| 8 |
from fastapi import FastAPI, UploadFile, HTTPException, Form, Depends
|
| 9 |
+
from fastapi.staticfiles import StaticFiles
|
| 10 |
from fastapi.responses import HTMLResponse, Response
|
| 11 |
from fastapi.security import HTTPBasic
|
| 12 |
from pydantic import BaseModel, field_validator
|
| 13 |
|
| 14 |
+
## THIS IS A BREAKING CHANGE. SRT FILE INPUT DEPRECATED. WIP.
|
| 15 |
+
## TODO: add word level highlighting option
|
| 16 |
+
## TODO: separate transcriber from subtitler logic + allow for interactive validation of trancription in-browser
|
| 17 |
+
## TODO: add video preview component
|
| 18 |
+
## TODO: improve loading spinner.
|
| 19 |
+
|
| 20 |
app = FastAPI()
|
| 21 |
security = HTTPBasic()
|
| 22 |
api_configs_file = os.path.abspath("api_config.yml")
|
| 23 |
+
static_dir = os.path.join(os.path.dirname(__file__), 'static')
|
| 24 |
+
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
| 25 |
|
| 26 |
class MP4Video(BaseModel):
|
| 27 |
video_file: UploadFile
|
|
|
|
| 39 |
raise HTTPException(status_code=500, detail='Invalid video file type. Please upload an MP4 file.')
|
| 40 |
return v
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
@app.get("/")
|
| 43 |
async def root():
|
| 44 |
html_content = f"""
|
|
|
|
| 63 |
|
| 64 |
@app.post("/process_video/")
|
| 65 |
async def process_video_api(video_file: MP4Video = Depends(),
|
|
|
|
| 66 |
task: Optional[str] = Form("transcribe"),
|
| 67 |
model_version: Optional[str] = Form("deepdml/faster-whisper-large-v3-turbo-ct2"),
|
| 68 |
max_words_per_line: Optional[int] = Form(6),
|
|
|
|
| 82 |
finally:
|
| 83 |
video_file.file.close()
|
| 84 |
logging.info("Copying SRT UploadFile to the temp_input_path")
|
| 85 |
+
with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.srt"), 'w+') as temp_srt_file:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
logging.info("Processing the video...")
|
| 87 |
+
output_path, srt_string = process_video(temp_file.name, task, model_version, max_words_per_line, fontsize, font, bg_color, text_color, caption_mode, api_configs_file)
|
| 88 |
+
temp_srt_file.write(srt_string)
|
| 89 |
+
logging.info("Zipping response...")
|
| 90 |
+
with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.zip"), 'w+b') as temp_zip_file:
|
| 91 |
+
zip_file = zip_response(temp_zip_file.name, [output_path, temp_srt_file.name])
|
| 92 |
+
return Response(
|
| 93 |
+
content = zip_file,
|
| 94 |
+
media_type="application/zip",
|
| 95 |
+
headers={"Content-Disposition": f"attachment; filename={video_file.filename.split('.')[0]}.zip"}
|
| 96 |
+
)
|
| 97 |
except Exception as e:
|
| 98 |
raise HTTPException(status_code=500, detail=str(e))
|
| 99 |
|
static/colors.txt
ADDED
|
@@ -0,0 +1,678 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
AliceBlue
|
| 2 |
+
AntiqueWhite
|
| 3 |
+
AntiqueWhite1
|
| 4 |
+
AntiqueWhite2
|
| 5 |
+
AntiqueWhite3
|
| 6 |
+
AntiqueWhite4
|
| 7 |
+
aqua
|
| 8 |
+
aquamarine
|
| 9 |
+
aquamarine1
|
| 10 |
+
aquamarine2
|
| 11 |
+
aquamarine3
|
| 12 |
+
aquamarine4
|
| 13 |
+
azure
|
| 14 |
+
azure1
|
| 15 |
+
azure2
|
| 16 |
+
azure3
|
| 17 |
+
azure4
|
| 18 |
+
beige
|
| 19 |
+
bisque
|
| 20 |
+
bisque1
|
| 21 |
+
bisque2
|
| 22 |
+
bisque3
|
| 23 |
+
bisque4
|
| 24 |
+
black
|
| 25 |
+
BlanchedAlmond
|
| 26 |
+
blue
|
| 27 |
+
blue1
|
| 28 |
+
blue2
|
| 29 |
+
blue3
|
| 30 |
+
blue4
|
| 31 |
+
BlueViolet
|
| 32 |
+
brown
|
| 33 |
+
brown1
|
| 34 |
+
brown2
|
| 35 |
+
brown3
|
| 36 |
+
brown4
|
| 37 |
+
burlywood
|
| 38 |
+
burlywood1
|
| 39 |
+
burlywood2
|
| 40 |
+
burlywood3
|
| 41 |
+
burlywood4
|
| 42 |
+
CadetBlue
|
| 43 |
+
CadetBlue1
|
| 44 |
+
CadetBlue2
|
| 45 |
+
CadetBlue3
|
| 46 |
+
CadetBlue4
|
| 47 |
+
chartreuse
|
| 48 |
+
chartreuse1
|
| 49 |
+
chartreuse2
|
| 50 |
+
chartreuse3
|
| 51 |
+
chartreuse4
|
| 52 |
+
chocolate
|
| 53 |
+
chocolate1
|
| 54 |
+
chocolate2
|
| 55 |
+
chocolate3
|
| 56 |
+
chocolate4
|
| 57 |
+
coral
|
| 58 |
+
coral1
|
| 59 |
+
coral2
|
| 60 |
+
coral3
|
| 61 |
+
coral4
|
| 62 |
+
CornflowerBlue
|
| 63 |
+
cornsilk
|
| 64 |
+
cornsilk1
|
| 65 |
+
cornsilk2
|
| 66 |
+
cornsilk3
|
| 67 |
+
cornsilk4
|
| 68 |
+
crimson
|
| 69 |
+
cyan
|
| 70 |
+
cyan1
|
| 71 |
+
cyan2
|
| 72 |
+
cyan3
|
| 73 |
+
cyan4
|
| 74 |
+
DarkBlue
|
| 75 |
+
DarkCyan
|
| 76 |
+
DarkGoldenrod
|
| 77 |
+
DarkGoldenrod1
|
| 78 |
+
DarkGoldenrod2
|
| 79 |
+
DarkGoldenrod3
|
| 80 |
+
DarkGoldenrod4
|
| 81 |
+
DarkGray
|
| 82 |
+
DarkGreen
|
| 83 |
+
DarkGrey
|
| 84 |
+
DarkKhaki
|
| 85 |
+
DarkMagenta
|
| 86 |
+
DarkOliveGreen
|
| 87 |
+
DarkOliveGreen1
|
| 88 |
+
DarkOliveGreen2
|
| 89 |
+
DarkOliveGreen3
|
| 90 |
+
DarkOliveGreen4
|
| 91 |
+
DarkOrange
|
| 92 |
+
DarkOrange1
|
| 93 |
+
DarkOrange2
|
| 94 |
+
DarkOrange3
|
| 95 |
+
DarkOrange4
|
| 96 |
+
DarkOrchid
|
| 97 |
+
DarkOrchid1
|
| 98 |
+
DarkOrchid2
|
| 99 |
+
DarkOrchid3
|
| 100 |
+
DarkOrchid4
|
| 101 |
+
DarkRed
|
| 102 |
+
DarkSalmon
|
| 103 |
+
DarkSeaGreen
|
| 104 |
+
DarkSeaGreen1
|
| 105 |
+
DarkSeaGreen2
|
| 106 |
+
DarkSeaGreen3
|
| 107 |
+
DarkSeaGreen4
|
| 108 |
+
DarkSlateBlue
|
| 109 |
+
DarkSlateGray
|
| 110 |
+
DarkSlateGray1
|
| 111 |
+
DarkSlateGray2
|
| 112 |
+
DarkSlateGray3
|
| 113 |
+
DarkSlateGray4
|
| 114 |
+
DarkSlateGrey
|
| 115 |
+
DarkTurquoise
|
| 116 |
+
DarkViolet
|
| 117 |
+
DeepPink
|
| 118 |
+
DeepPink1
|
| 119 |
+
DeepPink2
|
| 120 |
+
DeepPink3
|
| 121 |
+
DeepPink4
|
| 122 |
+
DeepSkyBlue
|
| 123 |
+
DeepSkyBlue1
|
| 124 |
+
DeepSkyBlue2
|
| 125 |
+
DeepSkyBlue3
|
| 126 |
+
DeepSkyBlue4
|
| 127 |
+
DimGray
|
| 128 |
+
DimGrey
|
| 129 |
+
DodgerBlue
|
| 130 |
+
DodgerBlue1
|
| 131 |
+
DodgerBlue2
|
| 132 |
+
DodgerBlue3
|
| 133 |
+
DodgerBlue4
|
| 134 |
+
firebrick
|
| 135 |
+
firebrick1
|
| 136 |
+
firebrick2
|
| 137 |
+
firebrick3
|
| 138 |
+
firebrick4
|
| 139 |
+
FloralWhite
|
| 140 |
+
ForestGreen
|
| 141 |
+
fractal
|
| 142 |
+
freeze
|
| 143 |
+
fuchsia
|
| 144 |
+
gainsboro
|
| 145 |
+
GhostWhite
|
| 146 |
+
gold
|
| 147 |
+
gold1
|
| 148 |
+
gold2
|
| 149 |
+
gold3
|
| 150 |
+
gold4
|
| 151 |
+
goldenrod
|
| 152 |
+
goldenrod1
|
| 153 |
+
goldenrod2
|
| 154 |
+
goldenrod3
|
| 155 |
+
goldenrod4
|
| 156 |
+
gray
|
| 157 |
+
gray
|
| 158 |
+
gray0
|
| 159 |
+
gray1
|
| 160 |
+
gray10
|
| 161 |
+
gray100
|
| 162 |
+
gray100
|
| 163 |
+
gray11
|
| 164 |
+
gray12
|
| 165 |
+
gray13
|
| 166 |
+
gray14
|
| 167 |
+
gray15
|
| 168 |
+
gray16
|
| 169 |
+
gray17
|
| 170 |
+
gray18
|
| 171 |
+
gray19
|
| 172 |
+
gray2
|
| 173 |
+
gray20
|
| 174 |
+
gray21
|
| 175 |
+
gray22
|
| 176 |
+
gray23
|
| 177 |
+
gray24
|
| 178 |
+
gray25
|
| 179 |
+
gray26
|
| 180 |
+
gray27
|
| 181 |
+
gray28
|
| 182 |
+
gray29
|
| 183 |
+
gray3
|
| 184 |
+
gray30
|
| 185 |
+
gray31
|
| 186 |
+
gray32
|
| 187 |
+
gray33
|
| 188 |
+
gray34
|
| 189 |
+
gray35
|
| 190 |
+
gray36
|
| 191 |
+
gray37
|
| 192 |
+
gray38
|
| 193 |
+
gray39
|
| 194 |
+
gray4
|
| 195 |
+
gray40
|
| 196 |
+
gray41
|
| 197 |
+
gray42
|
| 198 |
+
gray43
|
| 199 |
+
gray44
|
| 200 |
+
gray45
|
| 201 |
+
gray46
|
| 202 |
+
gray47
|
| 203 |
+
gray48
|
| 204 |
+
gray49
|
| 205 |
+
gray5
|
| 206 |
+
gray50
|
| 207 |
+
gray51
|
| 208 |
+
gray52
|
| 209 |
+
gray53
|
| 210 |
+
gray54
|
| 211 |
+
gray55
|
| 212 |
+
gray56
|
| 213 |
+
gray57
|
| 214 |
+
gray58
|
| 215 |
+
gray59
|
| 216 |
+
gray6
|
| 217 |
+
gray60
|
| 218 |
+
gray61
|
| 219 |
+
gray62
|
| 220 |
+
gray63
|
| 221 |
+
gray64
|
| 222 |
+
gray65
|
| 223 |
+
gray66
|
| 224 |
+
gray67
|
| 225 |
+
gray68
|
| 226 |
+
gray69
|
| 227 |
+
gray7
|
| 228 |
+
gray70
|
| 229 |
+
gray71
|
| 230 |
+
gray72
|
| 231 |
+
gray73
|
| 232 |
+
gray74
|
| 233 |
+
gray75
|
| 234 |
+
gray76
|
| 235 |
+
gray77
|
| 236 |
+
gray78
|
| 237 |
+
gray79
|
| 238 |
+
gray8
|
| 239 |
+
gray80
|
| 240 |
+
gray81
|
| 241 |
+
gray82
|
| 242 |
+
gray83
|
| 243 |
+
gray84
|
| 244 |
+
gray85
|
| 245 |
+
gray86
|
| 246 |
+
gray87
|
| 247 |
+
gray88
|
| 248 |
+
gray89
|
| 249 |
+
gray9
|
| 250 |
+
gray90
|
| 251 |
+
gray91
|
| 252 |
+
gray92
|
| 253 |
+
gray93
|
| 254 |
+
gray94
|
| 255 |
+
gray95
|
| 256 |
+
gray96
|
| 257 |
+
gray97
|
| 258 |
+
gray98
|
| 259 |
+
gray99
|
| 260 |
+
green
|
| 261 |
+
green
|
| 262 |
+
green1
|
| 263 |
+
green2
|
| 264 |
+
green3
|
| 265 |
+
green4
|
| 266 |
+
GreenYellow
|
| 267 |
+
grey
|
| 268 |
+
grey0
|
| 269 |
+
grey1
|
| 270 |
+
grey10
|
| 271 |
+
grey100
|
| 272 |
+
grey11
|
| 273 |
+
grey12
|
| 274 |
+
grey13
|
| 275 |
+
grey14
|
| 276 |
+
grey15
|
| 277 |
+
grey16
|
| 278 |
+
grey17
|
| 279 |
+
grey18
|
| 280 |
+
grey19
|
| 281 |
+
grey2
|
| 282 |
+
grey20
|
| 283 |
+
grey21
|
| 284 |
+
grey22
|
| 285 |
+
grey23
|
| 286 |
+
grey24
|
| 287 |
+
grey25
|
| 288 |
+
grey26
|
| 289 |
+
grey27
|
| 290 |
+
grey28
|
| 291 |
+
grey29
|
| 292 |
+
grey3
|
| 293 |
+
grey30
|
| 294 |
+
grey31
|
| 295 |
+
grey32
|
| 296 |
+
grey33
|
| 297 |
+
grey34
|
| 298 |
+
grey35
|
| 299 |
+
grey36
|
| 300 |
+
grey37
|
| 301 |
+
grey38
|
| 302 |
+
grey39
|
| 303 |
+
grey4
|
| 304 |
+
grey40
|
| 305 |
+
grey41
|
| 306 |
+
grey42
|
| 307 |
+
grey43
|
| 308 |
+
grey44
|
| 309 |
+
grey45
|
| 310 |
+
grey46
|
| 311 |
+
grey47
|
| 312 |
+
grey48
|
| 313 |
+
grey49
|
| 314 |
+
grey5
|
| 315 |
+
grey50
|
| 316 |
+
grey51
|
| 317 |
+
grey52
|
| 318 |
+
grey53
|
| 319 |
+
grey54
|
| 320 |
+
grey55
|
| 321 |
+
grey56
|
| 322 |
+
grey57
|
| 323 |
+
grey58
|
| 324 |
+
grey59
|
| 325 |
+
grey6
|
| 326 |
+
grey60
|
| 327 |
+
grey61
|
| 328 |
+
grey62
|
| 329 |
+
grey63
|
| 330 |
+
grey64
|
| 331 |
+
grey65
|
| 332 |
+
grey66
|
| 333 |
+
grey67
|
| 334 |
+
grey68
|
| 335 |
+
grey69
|
| 336 |
+
grey7
|
| 337 |
+
grey70
|
| 338 |
+
grey71
|
| 339 |
+
grey72
|
| 340 |
+
grey73
|
| 341 |
+
grey74
|
| 342 |
+
grey75
|
| 343 |
+
grey76
|
| 344 |
+
grey77
|
| 345 |
+
grey78
|
| 346 |
+
grey79
|
| 347 |
+
grey8
|
| 348 |
+
grey80
|
| 349 |
+
grey81
|
| 350 |
+
grey82
|
| 351 |
+
grey83
|
| 352 |
+
grey84
|
| 353 |
+
grey85
|
| 354 |
+
grey86
|
| 355 |
+
grey87
|
| 356 |
+
grey88
|
| 357 |
+
grey89
|
| 358 |
+
grey9
|
| 359 |
+
grey90
|
| 360 |
+
grey91
|
| 361 |
+
grey92
|
| 362 |
+
grey93
|
| 363 |
+
grey94
|
| 364 |
+
grey95
|
| 365 |
+
grey96
|
| 366 |
+
grey97
|
| 367 |
+
grey98
|
| 368 |
+
grey99
|
| 369 |
+
honeydew
|
| 370 |
+
honeydew1
|
| 371 |
+
honeydew2
|
| 372 |
+
honeydew3
|
| 373 |
+
honeydew4
|
| 374 |
+
HotPink
|
| 375 |
+
HotPink1
|
| 376 |
+
HotPink2
|
| 377 |
+
HotPink3
|
| 378 |
+
HotPink4
|
| 379 |
+
IndianRed
|
| 380 |
+
IndianRed1
|
| 381 |
+
IndianRed2
|
| 382 |
+
IndianRed3
|
| 383 |
+
IndianRed4
|
| 384 |
+
indigo
|
| 385 |
+
ivory
|
| 386 |
+
ivory1
|
| 387 |
+
ivory2
|
| 388 |
+
ivory3
|
| 389 |
+
ivory4
|
| 390 |
+
khaki
|
| 391 |
+
khaki1
|
| 392 |
+
khaki2
|
| 393 |
+
khaki3
|
| 394 |
+
khaki4
|
| 395 |
+
lavender
|
| 396 |
+
LavenderBlush
|
| 397 |
+
LavenderBlush1
|
| 398 |
+
LavenderBlush2
|
| 399 |
+
LavenderBlush3
|
| 400 |
+
LavenderBlush4
|
| 401 |
+
LawnGreen
|
| 402 |
+
LemonChiffon
|
| 403 |
+
LemonChiffon1
|
| 404 |
+
LemonChiffon2
|
| 405 |
+
LemonChiffon3
|
| 406 |
+
LemonChiffon4
|
| 407 |
+
LightBlue
|
| 408 |
+
LightBlue1
|
| 409 |
+
LightBlue2
|
| 410 |
+
LightBlue3
|
| 411 |
+
LightBlue4
|
| 412 |
+
LightCoral
|
| 413 |
+
LightCyan
|
| 414 |
+
LightCyan1
|
| 415 |
+
LightCyan2
|
| 416 |
+
LightCyan3
|
| 417 |
+
LightCyan4
|
| 418 |
+
LightGoldenrod
|
| 419 |
+
LightGoldenrod1
|
| 420 |
+
LightGoldenrod2
|
| 421 |
+
LightGoldenrod3
|
| 422 |
+
LightGoldenrod4
|
| 423 |
+
LightGoldenrodYellow
|
| 424 |
+
LightGray
|
| 425 |
+
LightGreen
|
| 426 |
+
LightGrey
|
| 427 |
+
LightPink
|
| 428 |
+
LightPink1
|
| 429 |
+
LightPink2
|
| 430 |
+
LightPink3
|
| 431 |
+
LightPink4
|
| 432 |
+
LightSalmon
|
| 433 |
+
LightSalmon1
|
| 434 |
+
LightSalmon2
|
| 435 |
+
LightSalmon3
|
| 436 |
+
LightSalmon4
|
| 437 |
+
LightSeaGreen
|
| 438 |
+
LightSkyBlue
|
| 439 |
+
LightSkyBlue1
|
| 440 |
+
LightSkyBlue2
|
| 441 |
+
LightSkyBlue3
|
| 442 |
+
LightSkyBlue4
|
| 443 |
+
LightSlateBlue
|
| 444 |
+
LightSlateGray
|
| 445 |
+
LightSlateGrey
|
| 446 |
+
LightSteelBlue
|
| 447 |
+
LightSteelBlue1
|
| 448 |
+
LightSteelBlue2
|
| 449 |
+
LightSteelBlue3
|
| 450 |
+
LightSteelBlue4
|
| 451 |
+
LightYellow
|
| 452 |
+
LightYellow1
|
| 453 |
+
LightYellow2
|
| 454 |
+
LightYellow3
|
| 455 |
+
LightYellow4
|
| 456 |
+
lime
|
| 457 |
+
LimeGreen
|
| 458 |
+
linen
|
| 459 |
+
magenta
|
| 460 |
+
magenta1
|
| 461 |
+
magenta2
|
| 462 |
+
magenta3
|
| 463 |
+
magenta4
|
| 464 |
+
maroon
|
| 465 |
+
maroon
|
| 466 |
+
maroon1
|
| 467 |
+
maroon2
|
| 468 |
+
maroon3
|
| 469 |
+
maroon4
|
| 470 |
+
matte
|
| 471 |
+
MediumAquamarine
|
| 472 |
+
MediumBlue
|
| 473 |
+
MediumForestGreen
|
| 474 |
+
MediumGoldenRod
|
| 475 |
+
MediumOrchid
|
| 476 |
+
MediumOrchid1
|
| 477 |
+
MediumOrchid2
|
| 478 |
+
MediumOrchid3
|
| 479 |
+
MediumOrchid4
|
| 480 |
+
MediumPurple
|
| 481 |
+
MediumPurple1
|
| 482 |
+
MediumPurple2
|
| 483 |
+
MediumPurple3
|
| 484 |
+
MediumPurple4
|
| 485 |
+
MediumSeaGreen
|
| 486 |
+
MediumSlateBlue
|
| 487 |
+
MediumSpringGreen
|
| 488 |
+
MediumTurquoise
|
| 489 |
+
MediumVioletRed
|
| 490 |
+
MidnightBlue
|
| 491 |
+
MintCream
|
| 492 |
+
MistyRose
|
| 493 |
+
MistyRose1
|
| 494 |
+
MistyRose2
|
| 495 |
+
MistyRose3
|
| 496 |
+
MistyRose4
|
| 497 |
+
moccasin
|
| 498 |
+
NavajoWhite
|
| 499 |
+
NavajoWhite1
|
| 500 |
+
NavajoWhite2
|
| 501 |
+
NavajoWhite3
|
| 502 |
+
NavajoWhite4
|
| 503 |
+
navy
|
| 504 |
+
NavyBlue
|
| 505 |
+
none
|
| 506 |
+
OldLace
|
| 507 |
+
olive
|
| 508 |
+
OliveDrab
|
| 509 |
+
OliveDrab1
|
| 510 |
+
OliveDrab2
|
| 511 |
+
OliveDrab3
|
| 512 |
+
OliveDrab4
|
| 513 |
+
opaque
|
| 514 |
+
orange
|
| 515 |
+
orange1
|
| 516 |
+
orange2
|
| 517 |
+
orange3
|
| 518 |
+
orange4
|
| 519 |
+
OrangeRed
|
| 520 |
+
OrangeRed1
|
| 521 |
+
OrangeRed2
|
| 522 |
+
OrangeRed3
|
| 523 |
+
OrangeRed4
|
| 524 |
+
orchid
|
| 525 |
+
orchid1
|
| 526 |
+
orchid2
|
| 527 |
+
orchid3
|
| 528 |
+
orchid4
|
| 529 |
+
PaleGoldenrod
|
| 530 |
+
PaleGreen
|
| 531 |
+
PaleGreen1
|
| 532 |
+
PaleGreen2
|
| 533 |
+
PaleGreen3
|
| 534 |
+
PaleGreen4
|
| 535 |
+
PaleTurquoise
|
| 536 |
+
PaleTurquoise1
|
| 537 |
+
PaleTurquoise2
|
| 538 |
+
PaleTurquoise3
|
| 539 |
+
PaleTurquoise4
|
| 540 |
+
PaleVioletRed
|
| 541 |
+
PaleVioletRed1
|
| 542 |
+
PaleVioletRed2
|
| 543 |
+
PaleVioletRed3
|
| 544 |
+
PaleVioletRed4
|
| 545 |
+
PapayaWhip
|
| 546 |
+
PeachPuff
|
| 547 |
+
PeachPuff1
|
| 548 |
+
PeachPuff2
|
| 549 |
+
PeachPuff3
|
| 550 |
+
PeachPuff4
|
| 551 |
+
peru
|
| 552 |
+
pink
|
| 553 |
+
pink1
|
| 554 |
+
pink2
|
| 555 |
+
pink3
|
| 556 |
+
pink4
|
| 557 |
+
plum
|
| 558 |
+
plum1
|
| 559 |
+
plum2
|
| 560 |
+
plum3
|
| 561 |
+
plum4
|
| 562 |
+
PowderBlue
|
| 563 |
+
purple
|
| 564 |
+
purple
|
| 565 |
+
purple1
|
| 566 |
+
purple2
|
| 567 |
+
purple3
|
| 568 |
+
purple4
|
| 569 |
+
red
|
| 570 |
+
red1
|
| 571 |
+
red2
|
| 572 |
+
red3
|
| 573 |
+
red4
|
| 574 |
+
RosyBrown
|
| 575 |
+
RosyBrown1
|
| 576 |
+
RosyBrown2
|
| 577 |
+
RosyBrown3
|
| 578 |
+
RosyBrown4
|
| 579 |
+
RoyalBlue
|
| 580 |
+
RoyalBlue1
|
| 581 |
+
RoyalBlue2
|
| 582 |
+
RoyalBlue3
|
| 583 |
+
RoyalBlue4
|
| 584 |
+
SaddleBrown
|
| 585 |
+
salmon
|
| 586 |
+
salmon1
|
| 587 |
+
salmon2
|
| 588 |
+
salmon3
|
| 589 |
+
salmon4
|
| 590 |
+
SandyBrown
|
| 591 |
+
SeaGreen
|
| 592 |
+
SeaGreen1
|
| 593 |
+
SeaGreen2
|
| 594 |
+
SeaGreen3
|
| 595 |
+
SeaGreen4
|
| 596 |
+
seashell
|
| 597 |
+
seashell1
|
| 598 |
+
seashell2
|
| 599 |
+
seashell3
|
| 600 |
+
seashell4
|
| 601 |
+
sienna
|
| 602 |
+
sienna1
|
| 603 |
+
sienna2
|
| 604 |
+
sienna3
|
| 605 |
+
sienna4
|
| 606 |
+
silver
|
| 607 |
+
SkyBlue
|
| 608 |
+
SkyBlue1
|
| 609 |
+
SkyBlue2
|
| 610 |
+
SkyBlue3
|
| 611 |
+
SkyBlue4
|
| 612 |
+
SlateBlue
|
| 613 |
+
SlateBlue1
|
| 614 |
+
SlateBlue2
|
| 615 |
+
SlateBlue3
|
| 616 |
+
SlateBlue4
|
| 617 |
+
SlateGray
|
| 618 |
+
SlateGray1
|
| 619 |
+
SlateGray2
|
| 620 |
+
SlateGray3
|
| 621 |
+
SlateGray4
|
| 622 |
+
SlateGrey
|
| 623 |
+
snow
|
| 624 |
+
snow1
|
| 625 |
+
snow2
|
| 626 |
+
snow3
|
| 627 |
+
snow4
|
| 628 |
+
SpringGreen
|
| 629 |
+
SpringGreen1
|
| 630 |
+
SpringGreen2
|
| 631 |
+
SpringGreen3
|
| 632 |
+
SpringGreen4
|
| 633 |
+
SteelBlue
|
| 634 |
+
SteelBlue1
|
| 635 |
+
SteelBlue2
|
| 636 |
+
SteelBlue3
|
| 637 |
+
SteelBlue4
|
| 638 |
+
tan
|
| 639 |
+
tan1
|
| 640 |
+
tan2
|
| 641 |
+
tan3
|
| 642 |
+
tan4
|
| 643 |
+
teal
|
| 644 |
+
thistle
|
| 645 |
+
thistle1
|
| 646 |
+
thistle2
|
| 647 |
+
thistle3
|
| 648 |
+
thistle4
|
| 649 |
+
tomato
|
| 650 |
+
tomato1
|
| 651 |
+
tomato2
|
| 652 |
+
tomato3
|
| 653 |
+
tomato4
|
| 654 |
+
transparent
|
| 655 |
+
turquoise
|
| 656 |
+
turquoise1
|
| 657 |
+
turquoise2
|
| 658 |
+
turquoise3
|
| 659 |
+
turquoise4
|
| 660 |
+
violet
|
| 661 |
+
VioletRed
|
| 662 |
+
VioletRed1
|
| 663 |
+
VioletRed2
|
| 664 |
+
VioletRed3
|
| 665 |
+
VioletRed4
|
| 666 |
+
wheat
|
| 667 |
+
wheat1
|
| 668 |
+
wheat2
|
| 669 |
+
wheat3
|
| 670 |
+
wheat4
|
| 671 |
+
white
|
| 672 |
+
WhiteSmoke
|
| 673 |
+
yellow
|
| 674 |
+
yellow1
|
| 675 |
+
yellow2
|
| 676 |
+
yellow3
|
| 677 |
+
yellow4
|
| 678 |
+
YellowGreen
|
static/fonts.txt
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Courier
|
| 2 |
+
Helvetica-Narrow-BoldOblique
|
| 3 |
+
AvantGarde-Book
|
| 4 |
+
AvantGarde-BookOblique
|
| 5 |
+
AvantGarde-Demi
|
| 6 |
+
AvantGarde-DemiOblique
|
| 7 |
+
Bookman-Demi
|
| 8 |
+
Bookman-DemiItalic
|
| 9 |
+
Bookman-Light
|
| 10 |
+
Bookman-LightItalic
|
| 11 |
+
Courier-Bold
|
| 12 |
+
Courier-BoldOblique
|
| 13 |
+
Courier-Oblique
|
| 14 |
+
fixed
|
| 15 |
+
Helvetica
|
| 16 |
+
Helvetica-Bold
|
| 17 |
+
Helvetica-BoldOblique
|
| 18 |
+
Helvetica-Narrow
|
| 19 |
+
Helvetica-Narrow-Bold
|
| 20 |
+
Helvetica-Narrow-Oblique
|
| 21 |
+
Helvetica-Oblique
|
| 22 |
+
NewCenturySchlbk-Bold
|
| 23 |
+
NewCenturySchlbk-BoldItalic
|
| 24 |
+
NewCenturySchlbk-Italic
|
| 25 |
+
NewCenturySchlbk-Roman
|
| 26 |
+
Palatino-Bold
|
| 27 |
+
Palatino-BoldItalic
|
| 28 |
+
Palatino-Italic
|
| 29 |
+
Palatino-Roman
|
| 30 |
+
Symbol
|
| 31 |
+
Times-Bold
|
| 32 |
+
Times-BoldItalic
|
| 33 |
+
Times-Italic
|
| 34 |
+
Times-Roman
|
| 35 |
+
C059-BdIta
|
| 36 |
+
C059-Bold
|
| 37 |
+
C059-Bold-Italic
|
| 38 |
+
C059-Italic
|
| 39 |
+
C059-Roman
|
| 40 |
+
Century-Schoolbook-L-Bold
|
| 41 |
+
Century-Schoolbook-L-Bold-Italic
|
| 42 |
+
Century-Schoolbook-L-Italic
|
| 43 |
+
Century-Schoolbook-L-Roman
|
| 44 |
+
D050000L
|
| 45 |
+
DejaVu-Sans
|
| 46 |
+
DejaVu-Sans-Bold
|
| 47 |
+
DejaVu-Sans-Mono
|
| 48 |
+
DejaVu-Sans-Mono-Bold
|
| 49 |
+
DejaVu-Serif
|
| 50 |
+
DejaVu-Serif-Bold
|
| 51 |
+
Dingbats
|
| 52 |
+
Droid-Sans-Fallback
|
| 53 |
+
Nimbus-Mono-L
|
| 54 |
+
Nimbus-Mono-L-Bold
|
| 55 |
+
Nimbus-Mono-L-Bold-Oblique
|
| 56 |
+
Nimbus-Mono-L-Regular-Oblique
|
| 57 |
+
Nimbus-Mono-PS
|
| 58 |
+
Nimbus-Mono-PS-Bold
|
| 59 |
+
Nimbus-Mono-PS-Bold-Italic
|
| 60 |
+
Nimbus-Mono-PS-Italic
|
| 61 |
+
Nimbus-Roman
|
| 62 |
+
Nimbus-Roman-Bold
|
| 63 |
+
Nimbus-Roman-Bold-Italic
|
| 64 |
+
Nimbus-Roman-Italic
|
| 65 |
+
Nimbus-Roman-No9-L
|
| 66 |
+
Nimbus-Roman-No9-L-Medium
|
| 67 |
+
Nimbus-Roman-No9-L-Medium-Italic
|
| 68 |
+
Nimbus-Roman-No9-L-Regular-Italic
|
| 69 |
+
Nimbus-Sans
|
| 70 |
+
Nimbus-Sans-Bold
|
| 71 |
+
Nimbus-Sans-Bold-Italic
|
| 72 |
+
Nimbus-Sans-Italic
|
| 73 |
+
Nimbus-Sans-L
|
| 74 |
+
Nimbus-Sans-L-Bold
|
| 75 |
+
Nimbus-Sans-L-Bold-Condensed
|
| 76 |
+
Nimbus-Sans-L-Bold-Condensed-Italic
|
| 77 |
+
Nimbus-Sans-L-Bold-Italic
|
| 78 |
+
Nimbus-Sans-L-Regular-Condensed
|
| 79 |
+
Nimbus-Sans-L-Regular-Condensed-Italic
|
| 80 |
+
Nimbus-Sans-L-Regular-Italic
|
| 81 |
+
Nimbus-Sans-Narrow
|
| 82 |
+
Nimbus-Sans-Narrow-Bold
|
| 83 |
+
Nimbus-Sans-Narrow-Bold-Oblique
|
| 84 |
+
Nimbus-Sans-Narrow-Oblique
|
| 85 |
+
NimbusMonoPS-Bold
|
| 86 |
+
NimbusMonoPS-BoldItalic
|
| 87 |
+
NimbusMonoPS-Italic
|
| 88 |
+
NimbusMonoPS-Regular
|
| 89 |
+
NimbusRoman-Bold
|
| 90 |
+
NimbusRoman-BoldItalic
|
| 91 |
+
NimbusRoman-Italic
|
| 92 |
+
NimbusRoman-Regular
|
| 93 |
+
NimbusSans-Bold
|
| 94 |
+
NimbusSans-BoldItalic
|
| 95 |
+
NimbusSans-Italic
|
| 96 |
+
NimbusSans-Regular
|
| 97 |
+
NimbusSansNarrow-Bold
|
| 98 |
+
NimbusSansNarrow-BoldOblique
|
| 99 |
+
NimbusSansNarrow-Oblique
|
| 100 |
+
NimbusSansNarrow-Regular
|
| 101 |
+
Noto-Mono
|
| 102 |
+
Noto-Sans-Mono-Bold
|
| 103 |
+
Noto-Sans-Mono-Regular
|
| 104 |
+
P052-Bold
|
| 105 |
+
P052-Bold-Italic
|
| 106 |
+
P052-BoldItalic
|
| 107 |
+
P052-Italic
|
| 108 |
+
P052-Roman
|
| 109 |
+
Standard-Symbols-L
|
| 110 |
+
Standard-Symbols-PS
|
| 111 |
+
URW-Bookman-Demi
|
| 112 |
+
URW-Bookman-Demi-Italic
|
| 113 |
+
URW-Bookman-L-Demi-Bold
|
| 114 |
+
URW-Bookman-L-Demi-Bold-Italic
|
| 115 |
+
URW-Bookman-L-Light
|
| 116 |
+
URW-Bookman-L-Light-Italic
|
| 117 |
+
URW-Bookman-Light
|
| 118 |
+
URW-Bookman-Light-Italic
|
| 119 |
+
URW-Chancery-L-Medium-Italic
|
| 120 |
+
URW-Gothic-Book
|
| 121 |
+
URW-Gothic-Book-Oblique
|
| 122 |
+
URW-Gothic-Demi
|
| 123 |
+
URW-Gothic-Demi-Oblique
|
| 124 |
+
URW-Gothic-L-Book
|
| 125 |
+
URW-Gothic-L-Book-Oblique
|
| 126 |
+
URW-Gothic-L-Demi
|
| 127 |
+
URW-Gothic-L-Demi-Oblique
|
| 128 |
+
URW-Palladio-L-Bold
|
| 129 |
+
URW-Palladio-L-Bold-Italic
|
| 130 |
+
URW-Palladio-L-Italic
|
| 131 |
+
URW-Palladio-L-Roman
|
| 132 |
+
URWBookman-Demi
|
| 133 |
+
URWBookman-DemiItalic
|
| 134 |
+
URWBookman-Light
|
| 135 |
+
URWBookman-LightItalic
|
| 136 |
+
URWGothic-Book
|
| 137 |
+
URWGothic-BookOblique
|
| 138 |
+
URWGothic-Demi
|
| 139 |
+
URWGothic-DemiOblique
|
| 140 |
+
Z003-Medium-Italic
|
| 141 |
+
Z003-MediumItalic
|
static/submit_video.html
CHANGED
|
@@ -151,51 +151,104 @@
|
|
| 151 |
</style>
|
| 152 |
</head>
|
| 153 |
<body>
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
<
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
</
|
| 172 |
-
</
|
| 173 |
-
<div class="form-group">
|
| 174 |
-
<h3>Visual Parameters</h3>
|
| 175 |
-
<label for="max_words_per_line">Max words per line</label>
|
| 176 |
-
<input type="number" id="max_words_per_line" name="max_words_per_line" value="6"><br>
|
| 177 |
-
<label for="fontsize">Font size</label>
|
| 178 |
-
<input type="number" id="fontsize" name="fontsize" value="42"><br>
|
| 179 |
-
<label for="font">Font:</label>
|
| 180 |
-
<input type="text" id="font" name="font" value="FuturaPTHeavy"><br>
|
| 181 |
-
<label for="bg_color">Background color</label>
|
| 182 |
-
<input type="text" id="bg_color" name="bg_color" value="#00FFFF00"><br>
|
| 183 |
-
<label for="text_color">Text color</label>
|
| 184 |
-
<input type="text" id="text_color" name="text_color" value="white"><br>
|
| 185 |
-
<label for="caption_mode">Caption mode</label>
|
| 186 |
-
<select id="caption_mode" name="caption_mode">
|
| 187 |
-
<option value="desktop">Desktop</option>
|
| 188 |
-
<option value="mobile">Mobile</option>
|
| 189 |
-
</select>
|
| 190 |
-
</div>
|
| 191 |
</div>
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
</body>
|
| 201 |
</html>
|
|
|
|
|
|
|
|
|
| 151 |
</style>
|
| 152 |
</head>
|
| 153 |
<body>
|
| 154 |
+
<form id="video-form" action="/process_video/" method="post" enctype="multipart/form-data">
|
| 155 |
+
<div class="form-wrapper">
|
| 156 |
+
<div class="form-group">
|
| 157 |
+
<h3>Inputs & Task Selection</h3>
|
| 158 |
+
<label for="video_file">Video File</label>
|
| 159 |
+
<input type="file" id="video_file" name="video_file"><br>
|
| 160 |
+
|
| 161 |
+
<label for="task">Task</label>
|
| 162 |
+
<select id="task" name="task">
|
| 163 |
+
<option value="transcribe">Transcribe</option>
|
| 164 |
+
<option value="translate">Translate</option>
|
| 165 |
+
</select>
|
| 166 |
+
|
| 167 |
+
<label for="model_version">Model Version</label>
|
| 168 |
+
<select id="model_version" name="model_version">
|
| 169 |
+
<option value="deepdml/faster-whisper-large-v3-turbo-ct2">faster-whisper-large-v3-turbo</option>
|
| 170 |
+
<option value="turbo">turbo</option>
|
| 171 |
+
<option value="large-v3">large-v3</option>
|
| 172 |
+
</select>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
</div>
|
| 174 |
+
|
| 175 |
+
<div class="form-group">
|
| 176 |
+
<h3>Visual Parameters</h3>
|
| 177 |
+
<label for="max_words_per_line">Max words per line</label>
|
| 178 |
+
<input type="number" id="max_words_per_line" name="max_words_per_line" value="6"><br>
|
| 179 |
+
|
| 180 |
+
<label for="fontsize">Font size</label>
|
| 181 |
+
<input type="number" id="fontsize" name="fontsize" value="42"><br>
|
| 182 |
+
|
| 183 |
+
<label for="font">Font</label>
|
| 184 |
+
<select id="font" name="font">
|
| 185 |
+
<option>Loading fonts...</option>
|
| 186 |
+
</select><br>
|
| 187 |
+
|
| 188 |
+
<label for="bg_color">Background color</label>
|
| 189 |
+
<input type="text" id="bg_color" name="bg_color" value="#00FFFF00"><br>
|
| 190 |
+
|
| 191 |
+
<label for="text_color">Text color</label>
|
| 192 |
+
<select id="text_color" name="text_color">
|
| 193 |
+
<option>Loading colors...</option>
|
| 194 |
+
</select><br>
|
| 195 |
+
|
| 196 |
+
<label for="caption_mode">Caption mode</label>
|
| 197 |
+
<select id="caption_mode" name="caption_mode">
|
| 198 |
+
<option value="desktop">Desktop</option>
|
| 199 |
+
<option value="mobile">Mobile</option>
|
| 200 |
+
</select>
|
| 201 |
+
</div>
|
| 202 |
+
</div>
|
| 203 |
+
|
| 204 |
+
<div id="loading" style="display:none; text-align: center; margin-top: 10px; font-weight: bold;">
|
| 205 |
+
<i class="fas fa-spinner fa-spin"></i> Processing, please wait...
|
| 206 |
</div>
|
| 207 |
+
|
| 208 |
+
<input type="submit" value="Submit">
|
| 209 |
+
</form>
|
| 210 |
+
<div class="footer">
|
| 211 |
+
<p>Created by:</p>
|
| 212 |
+
<a href="https://github.com/marquesafonso" class="github"><i class="fab fa-github fa-3x"></i></a>
|
| 213 |
+
<a href="https://www.linkedin.com/in/marquesafonso" class="linkedin"><i class="fab fa-linkedin fa-3x"></i></a>
|
| 214 |
+
</div>
|
| 215 |
+
<script>
|
| 216 |
+
// Loading dropdown options
|
| 217 |
+
function populateDropdown(id, url, defaultValue = null) {
|
| 218 |
+
fetch(url)
|
| 219 |
+
.then(response => response.text())
|
| 220 |
+
.then(data => {
|
| 221 |
+
const select = document.getElementById(id);
|
| 222 |
+
select.innerHTML = '';
|
| 223 |
+
const lines = data.split('\n').map(x => x.trim()).filter(Boolean);
|
| 224 |
+
|
| 225 |
+
lines.forEach(item => {
|
| 226 |
+
const opt = document.createElement('option');
|
| 227 |
+
opt.value = item;
|
| 228 |
+
opt.textContent = item;
|
| 229 |
+
if (item === defaultValue) {
|
| 230 |
+
opt.selected = true;
|
| 231 |
+
}
|
| 232 |
+
select.appendChild(opt);
|
| 233 |
+
});
|
| 234 |
+
})
|
| 235 |
+
.catch(error => {
|
| 236 |
+
console.error(`Error loading ${url}:`, error);
|
| 237 |
+
});
|
| 238 |
+
}
|
| 239 |
+
// default font and color:
|
| 240 |
+
const DEFAULT_FONT = "Helvetica";
|
| 241 |
+
const DEFAULT_COLOR = "white";
|
| 242 |
+
// Init dropdowns
|
| 243 |
+
populateDropdown('font', '/static/fonts.txt', DEFAULT_FONT);
|
| 244 |
+
populateDropdown('text_color', '/static/colors.txt', DEFAULT_COLOR);
|
| 245 |
+
|
| 246 |
+
// Show loading spinner on submit
|
| 247 |
+
document.getElementById('video-form').addEventListener('submit', function () {
|
| 248 |
+
document.getElementById('loading').style.display = 'block';
|
| 249 |
+
});
|
| 250 |
+
</script>
|
| 251 |
</body>
|
| 252 |
</html>
|
| 253 |
+
|
| 254 |
+
|
utils/get_moviepy_configs.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from moviepy.editor import TextClip
|
| 2 |
+
|
| 3 |
+
with open('static/fonts.txt', 'w', encoding='utf-8') as fonts:
|
| 4 |
+
fonts.write("\n".join(TextClip.list('font')))
|
| 5 |
+
|
| 6 |
+
with open('static/colors.txt', 'w', encoding='utf-8') as colors:
|
| 7 |
+
colors_list = [color.decode("utf-8") for color in TextClip.list('color')[3:]]
|
| 8 |
+
colors.write("\n".join(colors_list))
|
utils/process_video.py
CHANGED
|
@@ -3,7 +3,6 @@ from utils.transcriber import transcriber
|
|
| 3 |
from utils.subtitler import subtitler
|
| 4 |
|
| 5 |
def process_video(invideo_file: str,
|
| 6 |
-
srt_file: str | None,
|
| 7 |
task: str,
|
| 8 |
model_version: str,
|
| 9 |
max_words_per_line:int,
|
|
@@ -17,12 +16,7 @@ def process_video(invideo_file: str,
|
|
| 17 |
invideo_path_parts = os.path.normpath(invideo_file).split(os.path.sep)
|
| 18 |
VIDEO_NAME = os.path.basename(invideo_file)
|
| 19 |
OUTVIDEO_PATH = os.path.join(os.path.normpath('/'.join(invideo_path_parts[:-1])), f"result_{VIDEO_NAME}")
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
srt_file = os.path.normpath(f"{invideo_file.split('.')[0]}.srt")
|
| 25 |
-
transcriber(invideo_file, srt_file, max_words_per_line, task, model_version, config_file)
|
| 26 |
-
logging.info("Subtitling...")
|
| 27 |
-
subtitler(invideo_file, srt_file, OUTVIDEO_PATH, fontsize, font, bg_color, text_color, caption_mode)
|
| 28 |
-
return OUTVIDEO_PATH, srt_file
|
|
|
|
| 3 |
from utils.subtitler import subtitler
|
| 4 |
|
| 5 |
def process_video(invideo_file: str,
|
|
|
|
| 6 |
task: str,
|
| 7 |
model_version: str,
|
| 8 |
max_words_per_line:int,
|
|
|
|
| 16 |
invideo_path_parts = os.path.normpath(invideo_file).split(os.path.sep)
|
| 17 |
VIDEO_NAME = os.path.basename(invideo_file)
|
| 18 |
OUTVIDEO_PATH = os.path.join(os.path.normpath('/'.join(invideo_path_parts[:-1])), f"result_{VIDEO_NAME}")
|
| 19 |
+
srt_string = transcriber(invideo_file, max_words_per_line, task, model_version, config_file)
|
| 20 |
+
logging.info("Subtitling...")
|
| 21 |
+
subtitler(invideo_file, srt_string, OUTVIDEO_PATH, fontsize, font, bg_color, text_color, caption_mode)
|
| 22 |
+
return OUTVIDEO_PATH, srt_string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
utils/subtitler.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
| 1 |
from moviepy.editor import VideoFileClip, CompositeVideoClip, TextClip
|
| 2 |
import os
|
| 3 |
|
| 4 |
-
def parse_srt(
|
| 5 |
-
"""Parse the SRT
|
| 6 |
-
|
| 7 |
-
lines = file.readlines()
|
| 8 |
i = 0
|
| 9 |
subtitles = []
|
| 10 |
while i < len(lines):
|
|
@@ -29,7 +28,7 @@ def filter_caption_width(caption_mode:str):
|
|
| 29 |
return caption_width_ratio, caption_height_ratio
|
| 30 |
|
| 31 |
def subtitler(video_file:str,
|
| 32 |
-
|
| 33 |
output_file:str,
|
| 34 |
fontsize:int,
|
| 35 |
font: str,
|
|
@@ -37,12 +36,11 @@ def subtitler(video_file:str,
|
|
| 37 |
text_color:str,
|
| 38 |
caption_mode:str
|
| 39 |
):
|
| 40 |
-
"""Add subtitles from an SRT
|
| 41 |
video_file = os.path.abspath(video_file)
|
| 42 |
-
srt_path = os.path.abspath(srt_path)
|
| 43 |
output_file = os.path.abspath(output_file)
|
| 44 |
clip = VideoFileClip(filename=video_file, target_resolution=None)
|
| 45 |
-
subtitles = parse_srt(
|
| 46 |
subtitle_clips = []
|
| 47 |
caption_width_ratio, caption_height_ratio = filter_caption_width(caption_mode)
|
| 48 |
for start, end, text in subtitles:
|
|
|
|
| 1 |
from moviepy.editor import VideoFileClip, CompositeVideoClip, TextClip
|
| 2 |
import os
|
| 3 |
|
| 4 |
+
def parse_srt(srt_string):
|
| 5 |
+
"""Parse the SRT string and return a list of (start, end, text) for each subtitle."""
|
| 6 |
+
lines = srt_string.split("\n")
|
|
|
|
| 7 |
i = 0
|
| 8 |
subtitles = []
|
| 9 |
while i < len(lines):
|
|
|
|
| 28 |
return caption_width_ratio, caption_height_ratio
|
| 29 |
|
| 30 |
def subtitler(video_file:str,
|
| 31 |
+
srt_string:str,
|
| 32 |
output_file:str,
|
| 33 |
fontsize:int,
|
| 34 |
font: str,
|
|
|
|
| 36 |
text_color:str,
|
| 37 |
caption_mode:str
|
| 38 |
):
|
| 39 |
+
"""Add subtitles from an SRT string to a video."""
|
| 40 |
video_file = os.path.abspath(video_file)
|
|
|
|
| 41 |
output_file = os.path.abspath(output_file)
|
| 42 |
clip = VideoFileClip(filename=video_file, target_resolution=None)
|
| 43 |
+
subtitles = parse_srt(srt_string)
|
| 44 |
subtitle_clips = []
|
| 45 |
caption_width_ratio, caption_height_ratio = filter_caption_width(caption_mode)
|
| 46 |
for start, end, text in subtitles:
|
utils/transcriber.py
CHANGED
|
@@ -1,19 +1,21 @@
|
|
| 1 |
from gradio_client import Client, handle_file
|
| 2 |
from utils.api_configs import api_configs
|
| 3 |
|
| 4 |
-
def transcriber(invideo_file:str,
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
| 7 |
HF_TOKEN = api_configs(config_file)["secrets"]["hf-token"]
|
| 8 |
HF_SPACE = api_configs(config_file)["secrets"]["hf-space"]
|
| 9 |
client = Client(HF_SPACE, hf_token=HF_TOKEN)
|
| 10 |
result = client.predict(
|
| 11 |
-
|
|
|
|
| 12 |
max_words_per_line=max_words_per_line,
|
| 13 |
task=task,
|
| 14 |
model_version=model_version,
|
| 15 |
api_name="/predict"
|
| 16 |
)
|
| 17 |
-
|
| 18 |
-
file.write(result[0])
|
| 19 |
-
return srt_file
|
|
|
|
| 1 |
from gradio_client import Client, handle_file
|
| 2 |
from utils.api_configs import api_configs
|
| 3 |
|
| 4 |
+
def transcriber(invideo_file:str,
|
| 5 |
+
max_words_per_line:int,
|
| 6 |
+
task:str,
|
| 7 |
+
model_version:str,
|
| 8 |
+
config_file:str
|
| 9 |
+
):
|
| 10 |
HF_TOKEN = api_configs(config_file)["secrets"]["hf-token"]
|
| 11 |
HF_SPACE = api_configs(config_file)["secrets"]["hf-space"]
|
| 12 |
client = Client(HF_SPACE, hf_token=HF_TOKEN)
|
| 13 |
result = client.predict(
|
| 14 |
+
file_input=handle_file(invideo_file),
|
| 15 |
+
file_type = "video",
|
| 16 |
max_words_per_line=max_words_per_line,
|
| 17 |
task=task,
|
| 18 |
model_version=model_version,
|
| 19 |
api_name="/predict"
|
| 20 |
)
|
| 21 |
+
return result[0]
|
|
|
|
|
|