ChandimaPrabath commited on
Commit
f505705
·
1 Parent(s): 632ec73

test player

Browse files
Files changed (4) hide show
  1. app.py +44 -9
  2. templates/film_details_page.html +1 -1
  3. templates/film_player.html +69 -30
  4. video.py +74 -16
app.py CHANGED
@@ -1,10 +1,10 @@
1
- # app.py
2
  from flask import Flask, jsonify, render_template, request, Response
3
  import os
4
  import json
5
  import re
6
  import urllib.parse
7
  from threading import Thread
 
8
  from video import ffmpeg_stream
9
  from indexer import indexer
10
  from dotenv import load_dotenv
@@ -92,8 +92,22 @@ def start_prefetching():
92
  prefetch_metadata()
93
 
94
  def generate(file_url):
 
 
 
 
 
 
 
 
 
95
  token = TOKEN
96
- output_stream = ffmpeg_stream(file_url, token)
 
 
 
 
 
97
 
98
  thread = Thread(target=start_prefetching)
99
  thread.daemon = True
@@ -111,7 +125,10 @@ def tvshow_player():
111
 
112
  @app.route('/film_player')
113
  def film_player():
114
- return render_template('film_player.html')
 
 
 
115
 
116
  @app.route('/films')
117
  def films():
@@ -184,18 +201,36 @@ def get_metadata():
184
 
185
  return jsonify({'error': 'Metadata not found'}), 404
186
 
187
- @app.route('/stream')
 
 
 
 
188
  def stream_video():
189
  file_path = request.args.get('path')
190
  if not file_path:
191
  return "File path not provided", 400
192
 
193
  file_url = f"https://huggingface.co/{REPO}/resolve/main/{file_path}"
194
- return Response(generate(file_url), mimetype="video/mp4")
195
-
196
- @app.route('/film/<path:title>')
197
- def film_details(title):
198
- return render_template('film_details_page.html', title=title)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  if __name__ == '__main__':
201
  app.run(debug=True, host="0.0.0.0", port=7860)
 
 
1
  from flask import Flask, jsonify, render_template, request, Response
2
  import os
3
  import json
4
  import re
5
  import urllib.parse
6
  from threading import Thread
7
+ import uuid
8
  from video import ffmpeg_stream
9
  from indexer import indexer
10
  from dotenv import load_dotenv
 
92
  prefetch_metadata()
93
 
94
  def generate(file_url):
95
+ # Generate a unique stream ID
96
+ stream_id = str(uuid.uuid4())
97
+ output_dir = os.path.join(CACHE_DIR, "stream", stream_id)
98
+
99
+ # Ensure output directory exists
100
+ if not os.path.exists(output_dir):
101
+ os.makedirs(output_dir)
102
+
103
+ # Set up HLS streaming
104
  token = TOKEN
105
+ output_path, process = ffmpeg_stream(file_url, token, output_dir=output_dir)
106
+
107
+ if output_path:
108
+ # Return the unique stream ID for later use
109
+ return stream_id
110
+ return None
111
 
112
  thread = Thread(target=start_prefetching)
113
  thread.daemon = True
 
125
 
126
  @app.route('/film_player')
127
  def film_player():
128
+ title = request.args.get('title')
129
+ if not title:
130
+ return "No film title provided", 400
131
+ return render_template('film_player.html', title=urllib.parse.unquote(title))
132
 
133
  @app.route('/films')
134
  def films():
 
201
 
202
  return jsonify({'error': 'Metadata not found'}), 404
203
 
204
+ @app.route('/film/<path:title>')
205
+ def film_details(title):
206
+ return render_template('film_details_page.html', title=title)
207
+
208
+ @app.route('/api/stream')
209
  def stream_video():
210
  file_path = request.args.get('path')
211
  if not file_path:
212
  return "File path not provided", 400
213
 
214
  file_url = f"https://huggingface.co/{REPO}/resolve/main/{file_path}"
215
+ stream_id = generate(file_url)
216
+
217
+ if stream_id:
218
+ # Return the UUID for the client to use
219
+ return jsonify({'stream_id': stream_id})
220
+
221
+ return "Streaming error", 500
222
+
223
+ @app.route('/stream/<stream_id>')
224
+ def stream_file(stream_id):
225
+ stream_dir = os.path.join(CACHE_DIR, "stream", stream_id)
226
+ playlist_path = os.path.join(stream_dir, 'output.m3u8')
227
+
228
+ if os.path.exists(playlist_path):
229
+ return Response(
230
+ open(playlist_path, 'rb').read(),
231
+ mimetype='application/vnd.apple.mpegurl'
232
+ )
233
+ return "Stream not found", 404
234
 
