sync
This commit is contained in:
100
tool/core/cmd/put_file.py
Normal file
100
tool/core/cmd/put_file.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# tool/core/cmd/put_file.py
|
||||
import struct
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
|
||||
from core.utils import console, console_err
|
||||
from core.protocol import COMMANDS
|
||||
from core.tag import TagManager
|
||||
from core.cmd.put_tags import put_tags
|
||||
|
||||
class put_file:
|
||||
def __init__(self, bus):
|
||||
self.bus = bus
|
||||
|
||||
def get(self, source_path: str, dest_path: str, cli_tags_json: str = None):
|
||||
try:
|
||||
p = Path(source_path)
|
||||
if not p.exists() or not p.is_file():
|
||||
console_err.print(f"Fehler: Quelldatei existiert nicht: {source_path}")
|
||||
return None
|
||||
with open(p, 'rb') as f:
|
||||
file_data = f.read()
|
||||
except Exception as e:
|
||||
console_err.print(f"Fehler beim Lesen: {e}")
|
||||
return None
|
||||
|
||||
# 1. Lokale Tags abtrennen
|
||||
audio_data, local_tlvs = TagManager.split_file(file_data)
|
||||
audio_size = len(audio_data)
|
||||
|
||||
# 2. Upload der REINEN Audiodaten
|
||||
dest_path_bytes = dest_path.encode('utf-8')
|
||||
payload = struct.pack('B', len(dest_path_bytes)) + dest_path_bytes + struct.pack('<I', audio_size)
|
||||
|
||||
self.bus.send_request(COMMANDS['put_file'], payload)
|
||||
self.bus.receive_ack(timeout=5.0)
|
||||
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), BarColumn(), DownloadColumn(), TransferSpeedColumn(), "•", TimeRemainingColumn(), console=console, transient=False) as progress:
|
||||
task = progress.add_task(f"Sende {source_path}...", total=audio_size)
|
||||
stream_res = self.bus.send_stream(audio_data, progress_callback=lambda sent, total: progress.update(task, total=total, completed=sent))
|
||||
|
||||
if not stream_res: return None
|
||||
|
||||
remote_crc = stream_res.get('crc32')
|
||||
local_crc = zlib.crc32(audio_data) & 0xFFFFFFFF
|
||||
|
||||
if local_crc != remote_crc:
|
||||
return {'success': False, 'source_path': source_path, 'crc32_remote': remote_crc, 'crc32_local': local_crc}
|
||||
|
||||
# 3. Tags aktualisieren (CRC32 + evtl. CLI-Tags)
|
||||
# Alten CRC-Tag entfernen, neuen einsetzen
|
||||
final_tlvs = [t for t in local_tlvs if not (t['type'] == 0x00 and t['index'] == 0x01)]
|
||||
final_tlvs.append({'type': 0x00, 'index': 0x01, 'value': struct.pack('<I', local_crc)})
|
||||
|
||||
# Falls CLI-Tags übergeben wurden (-t), diese priorisiert anwenden
|
||||
if cli_tags_json:
|
||||
try:
|
||||
cli_tlvs = TagManager.parse_cli_json(cli_tags_json)
|
||||
# Bestehendes JSON löschen, wenn neues im CLI-Input definiert ist
|
||||
if any(t['type'] == 0x10 for t in cli_tlvs):
|
||||
final_tlvs = [t for t in final_tlvs if t['type'] != 0x10]
|
||||
final_tlvs.extend(cli_tlvs)
|
||||
except ValueError as e:
|
||||
console_err.print(f"[warning]Warnung: Tags konnten nicht geparst werden ({e}). Datei wurde ohne extra Tags hochgeladen.[/warning]")
|
||||
|
||||
# 4. Tags via separatem Befehl anhängen
|
||||
tag_cmd = put_tags(self.bus)
|
||||
tag_blob = TagManager.build_blob(final_tlvs)
|
||||
tag_cmd.send_blob(dest_path, tag_blob)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'source_path': source_path,
|
||||
'dest_path': dest_path,
|
||||
'crc32_remote': remote_crc,
|
||||
'crc32_local': local_crc,
|
||||
'size': audio_size,
|
||||
'duration': stream_res.get('duration')
|
||||
}
|
||||
|
||||
def print(self, result):
|
||||
if not result:
|
||||
return
|
||||
|
||||
if result.get('success'):
|
||||
console.print(f"✓ Datei [info]{result['source_path']}[/info] erfolgreich hochgeladen und Tags generiert.")
|
||||
console.print(f" • Größe: [info]{result['size'] / 1024:.2f} KB[/info]")
|
||||
else:
|
||||
console_err.print(f"❌ CRC-FEHLER: Datei [error]{result['source_path']}[/error] wurde auf dem Gerät korrumpiert!")
|
||||
|
||||
if 'crc32_remote' in result:
|
||||
console.print(f" • Remote CRC: [info]{result['crc32_remote']:08X}[/info]")
|
||||
if 'crc32_local' in result:
|
||||
console.print(f" • Local CRC: [info]{result['crc32_local']:08X}[/info]")
|
||||
|
||||
if 'dest_path' in result:
|
||||
console.print(f" • Zielpfad: [info]{result['dest_path']}[/info]")
|
||||
|
||||
if result.get('duration') is not None and result.get('duration') > 0:
|
||||
console.print(f" • Dauer: [info]{result['duration']:.2f} s[/info]")
|
||||
Reference in New Issue
Block a user