def search(self, keyword, type_in=None, source_in=None, **kwargs): """search song/artist/album/playlist by keyword please use a_search method if you can. :param keyword: search keyword :param type_in: search type :param source_in: None or provider identifier list - TODO: support search with filters(by artist or by source) """ type_in = SearchType.batch_parse(type_in) if type_in else [ SearchType.so ] for provider in self._filter(identifier_in=source_in): for type_ in type_in: try: result = provider.search(keyword=keyword, type_=type_, **kwargs) except Exception: # pylint: disable=broad-except logger.exception('Search %s in %s failed.', keyword, provider) else: if result is not None: yield result
async def a_search(self, keyword, source_in=None, timeout=None, type_in=None, **kwargs): """async version of search TODO: add Happy Eyeballs requesting strategy if needed """ type_in = SearchType.batch_parse(type_in) if type_in else [ SearchType.so ] fs = [] # future list for provider in self._filter(identifier_in=source_in): for type_ in type_in: future = aio.run_in_executor( None, partial(provider.search, keyword, type_=type_)) fs.append(future) for future in aio.as_completed(fs, timeout=timeout): try: result = await future except: # noqa logger.exception('search task failed') continue else: yield result
async def a_search(self, keyword, source_in=None, timeout=None, type_in=None, **kwargs): """async version of search TODO: add Happy Eyeballs requesting strategy if needed """ type_in = SearchType.batch_parse(type_in) if type_in else [ SearchType.so ] fs = [] # future list for provider in self._filter(identifier_in=source_in): for type_ in type_in: future = aio.run_in_executor( None, partial(provider.search, keyword, type_=type_)) fs.append(future) results = [] # TODO: use async generator when we only support Python 3.6 or above for future in aio.as_completed(fs, timeout=timeout): try: result = await future except Exception as e: logger.exception(str(e)) else: if result is not None: results.append(result) return results