Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.

Commit e9a5dc0

Browse files
committed
Refactor filebrowser uploader to disable SSL verification and implement upload callback mechanism
1 parent 11b9b81 commit e9a5dc0

2 files changed

Lines changed: 83 additions & 50 deletions

File tree

filebrowser_uploader.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ async def get_public_share_url(file_relative_path: str, token: str) -> str:
5252
f"{FILEBROWSER_URL}/api/share/{file_relative_path}",
5353
headers=headers,
5454
json={"path": f"/{file_relative_path}"},
55+
ssl=False, # This explicitly tells aiohttp not to use SSL
5556
) as response:
5657
if response.status != 200:
5758
body = await response.text()
@@ -67,6 +68,7 @@ async def get_filebrowser_token():
6768
async with session.post(
6869
f"{FILEBROWSER_URL}/api/login",
6970
json={"username": FILEBROWSER_USERNAME, "password": FILEBROWSER_PASSWORD},
71+
ssl=False, # This explicitly tells aiohttp not to use SSL
7072
) as response:
7173
token = await response.text()
7274
return token.strip()
@@ -77,6 +79,7 @@ async def delete_existing_file(file_relative_path: str, token: str):
7779
async with session.delete(
7880
f"{FILEBROWSER_URL}/api/resources/{file_relative_path}",
7981
headers={"X-Auth": token},
82+
ssl=False
8083
) as response:
8184
if response.status not in [200, 204, 404]:
8285
body = await response.text()
@@ -101,6 +104,7 @@ async def upload_to_filebrowser(file_path, file_name) -> str:
101104
f"{FILEBROWSER_URL}/api/resources/{FILEBROWSER_UPLOAD_PATH}/{file_name}",
102105
headers=headers,
103106
data=form,
107+
ssl=False, # This explicitly tells aiohttp not to use SSL
104108
) as response:
105109
if response.status != 200:
106110
body = await response.text()
@@ -145,12 +149,12 @@ async def upload(
145149
if __name__ == "__main__":
146150
asyncio.run(
147151
upload(
148-
"Glenwayprivate - Unspecified description - February 20 Thursday 2025 08_50 PM - 1h 36m 34s.mp3",
149-
"CURRENTLY_RECORDING/Glenwayprivate - Unspecified description - February 20 Thursday 2025 08_50 PM - 1h 36m 34s.mp3",
150-
"glenway",
151-
"Unspecified description",
152-
"February 20 Thursday 2025 08_50 PM",
153-
96.53333333333334,
152+
"Pineland - just seeing if stuff works. - April 05 Saturday 2025 03_34 PM - 1m 1s.mp3",
153+
"CURRENTLY_RECORDING/Pineland - just seeing if stuff works. - April 05 Saturday 2025 03_34 PM - 1m 1s.mp3",
154+
"pineland",
155+
"just seeing if stuff works.",
156+
"April 05 Saturday 2025 03_34 PM",
157+
1.1,
154158
),
155159
debug=True,
156160
)

main.py

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def excepthook(exc_type, exc_value, exc_traceback):
8484

8585
class Stream:
8686
def __init__(
87-
self, title: str, url: str, host: str, description: str, recording_finished
87+
self, title: str, url: str, host: str, description: str, recording_finished, upload_callback
8888
) -> None:
8989
load_dotenv()
9090
self.title = title
@@ -107,6 +107,7 @@ def __init__(
107107
self.recording_file_path = (
108108
f"{FOLDER_LOCATION}/CURRENTLY_RECORDING/{self.recording_file_name}"
109109
)
110+
self.upload_callback = upload_callback
110111
self.send_notification()
111112

112113
def start_recording(self):
@@ -192,24 +193,28 @@ def process_file(self):
192193
)
193194
self.uploaded = True
194195

195-
self.backup_stream(final_recording_file_path)
196+
# self.backup_stream(final_recording_file_path)
196197
os.remove(final_recording_file_path)
197198
app_log.info(f"Original copy deleted: {self.recording_file_name}")
198199

199200
def upload_stream(self, file_name: str, file_path: str):
200201
app_log.info(f"Uploading {self.host}: {self.recording_file_name}")
201-
asyncio.run(
202-
filebrowser_uploader.upload(
203-
file_name,
204-
file_path,
205-
self.host,
206-
self.description,
207-
self.starting_time.strftime("%B %d %A %Y %I_%M %p"),
208-
self.audio_file_length,
209-
)
210-
)
211-
self.uploaded = True
212-
app_log.info(f"Uploaded {self.host}: {self.recording_file_name}")
202+
try:
203+
if self.upload_callback:
204+
self.upload_callback(
205+
file_name,
206+
file_path,
207+
self.host,
208+
self.description,
209+
self.starting_time.strftime("%B %d %A %Y %I_%M %p"),
210+
self.audio_file_length,
211+
)
212+
self.uploaded = True
213+
app_log.info(f"Uploaded {self.host}: {self.recording_file_name}")
214+
else:
215+
raise RuntimeError("No upload callback provided.")
216+
except Exception as e:
217+
app_log.error(f"Failed to upload stream: {e}")
213218

214219
def backup_stream(self, file_path: str):
215220
app_log.info(f"Starting compression for {self.recording_file_name}")
@@ -250,30 +255,28 @@ class StreamRecorder:
250255
def __init__(self) -> None:
251256
load_dotenv()
252257
self.active_streams: dict[str, Stream] = {}
258+
self.loop = asyncio.new_event_loop()
259+
asyncio.set_event_loop(self.loop)
260+
threading.Thread(target=self.loop.run_forever, daemon=True).start()
253261

254-
def fetch_icecast_status_json(
255-
self, icecast_source="https://hbniaudio.hbni.net"
262+
def fetch_broadcast_data(
263+
self, source="https://broadcasting.hbni.net/get_broadcast_data"
256264
) -> (
257-
dict[
258-
Literal["icestats"],
259-
None | str | dict[Literal["source"], dict[str, str] | list[dict[str, str]]],
260-
]
265+
list[dict]
261266
| None
262267
):
263268
try:
264-
response = requests.get(f"{icecast_source}/status-json.xsl")
269+
response = requests.get(source)
265270
if response.status_code == 200:
266-
json_content = response.text.replace('"title": - ,', '"title": null,')
267-
json_data = json.loads(json_content)
268-
json_data["icestats"]["icecast_source"] = icecast_source
269-
app_log.info(f"Icecast status: {json_data}")
271+
json_data = json.loads(response.text)
272+
app_log.info(f"Broadcast data: {json_data}")
270273
return json_data
271274
else:
272-
app_log.info(f"Error fetching Icecast status: {response.status_code}")
273-
return self.fetch_icecast_status_json("http://hbniaudio.hbni.net:8000")
275+
app_log.info(f"Error fetching Broadcast data: {response.status_code}")
276+
return self.fetch_broadcast_data()
274277
except Exception as e:
275-
app_log.error(f"Error fetching Icecast status: {e}")
276-
return self.fetch_icecast_status_json("http://hbniaudio.hbni.net:8000")
278+
app_log.error(f"Error fetching Broadcast data: {e}")
279+
return self.fetch_broadcast_data()
277280

278281
def process_sources(
279282
self, sources: dict[str, str] | list[dict[str, str]]
@@ -289,7 +292,7 @@ def remove_stream(self, host: str):
289292
)
290293
del self.active_streams[host]
291294
if not list(self.active_streams.keys()):
292-
self.update_recording_status()
295+
self.loop.create_task(self.update_recording_status())
293296

294297
def run(self):
295298
self.send_notification()
@@ -300,26 +303,31 @@ def run(self):
300303

301304
while True:
302305
try:
303-
status_data = self.fetch_icecast_status_json()
306+
status_data = self.fetch_broadcast_data()
304307
if not status_data:
305308
time.sleep(15)
306309
continue
307310

308-
sources = status_data.get("icestats", {}).get("source", [])
309-
sources = self.process_sources(sources)
310-
311-
for source in sources:
312-
host = source["listenurl"].split("/")[-1]
311+
for source in status_data:
312+
host: str = source.get("host")
313313
description = source.get("server_description", "No description")
314-
title = host.replace("/", "").title()
315-
icecast_source = status_data.get("icestats", {}).get("icecast_source", "https://hbniaudio.hbni.net")
314+
title = host.title()
315+
icecast_source = "https://hbniaudio.hbni.net"
316+
is_private = source.get("is_private", False)
316317
is_recording = source.get("genre", "various") == "RECORDING"
317318

318319
if (
319-
host not in self.active_streams and "test" not in host.lower() and "test" not in description.lower()
320+
host not in self.active_streams and "test" not in host.lower() and "test" not in description.lower() and not is_private
320321
# and not is_recording # It is being recorded by HBNI Audio
321322
):
322-
stream = Stream(title, icecast_source, host, description, self.remove_stream)
323+
stream = Stream(
324+
title,
325+
icecast_source,
326+
host,
327+
description,
328+
self.remove_stream,
329+
upload_callback=upload_sync
330+
)
323331
self.active_streams[host] = stream
324332
stream.start_recording()
325333
app_log.info(
@@ -328,13 +336,13 @@ def run(self):
328336

329337
# Cleanup inactive streams
330338
active_hosts = {
331-
source["listenurl"].split("/")[-1] for source in sources
339+
source["host"].split("/")[-1] for source in status_data
332340
}
333341
for host in list(self.active_streams.keys()):
334342
if host not in active_hosts:
335343
self.remove_stream(host)
336344

337-
self.update_recording_status()
345+
self.loop.create_task(self.update_recording_status())
338346

339347
time.sleep(15)
340348
except Exception as e:
@@ -380,6 +388,7 @@ async def update_recording_status(self):
380388
await conn.execute(query, host, link, length, description, starting_time)
381389

382390
await pool.close()
391+
383392
def send_notification(self):
384393
send_email.send(
385394
"HBNI Audio Stream Recorder Started Successfully",
@@ -417,16 +426,36 @@ def start_log_server():
417426
httpd.serve_forever()
418427

419428

429+
def upload_sync(
430+
file_name: str,
431+
file_path: str,
432+
host: str,
433+
description: str,
434+
date: str,
435+
length: float,
436+
):
437+
return asyncio.run(
438+
filebrowser_uploader.upload(
439+
file_name,
440+
file_path,
441+
host,
442+
description,
443+
date,
444+
length,
445+
)
446+
)
447+
448+
420449
def start_recorder():
421450
stream_recorder = StreamRecorder()
422451
app_log.info("Starting stream recorder")
423452
stream_recorder.run()
424453

425454

426455
def main() -> None:
427-
428-
threading.Thread(target=start_recorder).start()
456+
# threading.Thread(target=start_recorder).start()
429457
threading.Thread(target=start_log_server).start()
458+
start_recorder()
430459

431460

432461
if __name__ == "__main__":

0 commit comments

Comments
 (0)