Skip to content

Commit

Permalink
Minor improvements for remove search suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
comarquet committed Nov 16, 2024
1 parent 2d52e04 commit 1da1967
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 46 deletions.
12 changes: 6 additions & 6 deletions tests/mixins/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,25 +117,25 @@ def test_search_library(self, config, yt_oauth):
yt_oauth.search("beatles", filter="featured_playlists", scope="library", limit=40)

def test_remove_suggestion_valid(self, yt_auth):
first_pass = yt_auth.search("b")
first_pass = yt_auth.search("b") # Populate the suggestion history
assert len(first_pass) > 0, "Search returned no results"

results = yt_auth.get_search_suggestions("b", detailed_runs=True)
results, feedback_tokens = yt_auth.get_search_suggestions("b", detailed_runs=True)
assert len(results) > 0, "No search suggestions returned"
assert any(item.get("fromHistory") for item in results), "No suggestions from history found"

suggestion_to_remove = 1
response = yt_auth.remove_search_suggestion(suggestion_to_remove)
suggestion_to_remove = 0
response = yt_auth.remove_search_suggestion(suggestion_to_remove, feedback_tokens)
assert response is True, "Failed to remove search suggestion"

def test_remove_suggestion_invalid_number(self, yt_auth):
first_pass = yt_auth.search("a")
assert len(first_pass) > 0, "Search returned no results"

results = yt_auth.get_search_suggestions("a", detailed_runs=True)
results, feedback_tokens = yt_auth.get_search_suggestions("a", detailed_runs=True)
assert len(results) > 0, "No search suggestions returned"
assert any(item.get("fromHistory") for item in results), "No suggestions from history found"

suggestion_to_remove = 99
response = yt_auth.remove_search_suggestion(suggestion_to_remove)
response = yt_auth.remove_search_suggestion(suggestion_to_remove, feedback_tokens)
assert response is False
51 changes: 22 additions & 29 deletions ytmusicapi/mixins/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@


class SearchMixin(MixinProtocol):
def __init__(self):
self._latest_suggestions = None
self._latest_feedback_tokens = None

