aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/music
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2025-10-20 17:45:37 +0200
committersalmonik <raisersoft@proton.me>2025-10-20 17:45:37 +0200
commit19ff005b7d340bf271c8cde245857d512f5148db (patch)
tree8f68e197cd083062069e991146da881593430e51 /cogs/music
parentupload to server if file too big for conv (diff)
downloadsenator-sperma-19ff005b7d340bf271c8cde245857d512f5148db.tar.gz
senator-sperma-19ff005b7d340bf271c8cde245857d512f5148db.zip
simplified the searching algorithm
Diffstat (limited to 'cogs/music')
-rw-r--r--cogs/music/play_utils.py60
1 files changed, 13 insertions, 47 deletions
diff --git a/cogs/music/play_utils.py b/cogs/music/play_utils.py
index ad2a2e1..6fa0edd 100644
--- a/cogs/music/play_utils.py
+++ b/cogs/music/play_utils.py
@@ -196,16 +196,15 @@ class PlayUtils:
196 # -- LOCAL PLAY -- 196 # -- LOCAL PLAY --
197 197
198 @staticmethod 198 @staticmethod
199 async def search_local(query, max_results=5, min_score=30): 199 async def search_local(query, max_results=5):
200 """Search for audio files using fuzzy matching on both filename and path. 200 """Search for audio files that contain the query in their name (case-insensitive).
201 201
202 Args: 202 Args:
203 query: Search query string 203 query: Search query string
204 max_results: Maximum number of results to return 204 max_results: Maximum number of results to return
205 min_score: Minimum score threshold for matches (0-100)
206 205
207 Returns: 206 Returns:
208 List of matching file paths, sorted by relevance 207 List of matching file paths
209 """ 208 """
210 logger.info(f"Starting local search for query: '{query}'") 209 logger.info(f"Starting local search for query: '{query}'")
211 try: 210 try:
@@ -214,9 +213,8 @@ class PlayUtils:
214 search_paths = data.get('audio_paths', []) 213 search_paths = data.get('audio_paths', [])
215 logger.info(f"Searching in paths: {search_paths}") 214 logger.info(f"Searching in paths: {search_paths}")
216 215
217 candidates = [] 216 matches = []
218 files_checked = 0 217 q = query.lower()
219 q = query.lower().replace('_', ' ').replace('-', ' ')
220 218
221 for path in search_paths: 219 for path in search_paths:
222 path = Path(path) 220 path = Path(path)
@@ -231,51 +229,19 @@ class PlayUtils:
231 if not file_path.is_file(): 229 if not file_path.is_file():
232 continue 230 continue
233 231
234 files_checked += 1
235
236 # Check if file has a valid extension 232 # Check if file has a valid extension
237 if file_path.suffix.lower() not in {'.mp4', '.mp3', '.wav', '.opus', '.m4a'}: 233 if file_path.suffix.lower() not in {'.mp4', '.mp3', '.wav', '.opus', '.m4a'}:
238 continue 234 continue
239 235
240 # Get relative path from search root 236 # Check if query is in filename (case-insensitive)
241 rel_path = file_path.relative_to(path).parent 237 if q in file_path.name.lower():
242 238 matches.append(str(file_path.absolute()))
243 # Create searchable strings 239 if len(matches) >= max_results:
244 filename = Utils.normalize_name(file_path, keep_ext=False) 240 logger.info(f"Found {len(matches)} matches, stopping search")
245 full_path_str = str(rel_path / file_path.stem).lower() 241 return matches
246
247 # Calculate scores
248 score_filename = Utils.combined_score(q, filename)
249 score_path = Utils.combined_score(q, full_path_str)
250
251 # Use the better score
252 score = max(score_filename, score_path)
253
254 # Apply bonuses
255 depth_bonus = max(0, 1.0 - (len(rel_path.parts) / 10.0)) # Prefer shallower paths
256 ext_bonus = 1.1 if file_path.suffix.lower() in q.split('.')[-1].lower() else 1.0
257
258 final_score = score * (0.9 + depth_bonus * 0.1) * ext_bonus
259
260 if final_score >= min_score:
261 candidates.append((final_score, str(file_path.absolute())))
262 logger.debug(f"Match: {file_path} (score: {final_score:.1f})")
263
264 logger.info(f"Search complete. Checked {files_checked} files, found {len(candidates)} matches.")
265
266 if not candidates:
267 logger.warning("No matching audio files found.")
268 return []
269
270 # Sort by score (descending) and get top results
271 candidates.sort(key=lambda x: x[0], reverse=True)
272 top_matches = candidates[:max_results]
273
274 logger.info(f"Top {len(top_matches)} matches:")
275 for i, (score, path) in enumerate(top_matches, 1):
276 logger.info(f" {i}. {path} (score: {score:.1f})")
277 242
278 return [c[1] for c in top_matches] 243 logger.info(f"Search complete. Found {len(matches)} matches.")
244 return matches
279 245
280 except Exception as e: 246 except Exception as e:
281 logger.error(f"Error during local search: {str(e)}", exc_info=True) 247 logger.error(f"Error during local search: {str(e)}", exc_info=True)