refactor: rename AudituiApp to Auditui to have the right name in TUI interface

This commit is contained in:
2025-12-06 15:46:16 +01:00
parent 37ac47698c
commit fc15096918

63
main.py
View File

@@ -20,7 +20,7 @@ from textual.worker import get_current_worker
from textual import work from textual import work
class AudituiApp(App): class Auditui(App):
"""Main application class for the Audible TUI app.""" """Main application class for the Audible TUI app."""
BINDINGS = [ BINDINGS = [
@@ -48,7 +48,9 @@ class AudituiApp(App):
AUTH_PATH = Path.home() / ".config" / "auditui" / "auth.json" AUTH_PATH = Path.home() / ".config" / "auditui" / "auth.json"
CACHE_DIR = Path.home() / ".cache" / "auditui" / "books" CACHE_DIR = Path.home() / ".cache" / "auditui" / "books"
DOWNLOAD_URL = "https://cde-ta-g7g.amazon.com/FionaCDEServiceEngine/FSDownloadContent" DOWNLOAD_URL = (
"https://cde-ta-g7g.amazon.com/FionaCDEServiceEngine/FSDownloadContent"
)
DEFAULT_CODEC = "LC_128_44100_stereo" DEFAULT_CODEC = "LC_128_44100_stereo"
MIN_FILE_SIZE = 1024 * 1024 MIN_FILE_SIZE = 1024 * 1024
@@ -144,7 +146,7 @@ class AudituiApp(App):
path="library", path="library",
num_results=page_size, num_results=page_size,
page=page, page=page,
response_groups=response_groups response_groups=response_groups,
) )
items = library.get("items", []) items = library.get("items", [])
@@ -153,8 +155,7 @@ class AudituiApp(App):
all_items.extend(items) all_items.extend(items)
self.call_from_thread( self.call_from_thread(
self.update_status, self.update_status, f"Fetched page {page} ({len(items)} items)..."
f"Fetched page {page} ({len(items)} items)..."
) )
if len(items) < page_size: if len(items) < page_size:
@@ -178,9 +179,9 @@ class AudituiApp(App):
"""Extract title from library item.""" """Extract title from library item."""
product = item.get("product", {}) product = item.get("product", {})
return ( return (
product.get("title") or product.get("title")
item.get("title") or or item.get("title")
product.get("asin", "Unknown Title") or product.get("asin", "Unknown Title")
) )
def _extract_authors(self, item: dict) -> str: def _extract_authors(self, item: dict) -> str:
@@ -190,9 +191,7 @@ class AudituiApp(App):
if not authors and "authors" in item: if not authors and "authors" in item:
authors = item.get("authors", []) authors = item.get("authors", [])
author_names = [ author_names = [a.get("name", "") for a in authors if isinstance(a, dict)]
a.get("name", "") for a in authors if isinstance(a, dict)
]
return ", ".join(author_names) or "Unknown" return ", ".join(author_names) or "Unknown"
def _extract_runtime_minutes(self, item: dict) -> int | None: def _extract_runtime_minutes(self, item: dict) -> int | None:
@@ -203,7 +202,7 @@ class AudituiApp(App):
"runtime_length", "runtime_length",
"vLength", "vLength",
"length", "length",
"duration" "duration",
] ]
runtime = None runtime = None
@@ -244,7 +243,9 @@ class AudituiApp(App):
listening_status = item.get("listening_status") listening_status = item.get("listening_status")
if isinstance(listening_status, dict): if isinstance(listening_status, dict):
is_finished_flag = is_finished_flag or listening_status.get("is_finished", False) is_finished_flag = is_finished_flag or listening_status.get(
"is_finished", False
)
if percent_complete is None: if percent_complete is None:
percent_complete = listening_status.get("percent_complete", 0) percent_complete = listening_status.get("percent_complete", 0)
@@ -252,12 +253,14 @@ class AudituiApp(App):
isinstance(percent_complete, (int, float)) and percent_complete >= 100 isinstance(percent_complete, (int, float)) and percent_complete >= 100
) )
def format_duration(self, value: int | None, unit: str = 'minutes', default_none: str | None = None) -> str | None: def format_duration(
self, value: int | None, unit: str = "minutes", default_none: str | None = None
) -> str | None:
"""Format duration value into human-readable string.""" """Format duration value into human-readable string."""
if value is None or value <= 0: if value is None or value <= 0:
return default_none return default_none
if unit == 'seconds': if unit == "seconds":
total_minutes = int(value) // 60 total_minutes = int(value) // 60
else: else:
total_minutes = int(value) total_minutes = int(value)
@@ -285,7 +288,7 @@ class AudituiApp(App):
author_names = self._extract_authors(item) author_names = self._extract_authors(item)
minutes = self._extract_runtime_minutes(item) minutes = self._extract_runtime_minutes(item)
runtime_str = self.format_duration( runtime_str = self.format_duration(
minutes, unit='minutes', default_none="Unknown length" minutes, unit="minutes", default_none="Unknown length"
) )
percent_complete = self._extract_progress_info(item) percent_complete = self._extract_progress_info(item)
@@ -298,7 +301,7 @@ class AudituiApp(App):
author_names or "Unknown", author_names or "Unknown",
runtime_str or "Unknown", runtime_str or "Unknown",
progress_str, progress_str,
key=title key=title,
) )
self.current_items = items self.current_items = items
@@ -564,8 +567,7 @@ class AudituiApp(App):
return return
self.call_from_thread( self.call_from_thread(
self.update_status, self.update_status, f"Starting playback of {local_path.name}..."
f"Starting playback of {local_path.name}..."
) )
self.call_from_thread(self._start_playback, local_path, activation_hex) self.call_from_thread(self._start_playback, local_path, activation_hex)
@@ -601,7 +603,7 @@ class AudituiApp(App):
url=self.DOWNLOAD_URL, url=self.DOWNLOAD_URL,
params=params, params=params,
follow_redirects=False, follow_redirects=False,
auth=self.auth auth=self.auth,
) )
response.raise_for_status() response.raise_for_status()
@@ -631,7 +633,7 @@ class AudituiApp(App):
percent = (downloaded / total_size) * 100 percent = (downloaded / total_size) * 100
self.call_from_thread( self.call_from_thread(
self.update_status, self.update_status,
f"Downloading: {percent:.1f}% ({downloaded}/{total_size} bytes)" f"Downloading: {percent:.1f}% ({downloaded}/{total_size} bytes)",
) )
return dest_path return dest_path
@@ -646,14 +648,12 @@ class AudituiApp(App):
if local_path.exists() and local_path.stat().st_size >= self.MIN_FILE_SIZE: if local_path.exists() and local_path.stat().st_size >= self.MIN_FILE_SIZE:
self.call_from_thread( self.call_from_thread(
self.update_status, self.update_status, f"Using cached file: {local_path.name}"
f"Using cached file: {local_path.name}"
) )
return local_path return local_path
self.call_from_thread( self.call_from_thread(
self.update_status, self.update_status, f"Downloading to {local_path.name}..."
f"Downloading to {local_path.name}..."
) )
dl_link = self._get_download_link(asin) dl_link = self._get_download_link(asin)
@@ -667,8 +667,7 @@ class AudituiApp(App):
if not local_path.exists() or local_path.stat().st_size < self.MIN_FILE_SIZE: if not local_path.exists() or local_path.stat().st_size < self.MIN_FILE_SIZE:
self.call_from_thread( self.call_from_thread(
self.update_status, self.update_status, "Download failed or file too small"
"Download failed or file too small"
) )
return None return None
@@ -707,15 +706,11 @@ def authenticate():
email = input("\nEmail: ") email = input("\nEmail: ")
password = getpass("Password: ") password = getpass("Password: ")
marketplace = input( marketplace = input("Marketplace locale (default: US): ").strip().upper() or "US"
"Marketplace locale (default: US): "
).strip().upper() or "US"
try: try:
authenticator = audible.Authenticator.from_login( authenticator = audible.Authenticator.from_login(
username=email, username=email, password=password, locale=marketplace
password=password,
locale=marketplace
) )
auth_path.parent.mkdir(parents=True, exist_ok=True) auth_path.parent.mkdir(parents=True, exist_ok=True)
@@ -731,7 +726,7 @@ def authenticate():
if __name__ == "__main__": if __name__ == "__main__":
auth, client = authenticate() auth, client = authenticate()
app = AudituiApp() app = Auditui()
app.auth = auth app.auth = auth
app.client = client app.client = client
app.run() app.run()