Add the season 2 intro clip, with its credit
Browse files- .gitattributes +1 -0
- app.py +10 -0
- assets/season2-intro.mp4 +3 -0
- index.html +33 -0
.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
assets/season2-intro.mp4 filter=lfs diff=lfs merge=lfs -text
|
app.py
CHANGED
|
@@ -243,6 +243,16 @@ def logout():
|
|
| 243 |
return r
|
| 244 |
|
| 245 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
@app.get("/api/season")
|
| 247 |
def season(request: Request):
|
| 248 |
return seasons.public(seasons.get(request.query_params.get("season")))
|
|
|
|
| 243 |
return r
|
| 244 |
|
| 245 |
|
| 246 |
+
@app.get("/assets/{name}")
|
| 247 |
+
def asset(name: str):
|
| 248 |
+
"""Static files for the page. Names are matched against what is actually on disk, so
|
| 249 |
+
a crafted name cannot walk out of the directory."""
|
| 250 |
+
d = os.path.join(HERE, "assets")
|
| 251 |
+
if name not in set(os.listdir(d) if os.path.isdir(d) else []):
|
| 252 |
+
raise HTTPException(404, "not found")
|
| 253 |
+
return FileResponse(os.path.join(d, name))
|
| 254 |
+
|
| 255 |
+
|
| 256 |
@app.get("/api/season")
|
| 257 |
def season(request: Request):
|
| 258 |
return seasons.public(seasons.get(request.query_params.get("season")))
|
assets/season2-intro.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d7c030572da28908115be8fbdea9a9abb45e263bc8b60f44fb465e411cf00a46
|
| 3 |
+
size 5885191
|
index.html
CHANGED
|
@@ -48,6 +48,12 @@
|
|
| 48 |
border:1px solid var(--line);border-radius:20px;padding:4px 12px}
|
| 49 |
.wts b{color:var(--accent)}
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
#seasonbar{display:flex;gap:6px;margin-bottom:14px}
|
| 52 |
#seasonbar button{border:1px solid var(--line);background:#fff;color:var(--muted);
|
| 53 |
font:inherit;font-size:12.5px;font-weight:700;padding:7px 14px;
|
|
@@ -340,6 +346,7 @@
|
|
| 340 |
</div>
|
| 341 |
<div id="authbar"></div>
|
| 342 |
<div id="langnote"></div>
|
|
|
|
| 343 |
<div id="seasonbar"></div>
|
| 344 |
<div id="cd"><span class="cdlab" id="cdlab"></span><span class="cdval" id="cdval"> </span></div>
|
| 345 |
<p class="eyebrow">Open Discovery Challenge</p>
|
|
@@ -511,6 +518,7 @@ const T = {
|
|
| 511 |
},
|
| 512 |
ov_pred:"์์ธก์น", ov_pf:"๋ง๋ผ๋ฆฌ์ ํจ์", ov_hs:"์ฌ๋ ํจ์", ov_sel:"์ ํ๋",
|
| 513 |
private_note:"์ ์ถ์๊ฐ ๋น๊ณต๊ฐ๋ฅผ ์ ํํ์ต๋๋ค", copy_smiles:"๋ถ์์ ๋ณต์ฌ",
|
|
|
|
| 514 |
season_soon:"์ค๋น์ค", season_notopen:"์ด ์์ฆ์ ์์ง ์ ์๋ฅผ ๋ฐ์ง ์์ต๋๋ค. ์ฑ์ ๊ธฐ ๊ฒ์ฆ์ด ๋๋๋ฉด ๊ณต์ง์ ํจ๊ป ์ฝ๋๋ค.",
|
| 515 |
cd_label:"์์ฆ #1 ๋ง๊ฐ๊น์ง", cd_day:"์ผ", cd_over_label:"์์ฆ #1 ๋ง๊ฐ",
|
| 516 |
cd_over:"๋ง๊ฐ๋์์ต๋๋ค", view_3d:"3D ์
์ฒด ๊ตฌ์กฐ๋ก ๋ณด๊ธฐ",
|
|
@@ -793,6 +801,30 @@ const submittedDate = e => {
|
|
| 793 |
}).format(new Date(Number(e.submitted_at) * 1000));
|
| 794 |
};
|
| 795 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 796 |
function renderSeasonBar(){
|
| 797 |
if(!SEASONS) return;
|
| 798 |
const d = t();
|
|
@@ -853,6 +885,7 @@ function applyLang(){
|
|
| 853 |
}
|
| 854 |
if(d.prize_amt) $("#prize_amt").firstChild.nodeValue = d.prize_amt + " ";
|
| 855 |
renderSeasonBar();
|
|
|
|
| 856 |
renderAuth();
|
| 857 |
tickCountdown();
|
| 858 |
if(DATA) render();
|
|
|
|
| 48 |
border:1px solid var(--line);border-radius:20px;padding:4px 12px}
|
| 49 |
.wts b{color:var(--accent)}
|
| 50 |
|
| 51 |
+
#intro{margin:0 0 16px;border-radius:14px;overflow:hidden;border:1px solid var(--line);
|
| 52 |
+
background:#0d1420;line-height:0;box-shadow:var(--shadow)}
|
| 53 |
+
#intro:empty{display:none;margin:0;border:0}
|
| 54 |
+
#intro video{width:100%;height:auto;display:block}
|
| 55 |
+
#intro .credit{line-height:1.5;font-size:11px;color:#8ea3c0;background:#0d1420;
|
| 56 |
+
padding:7px 12px;text-align:right}
|
| 57 |
#seasonbar{display:flex;gap:6px;margin-bottom:14px}
|
| 58 |
#seasonbar button{border:1px solid var(--line);background:#fff;color:var(--muted);
|
| 59 |
font:inherit;font-size:12.5px;font-weight:700;padding:7px 14px;
|
|
|
|
| 346 |
</div>
|
| 347 |
<div id="authbar"></div>
|
| 348 |
<div id="langnote"></div>
|
| 349 |
+
<div id="intro"></div>
|
| 350 |
<div id="seasonbar"></div>
|
| 351 |
<div id="cd"><span class="cdlab" id="cdlab"></span><span class="cdval" id="cdval"> </span></div>
|
| 352 |
<p class="eyebrow">Open Discovery Challenge</p>
|
|
|
|
| 518 |
},
|
| 519 |
ov_pred:"์์ธก์น", ov_pf:"๋ง๋ผ๋ฆฌ์ ํจ์", ov_hs:"์ฌ๋ ํจ์", ov_sel:"์ ํ๋",
|
| 520 |
private_note:"์ ์ถ์๊ฐ ๋น๊ณต๊ฐ๋ฅผ ์ ํํ์ต๋๋ค", copy_smiles:"๋ถ์์ ๋ณต์ฌ",
|
| 521 |
+
intro_credit:"์์ ์ ์ํด์ฃผ์ ์นด์นด์คํก @๋ฆฌ์นด ๋์๊ฒ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.",
|
| 522 |
season_soon:"์ค๋น์ค", season_notopen:"์ด ์์ฆ์ ์์ง ์ ์๋ฅผ ๋ฐ์ง ์์ต๋๋ค. ์ฑ์ ๊ธฐ ๊ฒ์ฆ์ด ๋๋๋ฉด ๊ณต์ง์ ํจ๊ป ์ฝ๋๋ค.",
|
| 523 |
cd_label:"์์ฆ #1 ๋ง๊ฐ๊น์ง", cd_day:"์ผ", cd_over_label:"์์ฆ #1 ๋ง๊ฐ",
|
| 524 |
cd_over:"๋ง๊ฐ๋์์ต๋๋ค", view_3d:"3D ์
์ฒด ๊ตฌ์กฐ๋ก ๋ณด๊ธฐ",
|
|
|
|
| 801 |
}).format(new Date(Number(e.submitted_at) * 1000));
|
| 802 |
};
|
| 803 |
|
| 804 |
+
// Seasons can carry an intro clip. It is written into the page only for the season it
|
| 805 |
+
// belongs to - emptied rather than hidden - so a reader on another season never fetches
|
| 806 |
+
// the file. Muted and inline because autoplay with sound is blocked everywhere; the clip
|
| 807 |
+
// has no audio track, so nothing is lost.
|
| 808 |
+
const SEASON_INTRO = {2: "assets/season2-intro.mp4"};
|
| 809 |
+
|
| 810 |
+
function renderIntro(){
|
| 811 |
+
const src = SEASON_INTRO[SEASON], box = $("#intro");
|
| 812 |
+
// clearing the marker as well as the markup: leaving it set made a return to this
|
| 813 |
+
// season look like "already playing" and the slot stayed empty
|
| 814 |
+
if(!src){ box.innerHTML = ""; delete box.dataset.src; return; }
|
| 815 |
+
const cred = t().intro_credit || "";
|
| 816 |
+
if(box.dataset.src === src && box.querySelector("video")){
|
| 817 |
+
// the clip is already playing; only the wording can have changed, and rewriting the
|
| 818 |
+
// whole block would restart the video every time the language is switched
|
| 819 |
+
const c = box.querySelector(".credit");
|
| 820 |
+
if(c) c.textContent = cred;
|
| 821 |
+
return;
|
| 822 |
+
}
|
| 823 |
+
box.dataset.src = src;
|
| 824 |
+
box.innerHTML = `<video src="${src}" autoplay loop muted playsinline preload="metadata"></video>`
|
| 825 |
+
+ (cred ? `<div class="credit">${cred}</div>` : "");
|
| 826 |
+
}
|
| 827 |
+
|
| 828 |
function renderSeasonBar(){
|
| 829 |
if(!SEASONS) return;
|
| 830 |
const d = t();
|
|
|
|
| 885 |
}
|
| 886 |
if(d.prize_amt) $("#prize_amt").firstChild.nodeValue = d.prize_amt + " ";
|
| 887 |
renderSeasonBar();
|
| 888 |
+
renderIntro();
|
| 889 |
renderAuth();
|
| 890 |
tickCountdown();
|
| 891 |
if(DATA) render();
|