Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""LICENSE
2Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
4This file is part of toktokkie.
6toktokkie is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
11toktokkie is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
16You should have received a copy of the GNU General Public License
17along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
18LICENSE"""
20import os
21import logging
22import mimetypes
23from typing import Dict, Any, List
24from puffotter.os import listdir
25from toktokkie.enums import IdType
26from toktokkie.exceptions import InvalidMetadata
27from toktokkie.metadata.base.IdHelper import IdHelper
28from toktokkie.metadata.base.components.JsonComponent import JsonComponent
29from toktokkie.metadata.music.components.MusicSong import MusicSong
30from toktokkie.metadata.music.components.MusicVideo import MusicVideo
33class MusicAlbum(JsonComponent):
34 """
35 Class that defines attributes of music albums
36 """
38 def __init__(
39 self,
40 parent_path: str,
41 parent_ids: Dict[IdType, List[str]],
42 ids: Dict[IdType, List[str]],
43 name: str,
44 genre: str,
45 year: int
46 ):
47 """
48 Initializes the MusicAlbum object
49 :param parent_path: The path to the parent directory
50 :param parent_ids: The IDs associated with the parent
51 :param ids: The specific IDs for this album
52 :param name: The name of the album
53 :param genre: The genre of the album
54 :param year: The year this album was released
55 """
56 self.logger = logging.getLogger(self.__class__.__name__)
58 self.parent_path = parent_path
59 self.parent_ids = parent_ids
61 self.artist_name = os.path.basename(os.path.abspath(parent_path))
63 self.name = name
64 self.genre = genre
65 self.year = year
66 self.path = os.path.join(parent_path, self.name)
68 self.ids = IdHelper.fill_ids(
69 ids, [IdType.MUSICBRAINZ_RELEASE], parent_ids
70 )
72 @property
73 def json(self) -> Dict[str, Any]:
74 """
75 Converts the component into a JSON-compatible dictionary
76 :return: The JSON-compatible dictionary
77 """
78 return {
79 "name": self.name,
80 "genre": self.genre,
81 "year": self.year,
82 "ids": IdHelper.stringify_ids(
83 IdHelper.minimize_ids(self.ids, self.parent_ids)
84 )
85 }
87 @classmethod
88 def from_json(
89 cls,
90 parent_path: str,
91 parent_ids: Dict[IdType, List[str]],
92 json_data: Dict[str, Any]
93 ) -> "MusicAlbum":
94 """
95 Generates a new MusicAlbum object based on JSON data
96 :param parent_path: The path to the parent metadata directory
97 :param parent_ids: The IDs of the parent metadata
98 :param json_data: The JSON data
99 :return: The generated object
100 :raises InvalidMetadataException: If the provided JSON is invalid
101 """
102 try:
103 return cls(
104 parent_path,
105 parent_ids,
106 IdHelper.objectify_ids(json_data["ids"]),
107 json_data["name"],
108 json_data["genre"],
109 json_data["year"]
110 )
111 except KeyError as e:
112 raise InvalidMetadata(f"Attribute missing: {e}")
114 def load_songs(self, tracknumber_sort: bool = True) -> List["MusicSong"]:
115 """
116 Loads songs from this album
117 :param tracknumber_sort: Whether or not to sort the songs by
118 tracknumber
119 Needed to avoid infinite recursion
120 in MusicSong class
121 :return: All songs in this album
122 """
123 song_files = self.__get_files("audio")
124 songs = [MusicSong(x, self) for x in song_files]
125 songs.sort(key=lambda x: x.path)
126 if tracknumber_sort:
127 songs.sort(key=lambda x: x.tracknumber[0])
128 return songs
130 @property
131 def songs(self) -> List["MusicSong"]:
132 """
133 :return: All songs in this album
134 """
135 return self.load_songs(True)
137 @property
138 def videos(self) -> List["MusicVideo"]:
139 """
140 :return: All music videos in this album
141 """
142 video_files = self.__get_files("video")
143 videos = [MusicVideo(x, self) for x in video_files]
144 videos.sort(key=lambda x: x.title)
145 return videos
147 def __get_files(self, mimetype: str) -> List[str]:
148 """
149 Retrieves the files in the album directory based on their mime type
150 :param mimetype: The mime type of the files to find
151 :return: The files with that mimetype
152 """
153 files = []
154 for _file, path in listdir(self.path, no_dirs=True):
155 guess = str(mimetypes.MimeTypes().guess_type(path)[0])
156 if guess.startswith(mimetype):
157 files.append(path)
158 return files