235
  if __name__ == '__main__':
236
  app.run(debug=True, host="0.0.0.0", port=7860)
templates/film_details_page.html CHANGED
@@ -172,7 +172,7 @@
172
  metadataContainer.appendChild(createMetadataElement('Release Date', metadata.first_air_time));
173
 
174
  const playButton = document.getElementById('play-button');
175
- playButton.href = `/stream?path=${encodeURIComponent(data.file_path)}`;
176
  }
177
 
178
  const urlParams = new URLSearchParams(window.location.search);
 
172
  metadataContainer.appendChild(createMetadataElement('Release Date', metadata.first_air_time));
173
 
174
  const playButton = document.getElementById('play-button');
175
+ playButton.href = `/film_player?title=${encodeURIComponent(title)}`;
176
  }
177
 
178
  const urlParams = new URLSearchParams(window.location.search);
templates/film_player.html CHANGED
@@ -1,50 +1,89 @@
1
  <!DOCTYPE html>
2
- <html>
3
  <head>
4
- <title>Media Player</title>
 
 
5
  <style>
6
  body {
7
  font-family: Arial, sans-serif;
8
- background-color: #141414;
9
- color: #fff;
10
  margin: 0;
11
  padding: 0;
 
12
  }
13
- .header {
14
- background-color: #000;
15
- padding: 20px;
16
- text-align: center;
17
- }
18
- .header h1 {
19
- margin: 0;
20
- font-size: 24px;
21
- }
22
- .content {
23
- padding: 20px;
24
- }
25
- .player-container {
26
- max-width: 100%;
27
  margin: auto;
28
- text-align: center;
 
 
 
29
  }
30
  video {
31
  width: 100%;
32
  height: auto;
33
- background-color: #333;
 
 
 
 
 
 
 
 
 
 
34
  }
35
  </style>
36
  </head>
37
  <body>
38
- <div class="header">
39
- <h1>Movie Player</h1>
40
- </div>
41
- <div class="content">
42
- <div class="player-container">
43
- <video id="videoPlayer" controls>
44
- <source id="videoSource" type="video/mp4">
45
- Your browser does not support the video tag.
46
- </video>
47
- </div>
48
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  </body>
50
  </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Film Player</title>
7
  <style>
8
  body {
9
  font-family: Arial, sans-serif;
 
 
10
  margin: 0;
11
  padding: 0;
12
+ background-color: #f0f0f0;
13
  }
14
+ .container {
15
+ max-width: 800px;
 
 
 
 
 
 
 
 
 
 
 
 
16
  margin: auto;
17
+ padding: 20px;
18
+ background-color: #fff;
19
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
20
+ border-radius: 8px;
21
  }
22
  video {
23
  width: 100%;
24
  height: auto;
25
+ border-radius: 8px;
26
+ }
27
+ .title {
28
+ font-size: 24px;
29
+ font-weight: bold;
30
+ margin-bottom: 20px;
31
+ }
32
+ .error {
33
+ color: red;
34
+ font-size: 18px;
35
+ margin-top: 20px;
36
  }
37
  </style>
38
  </head>
39
  <body>
40
+ <div class="container">
41
+ <div class="title" id="filmTitle">Film Title</div>
42
+ <video id="videoPlayer" controls>
43
+ <source id="videoSource" type="application/vnd.apple.mpegurl">
44
+ Your browser does not support the video tag.
45
+ </video>
46
+ <div id="error" class="error"></div>
 
 
 
47
  </div>
48
+
49
+ <script>
50
+ document.addEventListener("DOMContentLoaded", function() {
51
+ const queryParams = new URLSearchParams(window.location.search);
52
+ const filmTitle = queryParams.get('title');
53
+
54
+ if (!filmTitle) {
55
+ document.getElementById('error').innerText = 'No film title provided.';
56
+ return;
57
+ }
58
+
59
+ // Display the film title
60
+ document.getElementById('filmTitle').innerText = decodeURIComponent(filmTitle);
61
+
62
+ // Fetch film metadata and stream URL
63
+ fetch(`/api/film/${encodeURIComponent(filmTitle)}`)
64
+ .then(response => response.json())
65
+ .then(data => {
66
+ if (data.file_path) {
67
+ return fetch(`/api/stream?path=${encodeURIComponent(data.file_path)}`);
68
+ } else {
69
+ throw new Error('File path not found.');
70
+ }
71
+ })
72
+ .then(response => response.json())
73
+ .then(data => {
74
+ if (data.stream_id) {
75
+ // Update video source with the stream URL
76
+ const videoSource = document.getElementById('videoSource');
77
+ videoSource.src = `/stream/${data.stream_id}`;
78
+ document.getElementById('videoPlayer').load();
79
+ } else {
80
+ throw new Error('Stream ID not found.');
81
+ }
82
+ })
83
+ .catch(error => {
84
+ document.getElementById('error').innerText = `Error: ${error.message}`;
85
+ });
86
+ });
87
+ </script>
88
  </body>
