Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
YouTube search uses the YouTube API class
There is a new behaviour defined: on `YouTubeVideoData` it is possible to ignore errors and fallback to default values (`None`). So, for YouTube search results in `YouTubeAPI` class now can be merged and combined with the `YouTubeVideoData` class
  • Loading branch information
Javinator9889 committed Sep 26, 2019
1 parent f1a7c4b commit b61bd81
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 18 deletions.
54 changes: 44 additions & 10 deletions YouTubeMDBot/api/youtube_api.py
Expand Up @@ -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")
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"]
self.duration = isodate.parse_duration(details["duration"]).total_seconds()
self.view = int(statistics["viewCount"])
self.like = int(statistics["likeCount"])
self.dislike = int(statistics["dislikeCount"])
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):
Expand All @@ -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()))
4 changes: 2 additions & 2 deletions YouTubeMDBot/metadata/MetadataIdentifier.py
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
16 changes: 10 additions & 6 deletions YouTubeMDBot/tests/identifier.py
Expand Up @@ -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()


Expand Down
25 changes: 25 additions & 0 deletions 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()

0 comments on commit b61bd81

Please sign in to comment.