# -*- coding: utf-8 -*-
# Copyright (C) 2019-2022 morguldir
# Copyright (C) 2014 Thomas Amland
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
A module containing information about various media types.
Classes: :class:`Media`, :class:`Track`, :class:`Video`
"""
import copy
import dateutil.parser
import tidalapi
[docs]class Track(Media):
"""
An object containing information about a track.
"""
replay_gain = None
peak = None
isrc = None
audio_quality = None
version = None
copyright = None
[docs] def parse_track(self, json_obj):
Media.parse(self, json_obj)
self.replay_gain = json_obj['replayGain']
# Tracks from the pages endpoints might not actually exist
if 'peak' in json_obj and 'isrc' in json_obj:
self.peak = json_obj['peak']
self.isrc = json_obj['isrc']
self.copyright = json_obj['copyright']
self.audio_quality = tidalapi.Quality(json_obj['audioQuality'])
self.version = json_obj['version']
return copy.copy(self)
def _get(self, media_id):
"""
Returns information about a track, and also replaces the track used to call this function.
:param media_id: TIDAL's identifier of the track
:return: A :class:`Track` object containing all the information about the track
"""
parse = self.parse_track
return self.requests.map_request('tracks/%s' % media_id, parse=parse)
[docs] def get_url(self):
params = {
'urlusagemode': 'STREAM',
'audioquality' : self.session.config.quality,
'assetpresentation': 'FULL',
}
request = self.requests.request('GET', 'tracks/%s/urlpostpaywall' % self.id, params)
return request.json()['urls'][0]
[docs] def lyrics(self):
"""
Retrieves the lyrics for a song
:return: A :class:`Lyrics` object containing the lyrics
:raises: A :class:`requests.HTTPError` if there aren't any lyrics
"""
return self.requests.map_request('tracks/%s/lyrics' % self.id, parse=Lyrics().parse)
class Lyrics(object):
track_id = -1
provider = ""
provider_track_id = -1
provider_lyrics_id = -1
text = ""
#: Contains timestamps as well
subtitles = ""
right_to_left = False
def parse(self, json_obj):
self.track_id = json_obj['trackId']
self.provider = json_obj['lyricsProvider']
self.provider_track_id = json_obj['providerCommontrackId']
self.provider_lyrics_id = json_obj['providerLyricsId']
self.text = json_obj['lyrics']
self.subtitles = json_obj['subtitles']
self.right_to_left = bool(json_obj['isRightToLeft'])
return copy.copy(self)
[docs]class Video(Media):
"""
An object containing information about a video
"""
release_date = None
video_quality = None
cover = None
[docs] def parse_video(self, json_obj):
Media.parse(self, json_obj)
release_date = json_obj.get('releaseDate')
self.release_date = dateutil.parser.isoparse(release_date) if release_date else None
self.cover = json_obj['imageId']
# Videos found in the /pages endpoints don't have quality
self.video_quality = json_obj.get('quality')
return copy.copy(self)
def _get(self, media_id):
"""
Returns information about the video, and replaces the object used to call this function.
:param media_id: TIDAL's identifier of the video
:return: A :class:`Video` object containing all the information about the video.
"""
parse = self.parse_video
return self.requests.map_request('videos/%s' % media_id, parse=parse)
[docs] def get_url(self):
params = {
'urlusagemode': 'STREAM',
'videoquality': self.session.config.video_quality,
'assetpresentation': 'FULL'
}
request = self.requests.request('GET', 'videos/%s/urlpostpaywall' % self.id, params)
return request.json()['urls'][0]
[docs] def image(self, width=1080, height=720):
if (width, height) not in [(160, 107), (480, 320), (750, 500), (1080, 720)]:
raise ValueError("Invalid resolution {} x {}".format(width, height))
return self.session.config.image_url % (self.cover.replace('-', '/'), width, height)