def test_find_exact_combines_results_from_all_backends(self): track1 = Track(uri='dummy1:a') track2 = Track(uri='dummy2:a') result1 = SearchResult(tracks=[track1]) result2 = SearchResult(tracks=[track2]) self.library1.search.return_value.get.return_value = result1 self.library2.search.return_value.get.return_value = result2 result = self.core.library.find_exact({'any': ['a']}) self.assertIn(result1, result) self.assertIn(result2, result) self.library1.search.assert_called_once_with(query=dict(any=['a']), uris=None, exact=True) self.library2.search.assert_called_once_with(query=dict(any=['a']), uris=None, exact=True)
def search(self, query=None, uris=None, exact=False): result = [] self.backend.calmradio.do_search(' '.join(query['any'])) for channel in self.backend.calmradio.search_results: result.append(self.channel_to_track(channel)) return SearchResult(tracks=result)
def search(self, query=None, uris=None): if not query: return if 'uri' in query: search_query = ''.join(query['uri']) url = urlparse(search_query) if 'soundcloud.com' in url.netloc: logger.info('Resolving SoundCloud for \'%s\'', search_query) return SearchResult( uri='soundcloud:search', tracks=self.backend.remote.resolve_url(search_query)) else: search_query = simplify_search_query(query) logger.info('Searching SoundCloud for \'%s\'', search_query) return SearchResult( uri='soundcloud:search', tracks=self.backend.remote.search(search_query))
def test_list(self): self.backend.library.dummy_find_exact_result = SearchResult( tracks=[ Track(uri='dummy:a', name='A', artists=[ Artist(name='A Artist')])]) self.sendRequest('list "artist" "artist" "foo"') self.assertInResponse('Artist: A Artist') self.assertInResponse('OK')
def test_search_accepts_query_dict_instead_of_kwargs(self): track1 = Track(uri="dummy1:a") track2 = Track(uri="dummy2:a") result1 = SearchResult(tracks=[track1]) result2 = SearchResult(tracks=[track2]) self.library1.search.return_value.get.return_value = result1 self.library2.search.return_value.get.return_value = result2 result = self.core.library.search({"any": ["a"]}) assert result1 in result assert result2 in result self.library1.search.assert_called_once_with(query={"any": ["a"]}, uris=None, exact=False) self.library2.search.assert_called_once_with(query={"any": ["a"]}, uris=None, exact=False)
def test_find_accepts_query_dict_instead_of_kwargs(self): track1 = Track(uri='dummy1:a') track2 = Track(uri='dummy2:a') result1 = SearchResult(tracks=[track1]) result2 = SearchResult(tracks=[track2]) self.library1.find_exact().get.return_value = result1 self.library1.find_exact.reset_mock() self.library2.find_exact().get.return_value = result2 self.library2.find_exact.reset_mock() result = self.core.library.find_exact(dict(any=['a'])) self.assertIn(result1, result) self.assertIn(result2, result) self.library1.find_exact.assert_called_once_with( query=dict(any=['a']), uris=None) self.library2.find_exact.assert_called_once_with( query=dict(any=['a']), uris=None)
def test_find_accepts_query_dict_instead_of_kwargs(self): track1 = Track(uri='dummy1:a') track2 = Track(uri='dummy2:a') result1 = SearchResult(tracks=[track1]) result2 = SearchResult(tracks=[track2]) self.library1.search.return_value.get.return_value = result1 self.library2.search.return_value.get.return_value = result2 result = self.core.library.find_exact({'any': ['a']}) self.assertIn(result1, result) self.assertIn(result2, result) self.library1.search.assert_called_once_with(query={'any': ['a']}, uris=None, exact=True) self.library2.search.assert_called_once_with(query={'any': ['a']}, uris=None, exact=True)
def search(self, query=None, limit=100, offset=0, uris=None, exact=False): limit = self._config["max_search_results"] q = [] for field, values in query.items() if query else []: q.extend((field, value) for value in values) filters = [f for uri in uris or [] for f in self._filters(uri) if f] with self._connect() as c: tracks = schema.search_tracks(c, q, limit, offset, exact, filters) uri = uritools.uricompose("local", path="search", query=q) return SearchResult(uri=uri, tracks=tracks)
def test_search_combines_results_from_all_backends(self): track1 = Track(uri="dummy1:a") track2 = Track(uri="dummy2:a") result1 = SearchResult(tracks=[track1]) result2 = SearchResult(tracks=[track2]) self.library1.search.return_value.get.return_value = result1 self.library2.search.return_value.get.return_value = result2 result = self.core.library.search({"any": ["a"]}) assert result1 in result assert result2 in result self.library1.search.assert_called_once_with(query={"any": ["a"]}, uris=None, exact=False) self.library2.search.assert_called_once_with(query={"any": ["a"]}, uris=None, exact=False)
def search(self, query=None, uris=None, exact=False): try: artists, albums, tracks = \ tidal_search(self.backend._session, query=query, exact=exact) return SearchResult(artists=artists, albums=albums, tracks=tracks) except Exception as ex: logger.info("EX") logger.info("%r", ex)
def test_search_combines_results_from_all_backends(self): track1 = Track(uri='dummy1:a') track2 = Track(uri='dummy2:a') result1 = SearchResult(tracks=[track1]) result2 = SearchResult(tracks=[track2]) self.library1.search().get.return_value = result1 self.library1.search.reset_mock() self.library2.search().get.return_value = result2 self.library2.search.reset_mock() result = self.core.library.search(any=['a']) self.assertIn(result1, result) self.assertIn(result2, result) self.library1.search.assert_called_once_with(query=dict(any=['a']), uris=None) self.library2.search.assert_called_once_with(query=dict(any=['a']), uris=None)
def test_searchadd(self): self.backend.library.dummy_search_result = SearchResult( tracks=[Track(uri='dummy:a', name='A')]) self.assertEqual(self.core.tracklist.length.get(), 0) self.sendRequest('searchadd "title" "a"') self.assertEqual(self.core.tracklist.length.get(), 1) self.assertEqual(self.core.tracklist.tracks.get()[0].uri, 'dummy:a') self.assertInResponse('OK')
def test_count_correct_length(self): # Count the lone track self.backend.library.dummy_find_exact_result = SearchResult(tracks=[ Track(uri='dummy:a', name="foo", date="2001", length=4000), ]) self.sendRequest('count "title" "foo"') self.assertInResponse('songs: 1') self.assertInResponse('playtime: 4') self.assertInResponse('OK') # Count multiple tracks self.backend.library.dummy_find_exact_result = SearchResult(tracks=[ Track(uri='dummy:b', date="2001", length=50000), Track(uri='dummy:c', date="2001", length=600000), ]) self.sendRequest('count "date" "2001"') self.assertInResponse('songs: 2') self.assertInResponse('playtime: 650') self.assertInResponse('OK')
def test_list_performer_should_not_return_artists_without_names(self): self.backend.library.dummy_find_exact_result = SearchResult( tracks=[Track(performers=[Artist(name='')])]) self.sendRequest('list "performer"') self.assertNotInResponse('Artist: ') self.assertNotInResponse('Albumartist: ') self.assertNotInResponse('Composer: ') self.assertNotInResponse('Performer: ') self.assertInResponse('OK')
def search(self, query=None, uris=None): # TODO Only return results within URI roots given by ``uris`` if query is None: query = {} self._validate_query(query) result_tracks = self._uri_mapping.values() for (field, values) in query.iteritems(): if not hasattr(values, '__iter__'): values = [values] # FIXME this is bound to be slow for large libraries for value in values: if field == 'track_no': q = value else: q = value.strip().lower() uri_filter = lambda t: q in t.uri.lower() track_filter = lambda t: q in t.name.lower() album_filter = lambda t: q in getattr(t, 'album', Album() ).name.lower() artist_filter = lambda t: filter(lambda a: q in a.name.lower(), t.artists) albumartist_filter = lambda t: any([ q in a.name.lower() for a in getattr(t.album, 'artists', []) ]) track_no_filter = lambda t: q == t.track_no date_filter = lambda t: t.date and t.date.startswith(q) any_filter = lambda t: (uri_filter(t) or track_filter( t) or album_filter(t) or artist_filter( t) or albumartist_filter(t) or track_no_filter(t) or date_filter(t)) if field == 'uri': result_tracks = filter(uri_filter, result_tracks) elif field == 'track': result_tracks = filter(track_filter, result_tracks) elif field == 'album': result_tracks = filter(album_filter, result_tracks) elif field == 'artist': result_tracks = filter(artist_filter, result_tracks) elif field == 'albumartist': result_tracks = filter(albumartist_filter, result_tracks) elif field == 'track_no': result_tracks = filter(track_no_filter, result_tracks) elif field == 'date': result_tracks = filter(date_filter, result_tracks) elif field == 'any': result_tracks = filter(any_filter, result_tracks) else: raise LookupError('Invalid lookup field: %s' % field) # TODO: add local:search:<query> return SearchResult(uri='local:search', tracks=result_tracks)
def search(self, query=None, uris=None, exact=False): if "artist" in query and "album" in query and "track_name" in query: return self.search_by_artist_album_and_track( query.get("artist")[0], query.get("album")[0], query.get("track_name")[0], ) if "artist" in query and "album" in query: return self.search_by_artist_and_album( query.get("artist")[0], query.get("album")[0]) if "artist" in query: return self.search_by_artist(query.get("artist")[0], exact) if "comment" in query: if query.get("comment")[0] == "random": return SearchResult( tracks=self.subsonic_api.get_random_songs_as_tracks()) if "any" in query: return self.subsonic_api.find_as_search_result(query.get("any")[0]) return SearchResult(artists=self.subsonic_api.get_artists_as_artists())
def search_by_artist_and_album(self, artist_name, album_name): artists = self.subsonic_api.find_raw(artist_name).get("artist") if artists is None: return None tracks = [] for artist in artists: for album in self.subsonic_api.get_raw_albums(artist.get("id")): if album_name in album.get("name"): tracks.extend( self.subsonic_api.get_songs_as_tracks(album.get("id"))) return SearchResult(tracks=tracks)
def test_list_composer_should_not_return_artists_without_names(self): self.backend.library.dummy_find_exact_result = SearchResult( tracks=[Track(composers=[Artist(name="")])] ) self.send_request('list "composer"') self.assertNotInResponse("Artist: ") self.assertNotInResponse("Albumartist: ") self.assertNotInResponse("Composer: ") self.assertNotInResponse("Performer: ") self.assertInResponse("OK")
def test_searchadd(self): track = Track(uri="dummy:a", name="A") self.backend.library.dummy_library = [track] self.backend.library.dummy_search_result = SearchResult(tracks=[track]) assert self.core.tracklist.get_length().get() == 0 self.send_request('searchadd "title" "a"') assert self.core.tracklist.get_length().get() == 1 assert self.core.tracklist.get_tracks().get()[0].uri == "dummy:a" self.assertInResponse("OK")
def _find_exact(self, query=None, uris=None): # Find exact can only be done on gmusic library, # since one can't filter all access searches lib_tracks, lib_artists, lib_albums = self._search_library(query, uris) return SearchResult( uri="gmusic:search", tracks=lib_tracks, artists=lib_artists, albums=lib_albums, )
def test_searchaddpl_creates_missing_playlist(self): self.backend.library.dummy_search_result = SearchResult( tracks=[Track(uri='dummy:a', name='A')]) self.assertEqual(len(self.core.playlists.filter(name='my favs').get()), 0) self.sendRequest('searchaddpl "my favs" "title" "a"') playlists = self.core.playlists.filter(name='my favs').get() self.assertEqual(len(playlists), 1) self.assertEqual(playlists[0].tracks[0].uri, 'dummy:a') self.assertInResponse('OK')
def search(self, query=None, limit=100, offset=0, uris=None, exact=False): q = [] for field, values in (query.items() if query else []): q.extend((field, value) for value in values) # temporary workaround until Mopidy core sets limit if self._config['search_limit'] is not None: limit = self._config['search_limit'] filters = [f for uri in uris or [] for f in self._filters(uri) if f] with self._connect() as c: tracks = schema.search_tracks(c, q, limit, offset, exact, filters) uri = uritools.uricompose('local', path='search', query=q) return SearchResult(uri=uri, tracks=tracks)
def search(self, query=None, uris=None, exact=False): result = [] self.backend.radionet.do_search(' '.join(query['any'])) for station in self.backend.radionet.search_results: result.append(self.station_to_track(station)) return SearchResult( tracks=result )
def test_count_correct_length(self): # Count the lone track self.backend.library.dummy_find_exact_result = SearchResult( tracks=[Track(uri="dummy:a", name="foo", date="2001", length=4000)] ) self.send_request('count "title" "foo"') self.assertInResponse("songs: 1") self.assertInResponse("playtime: 4") self.assertInResponse("OK") # Count multiple tracks self.backend.library.dummy_find_exact_result = SearchResult( tracks=[ Track(uri="dummy:b", date="2001", length=50000), Track(uri="dummy:c", date="2001", length=600000), ] ) self.send_request('count "date" "2001"') self.assertInResponse("songs: 2") self.assertInResponse("playtime: 650") self.assertInResponse("OK")
def search(self, query=None, limit=100, offset=0, uris=None, exact=False): q = [] for field, values in (query.items() if query else []): if isinstance(values, basestring): q.append((field, values)) else: q.extend((field, value) for value in values) filters = [f for uri in uris or [] for f in self._filters(uri) if f] with self._connect() as c: tracks = schema.search_tracks(c, q, limit, offset, exact, filters) uri = uritools.uricompose('local', path='search', query=q) return SearchResult(uri=uri, tracks=tracks)
def search(self, query=None, uris=None, exact=False): # TODO Support exact search logger.info('youtube LibraryProvider.search "%s"', query) # handle only searching (queries with 'any') not browsing! if not (query and "any" in query): return None search_query = " ".join(query["any"]) logger.info('Searching YouTube for query "%s"', search_query) try: entries = youtube.Entry.search(search_query) except Exception as e: logger.error('search error "%s"', e) return None # load playlist info (to get video_count) of all playlists together playlists = [entry for entry in entries if not entry.is_video] youtube.Playlist.load_info(playlists) tracks = [] for entry in entries: if entry.is_video: uri_base = "youtube:video" album = "YouTube Video" length = int(entry.length.get()) * 1000 else: uri_base = "youtube:playlist" album = "YouTube Playlist (%s videos)" % entry.video_count.get() length = 0 name = entry.title.get() tracks.append( Track( name=name.replace(";", ""), comment=entry.id, length=length, artists=[Artist(name=entry.channel.get())], album=Album(name=album), uri="%s/%s.%s" % (uri_base, safe_url(name), entry.id), ) ) # load video info and playlist videos in the background. they should be # ready by the time the user adds search results to the playing queue for pl in playlists: pl.videos # start loading return SearchResult(uri="youtube:search", tracks=tracks)
def search(self, query=None, uris=None): if query is None: return stations = [] for (field, values) in query.iteritems(): if field == 'any': if hasattr(values, '__iter__'): values = ' '.join(values) stations += self.backend.api.search_stations_by_string(values) tracks = [self._station_to_track(station) for station in stations] return SearchResult(uri='radio-de:search', tracks=tracks)
def search(self, query=None, uris=None, exact=False): logger.debug('RadioBrowser: Start backend.RadioBrowserLibrary.search') if query is None or not query: return radiobrowser_query = translator.mopidy_to_radiobrowser_query(query) tracks = [] stations = self.backend.radiobrowser.search(radiobrowser_query) for station in stations: self.backend.radiobrowser.addStation(station) track = translator.station_to_track(station) tracks.append(track) return SearchResult(uri='radiobrowser:search', tracks=tracks)
def search(self, query=None, uris=None, exact=False): # TODO Support exact search if not query: return if "uri" in query: search_query = "".join(query["uri"]) url = urllib.parse.urlparse(search_query) if "soundcloud.com" in url.netloc: logger.info(f"Resolving SoundCloud for: {search_query}") return SearchResult( uri="soundcloud:search", tracks=self.backend.remote.resolve_url(search_query), ) else: search_query = simplify_search_query(query) logger.info(f"Searching SoundCloud for: {search_query}") return SearchResult( uri="soundcloud:search", tracks=self.backend.remote.search(search_query), )
def search(self, query=None, uris=None): if not query: return if 'uri' in query: search_query = ''.join(query['uri']) url = urlparse(search_query) if 'youtube.com' in url.netloc: req = parse_qs(url.query) if 'list' in req: return SearchResult(uri='youtube:search', tracks=resolve_playlist( req.get('list')[0])) else: logger.info("Resolving Youtube for track '%s'", search_query) return SearchResult(uri='youtube:search', tracks=[resolve_url(search_query)]) else: search_query = ' '.join(query.values()[0]) logger.info("Searching Youtube for query '%s'", search_query) return SearchResult(uri='youtube:search', tracks=search_youtube(search_query))