def search(
self,
query: str,
Expand Down Expand Up @@ -262,7 +258,7 @@ def parse_func(contents):

return search_results

def get_search_suggestions(self, query: str, detailed_runs=False) -> Union[list[str], list[dict]]:
def get_search_suggestions(self, query: str, detailed_runs=False) -> tuple[Union[list[str], list[dict]], dict[int, str]]:
"""
Get Search Suggestions
Expand All @@ -272,7 +268,10 @@ def get_search_suggestions(self, query: str, detailed_runs=False) -> Union[list[
suggestion along with the complete text (like many search services
usually bold the text typed by the user).
Default: False, returns the list of search suggestions in plain text.
:return: List of search suggestion results depending on ``detailed_runs`` param.
:return: A tuple containing:
- A list of search suggestions. If ``detailed_runs`` is False, it returns plain text suggestions.
If ``detailed_runs`` is True, it returns a list of dictionaries with detailed information.
- A dictionary of feedback tokens that can be used to remove suggestions later.
Example response when ``query`` is 'fade' and ``detailed_runs`` is set to ``False``::
Expand Down Expand Up @@ -300,7 +299,7 @@ def get_search_suggestions(self, query: str, detailed_runs=False) -> Union[list[
"text": "d"
}
],
"number": 1
"index": 0
},
{
"text": "faded alan walker lyrics",
Expand All @@ -313,7 +312,7 @@ def get_search_suggestions(self, query: str, detailed_runs=False) -> Union[list[
"text": "d alan walker lyrics"
}
],
"number": 2
"index": 1
},
{
"text": "faded alan walker",
Expand All @@ -326,7 +325,7 @@ def get_search_suggestions(self, query: str, detailed_runs=False) -> Union[list[
"text": "d alan walker"
}
],
"number": 3
"index": 2
},
...
]
Expand All @@ -340,36 +339,33 @@ def get_search_suggestions(self, query: str, detailed_runs=False) -> Union[list[
feedback_tokens: dict[int, str] = {}
search_suggestions = parse_search_suggestions(response, detailed_runs, feedback_tokens)

# Store the suggestions and feedback tokens for later use
self._latest_suggestions = search_suggestions
self._latest_feedback_tokens = feedback_tokens

return search_suggestions
return search_suggestions, feedback_tokens

def remove_search_suggestion(self, number: int) -> bool:
def remove_search_suggestion(self, index: int, feedback_tokens: dict[int, str]) -> bool:
"""
Remove a search suggestion from the user search history based on the number displayed next to it.
:param number: The number of the suggestion to be removed.
:param index: The number of the suggestion to be removed.
This number is displayed when the `detailed_runs` and `display_numbers` parameters are set to True
in the `get_search_suggestions` method.
:param feedback_tokens: A dictionary containing feedback tokens for each suggestion.
This dictionary is obtained from the `get_search_suggestions` method.
:return: True if the operation was successful, False otherwise.
Example usage:
Example usage::
# Assuming you want to remove suggestion number 1
success = ytmusic.remove_search_suggestion(number=1)
# Assuming you want to remove suggestion number 0
suggestions, feedback_tokens = ytmusic.get_search_suggestions(query="fade", detailed_runs=True)
success = ytmusic.remove_search_suggestion(index=0, feedback_tokens=feedback_tokens)
if success:
print("Suggestion removed successfully")
else:
print("Failed to remove suggestion")
"""
if self._latest_suggestions is None or self._latest_feedback_tokens is None:
raise ValueError(
"No suggestions available. Please run get_search_suggestions first to retrieve suggestions."
)

feedback_token = self._latest_feedback_tokens.get(number)
if not feedback_tokens:
raise YTMusicUserError("No feedback tokens provided. Please run get_search_suggestions first to retrieve suggestions.")

feedback_token = feedback_tokens.get(index)

if not feedback_token:
return False
Expand All @@ -379,7 +375,4 @@ def remove_search_suggestion(self, number: int) -> bool:

response = self._send_request(endpoint, body)

if "feedbackResponses" in response and response["feedbackResponses"][0].get("isProcessed", False):
return True

return False
return bool(nav(response, ["feedbackResponses", 0, "isProcessed"], none_if_absent=True))
14 changes: 3 additions & 11 deletions ytmusicapi/parsers/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

UNIQUE_RESULT_TYPES = ["artist", "playlist", "song", "video", "station", "profile", "podcast", "episode"]
ALL_RESULT_TYPES = ["album", *UNIQUE_RESULT_TYPES]
FEEDBACK_TOKENS: dict[int, str] = {}


def get_search_result_type(result_type_local, result_types_local):
Expand Down Expand Up @@ -265,8 +264,7 @@ def parse_search_suggestions(results, detailed_runs, feedback_tokens):
raw_suggestions = results["contents"][0]["searchSuggestionsSectionRenderer"]["contents"]
suggestions = []

count = 1 # Used for deleting a search suggestion
for raw_suggestion in raw_suggestions:
for index, raw_suggestion in enumerate(raw_suggestions):
if "historySuggestionRenderer" in raw_suggestion:
suggestion_content = raw_suggestion["historySuggestionRenderer"]
from_history = True
Expand All @@ -276,7 +274,7 @@ def parse_search_suggestions(results, detailed_runs, feedback_tokens):

# Store the feedback token in the provided dictionary if it exists
if feedback_token:
feedback_tokens[count] = feedback_token
feedback_tokens[index] = feedback_token
else:
suggestion_content = raw_suggestion["searchSuggestionRenderer"]
from_history = False
Expand All @@ -285,14 +283,8 @@ def parse_search_suggestions(results, detailed_runs, feedback_tokens):
runs = suggestion_content["suggestion"]["runs"]

if detailed_runs:
suggestions.append({"text": text, "runs": runs, "fromHistory": from_history, "number": count})
suggestions.append({"text": text, "runs": runs, "fromHistory": from_history, "index": index})
else:
suggestions.append(text)

count += 1

return suggestions


def get_feedback_token(suggestion_number):
return FEEDBACK_TOKENS.get(suggestion_number)

0 comments on commit 1da1967

Please sign in to comment.