File size: 9,029 Bytes
176b41e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#!/usr/bin/env python3
"""
Video Player Web App - Read-only video streaming server.
Loads videos from the 'playlist' folder and serves them via a web interface.
"""

import os
import json
import mimetypes
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import unquote, urlparse
import re

PLAYLIST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "playlist")
PORT = 8080

VIDEO_EXTENSIONS = {".mp4", ".webm", ".mov", ".m4v", ".avi", ".mkv", ".ogg", ".ogv"}


def get_video_files():
    """Get list of video files from playlist directory."""
    videos = []
    if not os.path.isdir(PLAYLIST_DIR):
        return videos
    
    for filename in sorted(os.listdir(PLAYLIST_DIR)):
        ext = os.path.splitext(filename)[1].lower()
        if ext in VIDEO_EXTENSIONS:
            filepath = os.path.join(PLAYLIST_DIR, filename)
            size = os.path.getsize(filepath)
            videos.append({
                "name": filename,
                "title": os.path.splitext(filename)[0].replace("_", " ").replace("-", " ").title(),
                "path": f"/playlist/{filename}",
                "size": size,
                "size_human": f"{size / (1024*1024):.1f} MB"
            })
    return videos


class VideoPlayerHandler(SimpleHTTPRequestHandler):
    """Custom handler for video player - read-only, no modifications allowed."""
    
    def do_GET(self):
        path = urlparse(self.path).path
        
        if path == "/" or path == "/index.html":
            self.serve_index()
        elif path == "/api/playlist":
            self.serve_playlist_api()
        elif path.startswith("/playlist/"):
            self.serve_video(path)
        elif path == "/style.css":
            self.serve_static("style.css", "text/css")
        elif path == "/script.js":
            self.serve_static("script.js", "application/javascript")
        else:
            self.send_error(404, "Not Found")
    
    def do_POST(self):
        self.send_error(405, "Method Not Allowed - Read Only")
    
    def do_PUT(self):
        self.send_error(405, "Method Not Allowed - Read Only")
    
    def do_DELETE(self):
        self.send_error(405, "Method Not Allowed - Read Only")
    
    def serve_index(self):
        """Serve the main HTML page."""
        html = self.get_index_html()
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", len(html.encode()))
        self.end_headers()
        self.wfile.write(html.encode())
    
    def serve_playlist_api(self):
        """Serve playlist as JSON."""
        videos = get_video_files()
        data = json.dumps({"videos": videos})
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", len(data.encode()))
        self.end_headers()
        self.wfile.write(data.encode())
    
    def serve_video(self, path):
        """Serve video file with range support for seeking."""
        filename = unquote(path.replace("/playlist/", ""))
        if "/" in filename or ".." in filename:
            self.send_error(403, "Forbidden")
            return
        
        filepath = os.path.join(PLAYLIST_DIR, filename)
        if not os.path.isfile(filepath):
            self.send_error(404, "Video Not Found")
            return
        
        file_size = os.path.getsize(filepath)
        content_type, _ = mimetypes.guess_type(filepath)
        if not content_type:
            content_type = "video/mp4"
        
        range_header = self.headers.get("Range")
        if range_header:
            range_match = re.match(r"bytes=(\d+)-(\d*)", range_header)
            if range_match:
                start = int(range_match.group(1))
                end = int(range_match.group(2)) if range_match.group(2) else file_size - 1
                end = min(end, file_size - 1)
                length = end - start + 1
                
                self.send_response(206)
                self.send_header("Content-Type", content_type)
                self.send_header("Content-Length", length)
                self.send_header("Content-Range", f"bytes {start}-{end}/{file_size}")
                self.send_header("Accept-Ranges", "bytes")
                self.end_headers()
                
                with open(filepath, "rb") as f:
                    f.seek(start)
                    remaining = length
                    chunk_size = 64 * 1024
                    while remaining > 0:
                        chunk = f.read(min(chunk_size, remaining))
                        if not chunk:
                            break
                        self.wfile.write(chunk)
                        remaining -= len(chunk)
                return
        
        self.send_response(200)
        self.send_header("Content-Type", content_type)
        self.send_header("Content-Length", file_size)
        self.send_header("Accept-Ranges", "bytes")
        self.end_headers()
        
        with open(filepath, "rb") as f:
            chunk_size = 64 * 1024
            while True:
                chunk = f.read(chunk_size)
                if not chunk:
                    break
                self.wfile.write(chunk)
    
    def serve_static(self, filename, content_type):
        """Serve static files (CSS, JS)."""
        filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
        if not os.path.isfile(filepath):
            self.send_error(404, "Not Found")
            return
        
        with open(filepath, "r", encoding="utf-8") as f:
            content = f.read()
        
        self.send_response(200)
        self.send_header("Content-Type", f"{content_type}; charset=utf-8")
        self.send_header("Content-Length", len(content.encode()))
        self.end_headers()
        self.wfile.write(content.encode())
    
    def get_index_html(self):
        return '''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Video demos of apps</title>
    <link rel="stylesheet" href="/style.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>๐ŸŽฌ Video demos of apps</h1>
        </header>
        
        <main>
            <div class="player-section">
                <div class="video-container">
                    <video id="videoPlayer" controls>
                        <source src="" type="video/mp4">
                        Your browser does not support the video tag.
                    </video>
                    <div class="video-overlay" id="videoOverlay">
                        <span>Select a video from the playlist</span>
                    </div>
                </div>
                
                <div class="controls-bar">
                    <div class="now-playing" id="nowPlaying">
                        <span class="label">Now Playing:</span>
                        <span class="title" id="currentTitle">-</span>
                    </div>
                    <div class="playback-controls">
                        <button id="prevBtn" title="Previous">โฎ</button>
                        <button id="playPauseBtn" title="Play/Pause">โ–ถ</button>
                        <button id="nextBtn" title="Next">โญ</button>
                        <button id="muteBtn" title="Mute">๐Ÿ”Š</button>
                        <input type="range" id="volumeSlider" min="0" max="1" step="0.1" value="1" title="Volume">
                        <button id="fullscreenBtn" title="Fullscreen">โ›ถ</button>
                    </div>
                </div>
            </div>
            
            <aside class="playlist-section">
                <h2>๐Ÿ“‹ Playlist</h2>
                <div class="playlist" id="playlist">
                    <div class="loading">Loading playlist...</div>
                </div>
            </aside>
        </main>
        
        <footer>
            <p>Read-only Video Player โ€ข Videos cannot be modified or deleted</p>
        </footer>
    </div>
    
    <script src="/script.js"></script>
</body>
</html>'''

    def log_message(self, format, *args):
        print(f"[{self.log_date_time_string()}] {args[0]}")


def main():
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    
    videos = get_video_files()
    print(f"\n{'='*50}")
    print("๐ŸŽฌ Video Player Server")
    print(f"{'='*50}")
    print(f"๐Ÿ“ Playlist folder: {PLAYLIST_DIR}")
    print(f"๐ŸŽฅ Videos found: {len(videos)}")
    for v in videos:
        print(f"   โ€ข {v['name']} ({v['size_human']})")
    print(f"\n๐ŸŒ Server starting at: http://localhost:{PORT}")
    print(f"{'='*50}\n")
    
    server = HTTPServer(("", PORT), VideoPlayerHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\n\nServer stopped.")
        server.shutdown()


if __name__ == "__main__":
    main()