89
  </html>
video.py CHANGED
@@ -1,21 +1,79 @@
1
- from ffmpy import FFmpeg
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- def ffmpeg_stream(file_url,token, output="tmp/cache/output.mp4"):
4
  try:
5
- # Set up the FFmpeg command with quality options
6
- ff = FFmpeg(
7
- inputs={
8
- file_url: None
9
- },
10
- outputs={
11
- f'{output}': '-c:v libx264 -crf 23 -preset medium -c:a aac -b:a 192k'
12
- },
13
- global_options= f'-headers "Authorization: Bearer {token}"'
14
- )
15
 
16
- # Run the command
17
- ff.run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  except Exception as e:
20
- print(f"Error using FFmpeg to stream file: {e}")
21
- return None
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+ import logging
4
+ import uuid
5
+
6
+ # Set up logging
7
+ logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
8
+
9
+ def ffmpeg_stream(file_url, token, output_dir="tmp/cache/stream"):
10
+ # Create unique directory for each stream using UUID
11
+ stream_id = str(uuid.uuid4())
12
+ stream_dir = os.path.join(output_dir, stream_id)
13
+
14
+ if not os.path.exists(stream_dir):
15
+ os.makedirs(stream_dir)
16
+ logging.info(f"Created directory: {stream_dir}")
17
+ else:
18
+ logging.info(f"Directory already exists: {stream_dir}")
19
+
20
+ # Set up the FFmpeg command for HLS
21
+ output_path = os.path.join(stream_dir, 'output.m3u8')
22
+ segment_filename = os.path.join(stream_dir, 'segment_%03d.ts')
23
+
24
+ ffmpeg_command = [
25
+ 'ffmpeg',
26
+ '-headers', f'Authorization: Bearer {token}',
27
+ '-i', file_url,
28
+ '-c:v', 'libx264',
29
+ '-crf', '23',
30
+ '-preset', 'medium',
31
+ '-c:a', 'aac',
32
+ '-b:a', '192k',
33
+ '-f', 'hls',
34
+ '-hls_time', '10',
35
+ '-hls_list_size', '0',
36
+ '-hls_segment_filename', segment_filename,
37
+ output_path
38
+ ]
39
 
 
40
  try:
41
+ # Log the command being executed
42
+ logging.debug(f"Running FFmpeg command: {' '.join(ffmpeg_command)}")
 
 
 
 
 
 
 
 
43
 
44
+ # Run the FFmpeg command
45
+ process = subprocess.Popen(
46
+ ffmpeg_command,
47
+ stdout=subprocess.PIPE,
48
+ stderr=subprocess.PIPE
49
+ )
50
+
51
+ # Capture stdout and stderr
52
+ stdout, stderr = process.communicate()
53
+
54
+ # Log FFmpeg output
55
+ logging.debug("FFmpeg stdout: %s", stdout.decode())
56
+ logging.error("FFmpeg stderr: %s", stderr.decode())
57
+
58
+ # Check if the output file was created
59
+ if os.path.exists(output_path):
60
+ logging.info(f"HLS playlist created at {output_path}")
61
+ else:
62
+ logging.error(f"HLS playlist not created at {output_path}")
63
+
64
+ # Return the unique stream ID and process
65
+ return stream_id, process
66
 
67
  except Exception as e:
68
+ logging.error(f"Error using FFmpeg to stream file: {e}")
69
+ return None, None
70
+
71
+ # # Example usage
72
+ # if __name__ == "__main__":
73
+ # url = "https://huggingface.co/Unicone-Studio/jellyfin_media/resolve/main/films/Funky%20Monkey%202004/Funky%20Monkey%20(2004)%20Web-dl%201080p.mp4"
74
+ # token = os.getenv("TOKEN")
75
+ # stream_id, process = ffmpeg_stream(url, token)
76
+ # if stream_id:
77
+ # logging.info(f"HLS playlist created with stream ID: {stream_id}")
78
+ # else:
79
+ # logging.error("Failed to create HLS playlist.")