ServerX commited on
Commit
aec2a6e
·
verified ·
1 Parent(s): 7b3bbce

Create fma_player.py

Browse files
Files changed (1) hide show
  1. fma_player.py +260 -0
fma_player.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy as np
4
+ import os
5
+ import requests
6
+ from PIL import Image
7
+ import io
8
+ import time
9
+ import tempfile
10
+ from IPython.display import display, HTML
11
+
12
+ # Costanti per il rilevamento
13
+ MATCH_THRESHOLD = 0.8 # Soglia per il template matching (0-1)
14
+
15
+ # Funzione per caricare un'immagine da file o URL
16
+ def load_image(path_or_url):
17
+ try:
18
+ # Se è un URL
19
+ if path_or_url.startswith(('http://', 'https://')):
20
+ response = requests.get(path_or_url)
21
+ img = Image.open(io.BytesIO(response.content))
22
+ return np.array(img)
23
+ # Se è un percorso locale
24
+ else:
25
+ return cv2.imread(path_or_url)
26
+ except Exception as e:
27
+ print(f"Errore nel caricamento dell'immagine: {e}")
28
+ return None
29
+
30
+ # Funzione per il template matching
31
+ def compute_similarity(frame, ref):
32
+ if frame is None or ref is None:
33
+ return 0
34
+
35
+ # Converto da RGB a BGR se necessario
36
+ if len(frame.shape) == 3 and frame.shape[2] == 3:
37
+ frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
38
+ else:
39
+ frame_bgr = frame
40
+
41
+ # Ridimensiona la reference per adattarla al frame
42
+ ref_resized = cv2.resize(ref, (frame_bgr.shape[1], frame_bgr.shape[0]))
43
+
44
+ # Converto in scala di grigi
45
+ frame_gray = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2GRAY)
46
+ ref_gray = cv2.cvtColor(ref_resized, cv2.COLOR_BGR2GRAY)
47
+
48
+ # Template matching
49
+ res = cv2.matchTemplate(frame_gray, ref_gray, cv2.TM_CCOEFF_NORMED)
50
+ return res.max()
51
+
52
+ class FMAPlayer:
53
+ def __init__(self):
54
+ # URL degli episodi (sostituisci con i tuoi URL)
55
+ self.base_url = "https://example.com/fullmetal/episode_{:02d}.mp4"
56
+ self.episode_number = 1
57
+ self.current_url = self.base_url.format(self.episode_number)
58
+
59
+ # Percorsi delle immagini di riferimento (usa URL per Hugging Face)
60
+ self.reference_images = {
61
+ "intro_start": "https://raw.githubusercontent.com/your-repo/fma-player/main/intro_start.png",
62
+ "intro_end": "https://raw.githubusercontent.com/your-repo/fma-player/main/intro_end.png",
63
+ "outro_start": "https://raw.githubusercontent.com/your-repo/fma-player/main/outro_start.png"
64
+ }
65
+
66
+ # Carica le immagini di riferimento
67
+ self.ref_images = {}
68
+ for key, url in self.reference_images.items():
69
+ self.ref_images[key] = None # Inizialmente None, caricalo solo quando necessario
70
+
71
+ def load_references(self):
72
+ # Carica le immagini di riferimento solo quando necessario
73
+ for key, url in self.reference_images.items():
74
+ if self.ref_images[key] is None:
75
+ self.ref_images[key] = load_image(url)
76
+
77
+ def get_episode_url(self, episode_number):
78
+ return self.base_url.format(episode_number)
79
+
80
+ def detect_intro_outro(self, frame):
81
+ self.load_references()
82
+
83
+ # Controlla la similarità con l'immagine di inizio intro
84
+ sim_intro = compute_similarity(frame, self.ref_images["intro_start"])
85
+ if sim_intro >= MATCH_THRESHOLD:
86
+ return "intro", sim_intro
87
+
88
+ # Controlla la similarità con l'immagine di inizio outro
89
+ sim_outro = compute_similarity(frame, self.ref_images["outro_start"])
90
+ if sim_outro >= MATCH_THRESHOLD:
91
+ return "outro", sim_outro
92
+
93
+ return None, 0
94
+
95
+ # Interfaccia Gradio
96
+ def create_interface():
97
+ player = FMAPlayer()
98
+
99
+ # CSS personalizzato per migliorare l'aspetto dell'interfaccia
100
+ css = """
101
+ body {
102
+ background-color: #1e1e2e;
103
+ color: #cdd6f4;
104
+ font-family: 'Segoe UI', Arial, sans-serif;
105
+ }
106
+
107
+ .gradio-container {
108
+ max-width: 1200px !important;
109
+ }
110
+
111
+ h1, h2, h3 {
112
+ color: #cba6f7;
113
+ }
114
+
115
+ .fma-title {
116
+ font-size: 24px;
117
+ font-weight: bold;
118
+ text-align: center;
119
+ margin-bottom: 20px;
120
+ color: #cba6f7;
121
+ }
122
+
123
+ button, select, .gradio-button {
124
+ background-color: #313244 !important;
125
+ color: #cdd6f4 !important;
126
+ border: none !important;
127
+ padding: 10px !important;
128
+ border-radius: 6px !important;
129
+ font-weight: bold !important;
130
+ }
131
+
132
+ button:hover, select:hover, .gradio-button:hover {
133
+ background-color: #45475a !important;
134
+ }
135
+
136
+ .video-container {
137
+ border-radius: 10px;
138
+ overflow: hidden;
139
+ background-color: #11111b;
140
+ }
141
+
142
+ .special-button {
143
+ background-color: #7f849c !important;
144
+ color: #1e1e2e !important;
145
+ }
146
+
147
+ .special-button:hover {
148
+ background-color: #9399b2 !important;
149
+ }
150
+
151
+ .footer {
152
+ margin-top: 20px;
153
+ text-align: center;
154
+ font-size: 12px;
155
+ color: #9399b2;
156
+ }
157
+ """
158
+
159
+ # Funzione per gestire il cambio di episodio
160
+ def change_episode(episode_num):
161
+ player.episode_number = episode_num
162
+ player.current_url = player.get_episode_url(episode_num)
163
+ return player.current_url, f"Fullmetal Alchemist Brotherhood - Episodio {episode_num:02d}"
164
+
165
+ # Funzione per saltare l'intro
166
+ def skip_intro():
167
+ return "Skip intro attivato"
168
+
169
+ # Funzione per saltare l'outro
170
+ def skip_outro():
171
+ next_ep = player.episode_number + 1
172
+ if next_ep <= 64:
173
+ url, title = change_episode(next_ep)
174
+ return f"Caricato episodio successivo: {next_ep}"
175
+ else:
176
+ return "Fine della serie raggiunta!"
177
+
178
+ # Creazione dell'interfaccia Gradio
179
+ with gr.Blocks(css=css) as interface:
180
+ gr.HTML("<div class='fma-title'>Fullmetal Alchemist Brotherhood Player</div>")
181
+
182
+ with gr.Row():
183
+ with gr.Column(scale=3):
184
+ # Titolo episodio
185
+ title = gr.Textbox(value=f"Fullmetal Alchemist Brotherhood - Episodio {player.episode_number:02d}",
186
+ label="",
187
+ interactive=False)
188
+
189
+ # Container video
190
+ with gr.Box(elem_classes=["video-container"]):
191
+ video = gr.Video(
192
+ player.current_url,
193
+ label="",
194
+ width=800,
195
+ height=450,
196
+ interactive=True,
197
+ autoplay=True
198
+ )
199
+
200
+ # Controlli
201
+ with gr.Row():
202
+ rewind_btn = gr.Button("⏪ 10s", elem_classes=["control-button"])
203
+ play_pause_btn = gr.Button("⏯️ Play/Pausa", elem_classes=["special-button", "control-button"])
204
+ forward_btn = gr.Button("10s ⏩", elem_classes=["control-button"])
205
+ skip_intro_btn = gr.Button("Salta Intro", elem_classes=["control-button"])
206
+ skip_outro_btn = gr.Button("Salta Outro", elem_classes=["control-button"])
207
+
208
+ # Volume
209
+ with gr.Row():
210
+ volume_slider = gr.Slider(0, 100, 75, label="Volume")
211
+
212
+ with gr.Column(scale=1):
213
+ # Selettore episodi
214
+ episode_selector = gr.Dropdown(
215
+ [f"Episodio {i:02d}" for i in range(1, 64)],
216
+ value=f"Episodio {player.episode_number:02d}",
217
+ label="Seleziona Episodio"
218
+ )
219
+
220
+ # Informazioni sull'episodio
221
+ episode_info = gr.Textbox(
222
+ "Questo è l'episodio 1 di Fullmetal Alchemist Brotherhood.",
223
+ label="Informazioni Episodio",
224
+ interactive=False,
225
+ lines=8
226
+ )
227
+
228
+ # Status
229
+ status = gr.Textbox(
230
+ "Player pronto",
231
+ label="Status",
232
+ interactive=False
233
+ )
234
+
235
+ # Eventi
236
+ skip_intro_btn.click(skip_intro, inputs=[], outputs=[status])
237
+ skip_outro_btn.click(skip_outro, inputs=[], outputs=[status])
238
+
239
+ # Conversione dell'indice episodio
240
+ def parse_episode(ep_str):
241
+ return int(ep_str.split()[1])
242
+
243
+ # Evento cambio episodio
244
+ episode_selector.change(
245
+ lambda ep_str: change_episode(parse_episode(ep_str)),
246
+ inputs=[episode_selector],
247
+ outputs=[video, title]
248
+ )
249
+
250
+ gr.HTML("<div class='footer'>Powered by Hugging Face Spaces | Fullmetal Alchemist Brotherhood Player</div>")
251
+
252
+ return interface
253
+
254
+ # Creazione e avvio dell'app
255
+ def main():
256
+ interface = create_interface()
257
+ interface.launch()
258
+
259
+ if __name__ == "__main__":
260
+ main()