diff --git a/YouTubeMDBot/api/__init__.py b/YouTubeMDBot/api/__init__.py
new file mode 100644
index 0000000..4ba8496
--- /dev/null
+++ b/YouTubeMDBot/api/__init__.py
@@ -0,0 +1,17 @@
+# YouTubeMDBot
+# Copyright (C) 2019 - Javinator9889
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+from ..api.youtube_api import YouTubeAPI
+from ..api.youtube_api import YouTubeVideoData
diff --git a/YouTubeMDBot/api/youtube_api.py b/YouTubeMDBot/api/youtube_api.py
new file mode 100644
index 0000000..9fa9ec1
--- /dev/null
+++ b/YouTubeMDBot/api/youtube_api.py
@@ -0,0 +1,72 @@
+# YouTubeMDBot
+# Copyright (C) 2019 - Javinator9889
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+try:
+ import ujson as json
+except ImportError:
+ import json
+from urllib.request import urlopen
+
+import isodate
+from googleapiclient.discovery import build
+
+from ..constants import YOUTUBE
+from ..errors import EmptyBodyError
+
+
+class YouTubeVideoData(object):
+ def __init__(self, data: dict):
+ if not data.get("items"):
+ raise EmptyBodyError("The data object has no items")
+ 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:
+ raise EmptyBodyError("No information available to requested video")
+ if not details:
+ raise EmptyBodyError("No video details available")
+ if not statistics:
+ 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"])
+
+
+class YouTubeAPI(object):
+ def __init__(self):
+ self.__youtube = build(serviceName=YOUTUBE["api"]["name"],
+ version=YOUTUBE["api"]["version"],
+ developerKey=YOUTUBE["key"])
+
+ def search(self, term: str):
+ return self.__youtube.search().list(
+ q=term,
+ type="video",
+ part="id,snippet",
+ maxResults=1
+ ).execute()
+
+ @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/constants/__init__.py b/YouTubeMDBot/constants/__init__.py
index 31760cf..4b9bf4d 100644
--- a/YouTubeMDBot/constants/__init__.py
+++ b/YouTubeMDBot/constants/__init__.py
@@ -16,3 +16,4 @@
from ..constants.app_constants import ACOUSTID_KEY
from ..constants.app_constants import FPCALC
from ..constants.app_constants import YDL_CLI_OPTIONS
+from ..constants.app_constants import YOUTUBE
diff --git a/YouTubeMDBot/constants/app_constants.py b/YouTubeMDBot/constants/app_constants.py
index 56866d6..e05c7a6 100644
--- a/YouTubeMDBot/constants/app_constants.py
+++ b/YouTubeMDBot/constants/app_constants.py
@@ -15,7 +15,22 @@
# along with this program. If not, see .
import os
+# YouTube DL options
YDL_CLI_OPTIONS = ["youtube-dl", "--format", "bestaudio[ext=m4a]", "--quiet", "--output",
"-"]
+
+# FPCalc command
FPCALC = ["fpcalc", "-"]
+
+# API keys
ACOUSTID_KEY = os.environ["ACOUSTID_KEY"]
+YOUTUBE = {
+ "key": os.environ["YOUTUBE_KEY"],
+ "api": {
+ "name": "youtube",
+ "version": "v3"
+ },
+ "endpoint":
+ "https://www.googleapis.com/youtube/v3/videos?"
+ "part=id,snippet,contentDetails,statistics&id={0}&key={1}"
+}
diff --git a/YouTubeMDBot/errors/EmptyBodyError.py b/YouTubeMDBot/errors/EmptyBodyError.py
new file mode 100644
index 0000000..4706bda
--- /dev/null
+++ b/YouTubeMDBot/errors/EmptyBodyError.py
@@ -0,0 +1,19 @@
+# YouTubeMDBot
+# Copyright (C) 2019 - Javinator9889
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+class EmptyBodyError(Exception):
+ pass
diff --git a/YouTubeMDBot/errors/__init__.py b/YouTubeMDBot/errors/__init__.py
index 48f3467..9fc7566 100644
--- a/YouTubeMDBot/errors/__init__.py
+++ b/YouTubeMDBot/errors/__init__.py
@@ -13,4 +13,5 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+from ..errors.EmptyBodyError import EmptyBodyError
from ..errors.NoMatchError import NoMatchError
diff --git a/YouTubeMDBot/metadata/MetadataIdentifier.py b/YouTubeMDBot/metadata/MetadataIdentifier.py
index aaf9fa2..20bc56a 100644
--- a/YouTubeMDBot/metadata/MetadataIdentifier.py
+++ b/YouTubeMDBot/metadata/MetadataIdentifier.py
@@ -22,6 +22,7 @@
import json
from ..audio import FPCalc
+from ..api import YouTubeAPI
from ..utils import youtube_utils
from ..constants import ACOUSTID_KEY
from ..downloader import YouTubeDownloader
@@ -37,8 +38,23 @@ def __init__(self, audio: bytes, downloader: YouTubeDownloader = None):
self.recording_id: str = ""
self.score: float = 0.0
self.cover: bytes = bytes(0)
+ self.duration: int = 0
self._downloader = downloader
+ @staticmethod
+ def _is_valid_result(data: json) -> bool:
+ if "results" not in data:
+ return False
+ elif data["status"] != "ok":
+ return False
+ elif len(data["results"]) == 0:
+ return False
+ else:
+ if "recordings" not in data["results"][0]:
+ return False
+ else:
+ return True
+
def identify_audio(self) -> json:
fingerprint = FPCalc(self.audio)
data: json = acoustid.lookup(apikey=ACOUSTID_KEY,
@@ -46,7 +62,9 @@ def identify_audio(self) -> json:
duration=fingerprint.duration(),
meta="recordings releaseids")
self.result = data
- if "results" in data and data["status"] == "ok":
+ print(len(data["results"]))
+ print(data["results"])
+ if self._is_valid_result(data):
for result in data["results"]:
if "recordings" not in result:
break
@@ -60,10 +78,17 @@ def identify_audio(self) -> json:
self.title = recording["title"]
self.release_id = recording["releases"][0]["id"]
self.recording_id = recording["id"]
+ self.duration = recording["duration"]
self.cover = musicbrainzngs.get_image_front(self.release_id)
break
break
elif self._downloader:
- id = youtube_utils.get_yt_video_id(self._downloader.get_url())
-
+ from urllib.request import urlopen
+
+ video_id = youtube_utils.get_yt_video_id(self._downloader.get_url())
+ video_data = YouTubeAPI.video_details(video_id)
+ self.title = video_data.title
+ self.artist = video_data.artist
+ self.duration = video_data.duration
+ self.cover = urlopen(video_data.thumbnail).read()
return data
diff --git a/YouTubeMDBot/requirements.txt b/YouTubeMDBot/requirements.txt
index 99a3959..d00dddf 100644
--- a/YouTubeMDBot/requirements.txt
+++ b/YouTubeMDBot/requirements.txt
@@ -1,3 +1,5 @@
+isodate
+google-api-python-client
musicbrainzngs
ujson
youtube_dl
diff --git a/YouTubeMDBot/tests/identifier.py b/YouTubeMDBot/tests/identifier.py
index 03517af..31af4f2 100644
--- a/YouTubeMDBot/tests/identifier.py
+++ b/YouTubeMDBot/tests/identifier.py
@@ -71,7 +71,7 @@ def find_metadata(self, downloader: YouTubeDownloader):
f_dl_t = time()
print("Downloaded {} - elapsed time: {:.1f}s".format(downloader.get_url(),
f_dl_t - st_dl_t))
- identifier = MetadataIdentifier(audio=data)
+ identifier = MetadataIdentifier(audio=data, downloader=downloader)
identifier.identify_audio()
self.song_info[downloader.get_url()] = {
"title": identifier.title,
@@ -80,8 +80,7 @@ def find_metadata(self, downloader: YouTubeDownloader):
"record_id": "https://musicbrainz.org/recording/{0}"
.format(identifier.recording_id),
"release_id": "https://musicbrainz.org/release/{0}"
- .format(identifier.release_id),
- "cover": identifier.cover
+ .format(identifier.release_id)
}
self.barrier()