rustream/templates/
profile.rs

1/// Get the HTML content to render the profile page.
2///
3/// # See Also
4///
5/// - This page is served as a response for the `/profile` entry point.
6///
7/// # Returns
8///
9/// A `String` version of the HTML, CSS and JS content.
10pub fn get_content() -> String {
11    r###"<!DOCTYPE html>
12<!--suppress JSUnresolvedLibraryURL -->
13<html lang="en">
14<head>
15    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
16    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
17    <meta http-equiv="Pragma" content="no-cache">
18    <meta http-equiv="Expires" content="0">
19    <title>RuStream - Self-hosted Streaming Engine - v{{ version }}</title>
20    <meta property="og:type" content="MediaStreaming">
21    <meta name="keywords" content="Rust, streaming, actix, JavaScript, HTML, CSS">
22    <meta name="author" content="Vignesh Rao">
23    <meta content="width=device-width, initial-scale=1" name="viewport">
24    <!-- Favicon.ico and Apple Touch Icon -->
25    <link rel="icon" href="https://thevickypedia.github.io/open-source/images/logo/actix.ico">
26    <link rel="apple-touch-icon" href="https://thevickypedia.github.io/open-source/images/logo/actix.png">
27    <!-- Font Awesome icons -->
28    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/fontawesome.min.css">
29    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/solid.css">
30    <!-- CSS and JS for night mode -->
31    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
32    <script type="text/javascript" src="https://thevickypedia.github.io/open-source/nightmode/night.js" defer></script>
33    <link rel="stylesheet" type="text/css" href="https://thevickypedia.github.io/open-source/nightmode/night.css">
34    <!-- Button CSS -->
35    <style>
36        /* Google fonts with a backup alternative */
37        @import url('https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;500;700&display=swap');
38        * {
39            font-family: 'Ubuntu', 'PT Serif', sans-serif;
40        }
41        body {
42            margin-left: 1%;  /* 1% away from left corner */
43            padding: 0.5%  /* 0.5% away from any surrounding elements */
44        }
45        .upload {
46            position: absolute;
47            top: 3.8%;
48            right: 313px;
49            border: none;
50            padding: 10px 14px;
51            font-size: 16px;
52            cursor: pointer;
53        }
54        .home {
55            position: absolute;
56            top: 3.8%;
57            right: 217px;
58            border: none;
59            padding: 10px 14px;
60            font-size: 16px;
61            cursor: pointer;
62        }
63        .back {
64            position: absolute;
65            top: 3.8%;
66            right: 132px;
67            border: none;
68            padding: 10px 14px;
69            font-size: 16px;
70            cursor: pointer;
71        }
72    </style>
73    <style>
74        .dropbtn {
75            position: absolute;
76            top: 3.8%;
77            right: 30px;
78            padding: 10px 24px;
79            font-size: 16px;
80            border: none;
81            cursor: pointer;
82        }
83        .dropdown {
84            position: absolute;
85            top: 3.8%;
86            right: 30px;
87            padding: 10px 24px;
88            display: inline-block;
89        }
90        .dropdown-content {
91            display: none;
92            position: absolute;
93            top: 40px;  /* Distance from the user icon button */
94            right: 30px;
95            width: 160px;
96            min-width: auto;
97            box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);  /* Basically, black with 20% opacity */
98            z-index: 1;
99        }
100        .dropdown-content a {
101            padding: 12px 16px;
102            text-decoration: none;
103            display: block;
104        }
105        .dropdown:hover .dropdown-content {display: block;}
106    </style>
107    <!-- Title list CSS -->
108    <style>
109        a:hover, a:active { font-size: 120%; opacity: 0.7; }
110        a:link { color: blue; }
111        a:visited { color: blue; }
112    </style>
113</head>
114<noscript>
115    <style>
116        body {
117            width: 100%;
118            height: 100%;
119            overflow: hidden;
120        }
121    </style>
122    <div style="position: fixed; text-align:center; height: 100%; width: 100%; background-color: #151515;">
123        <h2 style="margin-top:5%">This page requires JavaScript
124            to be enabled.
125            <br><br>
126            Please refer <a href="https://www.enable-javascript.com/">enable-javascript</a> for how to.
127        </h2>
128        <form>
129            <button type="submit" onClick="<meta httpEquiv='refresh' content='0'>">RETRY</button>
130        </form>
131    </div>
132</noscript>
133<body translate="no" onload="displayTimer(); displayExpiryUTC(); displayExpiryLocal()">
134<div class="toggler fa fa-moon-o"></div>
135<button class="upload" onclick="upload()"><i class="fa-solid fa-cloud-arrow-up"></i> Upload</button>
136<button class="home" onclick="goHome()"><i class="fa fa-home"></i> Home</button>
137<button class="back" onclick="goBack()"><i class="fa fa-backward"></i> Back</button>
138<div class="dropdown">
139    <button class="dropbtn"><i class="fa fa-user"></i></button>
140    <div class="dropdown-content">
141        <a onclick="goProfile()" style="cursor: pointer;"><i class="fa-solid fa-user-lock"></i> {{ user }}</a>
142        <a onclick="logOut()" style="cursor: pointer"><i class="fa fa-sign-out"></i> logout</a>
143    </div>
144</div>
145<br><br><br><br>
146<hr>
147<br><br>
148<h4 style="text-align: center">Welcome {{ user }}</h3>
149<h4>Session Validity</h4>
150<p id="secondsCountDown"><p>
151<p id="validityUTC"></h5>
152<p id="validityLocal"></h5>
153{% if file %}
154    <h4>Last Accessed</h4>
155    <i class="{{ file.font }}"></i>&nbsp;&nbsp;<a href="{{ file.path }}">{{ file.name }}</a>
156{% endif %}
157<script>
158    function goHome() { window.location.href = "/home"; }
159    function goProfile() { window.location.href = '/profile'; }
160    function logOut() { window.location.href = "/logout"; }
161    function upload() { window.location.href = "/upload"; }
162    function goBack() { window.history.back(); }
163</script>
164<script>
165    function secondsToStr(seconds) {
166        let levels = [
167            [Math.floor(seconds / 31536000), 'years'],
168            [Math.floor((seconds % 31536000) / 86400), 'days'],
169            [Math.floor(((seconds % 31536000) % 86400) / 3600), 'hours'],
170            [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'minutes'],
171            [Math.floor((((seconds % 31536000) % 86400) % 3600) % 60), 'seconds'],
172        ];
173        let returntext = '';
174
175        for (let i = 0, max = levels.length; i < max; i++) {
176            if (levels[i][0] === 0) continue;
177            returntext += ', ' + levels[i][0] + ' ' + (levels[i][0] === 1 ? levels[i][1].substr(0, levels[i][1].length - 1) : levels[i][1]);
178        }
179        return returntext.trim();
180    }
181
182    function displayTimer() {
183        let seconds = '{{ time_left }}';
184        let display = document.getElementById('secondsCountDown');
185        display.innerHTML = secondsToStr(seconds).substring(1);
186        let countdown = setInterval(function () {
187            seconds--;
188            display.innerHTML = secondsToStr(seconds).substring(1) + "s";
189            if (seconds <= 0) {
190                clearInterval(countdown);
191            }
192        }, 1000);
193    }
194</script>
195<script>
196    function displayExpiryUTC() {
197        let seconds = '{{ time_left }}';
198        let expiryTime = new Date(Date.now() + seconds * 1000);
199        let display = document.getElementById('validityUTC');
200        display.innerHTML = expiryTime.toUTCString();
201    }
202</script>
203<script>
204    function displayExpiryLocal() {
205        let seconds = '{{ time_left }}';
206        let expiryTime = new Date(Date.now() + seconds * 1000);
207        let display = document.getElementById('validityLocal');
208        // Options for date and time formatting
209        let options = {
210            weekday: 'short',
211            day: '2-digit',
212            month: 'short',
213            year: 'numeric',
214            hour: '2-digit',
215            minute: '2-digit',
216            second: '2-digit',
217            timeZoneName: 'short'
218        };
219        display.innerHTML = expiryTime.toLocaleString('en-US', options);
220    }
221
222    function setCookieWithShortExpiration(name, value, secondsToExpire) {
223        // Calculate the expiration date
224        var expirationDate = new Date();
225        expirationDate.setTime(expirationDate.getTime() + (secondsToExpire * 1000)); // Convert seconds to milliseconds
226
227        // Construct the cookie string
228        var cookieString = name + "=" + encodeURIComponent(value);
229        cookieString += "; expires=" + expirationDate.toUTCString();
230
231        // Set the cookie
232        document.cookie = cookieString;
233    }
234
235    setInterval(function () {
236        setCookieWithShortExpiration("detail", "Session Expired", 5);
237        window.location.href = "/error";
238    }, {{ time_left }} * 1000 - 1000); // Convert time_left to milliseconds and subract 1 second
239</script>
240</body>
241</html>
242"###.to_string()
243}