diff options
-rw-r--r-- | .clang-format | 6 | ||||
-rw-r--r-- | index.html | 106 | ||||
-rw-r--r-- | main.js | 68 | ||||
-rw-r--r-- | style.css | 141 |
4 files changed, 190 insertions, 131 deletions
diff --git a/.clang-format b/.clang-format index bda6336..3130d2e 100644 --- a/.clang-format +++ b/.clang-format @@ -23,7 +23,7 @@ BraceWrapping: AfterUnion: false AfterExternBlock: false BeforeCatch: false - BeforeElse: false + BeforeElse: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true @@ -31,7 +31,7 @@ BraceWrapping: BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true -ColumnLimit: 80 +ColumnLimit: 100 ContinuationIndentWidth: 8 DeriveLineEnding: true IndentCaseBlocks: false @@ -61,4 +61,4 @@ UseTab: Always # Taken from git's rules (Except PenaltyBreakAssignment) PenaltyBreakAssignment: 100 -PenaltyExcessCharacter: 100
\ No newline at end of file +PenaltyExcessCharacter: 100 @@ -1,74 +1,60 @@ <!DOCTYPE html> -<html> +<html theme="light"> <head> + <title>YouTube Frame Timer</title> <meta charset="utf-8"> <meta name="keywords" content="Speedrun, Retime"> <meta name="description" content="A speedrun retime tool"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>YouTube Frame Timer</title> <link rel="stylesheet" href="style.css" type="text/css" media="screen"> - <!-- - <link rel="stylesheet" href="dark.css" type="text/css" media="screen"> - --> - <script src="main.js"></script> </head> -<body class="stackedit"> - <div class="stackedit__html"> - <!-- - TODO: Finish dark theme! +<body> + <label class="switch"> + <input type="checkbox" id="page_theme" onclick="change_theme()"> + <span class="slider" id="slider"></span> + </label> + <!-- This needs to come after the above switch --> + <script src="main.js"></script> - <label class="switch"> - <input type="checkbox" id="color_preference" onclick="change_preferance()"> - <span class="slider round" id="slider"></span> - </label> - --> - <h1>Speedrun Retimer without Ads</h1> - <a href="https://github.com/Mango0x45/no-ad-retimer"> - Source code (GitHub) - </a> - <h3 id="video-framerate">Video Framerate</h3> - <p> - Right click the YouTube video and select “Stats for - nerds.” The third line is “Current / Optimal Res” - - find the two numbers after the @ and enter them for - framerate. - </p> - <p> - <label for="framerate">Framerate: </label> - <input type="text" id="framerate" size="3" value="30" - onchange='check_fps(event)'> - </p> - <h3>Video Endpoints</h3> - <p> - Find the starting point (you can use the <code>,</code> - and <code>.</code> keys to find the exact frame). Right - click the video and select “Copy debug info” and paste - it for starting frame. Repeat for ending frame. - </p> - <p> - <label for="startobj">Starting frame: </label> - <input type="text" id="startobj" style='width:100%' - onchange='parse_time(event)'> - </p> - <p> - <label for="endobj">Ending frame: </label> - <input type="text" id="endobj" style='width:100%' - onchange='parse_time(event)'> - </p> - <h3 id="video-time">Video Time</h3> - <input type="text" id="time" readonly size="40"> - <p> - <textarea id="mod_message" cols="40" rows="3" readonly - disabled> - </textarea> - </p> - <button id="mod_message_button" disabled - onclick="copy_mod_message()"> - Copy Mod Message to Clipboard - </button> - </div> + <h1>Speedrun Retimer without Ads</h1> + <a href="https://github.com/Mango0x45/no-ad-retimer" target="_blank"> + Source code (GitHub) + </a> + <h3 id="video-framerate">Video Framerate</h3> + <p> + Right click the YouTube video and select “Stats for nerds.” The third line is + “Current / Optimal Res” - find the two numbers after the @ and enter them for + framerate. + </p> + <p> + <label for="framerate">Framerate: </label> + <input type="text" id="framerate" size="3" value="30" onchange='check_fps(event)'> + </p> + <h3>Video Endpoints</h3> + <p> + Find the starting point (you can use the <code>,</code> and <code>.</code> keys to + find the exact frame). Right click the video and select “Copy debug info” and paste + it for starting frame. Repeat for ending frame. + </p> + <p> + <label for="startobj">Starting frame: </label> + <input type="text" id="startobj" style='width:100%' onchange='parse_time(event)'> + </p> + <p> + <label for="endobj">Ending frame: </label> + <input type="text" id="endobj" style='width:100%' onchange='parse_time(event)'> + </p> + <h3 id="video-time">Video Time</h3> + <input type="text" id="time" readonly size="40"> + <p> + <textarea id="mod_message" cols="40" rows="3" readonly disabled> + </textarea> + </p> + <button id="mod_message_button" disabled onclick="copy_mod_message()"> + Copy Mod Message to Clipboard + </button> </body> </html> @@ -5,18 +5,25 @@ function compute() const st = document.getElementById("startobj").value; const et = document.getElementById("endobj").value; + /* Return early if not all fields are filled */ if (st === undefined || et === undefined || fps === undefined) return; + /* Return early on a negative time */ const frames = (et - st) * fps; + if (frames < 0) { + document.getElementById("time").value = "Error: Negative time"; + return; + } + const s = Math.round(frames / fps * 1000) / 1000; /* Show the time and mod message in the DOM. */ const sf = Math.trunc(st * fps); const ef = Math.trunc(et * fps); const t = time_format(s); - const mod_message = `Mod Note: Retimed (Start Frame: ${ - sf}, End Frame: ${ef}, FPS: ${fps}, Total Time: ${t})`; + const mod_message = `Mod Note: Retimed (Start Frame: ${sf}, End Frame: ${ef}, FPS: ${ + fps}, Total Time: ${t})`; document.getElementById("time").value = t; document.getElementById("mod_message").disabled = false; @@ -49,63 +56,62 @@ function copy_mod_message() document.execCommand("copy"); } -/* - * If framerate is invalid, show an error message and disable start and end - * frame fields. - */ +/* If framerate is invalid, show an error message and disable start and end frame fields. */ function check_fps(event) { fps = event.target.value; if (fps > 0 && fps % 1 == 0) { document.getElementById("startobj").disabled = false; document.getElementById("endobj").disabled = false; - document.getElementById("compute_button").disabled = false; - } else { + } + else { document.getElementById("framerate") .setCustomValidity("Please enter a valid framerate."); document.getElementById("framerate").reportValidity(); document.getElementById("startobj").disabled = true; document.getElementById("endobj").disabled = true; - document.getElementById("compute_button").disabled = true; } } /* Get current frame from input field (either start time or end time). */ function parse_time(event) { - let inptext_frame; + /* Return early if invalid JSON is passed (numbers are valid) */ + let inp, dinfo; try { - inptext_frame = (JSON.parse(event.target.value)).cmt; + dinfo = JSON.parse(event.target.value); } catch { document.getElementById(event.target.id).value = ""; return; } - if (inptext_frame !== undefined) { - const fps = parseInt( - document.getElementById("framerate").value); - const frame_from_obj = (t, fps) => Math.floor(t * fps) / fps; - const fframe = frame_from_obj(inptext_frame, fps); - document.getElementById(event.target.id).value = `${fframe}`; + /* If cmt isn't available fallback to lct, also allow raw numbers */ + if (!(inp = dinfo.cmt) && !(inp = dinfo.lct) && typeof ((inp = dinfo)) !== "number") { + document.getElementById(event.target.id).value = ""; + return; } - if (document.getElementById("startobj").value - && document.getElementById("endobj").value) + /* Calculate the exact timestamp */ + const fps = parseInt(document.getElementById("framerate").value); + const frame = Math.floor(inp * fps) / fps; + document.getElementById(event.target.id).value = `${frame}`; + + /* If all fields are filled the compute */ + if (document.getElementById("startobj").value && document.getElementById("endobj").value) compute(); } /* Change the users preferred theme. */ -function change_preferance() +function change_theme() { - const color_switch = document.getElementById("color_preference"); - - if (color_switch.checked) { - document.body.classList.add("dark"); - document.body.classList.remove("light"); - localStorage.setItem("preference", "dark"); - } else { - document.body.classList.add("light"); - document.body.classList.remove("dark"); - localStorage.setItem("preference", "light"); - } + const theme_switch = document.getElementById("page_theme"); + const want = theme_switch.checked ? "dark" : "light"; + + document.documentElement.setAttribute("theme", want); + localStorage.setItem("theme", want); } + +/* Automatically select the users preferred theme */ +const theme = localStorage.getItem("theme"); +document.documentElement.setAttribute("theme", theme); +document.getElementById("page_theme").checked = (theme == "dark"); @@ -1,10 +1,33 @@ -/* - * This is a stripped down version of the style.css found over at - * https://stackedit.io - */ +:root { + --slider-color: #FFFFFF; + --slider-bg-on-color: #2196F3; + --slider-bg-off-color: #CCCCCC; +} + +[theme="light"] { + --bg-color: #FFFFFF; + --text-color: #24292E; + --box-color: #DDDDDD; + --url-color: #0366D6; + --underline-color: #EAECEF; +} + +[theme="dark"] { + --bg-color: #22272E; + --text-color: #ADBAC7; + --box-color: #2D333B; + --url-color: #539BF5; + --underline-color: #373E47; +} body { - margin: 0; + background-color: var(--bg-color); + margin-bottom: 20px; + margin-left: auto; + margin-right: auto; + max-width: 70%; + padding-left: 30px; + padding-right: 30px; } html { @@ -14,7 +37,6 @@ html { } body, html { - color: rgba(0, 0, 0, 0.75); font-size: 16px; font-family: Lato, Helvetica Neue, Helvetica, sans-serif; font-variant-ligatures: common-ligatures; @@ -24,16 +46,12 @@ body, html { } h1 { - font-size: 2em; - margin: 0.67em 0; -} - -h1:after { + border-bottom: 1px solid var(--underline-color); content: ""; display: block; + font-size: 2em; position: relative; top: 0.33em; - border-bottom: 1px solid hsla(0, 0%, 50%, 0.33); } h1, h3 { @@ -45,9 +63,18 @@ p { margin: 1.2em 0; } + +button, h1, h3, input, p, textarea { + color: var(--text-color); +} + +button, input, code, textarea { + background-color: var(--box-color); +} + a { background-color: transparent; - color: #0c93e4; + color: var(--url-color); text-decoration: underline; text-decoration-skip: ink; -webkit-text-decoration-skip: objects; @@ -57,27 +84,20 @@ a:focus, a:hover { text-decoration: none; } -code { - background-color: rgba(0, 0, 0, 0.05); - border-radius: 3px; - padding: 2px 4px; - font-family: Roboto Mono, Lucida Sans Typewriter, Lucida Console, - monaco, Courrier, monospace; - font-size: 0.85em; - font-family: monospace, monospace; - font-size: 1em; -} - -code * { - font-size: inherit; -} - button { overflow: visible; text-transform: none; } +code { + font-family: Roboto Mono, Lucida Sans Typewriter, Lucida Console, monaco, Courrier, + monospace; + font-size: 1em; + padding: 2px 4px; +} + input { + border: none; overflow: visible; } @@ -85,18 +105,65 @@ textarea { overflow: auto; } -button, input, textarea { +button, code, input, textarea { + border: none; + border-radius: 6px; font-family: sans-serif; font-size: 100%; - line-height: 1.15; + line-height: 1.5; margin: 0; } -.stackedit__html { - margin-bottom: 20px; - margin-left: auto; - margin-right: auto; - padding-left: 30px; - padding-right: 30px; - max-width: 70%; +.switch { + display: inline-flex; + float: right; + height: 34px; + position: relative; + width: 60px; +} + +.switch input { + height: 0; + opacity: 0; + width: 0; +} + +.slider { + background-color: var(--slider-bg-off-color); + border-radius: 34px; + bottom: 0; + position: absolute; + cursor: pointer; + left: 0; + right: 0; + top: 0; + transition: .4s; + -webkit-transition: .4s; +} + +.slider:before { + background-color: var(--slider-color); + border-radius: 50%; + bottom: 4px; + content: ""; + height: 26px; + left: 4px; + position: absolute; + transition: .4s; + width: 26px; + -webkit-transition: .4s; +} + +input:checked + .slider { + background-color: var(--slider-bg-on-color); +} + +input:focus + .slider { + box-shadow: 0 0 1px var(--slider-bg-on-color); +} + +input:checked + .slider:before { + transform: translateX(26px); + -ms-transform: translateX(26px); + -webkit-transform: translateX(26px); } |