diff --git a/YouTubeMDBot/api/youtube_api.py b/YouTubeMDBot/api/youtube_api.py index 9fa9ec1..23b26e9 100644 --- a/YouTubeMDBot/api/youtube_api.py +++ b/YouTubeMDBot/api/youtube_api.py @@ -19,35 +19,70 @@ import json from urllib.request import urlopen -import isodate from googleapiclient.discovery import build +from isodate import parse_duration from ..constants import YOUTUBE from ..errors import EmptyBodyError class YouTubeVideoData(object): - def __init__(self, data: dict): + def __init__(self, data: dict, ignore_errors: bool = False): if not data.get("items"): raise EmptyBodyError("The data object has no items") + self.id = None + self.title = None + self.thumbnail = None + self.artist = None + self.duration = None + self.views = None + self.likes = None + self.dislikes = None if len(data.get("items")) >= 1: content = data.get("items")[0] snippet = content.get("snippet") details = content.get("contentDetails") statistics = content.get("statistics") - if not snippet: + if not snippet and not ignore_errors: raise EmptyBodyError("No information available to requested video") - if not details: + elif not snippet and ignore_errors: + snippet_available = False + else: + snippet_available = True + if not details and not ignore_errors: raise EmptyBodyError("No video details available") - if not statistics: + elif not details and ignore_errors: + details_available = False + else: + details_available = True + if not statistics and not ignore_errors: raise EmptyBodyError("No statistics available") - self.title = snippet["title"] - self.thumbnail = snippet["thumbnails"]["maxres"]["url"] - self.artist = snippet["channelTitle"] - self.duration = isodate.parse_duration(details["duration"]).total_seconds() - self.view = int(statistics["viewCount"]) - self.like = int(statistics["likeCount"]) - self.dislike = int(statistics["dislikeCount"]) + elif not statistics and ignore_errors: + statistics_available = False + else: + statistics_available = True + self.id = content["id"] + if isinstance(self.id, dict): + self.id = self.id.get("videoId") + if snippet_available: + self.title = snippet["title"] + try: + self.thumbnail = snippet["thumbnails"]["maxres"]["url"] + except KeyError: + try: + self.thumbnail = snippet["thumbnails"]["high"]["url"] + except KeyError: + try: + self.thumbnail = snippet["thumbnails"]["medium"]["url"] + except KeyError: + self.thumbnail = snippet["thumbnails"]["default"]["url"] + self.artist = snippet["channelTitle"] + if details_available: + self.duration = parse_duration(details["duration"]).total_seconds() + if statistics_available: + self.views = int(statistics["viewCount"]) + self.likes = int(statistics["likeCount"]) + self.dislikes = int(statistics["dislikeCount"]) class YouTubeAPI(object): @@ -67,6 +102,5 @@ def search(self, term: str): @staticmethod def video_details(video_id: str) -> YouTubeVideoData: api_url = YOUTUBE["endpoint"].format(video_id, YOUTUBE["key"]) - print(api_url) data = urlopen(url=api_url) return YouTubeVideoData(data=json.loads(data.read())) diff --git a/YouTubeMDBot/metadata/MetadataIdentifier.py b/YouTubeMDBot/metadata/MetadataIdentifier.py index 20bc56a..5adde34 100644 --- a/YouTubeMDBot/metadata/MetadataIdentifier.py +++ b/YouTubeMDBot/metadata/MetadataIdentifier.py @@ -39,6 +39,7 @@ def __init__(self, audio: bytes, downloader: YouTubeDownloader = None): self.score: float = 0.0 self.cover: bytes = bytes(0) self.duration: int = 0 + self.youtube_data: bool = False self._downloader = downloader @staticmethod @@ -62,8 +63,6 @@ def identify_audio(self) -> json: duration=fingerprint.duration(), meta="recordings releaseids") self.result = data - print(len(data["results"])) - print(data["results"]) if self._is_valid_result(data): for result in data["results"]: if "recordings" not in result: @@ -91,4 +90,5 @@ def identify_audio(self) -> json: self.artist = video_data.artist self.duration = video_data.duration self.cover = urlopen(video_data.thumbnail).read() + self.youtube_data = True return data diff --git a/YouTubeMDBot/tests/identifier.py b/YouTubeMDBot/tests/identifier.py index 31af4f2..3937e0e 100644 --- a/YouTubeMDBot/tests/identifier.py +++ b/YouTubeMDBot/tests/identifier.py @@ -75,13 +75,17 @@ def find_metadata(self, downloader: YouTubeDownloader): identifier.identify_audio() self.song_info[downloader.get_url()] = { "title": identifier.title, - "artist": identifier.artist, - "score": identifier.score, - "record_id": "https://musicbrainz.org/recording/{0}" - .format(identifier.recording_id), - "release_id": "https://musicbrainz.org/release/{0}" - .format(identifier.release_id) + "artist": identifier.artist } + if not identifier.youtube_data: + self.song_info[downloader.get_url()]["score"] = identifier.score + self.song_info[downloader.get_url()]["record_id"] = \ + "https://musicbrainz.org/recording/{0}".format(identifier.recording_id) + self.song_info[downloader.get_url()]["release_id"] = \ + "https://musicbrainz.org/release/{0}".format(identifier.release_id) + else: + self.song_info[downloader.get_url()]["duration"] = identifier.duration + self.song_info[downloader.get_url()]["youtube_data"] = True self.barrier() diff --git a/YouTubeMDBot/tests/song_search.py b/YouTubeMDBot/tests/song_search.py new file mode 100644 index 0000000..c4afadb --- /dev/null +++ b/YouTubeMDBot/tests/song_search.py @@ -0,0 +1,25 @@ +import unittest + +from YouTubeMDBot.api import YouTubeAPI +from YouTubeMDBot.api import YouTubeVideoData + + +class TestSearch(unittest.TestCase): + def test_search(self): + s = YouTubeAPI() + search: dict = s.search(term="test") + data = YouTubeVideoData(data=search, ignore_errors=True) + print("Title: {0}\n" + "Artist: {1}\n" + "Thumbnail: {2}\n" + "Duration: {3}\n" + "Views: {4}\n" + "Likes: {5}\n" + "Dislikes: {6}\n" + "Id: {7}".format(data.title, data.artist, data.thumbnail, + data.duration, data.views, data.likes, + data.dislikes, data.id)) + + +if __name__ == '__main__': + unittest.main()