pub / tw2html

Checks online status of streams on twitch.tv and lets you watch them
git clone https://src.jayvii.de/pub/tw2html.git
Home | Log | Files | Exports | Refs | README | RSS

commit 0949aa8724013a7e9393df620346777c4fca46cb
parent d22f67223ad7a17cb975747fa820e72c6ce0bfa0
Author: JayVii <jayvii[AT]posteo[DOT]de>
Date:   Sun, 19 May 2024 20:50:55 +0200

refactor and simplification

Diffstat:
Massets/css/custom.css | 150+++++++++++++++++++++++++------------------------------------------------------
Dassets/css/miniport.css | 2443-------------------------------------------------------------------------------
Aassets/css/stylesheet.css | 8++++++++
Dassets/img/chat_mono.svg | 1-
Dassets/img/play_mono.svg | 1-
Dassets/img/streamlink_mono.svg | 1-
Massets/js/twitch.js | 7+++----
Mindex.php | 432++++++++++++++------------------------------------------------------------------
Alib/build_html.php | 35+++++++++++++++++++++++++++++++++++
Alib/load_streams.php | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/loadingscreen.php | 36++++++++++++++++++++++++++++++++++++
Atemplate.html | 33+++++++++++++++++++++++++++++++++
12 files changed, 314 insertions(+), 2913 deletions(-)

