@@ -1682,31 +1682,44 @@ def available_keys():
16821682 props = []
16831683 clip_titles = []
16841684
1685- # --- Materials: distinct properties + counts from uploads_log ---
1685+ # --- Materials: list every property from ` properties`, plus file count from uploads_log ---
16861686 try :
16871687 with sqlite3 .connect (DB_NAME ) as conn :
16881688 cur = conn .cursor ()
16891689 cur .execute ("""
1690- SELECT property, COUNT(*) AS cnt
1691- FROM uploads_log
1692- WHERE property IS NOT NULL AND TRIM(property) <> ''
1693- GROUP BY property
1694- ORDER BY LOWER(property)
1690+ SELECT p.slug, p.title, COALESCE(COUNT(u.filename), 0) AS cnt
1691+ FROM properties p
1692+ LEFT JOIN uploads_log u
1693+ ON u.property = p.slug
1694+ GROUP BY p.slug, p.title
1695+ ORDER BY LOWER(COALESCE(p.title, p.slug))
16951696 """ )
1696- rows = cur .fetchall ()
1697- for prop , cnt in rows :
1698- slug = (prop or "" ).strip ()
1699- if not slug :
1700- continue
1701- props .append ({
1702- "slug" : slug ,
1703- "title" : slug .replace ("_" , " " ).title (),
1704- "count" : int (cnt or 0 ),
1705- })
1697+ for slug , raw_title , cnt in cur .fetchall ():
1698+ title = (raw_title or slug .replace ("_" , " " ).title ()).strip ()
1699+ props .append ({"slug" : slug , "title" : title , "count" : int (cnt or 0 )})
17061700 except Exception as e :
1707- app .logger .warning ("available_keys: uploads_log aggregation failed: %s" , e )
1708-
1709- # --- Clips: prefer DB table (music_clips) ---
1701+ # Fallback if `properties` doesn't exist yet: derive from uploads_log
1702+ app .logger .warning ("available_keys: LEFT JOIN failed (%s); falling back." , e )
1703+ try :
1704+ with sqlite3 .connect (DB_NAME ) as conn :
1705+ cur = conn .cursor ()
1706+ cur .execute ("""
1707+ SELECT property, COUNT(*) AS cnt
1708+ FROM uploads_log
1709+ WHERE property IS NOT NULL AND TRIM(property) <> ''
1710+ GROUP BY property
1711+ ORDER BY LOWER(property)
1712+ """ )
1713+ for prop , cnt in cur .fetchall ():
1714+ slug = (prop or "" ).strip ()
1715+ if slug :
1716+ props .append ({"slug" : slug ,
1717+ "title" : slug .replace ("_" , " " ).title (),
1718+ "count" : int (cnt or 0 )})
1719+ except Exception as e2 :
1720+ app .logger .warning ("available_keys: uploads_log fallback failed: %s" , e2 )
1721+
1722+ # --- Clips: prefer DB table (music_clips); fallback to CSV if needed ---
17101723 try :
17111724 with sqlite3 .connect (DB_NAME ) as conn :
17121725 cur = conn .cursor ()
@@ -1719,10 +1732,8 @@ def available_keys():
17191732 """ )
17201733 clip_titles = [r [0 ] for r in cur .fetchall ()]
17211734 except Exception :
1722- # table may not exist yet; we'll fall back to CSV below
1723- pass
1735+ pass # table may not exist; try CSV below
17241736
1725- # --- Fallback to CSV if DB has no titles yet ---
17261737 if not clip_titles :
17271738 import csv , os
17281739 for path in ("/data/drive_music.csv" , "drive_music.csv" ):
@@ -1731,29 +1742,23 @@ def available_keys():
17311742 with open (path , encoding = "utf-8" ) as f :
17321743 sample = f .read (4096 )
17331744 f .seek (0 )
1734- # Try to detect header; if detection fails, we’ll still handle both cases.
1735- has_header = False
1745+ titles = set ()
17361746 try :
17371747 has_header = csv .Sniffer ().has_header (sample )
17381748 except Exception :
1739- pass
1749+ has_header = False
17401750
1741- titles = set ()
17421751 if has_header :
17431752 reader = csv .DictReader (f )
17441753 for row in reader :
17451754 t = (row .get ("title" ) or "" ).strip ()
1746- if t :
1747- titles .add (t )
1755+ if t : titles .add (t )
17481756 else :
17491757 reader = csv .reader (f )
17501758 for row in reader :
1751- if not row :
1752- continue
1753- # Your writer used: [title, description, preview_url, download_url]
1754- t = (row [0 ] or "" ).strip ()
1755- if t :
1756- titles .add (t )
1759+ if row :
1760+ t = (row [0 ] or "" ).strip ()
1761+ if t : titles .add (t )
17571762
17581763 clip_titles = sorted (titles , key = str .lower )
17591764 if clip_titles :
0 commit comments