Compare commits
10 commits
cbf25abfbc
...
904ff277ad
Author | SHA1 | Date | |
---|---|---|---|
904ff277ad | |||
3366c72ac1 | |||
47aa5ec591 | |||
bf31e8a4c9 | |||
335e229aa5 | |||
89fa362789 | |||
7f2fbfcfb4 | |||
9cf9eb8e7e | |||
89e92e1160 | |||
8027fce02e |
3 changed files with 252 additions and 0 deletions
113
build.py
Executable file
113
build.py
Executable file
|
@ -0,0 +1,113 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
SECTIONS = {
|
||||||
|
'drift': 'Drift',
|
||||||
|
'fs': 'FreeStyle',
|
||||||
|
'k': 'K projects',
|
||||||
|
'lol': 'LOL',
|
||||||
|
'pf': 'Press Forward',
|
||||||
|
'ta': 'Time Attack',
|
||||||
|
'trial': 'Trial',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def card(name, web, raw):
|
||||||
|
return f'''\
|
||||||
|
<div class="card">
|
||||||
|
<video controls="controls" preload="none">
|
||||||
|
<source src="{web}" />
|
||||||
|
</video>
|
||||||
|
<br />
|
||||||
|
<a href="{raw}">{name}</a>
|
||||||
|
</div>
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def a(href, text, active=False):
|
||||||
|
html = ['<a']
|
||||||
|
if active:
|
||||||
|
html.append(' class="active"')
|
||||||
|
html.append(f' href="{href}">{text}</a>')
|
||||||
|
return str().join(html)
|
||||||
|
|
||||||
|
|
||||||
|
def nav(sections, active):
|
||||||
|
html = ['<nav>']
|
||||||
|
for _, section in sorted(sections.items()):
|
||||||
|
id = section['id']
|
||||||
|
html.append(a(f"#{id}", section['label'], id == active))
|
||||||
|
html.append('</nav>')
|
||||||
|
return str().join(html)
|
||||||
|
|
||||||
|
|
||||||
|
def body(sections):
|
||||||
|
html = []
|
||||||
|
for _, section in sorted(sections.items()):
|
||||||
|
html.append(f'<section id="{section["id"]}">')
|
||||||
|
html.append(section['content'])
|
||||||
|
html.append('</section>')
|
||||||
|
return str().join(html)
|
||||||
|
|
||||||
|
|
||||||
|
def html(body):
|
||||||
|
return f'''\
|
||||||
|
<!DOCTYPE html><html><head>
|
||||||
|
<!----------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="stylesheet" href="index.css" />
|
||||||
|
<title>TrackMania vidz</title>
|
||||||
|
|
||||||
|
<!----------------------------------------------------------------------------->
|
||||||
|
</head></body>
|
||||||
|
<!----------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
{body}
|
||||||
|
|
||||||
|
<!----------------------------------------------------------------------------->
|
||||||
|
</body></html>
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
file = os.path.realpath(__file__)
|
||||||
|
root = os.path.dirname(file)
|
||||||
|
raw_root = os.path.join(root, 'raw')
|
||||||
|
web_root = os.path.join(root, 'web')
|
||||||
|
_, categories, _ = next(os.walk(raw_root))
|
||||||
|
sections = {
|
||||||
|
' ': {'id': 'home', 'label': '⋅', 'content': str()},
|
||||||
|
}
|
||||||
|
for category in categories:
|
||||||
|
section = {
|
||||||
|
'id': category,
|
||||||
|
'label': SECTIONS.get(category, category),
|
||||||
|
}
|
||||||
|
content = []
|
||||||
|
raw_category = os.path.join(raw_root, category)
|
||||||
|
videos = {}
|
||||||
|
for directory, directories, files in os.walk(raw_category):
|
||||||
|
for file in files:
|
||||||
|
relative = os.path.relpath(directory, raw_root)
|
||||||
|
name, _ = os.path.splitext(file)
|
||||||
|
raw_file = os.path.join('raw', relative, file)
|
||||||
|
web_file = os.path.join('web', relative, f'{name}.mp4')
|
||||||
|
videos[name] = [web_file, raw_file]
|
||||||
|
for name, files in sorted(videos.items()):
|
||||||
|
web_file, raw_file = files
|
||||||
|
content.append(card(name, web_file, raw_file))
|
||||||
|
section['content'] = os.linesep.join([
|
||||||
|
'<div class="cards">', os.linesep.join(content), '</div>'])
|
||||||
|
sections[category] = section
|
||||||
|
for id, section in sections.items():
|
||||||
|
section['content'] = nav(sections, id) + section['content']
|
||||||
|
index = os.path.join(root, 'index.html')
|
||||||
|
with open(index, 'w') as i:
|
||||||
|
i.write(html(body(sections)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
49
encode.py
Executable file
49
encode.py
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def encode(input_file, output_file):
|
||||||
|
output_directory = os.path.dirname(output_file)
|
||||||
|
os.makedirs(output_directory, exist_ok=True)
|
||||||
|
if not os.path.exists(output_file):
|
||||||
|
subprocess.call([
|
||||||
|
'ffmpeg',
|
||||||
|
'-i', input_file,
|
||||||
|
'-codec:a', 'libopus',
|
||||||
|
'-b:a', '128K',
|
||||||
|
'-codec:v', 'libx264',
|
||||||
|
'-preset', 'veryslow',
|
||||||
|
'-qp', '23',
|
||||||
|
'-movflags', '+faststart',
|
||||||
|
'-pix_fmt', 'yuv420p',
|
||||||
|
output_file
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
file = os.path.realpath(__file__)
|
||||||
|
root = os.path.dirname(file)
|
||||||
|
raw_root = os.path.join(root, 'raw')
|
||||||
|
web_root = os.path.join(root, 'web')
|
||||||
|
print(f'← {raw_root}')
|
||||||
|
print(f'→ {web_root}')
|
||||||
|
tasks = []
|
||||||
|
for directory, directories, files in os.walk(raw_root):
|
||||||
|
for file in files:
|
||||||
|
relative_directory = os.path.relpath(directory, raw_root)
|
||||||
|
name, ext = os.path.splitext(file)
|
||||||
|
relative_name = os.path.join(relative_directory, name)
|
||||||
|
tasks.append((relative_name, ext))
|
||||||
|
for relative_name, ext in sorted(tasks):
|
||||||
|
raw_file = os.path.join(raw_root, f'{relative_name}{ext}')
|
||||||
|
web_file = os.path.join(web_root, f'{relative_name}.mp4')
|
||||||
|
print()
|
||||||
|
print(f'← {raw_file}')
|
||||||
|
print(f'→ {web_file}')
|
||||||
|
encode(raw_file, web_file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
90
index.css
Normal file
90
index.css
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
@viewport {
|
||||||
|
width: device-width;
|
||||||
|
zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* { border: 1px solid; }
|
||||||
|
/*
|
||||||
|
header { background: #800000; }
|
||||||
|
nav { background: #008000; }
|
||||||
|
section { background: #000080; }
|
||||||
|
/**/
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
//margin: 0;
|
||||||
|
//padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
background: rgb(0,0,0);
|
||||||
|
color: rgb(160,160,160);
|
||||||
|
font-family: sans;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: none;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 1em 1vw 1vh 1vw;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#home,section:target {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
background: linear-gradient(rgba(64,64,64,1), rgba(64,64,64,0));
|
||||||
|
border-color: rgb(128,128,128);
|
||||||
|
border-radius: .5em;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px 1px 0 1px;
|
||||||
|
#color: rgb(128,128,0);
|
||||||
|
font-weight: bold;
|
||||||
|
padding: .25em .5em;
|
||||||
|
//transition: all .5s;
|
||||||
|
}
|
||||||
|
nav a.active {
|
||||||
|
background: linear-gradient(rgba(128,128,128,1), rgba(128,128,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: rgb(0,192,192);
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: rgb(192,0,0);
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: rgb(0,160,160);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: #101010;
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: .5em;
|
||||||
|
color: #404040;
|
||||||
|
margin: .1em;
|
||||||
|
padding: .5em .6em .5 em .25em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
Loading…
Reference in a new issue