diff --git a/assets/css/custom.css b/assets/css/custom.css @@ -1,112 +1,56 @@ -html, body { - height: 100%; - min-height: 100vh; - font-size: 105% !important; +* { scroll-behavior: smooth; } - -/* Navigation Bar */ -#nav { - font-size: 1.5em !important; - /* position: absolute!important; */ - z-index: 1 !important; -} - -/* Article container */ -article { - padding-top: 2em !important; -} - -/* External Player */ -#stream-window { - display: inline-block; - width: 100%; - min-width: 400px; - min-height: 225px; - aspect-ratio: 16/9; -} -#chat-window { - display: inline-block; - width: 100%; - min-width: 400px; - max-width: 500px; - height: 100vh; - min-height: 400px !important; -} -@media only screen and (min-width: 1000px) { - #stream-window { - width: calc(100% - 500px); - } -} - -/* Stream Preview Image */ .preview { - display: block; - vertical-align: top; - width: 100%; - max-width: 853px; - max-height: 480px; - aspect-ratio: 16/9; - margin-left: auto; - margin-right: auto; - margin-top: 5px; - margin-bottom: 5px; -} - -/* Button Container */ -.buttons-outer { - display: block; - width: 100%; - margin: 10px; - margin-left: auto; - margin-right: auto; - max-width: 853px; -} -.buttons-inner { - display: flex; - width: 100%; - margin: 10px; - margin-left: auto; - margin-right: auto; - max-width: 830px; -} - -/* Buttons */ -.button { - display: inline-block; - margin: 3px; - width: 100%; - text-align: center; - background-color: #5a03b9 !important; -} -.button:hover { - background-color: #8144c4 !important; -} -.button-img { + height: auto; width: 100%; - max-height: calc(80px - 53.15px); - color: #fff; -} -#button-reload { - color: #fff; - padding-left: 0.5em; - padding-right: 0.5em; + aspect-ratio: 16/9 !important; + margin-top: 1em; + margin-bottom: 1em; + border: 0; +} +a[href^="https"]:where([href*="www.twitch.tv"])::after { + content: "︎ ↗"; +} +#searchbar { + width: 100%; + margin: 8px; + color: var(--primary); + border-color: var(--tertiary); + border-style: solid; + border-radius: var(--radius); + border-width: 1px; + padding: 0.25em; +} +.chatwrapper, .chatwrapper > iframe { + height:100%; + min-height: 600px; + border: 0; + margin: 0px; +} +@media(prefers-color-scheme:dark){ + :root{ + --theme: rgb(29, 30, 32); + --entry: rgb(46, 46, 51); + --primary: rgb(218, 218, 219); + --secondary: rgb(155, 156, 157); + --tertiary: rgb(65, 66, 68); + --content: rgb(196, 196, 197); + --hljs-bg: rgb(46, 46, 51); + --code-bg: rgb(55, 56, 62); + --border: rgb(51, 51, 51) + } + .list{ + background:var(--theme) + } + .list:not(.dark)::-webkit-scrollbar-track{ + background:0 0 + } + .list:not(.dark)::-webkit-scrollbar-thumb{ + border-color:var(--theme) + } } -/* DarkMode */ -@media (prefers-color-scheme: dark) { - html { - background: #111; - color: #eee; - } - nav { - background: #000 !important; - color: #fff; - } - h1, h2, h3, h4, h5, h6, p, strong { - color: #ddd !important; - } -} /* Blinking dot */ .pulse { animation: 2s blink infinite; diff --git a/assets/css/miniport.css b/assets/css/miniport.css @@ -1,2443 +0,0 @@ -/* - Miniport by HTML5 UP - html5up.net | @ajlkn - Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) -*/ - -html, body, div, span, applet, object, -iframe, h1, h2, h3, h4, h5, h6, p, blockquote, -pre, a, abbr, acronym, address, big, cite, -code, del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, b, -u, i, center, dl, dt, dd, ol, ul, li, fieldset, -form, label, legend, table, caption, tbody, -tfoot, thead, tr, th, td, article, aside, -canvas, details, embed, figure, figcaption, -footer, header, hgroup, menu, nav, output, ruby, -section, summary, time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline;} - -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block;} - -body { - line-height: 1; -} - -ol, ul { - list-style: none; -} - -blockquote, q { - quotes: none; -} - - blockquote:before, blockquote:after, q:before, q:after { - content: ''; - content: none; - } - -table { - border-collapse: collapse; - border-spacing: 0; -} - -body { - -webkit-text-size-adjust: none; -} - -mark { - background-color: transparent; - color: inherit; -} - -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -input, select, textarea { - -moz-appearance: none; - -webkit-appearance: none; - -ms-appearance: none; - appearance: none; -} - -/* Basic */ - - html { - box-sizing: border-box; - } - - *, *:before, *:after { - box-sizing: inherit; - } - - body { - padding-top: 3.5em; - } - - body.is-preload *, body.is-preload *:before, body.is-preload *:after { - -moz-animation: none !important; - -webkit-animation: none !important; - -ms-animation: none !important; - animation: none !important; - -moz-transition: none !important; - -webkit-transition: none !important; - -ms-transition: none !important; - transition: none !important; - } - - body, input, textarea, select { - font-family: 'Open Sans', sans-serif; - line-height: 1.85em; - color: #888; - font-weight: 300; - font-size: 13pt; - } - - a { - -moz-transition: color .2s ease-in-out; - -webkit-transition: color .2s ease-in-out; - -ms-transition: color .2s ease-in-out; - transition: color .2s ease-in-out; - color: #43B3E0; - text-decoration: underline; - } - - a:hover { - color: #43bff0 !important; - } - - a img { - border: 0; - } - - b, strong { - font-weight: 600; - color: #3e3e3e; - } - - i, em { - font-style: italic; - } - - sub { - position: relative; - top: 0.5em; - font-size: 0.8em; - } - - sup { - position: relative; - top: -0.5em; - font-size: 0.8em; - } - - blockquote { - border-left: solid 0.75em #eee; - padding: 1em 0 1em 1.5em; - font-style: italic; - } - - h1, h2, h3, h4, h5, h6 { - color: #3e3e3e; - margin: 0 0 0.75em 0; - } - - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - text-decoration: none; - color: inherit; - } - - h2, h3, h4, h5, h6 { - font-weight: 700; - } - - h1 { - font-size: 3.25em; - letter-spacing: -0.025em; - font-weight: 300; - } - - h1 strong { - font-weight: 700; - } - - h2 { - font-size: 2em; - letter-spacing: -0.015em; - } - - h3 { - font-size: 1.5em; - letter-spacing: -0.015em; - } - - em, i { - font-style: italic; - } - - br.clear { - clear: both; - } - - hr { - border: 0; - border-top: solid 1px #444; - border-top-color: rgba(0, 0, 0, 0.35); - box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.1); - height: 1px; - margin: 3em 0; - } - - p, ul, ol, dl, table { - margin-bottom: 2em; - } - - header { - margin: 0 0 3em 0; - } - - header > p { - font-size: 1.25em; - margin: 0; - } - - footer { - margin: 3em 0 0 0; - } - - footer > p { - font-size: 1.25em; - } - -/* Container */ - - .container { - margin: 0 auto; - max-width: calc(100% - 50px); - width: 1200px; - } - - .container.medium { - width: 900px; - } - - @media screen and (max-width: 1680px) { - - .container { - width: 1200px; - } - - .container.medium { - width: 900px; - } - - } - - @media screen and (max-width: 1280px) { - - .container { - width: 960px; - } - - .container.medium { - width: 720px; - } - - } - - @media screen and (max-width: 980px) { - - .container { - width: 100%; - } - - .container.medium { - width: 75%; - } - - } - - @media screen and (max-width: 736px) { - - .container { - width: 100%; - max-width: calc(100% - 30px); - } - - .container.medium { - width: 100%; - } - - } - -/* Row */ - - .row { - display: flex; - flex-wrap: wrap; - box-sizing: border-box; - align-items: stretch; - } - - .row > * { - box-sizing: border-box; - } - - .row.gtr-uniform > * > :last-child { - margin-bottom: 0; - } - - .row.aln-left { - justify-content: flex-start; - } - - .row.aln-center { - justify-content: center; - } - - .row.aln-right { - justify-content: flex-end; - } - - .row.aln-top { - align-items: flex-start; - } - - .row.aln-middle { - align-items: center; - } - - .row.aln-bottom { - align-items: flex-end; - } - - .row > .imp { - order: -1; - } - - .row > .col-1 { - width: 8.33333%; - } - - .row > .off-1 { - margin-left: 8.33333%; - } - - .row > .col-2 { - width: 16.66667%; - } - - .row > .off-2 { - margin-left: 16.66667%; - } - - .row > .col-3 { - width: 25%; - } - - .row > .off-3 { - margin-left: 25%; - } - - .row > .col-4 { - width: 33.33333%; - } - - .row > .off-4 { - margin-left: 33.33333%; - } - - .row > .col-5 { - width: 41.66667%; - } - - .row > .off-5 { - margin-left: 41.66667%; - } - - .row > .col-6 { - width: 50%; - } - - .row > .off-6 { - margin-left: 50%; - } - - .row > .col-7 { - width: 58.33333%; - } - - .row > .off-7 { - margin-left: 58.33333%; - } - - .row > .col-8 { - width: 66.66667%; - } - - .row > .off-8 { - margin-left: 66.66667%; - } - - .row > .col-9 { - width: 75%; - } - - .row > .off-9 { - margin-left: 75%; - } - - .row > .col-10 { - width: 83.33333%; - } - - .row > .off-10 { - margin-left: 83.33333%; - } - - .row > .col-11 { - width: 91.66667%; - } - - .row > .off-11 { - margin-left: 91.66667%; - } - - .row > .col-12 { - width: 100%; - } - - .row > .off-12 { - margin-left: 100%; - } - - .row.gtr-0 { - margin-top: 0px; - margin-left: 0px; - } - - .row.gtr-0 > * { - padding: 0px 0 0 0px; - } - - .row.gtr-0.gtr-uniform { - margin-top: 0px; - } - - .row.gtr-0.gtr-uniform > * { - padding-top: 0px; - } - - .row.gtr-25 { - margin-top: -6.25px; - margin-left: -6.25px; - } - - .row.gtr-25 > * { - padding: 6.25px 0 0 6.25px; - } - - .row.gtr-25.gtr-uniform { - margin-top: -6.25px; - } - - .row.gtr-25.gtr-uniform > * { - padding-top: 6.25px; - } - - .row.gtr-50 { - margin-top: -12.5px; - margin-left: -12.5px; - } - - .row.gtr-50 > * { - padding: 12.5px 0 0 12.5px; - } - - .row.gtr-50.gtr-uniform { - margin-top: -12.5px; - } - - .row.gtr-50.gtr-uniform > * { - padding-top: 12.5px; - } - - .row { - margin-top: -25px; - margin-left: -25px; - } - - .row > * { - padding: 25px 0 0 25px; - } - - .row.gtr-uniform { - margin-top: -25px; - } - - .row.gtr-uniform > * { - padding-top: 25px; - } - - .row.gtr-150 { - margin-top: -37.5px; - margin-left: -37.5px; - } - - .row.gtr-150 > * { - padding: 37.5px 0 0 37.5px; - } - - .row.gtr-150.gtr-uniform { - margin-top: -37.5px; - } - - .row.gtr-150.gtr-uniform > * { - padding-top: 37.5px; - } - - .row.gtr-200 { - margin-top: -50px; - margin-left: -50px; - } - - .row.gtr-200 > * { - padding: 50px 0 0 50px; - } - - .row.gtr-200.gtr-uniform { - margin-top: -50px; - } - - .row.gtr-200.gtr-uniform > * { - padding-top: 50px; - } - - @media screen and (max-width: 1680px) { - - .row { - display: flex; - flex-wrap: wrap; - box-sizing: border-box; - align-items: stretch; - } - - .row > * { - box-sizing: border-box; - } - - .row.gtr-uniform > * > :last-child { - margin-bottom: 0; - } - - .row.aln-left { - justify-content: flex-start; - } - - .row.aln-center { - justify-content: center; - } - - .row.aln-right { - justify-content: flex-end; - } - - .row.aln-top { - align-items: flex-start; - } - - .row.aln-middle { - align-items: center; - } - - .row.aln-bottom { - align-items: flex-end; - } - - .row > .imp-xlarge { - order: -1; - } - - .row > .col-1-xlarge { - width: 8.33333%; - } - - .row > .off-1-xlarge { - margin-left: 8.33333%; - } - - .row > .col-2-xlarge { - width: 16.66667%; - } - - .row > .off-2-xlarge { - margin-left: 16.66667%; - } - - .row > .col-3-xlarge { - width: 25%; - } - - .row > .off-3-xlarge { - margin-left: 25%; - } - - .row > .col-4-xlarge { - width: 33.33333%; - } - - .row > .off-4-xlarge { - margin-left: 33.33333%; - } - - .row > .col-5-xlarge { - width: 41.66667%; - } - - .row > .off-5-xlarge { - margin-left: 41.66667%; - } - - .row > .col-6-xlarge { - width: 50%; - } - - .row > .off-6-xlarge { - margin-left: 50%; - } - - .row > .col-7-xlarge { - width: 58.33333%; - } - - .row > .off-7-xlarge { - margin-left: 58.33333%; - } - - .row > .col-8-xlarge { - width: 66.66667%; - } - - .row > .off-8-xlarge { - margin-left: 66.66667%; - } - - .row > .col-9-xlarge { - width: 75%; - } - - .row > .off-9-xlarge { - margin-left: 75%; - } - - .row > .col-10-xlarge { - width: 83.33333%; - } - - .row > .off-10-xlarge { - margin-left: 83.33333%; - } - - .row > .col-11-xlarge { - width: 91.66667%; - } - - .row > .off-11-xlarge { - margin-left: 91.66667%; - } - - .row > .col-12-xlarge { - width: 100%; - } - - .row > .off-12-xlarge { - margin-left: 100%; - } - - .row.gtr-0 { - margin-top: 0px; - margin-left: 0px; - } - - .row.gtr-0 > * { - padding: 0px 0 0 0px; - } - - .row.gtr-0.gtr-uniform { - margin-top: 0px; - } - - .row.gtr-0.gtr-uniform > * { - padding-top: 0px; - } - - .row.gtr-25 { - margin-top: -6.25px; - margin-left: -6.25px; - } - - .row.gtr-25 > * { - padding: 6.25px 0 0 6.25px; - } - - .row.gtr-25.gtr-uniform { - margin-top: -6.25px; - } - - .row.gtr-25.gtr-uniform > * { - padding-top: 6.25px; - } - - .row.gtr-50 { - margin-top: -12.5px; - margin-left: -12.5px; - } - - .row.gtr-50 > * { - padding: 12.5px 0 0 12.5px; - } - - .row.gtr-50.gtr-uniform { - margin-top: -12.5px; - } - - .row.gtr-50.gtr-uniform > * { - padding-top: 12.5px; - } - - .row { - margin-top: -25px; - margin-left: -25px; - } - - .row > * { - padding: 25px 0 0 25px; - } - - .row.gtr-uniform { - margin-top: -25px; - } - - .row.gtr-uniform > * { - padding-top: 25px; - } - - .row.gtr-150 { - margin-top: -37.5px; - margin-left: -37.5px; - } - - .row.gtr-150 > * { - padding: 37.5px 0 0 37.5px; - } - - .row.gtr-150.gtr-uniform { - margin-top: -37.5px; - } - - .row.gtr-150.gtr-uniform > * { - padding-top: 37.5px; - } - - .row.gtr-200 { - margin-top: -50px; - margin-left: -50px; - } - - .row.gtr-200 > * { - padding: 50px 0 0 50px; - } - - .row.gtr-200.gtr-uniform { - margin-top: -50px; - } - - .row.gtr-200.gtr-uniform > * { - padding-top: 50px; - } - - } - - @media screen and (max-width: 1280px) { - - .row { - display: flex; - flex-wrap: wrap; - box-sizing: border-box; - align-items: stretch; - } - - .row > * { - box-sizing: border-box; - } - - .row.gtr-uniform > * > :last-child { - margin-bottom: 0; - } - - .row.aln-left { - justify-content: flex-start; - } - - .row.aln-center { - justify-content: center; - } - - .row.aln-right { - justify-content: flex-end; - } - - .row.aln-top { - align-items: flex-start; - } - - .row.aln-middle { - align-items: center; - } - - .row.aln-bottom { - align-items: flex-end; - } - - .row > .imp-large { - order: -1; - } - - .row > .col-1-large { - width: 8.33333%; - } - - .row > .off-1-large { - margin-left: 8.33333%; - } - - .row > .col-2-large { - width: 16.66667%; - } - - .row > .off-2-large { - margin-left: 16.66667%; - } - - .row > .col-3-large { - width: 25%; - } - - .row > .off-3-large { - margin-left: 25%; - } - - .row > .col-4-large { - width: 33.33333%; - } - - .row > .off-4-large { - margin-left: 33.33333%; - } - - .row > .col-5-large { - width: 41.66667%; - } - - .row > .off-5-large { - margin-left: 41.66667%; - } - - .row > .col-6-large { - width: 50%; - } - - .row > .off-6-large { - margin-left: 50%; - } - - .row > .col-7-large { - width: 58.33333%; - } - - .row > .off-7-large { - margin-left: 58.33333%; - } - - .row > .col-8-large { - width: 66.66667%; - } - - .row > .off-8-large { - margin-left: 66.66667%; - } - - .row > .col-9-large { - width: 75%; - } - - .row > .off-9-large { - margin-left: 75%; - } - - .row > .col-10-large { - width: 83.33333%; - } - - .row > .off-10-large { - margin-left: 83.33333%; - } - - .row > .col-11-large { - width: 91.66667%; - } - - .row > .off-11-large { - margin-left: 91.66667%; - } - - .row > .col-12-large { - width: 100%; - } - - .row > .off-12-large { - margin-left: 100%; - } - - .row.gtr-0 { - margin-top: 0px; - margin-left: 0px; - } - - .row.gtr-0 > * { - padding: 0px 0 0 0px; - } - - .row.gtr-0.gtr-uniform { - margin-top: 0px; - } - - .row.gtr-0.gtr-uniform > * { - padding-top: 0px; - } - - .row.gtr-25 { - margin-top: -6.25px; - margin-left: -6.25px; - } - - .row.gtr-25 > * { - padding: 6.25px 0 0 6.25px; - } - - .row.gtr-25.gtr-uniform { - margin-top: -6.25px; - } - - .row.gtr-25.gtr-uniform > * { - padding-top: 6.25px; - } - - .row.gtr-50 { - margin-top: -12.5px; - margin-left: -12.5px; - } - - .row.gtr-50 > * { - padding: 12.5px 0 0 12.5px; - } - - .row.gtr-50.gtr-uniform { - margin-top: -12.5px; - } - - .row.gtr-50.gtr-uniform > * { - padding-top: 12.5px; - } - - .row { - margin-top: -25px; - margin-left: -25px; - } - - .row > * { - padding: 25px 0 0 25px; - } - - .row.gtr-uniform { - margin-top: -25px; - } - - .row.gtr-uniform > * { - padding-top: 25px; - } - - .row.gtr-150 { - margin-top: -37.5px; - margin-left: -37.5px; - } - - .row.gtr-150 > * { - padding: 37.5px 0 0 37.5px; - } - - .row.gtr-150.gtr-uniform { - margin-top: -37.5px; - } - - .row.gtr-150.gtr-uniform > * { - padding-top: 37.5px; - } - - .row.gtr-200 { - margin-top: -50px; - margin-left: -50px; - } - - .row.gtr-200 > * { - padding: 50px 0 0 50px; - } - - .row.gtr-200.gtr-uniform { - margin-top: -50px; - } - - .row.gtr-200.gtr-uniform > * { - padding-top: 50px; - } - - } - - @media screen and (max-width: 980px) { - - .row { - display: flex; - flex-wrap: wrap; - box-sizing: border-box; - align-items: stretch; - } - - .row > * { - box-sizing: border-box; - } - - .row.gtr-uniform > * > :last-child { - margin-bottom: 0; - } - - .row.aln-left { - justify-content: flex-start; - } - - .row.aln-center { - justify-content: center; - } - - .row.aln-right { - justify-content: flex-end; - } - - .row.aln-top { - align-items: flex-start; - } - - .row.aln-middle { - align-items: center; - } - - .row.aln-bottom { - align-items: flex-end; - } - - .row > .imp-medium { - order: -1; - } - - .row > .col-1-medium { - width: 8.33333%; - } - - .row > .off-1-medium { - margin-left: 8.33333%; - } - - .row > .col-2-medium { - width: 16.66667%; - } - - .row > .off-2-medium { - margin-left: 16.66667%; - } - - .row > .col-3-medium { - width: 25%; - } - - .row > .off-3-medium { - margin-left: 25%; - } - - .row > .col-4-medium { - width: 33.33333%; - } - - .row > .off-4-medium { - margin-left: 33.33333%; - } - - .row > .col-5-medium { - width: 41.66667%; - } - - .row > .off-5-medium { - margin-left: 41.66667%; - } - - .row > .col-6-medium { - width: 50%; - } - - .row > .off-6-medium { - margin-left: 50%; - } - - .row > .col-7-medium { - width: 58.33333%; - } - - .row > .off-7-medium { - margin-left: 58.33333%; - } - - .row > .col-8-medium { - width: 66.66667%; - } - - .row > .off-8-medium { - margin-left: 66.66667%; - } - - .row > .col-9-medium { - width: 75%; - } - - .row > .off-9-medium { - margin-left: 75%; - } - - .row > .col-10-medium { - width: 83.33333%; - } - - .row > .off-10-medium { - margin-left: 83.33333%; - } - - .row > .col-11-medium { - width: 91.66667%; - } - - .row > .off-11-medium { - margin-left: 91.66667%; - } - - .row > .col-12-medium { - width: 100%; - } - - .row > .off-12-medium { - margin-left: 100%; - } - - .row.gtr-0 { - margin-top: 0px; - margin-left: 0px; - } - - .row.gtr-0 > * { - padding: 0px 0 0 0px; - } - - .row.gtr-0.gtr-uniform { - margin-top: 0px; - } - - .row.gtr-0.gtr-uniform > * { - padding-top: 0px; - } - - .row.gtr-25 { - margin-top: -6.25px; - margin-left: -6.25px; - } - - .row.gtr-25 > * { - padding: 6.25px 0 0 6.25px; - } - - .row.gtr-25.gtr-uniform { - margin-top: -6.25px; - } - - .row.gtr-25.gtr-uniform > * { - padding-top: 6.25px; - } - - .row.gtr-50 { - margin-top: -12.5px; - margin-left: -12.5px; - } - - .row.gtr-50 > * { - padding: 12.5px 0 0 12.5px; - } - - .row.gtr-50.gtr-uniform { - margin-top: -12.5px; - } - - .row.gtr-50.gtr-uniform > * { - padding-top: 12.5px; - } - - .row { - margin-top: -25px; - margin-left: -25px; - } - - .row > * { - padding: 25px 0 0 25px; - } - - .row.gtr-uniform { - margin-top: -25px; - } - - .row.gtr-uniform > * { - padding-top: 25px; - } - - .row.gtr-150 { - margin-top: -37.5px; - margin-left: -37.5px; - } - - .row.gtr-150 > * { - padding: 37.5px 0 0 37.5px; - } - - .row.gtr-150.gtr-uniform { - margin-top: -37.5px; - } - - .row.gtr-150.gtr-uniform > * { - padding-top: 37.5px; - } - - .row.gtr-200 { - margin-top: -50px; - margin-left: -50px; - } - - .row.gtr-200 > * { - padding: 50px 0 0 50px; - } - - .row.gtr-200.gtr-uniform { - margin-top: -50px; - } - - .row.gtr-200.gtr-uniform > * { - padding-top: 50px; - } - - } - - @media screen and (max-width: 736px) { - - .row { - display: flex; - flex-wrap: wrap; - box-sizing: border-box; - align-items: stretch; - } - - .row > * { - box-sizing: border-box; - } - - .row.gtr-uniform > * > :last-child { - margin-bottom: 0; - } - - .row.aln-left { - justify-content: flex-start; - } - - .row.aln-center { - justify-content: center; - } - - .row.aln-right { - justify-content: flex-end; - } - - .row.aln-top { - align-items: flex-start; - } - - .row.aln-middle { - align-items: center; - } - - .row.aln-bottom { - align-items: flex-end; - } - - .row > .imp-small { - order: -1; - } - - .row > .col-1-small { - width: 8.33333%; - } - - .row > .off-1-small { - margin-left: 8.33333%; - } - - .row > .col-2-small { - width: 16.66667%; - } - - .row > .off-2-small { - margin-left: 16.66667%; - } - - .row > .col-3-small { - width: 25%; - } - - .row > .off-3-small { - margin-left: 25%; - } - - .row > .col-4-small { - width: 33.33333%; - } - - .row > .off-4-small { - margin-left: 33.33333%; - } - - .row > .col-5-small { - width: 41.66667%; - } - - .row > .off-5-small { - margin-left: 41.66667%; - } - - .row > .col-6-small { - width: 50%; - } - - .row > .off-6-small { - margin-left: 50%; - } - - .row > .col-7-small { - width: 58.33333%; - } - - .row > .off-7-small { - margin-left: 58.33333%; - } - - .row > .col-8-small { - width: 66.66667%; - } - - .row > .off-8-small { - margin-left: 66.66667%; - } - - .row > .col-9-small { - width: 75%; - } - - .row > .off-9-small { - margin-left: 75%; - } - - .row > .col-10-small { - width: 83.33333%; - } - - .row > .off-10-small { - margin-left: 83.33333%; - } - - .row > .col-11-small { - width: 91.66667%; - } - - .row > .off-11-small { - margin-left: 91.66667%; - } - - .row > .col-12-small { - width: 100%; - } - - .row > .off-12-small { - margin-left: 100%; - } - - .row.gtr-0 { - margin-top: 0px; - margin-left: 0px; - } - - .row.gtr-0 > * { - padding: 0px 0 0 0px; - } - - .row.gtr-0.gtr-uniform { - margin-top: 0px; - } - - .row.gtr-0.gtr-uniform > * { - padding-top: 0px; - } - - .row.gtr-25 { - margin-top: -3.75px; - margin-left: -3.75px; - } - - .row.gtr-25 > * { - padding: 3.75px 0 0 3.75px; - } - - .row.gtr-25.gtr-uniform { - margin-top: -3.75px; - } - - .row.gtr-25.gtr-uniform > * { - padding-top: 3.75px; - } - - .row.gtr-50 { - margin-top: -7.5px; - margin-left: -7.5px; - } - - .row.gtr-50 > * { - padding: 7.5px 0 0 7.5px; - } - - .row.gtr-50.gtr-uniform { - margin-top: -7.5px; - } - - .row.gtr-50.gtr-uniform > * { - padding-top: 7.5px; - } - - .row { - margin-top: -15px; - margin-left: -15px; - } - - .row > * { - padding: 15px 0 0 15px; - } - - .row.gtr-uniform { - margin-top: -15px; - } - - .row.gtr-uniform > * { - padding-top: 15px; - } - - .row.gtr-150 { - margin-top: -22.5px; - margin-left: -22.5px; - } - - .row.gtr-150 > * { - padding: 22.5px 0 0 22.5px; - } - - .row.gtr-150.gtr-uniform { - margin-top: -22.5px; - } - - .row.gtr-150.gtr-uniform > * { - padding-top: 22.5px; - } - - .row.gtr-200 { - margin-top: -30px; - margin-left: -30px; - } - - .row.gtr-200 > * { - padding: 30px 0 0 30px; - } - - .row.gtr-200.gtr-uniform { - margin-top: -30px; - } - - .row.gtr-200.gtr-uniform > * { - padding-top: 30px; - } - - } - -/* Form */ - - form label { - color: #3e3e3e; - font-weight: 700; - display: block; - margin: 0 0 0.5em 0; - } - - form input[type=text], - form input[type=email], - form input[type=password], - form select, - form textarea { - -moz-transition: background .2s ease-in-out, box-shadow .2s ease-in-out; - -webkit-transition: background .2s ease-in-out, box-shadow .2s ease-in-out; - -ms-transition: background .2s ease-in-out, box-shadow .2s ease-in-out; - transition: background .2s ease-in-out, box-shadow .2s ease-in-out; - -webkit-appearance: none; - display: block; - border: 0; - padding: 0.75em; - font-size: 1em; - border-radius: 8px; - border: solid 1px #ddd; - background: #fff; - color: #bbb; - box-shadow: inset 0px 2px 3px 1px rgba(0, 0, 0, 0.05), 0px 1px 0px 0px rgba(255, 255, 255, 0.025); - width: 100%; - } - - form input[type=text]:focus, - form input[type=email]:focus, - form input[type=password]:focus, - form select:focus, - form textarea:focus { - background: #fafafa; - box-shadow: inset 0px 2px 5px 0px rgba(0, 0, 0, 0.05), 0px 1px 0px 0px rgba(255, 255, 255, 0.025), inset 0px 0px 2px 1px #43bff0; - } - - form textarea { - height: 15em; - } - - form .actions:last-child { - margin-bottom: 0; - } - - form ::-webkit-input-placeholder { - color: #555 !important; - } - - form :-moz-placeholder { - color: #555 !important; - } - - form ::-moz-placeholder { - color: #555 !important; - } - - form :-ms-input-placeholder { - color: #555 !important; - } - - form ::-moz-focus-inner { - border: 0; - } - -/* Tables */ - - table { - width: 100%; - } - - table.default { - width: 100%; - } - - table.default tr { - border-top: solid 1px #eee; - } - - table.default tr:first-child { - border-top: 0; - } - - table.default td { - padding: 0.5em 1em 0.5em 1em; - } - - table.default th { - text-align: left; - padding: 0.5em 1em 0.5em 1em; - font-weight: 600; - margin: 0 0 1em 0; - } - - table.default thead { - background: #4f4f4f; - color: #fff; - } - -/* Section/Article */ - - section, article { - margin-bottom: 3em; - } - - section > :last-child, - article > :last-child, - section:last-child, - article:last-child { - margin-bottom: 0; - } - -/* Image */ - - .image { - display: inline-block; - position: relative; - } - - .image img { - display: block; - width: 100%; - } - - .image.fit { - display: block; - width: 100%; - } - - .image.featured { - display: block; - width: 100%; - margin: 0 0 2em 0; - } - - .image.left { - float: left; - margin: 0 2em 2em 0; - } - - .image.centered { - display: block; - margin: 0 0 2em 0; - } - - .image.centered img { - margin: 0 auto; - width: auto; - } - -/* Button */ - - input[type="button"], - input[type="submit"], - input[type="reset"], - button, - .button { - background-image: url("images/bg.png"), -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - background-image: url("images/bg.png"), -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - background-image: url("images/bg.png"), -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - background-image: url("images/bg.png"), linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - -moz-transition: background-color .2s ease-in-out; - -webkit-transition: background-color .2s ease-in-out; - -ms-transition: background-color .2s ease-in-out; - transition: background-color .2s ease-in-out; - -webkit-appearance: none; - position: relative; - display: inline-block; - color: #fff !important; - text-decoration: none; - font-weight: 700; - border: 0; - outline: 0; - cursor: pointer; - border-radius: 8px; - text-shadow: -1px -1px 0.5px rgba(0, 0, 0, 0.5); - overflow: hidden; - box-shadow: inset 0px 0px 0px 1px rgba(0, 0, 0, 0.5), inset 0px 2px 1px 0px rgba(255, 255, 255, 0.75); - background-color: #43B3E0; - padding: 1em 2.35em 1em 2.35em; - font-size: 1.1em; - max-width: 24em; - } - - input[type="button"]:hover, - input[type="submit"]:hover, - input[type="reset"]:hover, - button:hover, - .button:hover { - background-color: #43bff0; - color: #fff !important; - } - - input[type="button"]:active, - input[type="submit"]:active, - input[type="reset"]:active, - button:active, - .button:active { - background-color: #3BA8D3; - top: 1px; - } - - input[type="button"].large, - input[type="submit"].large, - input[type="reset"].large, - button.large, - .button.large { - font-size: 1.5em; - letter-spacing: -0.025em; - } - - input[type="button"].alt, - input[type="submit"].alt, - input[type="reset"].alt, - button.alt, - .button.alt { - background-color: #444; - box-shadow: inset 0px 0px 0px 1px #242424, inset 0px 2px 1px 0px rgba(255, 255, 255, 0.2); - } - - input[type="button"].alt:hover, - input[type="submit"].alt:hover, - input[type="reset"].alt:hover, - button.alt:hover, - .button.alt:hover { - background-color: #4f4f4f; - color: #fff !important; - } - - input[type="button"].alt:active, - input[type="submit"].alt:active, - input[type="reset"].alt:active, - button.alt:active, - .button.alt:active { - background-color: #3f3f3f; - } - -/* List */ - - ul { - list-style: disc; - padding-left: 1em; - } - - ul li { - padding-left: 0.5em; - } - - ol { - list-style: decimal; - padding-left: 1.25em; - } - - ol li { - padding-left: 0.25em; - } - -/* Social */ - - ul.social { - cursor: default; - margin: 0; - list-style: none; - padding-left: 0; - } - - ul.social li { - position: relative; - display: inline-block; - margin: 0.25em; - top: 0; - padding-left: 0; - } - - ul.social li a { - -moz-transition: top .2s ease-in-out; - -webkit-transition: top .2s ease-in-out; - -ms-transition: top .2s ease-in-out; - transition: top .2s ease-in-out; - display: block; - width: 48px; - height: 48px; - border-radius: 6px; - top: 0; - position: relative; - } - - ul.social li a:before { - background-image: url("images/bg.png"), -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - background-image: url("images/bg.png"), -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - background-image: url("images/bg.png"), -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - background-image: url("images/bg.png"), linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2)); - -moz-transition: background-color .2s ease-in-out; - -webkit-transition: background-color .2s ease-in-out; - -ms-transition: background-color .2s ease-in-out; - transition: background-color .2s ease-in-out; - background-color: #444; - border-radius: 6px; - box-shadow: inset 0px 0px 0px 1px #282828, inset 0px 2px 1px 0px rgba(255, 255, 255, 0.1); - color: #2E2E2E !important; - display: block; - font-size: 26px; - height: 48px; - line-height: 48px; - text-align: center; - outline: 0; - overflow: hidden; - text-shadow: 1px 1px 0px rgba(255, 255, 255, 0.1); - width: 48px; - } - - ul.social li a.fa-twitter { - background-color: #2DAAE4; - } - - ul.social li a.fa-facebook-f { - background-color: #3C5A98; - } - - ul.social li a.fa-dribbble { - background-color: #C4376B; - } - - ul.social li a.fa-linkedin-in { - background-color: #006599; - } - - ul.social li a.fa-tumblr { - background-color: #51718A; - } - - ul.social li a.fa-google-plus { - background-color: #DA2713; - } - - ul.social li a.fa-github { - background-color: #FAFAFA; - } - - ul.social li a.fa-rss { - background-color: #F2600B; - } - - ul.social li a.fa-instagram { - background-color: #E0D7C8; - } - - ul.social li a.fa-foursquare { - background-color: #39A3D4; - } - - ul.social li a.fa-skype { - background-color: #10BEF1; - } - - ul.social li a.fa-soundcloud { - background-color: #FE5419; - } - - ul.social li a.fa-youtube { - background-color: #BF2E25; - } - - ul.social li a.fa-blogger { - background-color: #FF6501; - } - - ul.social li a.fa-flickr { - background-color: #0062DB; - } - - ul.social li a.fa-vimeo { - background-color: #4C8AB0; - } - - ul.social li a:hover { - top: -5px; - } - - ul.social li a:hover:before { - background-color: transparent; - } - -/* Actions */ - - ul.actions { - list-style: none; - padding-left: 0; - } - - ul.actions li { - display: inline-block; - margin: 0 0 0 1em; - padding-left: 0; - } - - ul.actions li:first-child { - margin-left: 0; - } - -/* Box */ - - .box { - background: #fff; - box-shadow: inset 0px 0px 0px 1px rgba(0, 0, 0, 0.15), 0px 2px 3px 0px rgba(0, 0, 0, 0.1); - text-align: center; - padding: 2em; - } - - .box.style1 { - padding: 3em 2em 3.5em 2em; - } - - .box.style1 h3 { - margin-bottom: 0.5em; - } - - .box.style2 h3 { - margin-bottom: 0.25em; - } - - .box.style2 .image { - position: relative; - left: 2em; - top: 2em; - margin: -4em 0 4em -4em; - width: auto; - } - -/* Icons */ - - .icon { - text-decoration: none; - text-decoration: none; - } - - .icon:before { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - display: inline-block; - font-style: normal; - font-variant: normal; - text-rendering: auto; - line-height: 1; - text-transform: none !important; - font-family: 'Font Awesome 5 Free'; - font-weight: 400; - } - - .icon:before { - font-size: 1.25em; - } - - .icon > .label { - display: none; - } - - .icon.solid:before { - font-weight: 900; - } - - .icon.brands:before { - font-family: 'Font Awesome 5 Brands'; - } - - .icon.featured { - color: #EA8A95; - display: block; - margin: 0 0 1.5em 0; - cursor: default; - } - - .icon.featured:before { - font-size: 6em; - } - -/* Wrappers */ - - .wrapper { - background-image: url("images/bg.png"); - box-shadow: inset 0px 1px 0px 0px rgba(0, 0, 0, 0.05), inset 0px 2px 3px 0px rgba(0, 0, 0, 0.1); - padding: 8em 0 8em 0; - text-align: center; - } - - .wrapper.style1 { - background-image: none; - background-color: #fff; - } - - .wrapper.style2 { - background-color: #fafafa; - text-shadow: 1px 1px 0px #fff; - } - - .wrapper.style3 { - background-color: #f4f4f4; - text-shadow: 1px 1px 0px #fff; - } - - .wrapper.style4 { - background-color: #303030; - color: #999; - text-shadow: -1px -1px 0px #181818; - } - - .wrapper.style4 h1, .wrapper.style4 h2, .wrapper.style4 h3, .wrapper.style4 h4, .wrapper.style4 h5, .wrapper.style4 h6 { - color: #fff; - } - - .wrapper.style4 form input[type=text], - .wrapper.style4 form input[type=password], - .wrapper.style4 form select, - .wrapper.style4 form textarea { - border: none; - background: #282828; - } - - .wrapper.style4 form input[type=text]:focus, - .wrapper.style4 form input[type=password]:focus, - .wrapper.style4 form select:focus, - .wrapper.style4 form textarea:focus { - background: #252525; - } - -/* Nav */ - - #nav { - background-color: #282828; - text-align: center; - position: fixed; - left: 0; - top: 0; - width: 100%; - z-index: 10000; - cursor: default; - height: 3.5em; - line-height: 3.5em; - } - - #nav ul { - margin-bottom: 0; - list-style: none; - padding-left: 0; - } - - #nav li { - display: inline-block; - padding-left: 0; - } - - #nav a { - -moz-transition: background-color .2s ease-in-out; - -webkit-transition: background-color .2s ease-in-out; - -ms-transition: background-color .2s ease-in-out; - transition: background-color .2s ease-in-out; - position: relative; - display: block; - color: #fff; - text-decoration: none; - outline: 0; - font-weight: 600; - border-radius: 8px; - color: #fff; - height: 2.5em; - line-height: 2.5em; - padding: 0 1.25em; - } - - #nav a:hover { - color: #fff !important; - background: #383838; - } - - #nav a.active { - background: #484848; - } - - #nav a.active:before { - content: ''; - display: block; - position: absolute; - bottom: -0.6em; - left: 50%; - margin-left: -0.75em; - border-left: solid 0.75em transparent; - border-right: solid 0.75em transparent; - border-top: solid 0.6em #282828; - } - -/* Articles */ - - body > article { - margin-bottom: 0; - } - - #top { - padding: 10em 0 10em 0; - text-align: left; - } - - #top .image { - border-radius: 100%; - width: 20em; - height: 20em; - margin: 0; - } - - #top .image img { - border-radius: 100%; - } - - #top h1 { - margin-top: 0.35em; - } - - #top p { - font-size: 1.5em; - line-height: 1.75em; - } - - #top p a { - color: inherit; - } - - #contact footer { - font-size: 0.9em; - } - -/* Copyright */ - - #copyright { - color: #666; - font-size: 1em; - line-height: 1em; - list-style: none; - padding-left: 0; - margin-bottom: 0; - } - - #copyright li { - display: inline-block; - border-left: solid 1px rgba(0, 0, 0, 0.5); - box-shadow: -1px 0px 0px 0px rgba(255, 255, 255, 0.1); - padding: 0 0 0 1em; - margin: 0 0 0 1em; - } - - #copyright li:first-child { - border: 0; - box-shadow: none; - padding-left: 0; - margin-left: 0; - } - - #copyright a { - -moz-transition: color .2s ease-in-out; - -webkit-transition: color .2s ease-in-out; - -ms-transition: color .2s ease-in-out; - transition: color .2s ease-in-out; - color: inherit; - } - - #copyright a:hover { - color: #777; - } - -/* Large */ - - @media screen and (max-width: 1280px) { - - /* Basic */ - - body { - font-size: 11pt; - } - - input, textarea, select { - font-size: 11pt; - } - - header { - margin: 0 0 4em 0; - } - - /* Wrappers */ - - .wrapper { - padding: 5em 0 5em 0; - text-align: center; - } - - .wrapper.style4 .row-special { - margin: 2em 0 0 0; - padding: 2em 0 2em 0; - } - - /* Articles */ - - #top { - padding: 8em 0; - } - - #top .image { - width: 24em; - height: 24em; - margin: 0; - } - - } - -/* Medium */ - - @media screen and (max-width: 980px) { - - /* Articles */ - - #top { - text-align: center; - padding: 5em 0; - } - - #top .image { - margin: 0 auto 2em auto; - } - - } - -/* Small */ - - @media screen and (max-width: 736px) { - - /* Basic */ - - body { - padding-top: 44px; - } - - body, input, textarea, select { - line-height: 1.75em; - font-size: 10pt; - letter-spacing: 0; - } - - h1, h2, h3, h4, h5, h6 { - font-size: 1.25em; - margin: 0 0 0.4em 0; - } - - h1 { - font-size: 2.25em; - line-height: 1.25em; - } - - header { - margin: 0 0 2em 0; - } - - header > p { - font-size: 1.25em; - } - - footer { - margin: 2.5em 0 0 0; - } - - footer > p { - font-size: 1.25em; - } - - hr { - margin: 1.5em 0 2em 0; - } - - /* Section/Article */ - - section, article { - clear: both; - } - - /* Button */ - - input[type="button"], - input[type="submit"], - input[type="reset"], - button, - .button { - text-align: center; - font-size: 1.2em; - width: 100%; - padding: 1em 0 1em 0; - } - - input[type="button"].large, - input[type="submit"].large, - input[type="reset"].large, - button.large, - .button.large { - font-size: 1.2em; - letter-spacing: 0; - } - - /* Social */ - - ul.social { - padding: 1em 0.5em 0 0.5em; - } - - ul.social li { - margin: 0.5em 0.5em 0.5em 0.5em; - } - - ul.social li a { - top: 0 !important; - } - - ul.social li a:before { - background-color: transparent !important; - } - - /* Actions */ - - ul.actions { - margin: 0; - } - - ul.actions li { - display: block; - margin: 15px 0 0 0; - } - - ul.actions li:first-child { - margin-top: 0; - } - - /* Box */ - - .box { - padding: 30px 20px 30px 20px; - margin: 0 0 20px 0 !important; - } - - .box h3 { - margin-bottom: 0.25em; - } - - .box .image.centered { - margin-bottom: 1em; - } - - .box .image.featured { - position: relative; - left: 20px; - top: 20px; - margin: -50px 0 50px -40px; - width: auto; - } - - .box.style1 { - max-width: 32em; - margin-left: auto !important; - margin-right: auto !important; - } - - .box.style2 { - max-width: 32em; - margin-left: auto !important; - margin-right: auto !important; - } - - /* Wrappers */ - - .wrapper { - padding: 3em 0; - text-align: center; - } - - /* Nav */ - - #nav { - height: 44px; - line-height: 44px; - } - - #nav a { - padding: 0 0.75em; - height: inherit; - line-height: inherit; - border-radius: 0; - } - - #nav a:hover { - background-color: transparent; - } - - /* Articles */ - - #top { - padding: 3em 0; - } - - #top .image { - width: 15em; - height: 15em; - margin-bottom: 0; - } - - #top p { - font-size: 1em; - } - - #contact footer { - margin: 0; - } - - /* Copyright */ - - #copyright { - font-size: 1em; - margin: 0; - } - - #copyright li { - display: block; - margin: 1em 0 0 0; - padding: 0; - box-shadow: none; - border-left: 0; - } - - #copyright li:first-child { - margin-top: 0; - } - - } - diff --git a/assets/css/stylesheet.css b/assets/css/stylesheet.css @@ -0,0 +1,7 @@ +/* + PaperMod v6 + License: MIT https://github.com/adityatelange/hugo-PaperMod/blob/master/LICENSE + Copyright (c) 2020 nanxiaobei and adityatelange + Copyright (c) 2021-2022 adityatelange +*/ +:root{--gap:24px;--content-gap:20px;--nav-width:1024px;--main-width:720px;--header-height:60px;--footer-height:60px;--radius:8px;--theme:rgb(255, 255, 255);--entry:rgb(255, 255, 255);--primary:rgb(30, 30, 30);--secondary:rgb(108, 108, 108);--tertiary:rgb(214, 214, 214);--content:rgb(31, 31, 31);--hljs-bg:rgb(28, 29, 33);--code-bg:rgb(245, 245, 245);--border:rgb(238, 238, 238)}.dark{--theme:rgb(29, 30, 32);--entry:rgb(46, 46, 51);--primary:rgb(218, 218, 219);--secondary:rgb(155, 156, 157);--tertiary:rgb(65, 66, 68);--content:rgb(196, 196, 197);--hljs-bg:rgb(46, 46, 51);--code-bg:rgb(55, 56, 62);--border:rgb(51, 51, 51)}.list{background:var(--code-bg)}.dark.list{background:var(--theme)}*,::after,::before{box-sizing:border-box}html{-webkit-tap-highlight-color:transparent;overflow-y:scroll}a,button,body,h1,h2,h3,h4,h5,h6{color:var(--primary)}body{font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen,Ubuntu,Cantarell,open sans,helvetica neue,sans-serif;font-size:18px;line-height:1.6;word-break:break-word;background:var(--theme)}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section,table{display:block}h1,h2,h3,h4,h5,h6{line-height:1.2}h1,h2,h3,h4,h5,h6,p{margin-top:0;margin-bottom:0}ul{padding:0}a{text-decoration:none}body,figure,ul{margin:0}table{width:100%;border-collapse:collapse;border-spacing:0;overflow-x:auto;word-break:keep-all}button,input,textarea{padding:0;font:inherit;background:0 0;border:0}input,textarea{outline:0}button,input[type=button],input[type=submit]{cursor:pointer}input:-webkit-autofill,textarea:-webkit-autofill{box-shadow:0 0 0 50px var(--theme)inset}img{display:block;max-width:100%}.not-found{position:absolute;left:0;right:0;display:flex;align-items:center;justify-content:center;height:80%;font-size:160px;font-weight:700}.archive-posts{width:100%;font-size:16px}.archive-year{margin-top:40px}.archive-year:not(:last-of-type){border-bottom:2px solid var(--border)}.archive-month{display:flex;align-items:flex-start;padding:10px 0}.archive-month-header{margin:25px 0;width:200px}.archive-month:not(:last-of-type){border-bottom:1px solid var(--border)}.archive-entry{position:relative;padding:5px;margin:10px 0}.archive-entry-title{margin:5px 0;font-weight:400}.archive-count,.archive-meta{color:var(--secondary);font-size:14px}.footer,.top-link{font-size:12px;color:var(--secondary)}.footer{max-width:calc(var(--main-width) + var(--gap) * 2);margin:auto;padding:calc((var(--footer-height) - var(--gap))/2)var(--gap);text-align:center;line-height:24px}.footer span{margin-inline-start:1px;margin-inline-end:1px}.footer span:last-child{white-space:nowrap}.footer a{color:inherit;border-bottom:1px solid var(--secondary)}.footer a:hover{border-bottom:1px solid var(--primary)}.top-link{visibility:hidden;position:fixed;bottom:60px;right:30px;z-index:99;background:var(--tertiary);width:42px;height:42px;padding:12px;border-radius:64px;transition:visibility .5s,opacity .8s linear}.top-link,.top-link svg{filter:drop-shadow(0 0 0 var(--theme))}.footer a:hover,.top-link:hover{color:var(--primary)}.top-link:focus,#theme-toggle:focus{outline:0}.nav{display:flex;flex-wrap:wrap;justify-content:space-between;max-width:calc(var(--nav-width) + var(--gap) * 2);margin-inline-start:auto;margin-inline-end:auto;line-height:var(--header-height)}.nav a{display:block}.logo,#menu{display:flex;margin:auto var(--gap)}.logo{flex-wrap:inherit}.logo a{font-size:24px;font-weight:700}.logo a img,.logo a svg{display:inline;vertical-align:middle;pointer-events:none;transform:translate(0,-10%);border-radius:6px;margin-inline-end:8px}button#theme-toggle{font-size:26px;margin:auto 4px}body.dark #moon{vertical-align:middle;display:none}body:not(.dark) #sun{display:none}#menu{list-style:none;word-break:keep-all;overflow-x:auto;white-space:nowrap}#menu li+li{margin-inline-start:var(--gap)}#menu a{font-size:16px}#menu .active{font-weight:500;border-bottom:2px solid}.lang-switch li,.lang-switch ul,.logo-switches{display:inline-flex;margin:auto 4px}.lang-switch{display:flex;flex-wrap:inherit}.lang-switch a{margin:auto 3px;font-size:16px;font-weight:500}.logo-switches{flex-wrap:inherit}.main{position:relative;min-height:calc(100vh - var(--header-height) - var(--footer-height));max-width:calc(var(--main-width) + var(--gap) * 2);margin:auto;padding:var(--gap)}.page-header h1{font-size:40px}.pagination{display:flex}.pagination a{color:var(--theme);font-size:13px;line-height:36px;background:var(--primary);border-radius:calc(36px/2);padding:0 16px}.pagination .next{margin-inline-start:auto}.social-icons{padding:12px 0}.social-icons a:not(:last-of-type){margin-inline-end:12px}.social-icons a svg{height:26px;width:26px}code{direction:ltr}div.highlight,pre{position:relative}.copy-code{display:none;position:absolute;top:4px;right:4px;color:rgba(255,255,255,.8);background:rgba(78,78,78,.8);border-radius:var(--radius);padding:0 5px;font-size:14px;user-select:none}div.highlight:hover .copy-code,pre:hover .copy-code{display:block}.first-entry{position:relative;display:flex;flex-direction:column;justify-content:center;min-height:320px;margin:var(--gap)0 calc(var(--gap) * 2)}.first-entry .entry-header{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.first-entry .entry-header h1{font-size:34px;line-height:1.3}.first-entry .entry-content{margin:14px 0;font-size:16px;-webkit-line-clamp:3}.first-entry .entry-footer{font-size:14px}.home-info .entry-content{-webkit-line-clamp:unset}.post-entry{position:relative;margin-bottom:var(--gap);padding:var(--gap);background:var(--entry);border-radius:var(--radius);transition:transform .1s;border:1px solid var(--border)}.post-entry:active{transform:scale(.96)}.tag-entry .entry-cover{display:none}.entry-header h2{font-size:24px;line-height:1.3}.entry-content{margin:8px 0;color:var(--secondary);font-size:14px;line-height:1.6;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.entry-footer{color:var(--secondary);font-size:13px}.entry-link{position:absolute;left:0;right:0;top:0;bottom:0}.entry-cover,.entry-isdraft{font-size:14px;color:var(--secondary)}.entry-cover{margin-bottom:var(--gap);text-align:center}.entry-cover img{border-radius:var(--radius);pointer-events:none;width:100%;height:auto}.entry-cover a{color:var(--secondary);box-shadow:0 1px 0 var(--primary)}.page-header,.post-header{margin:24px auto var(--content-gap)}.post-title{margin-bottom:2px;font-size:40px}.post-description{margin-top:10px;margin-bottom:5px}.post-meta,.breadcrumbs{color:var(--secondary);font-size:14px;display:flex;flex-wrap:wrap}.post-meta .i18n_list li{display:inline-flex;list-style:none;margin:auto 3px;box-shadow:0 1px 0 var(--secondary)}.breadcrumbs a{font-size:16px}.post-content{color:var(--content)}.post-content h3,.post-content h4,.post-content h5,.post-content h6{margin:24px 0 16px}.post-content h1{margin:40px auto 32px;font-size:40px}.post-content h2{margin:32px auto 24px;font-size:32px}.post-content h3{font-size:24px}.post-content h4{font-size:16px}.post-content h5{font-size:14px}.post-content h6{font-size:12px}.post-content a,.toc a:hover{box-shadow:0 1px}.post-content a code{margin:auto 0;border-radius:0;box-shadow:0 -1px 0 var(--primary)inset}.post-content del{text-decoration:none;background:linear-gradient(to right,var(--primary) 100%,transparent 0)0/1px 1px repeat-x}.post-content dl,.post-content ol,.post-content p,.post-content figure,.post-content ul{margin-bottom:var(--content-gap)}.post-content ol,.post-content ul{padding-inline-start:20px}.post-content li{margin-top:5px}.post-content li p{margin-bottom:0}.post-content dl{display:flex;flex-wrap:wrap;margin:0}.post-content dt{width:25%;font-weight:700}.post-content dd{width:75%;margin-inline-start:0;padding-inline-start:10px}.post-content dd~dd,.post-content dt~dt{margin-top:10px}.post-content table{margin-bottom:32px}.post-content table th,.post-content table:not(.highlighttable,.highlight table,.gist .highlight) td{min-width:80px;padding:12px 8px;line-height:1.5;border-bottom:1px solid var(--border)}.post-content table th{font-size:14px;text-align:start}.post-content table:not(.highlighttable) td code:only-child{margin:auto 0}.post-content .highlight table{border-radius:var(--radius)}.post-content .highlight:not(table){margin:10px auto;background:var(--hljs-bg)!important;border-radius:var(--radius);direction:ltr}.post-content li>.highlight{margin-inline-end:0}.post-content ul pre{margin-inline-start:calc(var(--gap) * -2)}.post-content .highlight pre{margin:0}.post-content .highlighttable{table-layout:fixed}.post-content .highlighttable td:first-child{width:40px}.post-content .highlighttable td .linenodiv{padding-inline-end:0!important}.post-content .highlighttable td .highlight,.post-content .highlighttable td .linenodiv pre{margin-bottom:0}.post-content code{margin:auto 4px;padding:4px 6px;font-size:.78em;line-height:1.5;background:var(--code-bg);border-radius:2px}.post-content pre code{display:block;margin:auto 0;padding:10px;color:#d5d5d6;background:var(--hljs-bg)!important;border-radius:var(--radius);overflow-x:auto;word-break:break-all}.post-content blockquote{margin:20px 0;padding:0 14px;border-inline-start:3px solid var(--primary)}.post-content hr{margin:30px 0;height:2px;background:var(--tertiary);border:0}.post-content iframe{max-width:100%}.post-content img{border-radius:4px;margin:1rem 0}.post-content img[src*="#center"]{margin:1rem auto}.post-content figure.align-center{text-align:center}.post-content figure>figcaption{color:var(--primary);font-size:16px;font-weight:700;margin:8px 0 16px}.post-content figure>figcaption>p{color:var(--secondary);font-size:14px;font-weight:400}.toc{margin:0 2px 40px;border:1px solid var(--border);background:var(--code-bg);border-radius:var(--radius);padding:.4em}.dark .toc{background:var(--entry)}.toc details summary{cursor:zoom-in;margin-inline-start:20px}.toc details[open] summary{cursor:zoom-out}.toc .details{display:inline;font-weight:500}.toc .inner{margin:0 20px;padding:10px 20px}.toc li ul{margin-inline-start:var(--gap)}.toc summary:focus{outline:0}.post-footer{margin-top:56px}.post-tags li{display:inline-block;margin-inline-end:3px;margin-bottom:5px}.post-tags a,.share-buttons,.paginav{border-radius:var(--radius);background:var(--code-bg);border:1px solid var(--border)}.post-tags a{display:block;padding-inline-start:14px;padding-inline-end:14px;color:var(--secondary);font-size:14px;line-height:34px;background:var(--code-bg)}.post-tags a:hover,.paginav a:hover{background:var(--border)}.share-buttons{margin:14px 0;padding-inline-start:var(--radius);display:flex;justify-content:center;overflow-x:auto}.share-buttons a{margin-top:10px}.share-buttons a:not(:last-of-type){margin-inline-end:12px}h1:hover .anchor,h2:hover .anchor,h3:hover .anchor,h4:hover .anchor,h5:hover .anchor,h6:hover .anchor{display:inline-flex;color:var(--secondary);margin-inline-start:8px;font-weight:500;user-select:none}.paginav{margin:10px 0;display:flex;line-height:30px;border-radius:var(--radius)}.paginav a{padding-inline-start:14px;padding-inline-end:14px;border-radius:var(--radius)}.paginav .title{letter-spacing:1px;text-transform:uppercase;font-size:small;color:var(--secondary)}.paginav .prev,.paginav .next{width:50%}.paginav span:hover:not(.title){box-shadow:0 1px}.paginav .next{margin-inline-start:auto;text-align:right}[dir=rtl] .paginav .next{text-align:left}h1>a>svg{display:inline}img.in-text{display:inline;margin:auto}.buttons,.main .profile{display:flex;justify-content:center}.main .profile{align-items:center;min-height:calc(100vh - var(--header-height) - var(--footer-height) - (var(--gap) * 2));text-align:center}.profile .profile_inner h1{padding:12px 0}.profile img{display:inline-table;border-radius:50%}.buttons{flex-wrap:wrap;max-width:400px;margin:0 auto}.button{background:var(--tertiary);border-radius:var(--radius);margin:8px;padding:6px;transition:transform .1s}.button-inner{padding:0 8px}.button:active{transform:scale(.96)}#searchbox input{padding:4px 10px;width:100%;color:var(--primary);font-weight:700;border:2px solid var(--tertiary);border-radius:var(--radius)}#searchbox input:focus{border-color:var(--secondary)}#searchResults li{list-style:none;border-radius:var(--radius);padding:10px;margin:10px 0;position:relative;font-weight:500}#searchResults{margin:10px 0;width:100%}#searchResults li:active{transition:transform .1s;transform:scale(.98)}#searchResults a{position:absolute;width:100%;height:100%;top:0;left:0;outline:none}#searchResults .focus{transform:scale(.98);border:2px solid var(--tertiary)}.terms-tags li{display:inline-block;margin:10px;font-weight:500}.terms-tags a{display:block;padding:3px 10px;background:var(--tertiary);border-radius:6px;transition:transform .1s}.terms-tags a:active{background:var(--tertiary);transform:scale(.96)}.hljs-comment,.hljs-quote{color:#b6b18b}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#eb3c54}.hljs-built_in,.hljs-builtin-name,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#e7ce56}.hljs-attribute{color:#ee7c2b}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#4fb4d7}.hljs-section,.hljs-title{color:#78bb65}.hljs-keyword,.hljs-selector-tag{color:#b45ea4}.hljs{display:block;overflow-x:auto;background:#1c1d21;color:#c0c5ce;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}::-webkit-scrollbar-track{background:0 0}.list:not(.dark)::-webkit-scrollbar-track{background:var(--code-bg)}::-webkit-scrollbar-thumb{background:var(--tertiary);border:5px solid var(--theme);border-radius:var(--radius)}.list:not(.dark)::-webkit-scrollbar-thumb{border:5px solid var(--code-bg)}::-webkit-scrollbar-thumb:hover{background:var(--secondary)}::-webkit-scrollbar:not(.highlighttable,.highlight table,.gist .highlight){background:var(--theme)}.post-content .highlighttable td .highlight pre code::-webkit-scrollbar{display:none}.post-content :not(table) ::-webkit-scrollbar-thumb{border:2px solid var(--hljs-bg);background:#717175}.post-content :not(table) ::-webkit-scrollbar-thumb:hover{background:#a3a3a5}.gist table::-webkit-scrollbar-thumb{border:2px solid #fff;background:#adadad}.gist table::-webkit-scrollbar-thumb:hover{background:#707070}.post-content table::-webkit-scrollbar-thumb{border-width:2px}@media screen and (min-width:768px){::-webkit-scrollbar{width:19px;height:11px}}@media screen and (max-width:768px){:root{--gap:14px}.profile img{transform:scale(.85)}.first-entry{min-height:260px}.archive-month{flex-direction:column}.archive-year{margin-top:20px}.footer{padding:calc((var(--footer-height) - var(--gap) - 10px)/2)var(--gap)}}@media screen and (max-width:900px){.list .top-link{transform:translateY(-5rem)}}@media(prefers-reduced-motion){.terms-tags a:active,.button:active,.post-entry:active,.top-link,#searchResults .focus,#searchResults li:active{transform:none}} +\ No newline at end of file diff --git a/assets/img/chat_mono.svg b/assets/img/chat_mono.svg @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>forum-outline</title><path fill="#fff" d="M15,4V11H5.17L4,12.17V4H15M16,2H3A1,1 0 0,0 2,3V17L6,13H16A1,1 0 0,0 17,12V3A1,1 0 0,0 16,2M21,6H19V15H6V17A1,1 0 0,0 7,18H18L22,22V7A1,1 0 0,0 21,6Z" /></svg> diff --git a/assets/img/play_mono.svg b/assets/img/play_mono.svg @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>motion-play-outline</title><path fill="#fff" d="M10 16.5L16 12L10 7.5M22 12C22 6.46 17.54 2 12 2C10.83 2 9.7 2.19 8.62 2.56L9.32 4.5C10.17 4.16 11.06 3.97 12 3.97C16.41 3.97 20.03 7.59 20.03 12C20.03 16.41 16.41 20.03 12 20.03C7.59 20.03 3.97 16.41 3.97 12C3.97 11.06 4.16 10.12 4.5 9.28L2.56 8.62C2.19 9.7 2 10.83 2 12C2 17.54 6.46 22 12 22C17.54 22 22 17.54 22 12M5.47 3.97C6.32 3.97 7 4.68 7 5.47C7 6.32 6.32 7 5.47 7C4.68 7 3.97 6.32 3.97 5.47C3.97 4.68 4.68 3.97 5.47 3.97Z" /></svg> diff --git a/assets/img/streamlink_mono.svg b/assets/img/streamlink_mono.svg @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>link-circle-outline</title><path fill="#fff" d="M10 16H11V14H10C9.67 14 8 13.9 8 12C8 10.17 9.54 10 10 10H11V8H10C8.39 8 6 9.07 6 12C6 14.94 8.39 16 10 16M13 16H14C15.61 16 18 14.94 18 12C18 9.07 15.61 8 14 8H13V10H14C14.33 10 16 10.1 16 12C16 13.83 14.46 14 14 14H13V16M9 13H15V11H9V13M8.17 2.76C9.39 2.26 10.69 2 12 2C13.31 2 14.61 2.26 15.83 2.76C17.04 3.26 18.14 4 19.07 4.93C20 5.86 20.74 6.96 21.24 8.17C21.74 9.39 22 10.69 22 12C22 14.65 20.95 17.2 19.07 19.07C17.2 20.95 14.65 22 12 22C10.69 22 9.39 21.74 8.17 21.24C6.96 20.74 5.86 20 4.93 19.07C3.05 17.2 2 14.65 2 12C2 9.35 3.05 6.8 4.93 4.93C5.86 4 6.96 3.26 8.17 2.76M6.34 17.66C7.84 19.16 9.88 20 12 20C14.12 20 16.16 19.16 17.66 17.66C19.16 16.16 20 14.12 20 12C20 9.88 19.16 7.84 17.66 6.34C16.16 4.84 14.12 4 12 4C9.88 4 7.84 4.84 6.34 6.34C4.84 7.84 4 9.88 4 12C4 14.12 4.84 16.16 6.34 17.66Z" /></svg> diff --git a/assets/js/twitch.js b/assets/js/twitch.js @@ -1,4 +1,4 @@ -function toggle_player(stream, img64) { +function toggle_player(stream) { var img = document.querySelector("#img-" + stream); var ply = document.querySelector("#play-" + stream); if (img != null) { @@ -18,7 +18,7 @@ function toggle_player(stream, img64) { } if (ply != null) { var image = document.createElement("img"); - image.src = img64; + image.src = "https://static-cdn.jtvnw.net/previews-ttv/live_user_" + stream + "-1280x720.jpg"; image.id = "img-" + stream; image.classList.add("preview"); ply.replaceWith(image); @@ -35,7 +35,7 @@ function toggle_chat(stream) { if (plho != null) { var chatembed = document.createElement("iframe"); chatembed.width = "100%"; - chatembed.height = "100vh"; + chatembed.height = "100%"; chatembed.frameborder = "0"; chatembed.scrolling = "auto"; chatembed.src = "https://www.twitch.tv/embed/" + @@ -43,7 +43,6 @@ function toggle_chat(stream) { "/chat?parent=" + window.location.hostname; chatembed.id = "chat-" + stream; - chatembed.classList.add("preview"); /* FIXME: wrong class */ plho.replaceWith(chatembed); } } diff --git a/index.php b/index.php @@ -1,386 +1,98 @@ -<!DOCTYPE HTML> +<!-- SPDX-License-Identifier: AGPL-3.0-or-later + SPDX-FileCopyrightText: 2024 JayVii <jayvii[AT]posteo[DOT]de> +--> + +<!DOCTYPE html> <html> -<head> - <title>Twitch Streams</title> - <link rel="icon" type="image/png" href="/assets/img/twitch.png"> - <link crossorigin="use-credentials" rel="manifest" href="/manifest.json"> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> - <link rel="stylesheet" href="/assets/css/miniport.css" /> - <link rel="stylesheet" href="/assets/css/custom.css" /> - <link rel="stylesheet" href="/assets/css/loading.css" /> - <script async src="/assets/js/twitch.js"></script> -</head> <?php -// Start timer -$time0 = time(); - // Fetch GET and POST arguments if (is_null($_POST["streams"])) { - $loading_screen = true; - if (!is_null($_GET["streams"])) { - $channels = explode(",", $_GET["streams"]); - } else { - $channels = explode(",", $_COOKIE["streams"]); - } -} else { - $loading_screen = false; - $channels = unserialize($_POST["streams"]); -} - -if (is_null($_GET["stream"])) { - $extplayer = false; + $loading_screen = true; + if (!is_null($_GET["streams"])) { + $channels = explode(",", $_GET["streams"]); + } else { + $channels = explode(",", $_COOKIE["streams"]); + } } else { - $extplayer = true; + $loading_screen = false; + $channels = unserialize($_POST["streams"]); } // Prepare streams array $streams = array( - "stream" => $channels, - "desc" => array(), - "game" => array(), - "status" => array(), - "img" => array(), - "time" => array() + "stream" => $channels, + "desc" => array(), + "game" => array(), + "status" => array(), + "time" => array() ); -// Check whether to load streams or show the loading screen +// Streams or Loading Screen if (!$loading_screen) { - - // Check Online Status of streams - for ($i = 0; $i < sizeof($streams["stream"]); $i++) { - - // Fetch Stream Preview Image - $img = file_get_contents( - "https://static-cdn.jtvnw.net/previews-ttv/live_user_" . - $streams["stream"][$i] . - "-853x480.jpg" - ); - $img_base64 = "data:image/jpg;base64," . base64_encode($img); - - // Check Online-Status via HTTP status code - $http_code = preg_replace( - '/^.*(\d{3}).*/', - '\1', - $http_response_header[0] - ); - - if (!($http_code == "200")) { - - // Stream is not online! - array_push($streams["status"], 0); - $desc = ""; - $game = ""; - $img_base64 = ""; - - } else { - - // Stream is online! - array_push($streams["status"], 1); - - // Fetch HTML - $html = file_get_contents( - "https://m.twitch.tv/" . $streams["stream"][$i] - ); - $html = str_replace(array("\r", "\n"), "", $html); - - // Parse Game Name - $pattern = '/^.*<p.*?Playing <a.*?>(.*?)<\/a>.*$/'; - $replacement = '\1'; - $game = substr( - strip_tags( - preg_replace( - $pattern, - $replacement, - $html - ) - ), - 0, - 100 - ); - - // Parse Stream Description - $html = preg_replace('/<script.*<\/script>/', '', $html); - $html = explode(">", $html); - $desc_raw = implode("", preg_grep('/name="description"/', $html)); - $pattern = '/^.*content="(.*?)".*$/'; - $replacement = '\1'; - $desc = substr( - strip_tags( - preg_replace( - $pattern, - $replacement, - $desc_raw - ) - ), - 0, - 500 - ); - - } - - // Fill Streams array - array_push($streams["desc"], $desc); - array_push($streams["game"], $game); - array_push($streams["img"], $img_base64); - array_push($streams["time"], (time() - $time0)); - - } - - // Generate Main Menu - if (array_sum($streams["status"]) > 0) { - $beep_color = "#0f0"; - $beep_class = "pulse"; - } else { - $beep_color = "#f00"; - $beep_class = "nopulse"; - } - $menu_items = "<li><strong style='color:#fff;'>" . - "<span style='color:" . $beep_color . - "' class='" . $beep_class . "'>•</span>" . - "Live: " . array_sum($streams["status"]) . "</strong>" . - "</li>"; - - // Generate Content List - $content = ""; - for ($i = 0; $i < sizeof($streams["stream"]); $i++) { - if ($streams["status"][$i] > 0) { - $content = $content . - // Stream-Channel - "<div id='" . $streams["stream"][$i] . "'></div>" . - // Headline - "<h2>" . $streams["stream"][$i] . "</h2>" . - // Stream-Type and Description - "<p><span style='color:#3fa8d2;margin-right:1em;'>" . - $streams["game"][$i] . - "</span>" . - $streams["desc"][$i] . - "</p>" . - // Inner Container - "<div>" . - // Stream Preview - "<img id='img-" . $streams["stream"][$i] . "' " . - "class='preview' " . - "src='" . $streams["img"][$i] . "'>" . - // Button outer container - "<div class='buttons-outer'>" . - // Chat-Placeholder (for Embedding) - /*"<div id='chat-placeholder-" . - $streams["stream"][$i] . - "'></div>" .*/ - // Button inner container - "<div class='buttons-inner'>" . - // Stream (external Player) - "<a " . - "class='button' " . - // "target='_blank' " . - "href='/?stream=" . rawurlencode($streams["stream"][$i]) . - "' " . - "title='External Player'>" . - "<img " . - "class='button-img' " . - "src='/assets/img/play_mono.svg'>" . - "</a>" . - // Stream (Embedding) - // "<a " . - // "class='button' ". - // "href='javascript:toggle_player(\"" . - // $streams["stream"][$i] . "\", \"" . $streams["img"][$i] . - // "\")' " . - // "title='Player'>" . - // "<img " . - // "class='button-img' " . - // "src='/assets/img/play_mono.svg'>" . - // "</a>" . - // Stream (New Tab) - /*"<a " . - "class='button' ". - "target='_blank' ". - "href='https://m.twitch.tv/" . - $streams["stream"][$i] . "' " . - "title='Twitch'>". - "<img class='button-img' " . - "src='/assets/img/twitch_mono.svg'>" . - "</a>" .*/ - // Stream (Streamlink) - "<a " . - "class='button' " . - "href='streamlink://twitch.tv/" . - $streams["stream"][$i] . - "?title=" . - rawurlencode($streams["desc"][$i]) . - "' title='Streamlink'>" . - "<img class='button-img' " . - "src='/assets/img/streamlink_mono.svg'>" . - "</a>" . - /* Chat (New Tab) */ - "<a ". - "class='button' ". - "target='_blank' ". - "href='https://m.twitch.tv/popout/" . - $streams["stream"][$i] . - "/chat' " . - "title='Chat'>" . - "<img class='button-img' " . - "src='/assets/img/chat_mono.svg'>" . - "</a>" . - /* Chat (Embedding) */ - /*"<a " . - "class='button' ". - "href='javascript:toggle_chat(\"" . - $streams["stream"][$i] . - "\")' " . - "title='Chat'>" . - "<img class='button-img' " . - "src='/assets/img/chat_mono.svg'>" . - "</a>" .*/ - /* Close inner button container */ - "</div>" . - /* Close outer button container */ - "</div>" . - /* Close Stream container */ - "</div>" . - /* Divider */ - "<br><hr>"; - } - } - $content = "<ul class='container'>" . - $content_menu . - "</ul><br>" . - $content; -} else if (!$extplayer) { - // Generate Loading Screen items - $menu_items = "<li>" . - "<strong style='color:#fff;'>" . - "Loading Twitch Streams " . - "<span style='color:#ff0;' class='pulse'>&#8226;</span>" . - "</strong>" . - "</li>"; - $content = "<h1 style='text-align:center;'>Please be patient</h1>" . - "<p style='text-align:center;'>Loading " . - sizeof($streams["stream"]) . - " streams. This may take a moment.</p>" . - "<br>" . - /* Loading Screen Animation */ - "<div class='wrapper-loading'>" . - "<div class='box-wrap'>" . - "<div class='box one'></div>" . - "<div class='box two'></div>" . - "<div class='box three'></div>" . - "<div class='box four'></div>" . - "<div class='box five'></div>" . - "<div class='box six'></div>" . - "</div>" . - "</div>" . - /* Streams-form */ - "<form id='channels' action='/' method='post'>" . - "<input " . - "type='hidden' " . - "id='streams' " . - "name='streams' ". - "value='" . serialize($streams["stream"]) ."'" . - ">" . - /* Form Submitter */ - "<script>" . - "setTimeout(" . - "function(){" . - "document.querySelector('#channels').submit()" . - "}, " . - "1000);" . - "</script>"; -} else if ($extplayer) { - $menu_items = "<li>Playing stream of " . $_GET["stream"] . "</li>"; - $content = "<div id='player'>" . - "<div id='stream-window'>" . - "<iframe id='stream' allowfullscreen scrolling='no' " . - "src='https://player.twitch.tv/?channel=" . $_GET["stream"] . - "&parent=" . $_SERVER['SERVER_NAME'] . "' " . - "width='100%' height='100%'>" . - "</iframe>" . - "</div>" . - "<div id='chat-window'>" . - "<iframe scrolling='yes' " . - "src='https://www.twitch.tv/embed/" . $_GET["stream"] . - "/chat?parent=" . $_SERVER['SERVER_NAME'] . "'" . - " width='100%' height='100%'>" . - "</iframe>" . - "</div>" . - "</div>" . - // FIXME: make chat full height - "<script>setTimeout(function() { document.querySelector('#chat-window').style.height=document.querySelector('#stream-window').offsetHeight + 'px'; }, 1000);</script>"; - + // Load Stream Data + include("lib/load_streams.php"); + // Build HTML from Stream Data + include("lib/build_html.php"); } else { - - $menu_items = "<li><strong>Oh no!</strong></li>"; - $content = "<p>You tried to do something that is not implemented (yet?)..."; + // Load Loading Screen content + include("lib/loadingscreen.php"); } -?> -<!-- HTML --> - -<body> - - <!-- NAVIGATION BAR --> - - <nav id="nav"> - <ul class="container"> - -<?php - /* Reload & Save Buttons */ - if (implode(",", $streams["stream"]) == $_COOKIE["streams"]) { - $save_button_style = "display:none;"; - } else { - $save_button_style = ""; - } - echo "<li>" . - // Save Button - "<a " . - "style='color:#F00;" . $save_button_style . "'". - "href=\"#\"" . - "onclick=\"document.cookie='streams=" . - implode(",", $streams["stream"]) . - ";path=/;max-age=31536000;';\"" . - "title='Save' " . - "id='button-save'>" . - "&#128427;" . - "</a>" . - "</li>" . - "<li>" . - // Reoad Button - "<a " . - "href=\"./?streams=" . - implode(",", $streams["stream"]) . - "\"" . - "title='Reload' " . - "id='button-reload'>" . - "&#8635;" . - "</a>" . - "</li>"; - /* Other menu items */ - echo $menu_items; ?> - </ul> - </nav> - - <article class="wrapper"> - <!-- SITE CONTENT --> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Twitch Streams</title> + <link rel="icon" type="image/png" href="assets/twitch.png"> + <link rel="icon" type="image/png" sizes="16x16" href="assets/twitch_16.png"> + <link rel="icon" type="image/png" sizes="32x32" href="assets/twitch_32.png"> + <link rel="icon" type="image/png" sizes="64x64" href="assets/twitch_64.png"> + <link rel="icon" type="image/png" sizes="128x128" href="assets/twitch_128.png"> + <link rel="apple-touch-icon" href="assets/twitch.png"> + <link rel="stylesheet" type="text/css" href="assets/css/stylesheet.css"/> + <link rel="stylesheet" href="assets/css/loading.css" /> + <link rel="stylesheet" href="assets/css/custom.css" /> + <script async src="assets/js/twitch.js"></script> + <link crossorigin="use-credentials" rel="manifest" href="manifest.json"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + </head> + + <body class="list dark"> + <main class="main"> + + <h1>Streams</h1> + + <!-- Save Button --> + <button class="button" onclick="<?php echo "document.cookie='streams=" . implode(",", $streams["stream"]) . ";path=/;max-age=31536000;';" ?>" style="<?php echo "color:" . $save_col; ?>"> + &#128427; Save + </button> + + <!-- Reload Button --> + <a href="<?php echo "/?streams=" . implode(",", $streams["stream"]); ?>"> + <button class="button"> + &#8635; Reload + </button> + </a> + + <button class="button"> + Live: <?php echo array_sum($streams["status"]); ?> + </button> + + <br> + + <!-- Search Bar --> + <form action="https://www.twitch.tv/search" method="GET" style="width:100%;"> + <input id="searchbar" type="text" id="searchInput" name="term" placeholder="&#128269; Search..."> + </form><br> <?php - if (!$extplayer) { - echo "<div class=\"container\">"; - } - - echo $content; +echo $content; - if (!$extplayer) { - echo "</div>"; - } ?> - </article> -</body> + </main> + </body> </html> diff --git a/lib/build_html.php b/lib/build_html.php @@ -0,0 +1,35 @@ +<?php + +// Generate Content List +$content = ""; + +// Build "article" section if stream is online +for ($i = 0; $i < sizeof($streams["stream"]); $i++) { + if ($streams["status"][$i] > 0) { + $content = $content . + // "article" object + "<article class='post-entry' id='stream_" . $streams["stream"][$i] . "'>" . + "<h2><a href='https://www.twitch.tv/" . $streams["stream"][$i] . "' class='hyperlink'>" . + $streams["desc"][$i] . + "</a></h2>" . + "<a href='#stream_" . $streams["stream"][$i] . "' onclick='toggle_player(\"" . $streams["stream"][$i] . "\");'>" . + "<img class='preview' id='img-" . $streams["stream"][$i] . "' src='https://static-cdn.jtvnw.net/previews-ttv/live_user_" . $streams["stream"][$i] . "-1280x720.jpg'>" . + "</a>" . + "<p><button class='button'>" . $streams["stream"][$i] . "</button>" . + "<button class='button'>" . $streams["game"][$i] . "</button></p>" . + "<details class='button'>" . + "<summary onclick='toggle_chat(\"" . $streams["stream"][$i] ."\");'>&#128172; Chat</summary>" . + "<div class='chatwrapper'><div id='chat-placeholder-" . $streams["stream"][$i] . "'></div></div></details>". + "</summary>" . + "</article>"; + } +} + +// Color of save button +if (implode(",", $streams["stream"]) == $_COOKIE["streams"]) { + $save_col = "#0F0"; +} else { + $save_col = "#F00"; +} + +?> diff --git a/lib/load_streams.php b/lib/load_streams.php @@ -0,0 +1,80 @@ +<?php + +// Check Online Status of streams +for ($i = 0; $i < sizeof($streams["stream"]); $i++) { + + // Fetch Stream Preview Image + $img = file_get_contents( + "https://static-cdn.jtvnw.net/previews-ttv/live_user_" . + $streams["stream"][$i] . + "-853x480.jpg" + ); + + // Check Online-Status via HTTP status code + $http_code = preg_replace( + '/^.*(\d{3}).*/', + '\1', + $http_response_header[0] + ); + + if (!($http_code == "200")) { + + // Stream is not online! + array_push($streams["status"], 0); + $desc = ""; + $game = ""; + + } else { + + // Stream is online! + array_push($streams["status"], 1); + + // Fetch HTML + $html = file_get_contents( + "https://m.twitch.tv/" . $streams["stream"][$i] + ); + $html = str_replace(array("\r", "\n"), "", $html); + + // Parse Game Name + $pattern = '/^.*<p.*?Playing <a.*?>(.*?)<\/a>.*$/'; + $replacement = '\1'; + $game = substr( + strip_tags( + preg_replace( + $pattern, + $replacement, + $html + ) + ), + 0, + 100 + ); + + // Parse Stream Description + $html = preg_replace('/<script.*<\/script>/', '', $html); + $html = explode(">", $html); + $desc_raw = implode("", preg_grep('/name="description"/', $html)); + $pattern = '/^.*content="(.*?)".*$/'; + $replacement = '\1'; + $desc = substr( + strip_tags( + preg_replace( + $pattern, + $replacement, + $desc_raw + ) + ), + 0, + 500 + ); + + } + + // Fill Streams array + array_push($streams["desc"], $desc); + array_push($streams["game"], $game); + array_push($streams["time"], (time() - $time0)); + +} + +?> diff --git a/lib/loadingscreen.php b/lib/loadingscreen.php @@ -0,0 +1,36 @@ +<?php + +$content = "<h1 style='text-align:center;'>Please be patient</h1>" . + "<p style='text-align:center;'>Loading " . + sizeof($streams["stream"]) . + " streams. This may take a moment.</p>" . + "<br>" . + /* Loading Screen Animation */ + "<div class='wrapper-loading'>" . + "<div class='box-wrap'>" . + "<div class='box one'></div>" . + "<div class='box two'></div>" . + "<div class='box three'></div>" . + "<div class='box four'></div>" . + "<div class='box five'></div>" . + "<div class='box six'></div>" . + "</div>" . + "</div>" . + /* Streams-form */ + "<form id='channels' action='/' method='post'>" . + "<input " . + "type='hidden' " . + "id='streams' " . + "name='streams' ". + "value='" . serialize($streams["stream"]) ."'" . + ">" . + /* Form Submitter */ + "<script>" . + "setTimeout(" . + "function(){" . + "document.querySelector('#channels').submit()" . + "}, " . + "1000);" . + "</script>"; + +?> diff --git a/template.html b/template.html @@ -0,0 +1,33 @@ +<!-- SPDX-License-Identifier: AGPL-3.0-or-later + SPDX-FileCopyrightText: 2021-2024 JayVii <jayvii[AT]posteo[DOT]de> +--> + +<!DOCTYPE html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <!-- Title may be filled in by script --> + <title>%%TITLE%%</title> + <link rel="icon" type="image/png" href="/assets/favicon.png"> + <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon_16.png"> + <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon_32.png"> + <link rel="icon" type="image/png" sizes="64x64" href="/assets/favicon_64.png"> + <link rel="icon" type="image/png" sizes="128x128" href="/assets/favicon_128.png"> + <link rel="apple-touch-icon" href="/assets/favicon.png"> + <link rel="stylesheet" type="text/css" href="/assets/css/stylesheet.css"/> + <link rel="stylesheet" href="/assets/css/loading.css" /> + <script async src="/assets/js/twitch.js"></script> + <link crossorigin="use-credentials" rel="manifest" href="/manifest.json"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + </head> + + <body class="list dark"> + <main class="main"> + + <h1>Videos</h1> + <button class="button"><a href="/">&#8962; All Videos</a></button> + <a href="reload.php"><button class="button">&#10227; Refresh</button></a><br> + <form action="https://www.twitch.tv/search" method="GET" style="width:100%;"> + <input id="searchbar" type="text" id="searchInput" name="term" placeholder="&#128269; Search..."> + </form><br> + + <!-- HERE COMES SCRIPT GENERATED CONTENT -->