From: OzGav Date: Sun, 1 Jun 2025 11:53:31 +0000 (+1000) Subject: Fix bug when using random order (#2206) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=224392b4e758e56ee8ace1fd95dd3ea439caef77;p=music-assistant-server.git Fix bug when using random order (#2206) --- diff --git a/music_assistant/controllers/media/base.py b/music_assistant/controllers/media/base.py index 723b5cf6..ccdea0a0 100644 --- a/music_assistant/controllers/media/base.py +++ b/music_assistant/controllers/media/base.py @@ -714,22 +714,19 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta): query_params = extra_query_params or {} query_parts: list[str] = extra_query_parts or [] join_parts: list[str] = extra_join_parts or [] - # create special performant random query - if not search and order_by and order_by.startswith("random"): - query_parts.append( - f"{self.db_table}.item_id in " - f"(SELECT item_id FROM {self.db_table} ORDER BY RANDOM() LIMIT {limit})" - ) + # handle search if search: - search = create_safe_string(search, True, True) - query_params["search"] = f"%{search}%" + safe_search = create_safe_string(search, True, True) + query_params["search"] = f"%{safe_search}%" query_parts.append(f"{self.db_table}.search_name LIKE :search") + # handle favorite filter if favorite is not None: query_parts.append(f"{self.db_table}.favorite = :favorite") query_params["favorite"] = favorite - # handle provider filter + + # handle provider join if provider: join_parts.append( f"JOIN provider_mappings ON provider_mappings.item_id = {self.db_table}.item_id " @@ -737,23 +734,45 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta): f"AND (provider_mappings.provider_instance = '{provider}' " f"OR provider_mappings.provider_domain = '{provider}')" ) - # prevent duplicate where statement + + # Prevent duplicate WHERE query_parts = [x[5:] if x.lower().startswith("where ") else x for x in query_parts] - # concetenate all join and/or where queries - if join_parts: - sql_query += f" {' '.join(join_parts)} " - if query_parts: - sql_query += " WHERE " + " AND ".join(query_parts) - # build final query - sql_query += f" GROUP BY {self.db_table}.item_id" - if order_by: - if sort_key := SORT_KEYS.get(order_by): + + # --- Optimized RANDOM ORDER block --- + if order_by and order_by.startswith("random"): + # Build filtered subquery for item IDs + subquery = f"SELECT {self.db_table}.item_id FROM {self.db_table}" + if query_parts: + subquery += " WHERE " + " AND ".join(query_parts) + subquery += f" ORDER BY RANDOM() LIMIT {limit}" + + # Main query joins the subquery + sql_query = ( + f"SELECT * FROM {self.db_table} " + f"JOIN ({subquery}) AS filtered_random " + f"ON {self.db_table}.item_id = filtered_random.item_id " + f"GROUP BY {self.db_table}.item_id" + ) + # Note: limit is already applied in subquery, so use 0 offset + # and large limit to pass results + query_limit = limit + query_offset = 0 + else: + # Normal query path + sql_query = self.base_query + if join_parts: + sql_query += f" {' '.join(join_parts)}" + if query_parts: + sql_query += " WHERE " + " AND ".join(query_parts) + sql_query += f" GROUP BY {self.db_table}.item_id" + if order_by and (sort_key := SORT_KEYS.get(order_by)): sql_query += f" ORDER BY {sort_key}" - # return dbresult parsed to media item model + query_limit = limit + query_offset = offset return [ self.item_cls.from_dict(self._parse_db_row(db_row)) for db_row in await self.mass.music.database.get_rows_from_query( - sql_query, query_params, limit=limit, offset=offset + sql_query, query_params, limit=query_limit, offset=query_offset ) ]