12 import variables as var
13 from media.item import BaseItem, item_builders, item_loaders, item_id_generators
27 def file_item_builder(bot, **kwargs):
28 return FileItem(bot, kwargs['path'])
30 def file_item_loader(bot, _dict):
31 return FileItem(bot, "", _dict)
33 def file_item_id_generator(**kwargs):
34 return hashlib.md5(kwargs['path'].encode()).hexdigest()
36 item_builders['file'] = file_item_builder
37 item_loaders['file'] = file_item_loader
38 item_id_generators['file'] = file_item_id_generator
41 class FileItem(BaseItem):
42 def __init__(self, bot, path, from_dict=None):
50 self.id = hashlib.md5(path.encode()).hexdigest()
51 if os.path.exists(self.uri()):
52 self._get_info_from_tag()
55 super().__init__(bot, from_dict)
56 self.path = from_dict['path']
57 self.title = from_dict['title']
58 self.artist = from_dict['artist']
59 self.thumbnail = from_dict['thumbnail']
60 if not self.validate():
66 return var.music_folder + self.path if self.path[0] != "/" else self.path
72 if not os.path.exists(self.uri()):
74 "file: music file missed for %s" % self.format_debug_string())
75 self.send_client_message(constants.strings('file_missed', file=self.path))
78 self.version = 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time
82 def _get_info_from_tag(self):
83 match = re.search("(.+)\.(.+)", self.uri())
84 assert match is not None
86 file_no_ext = match[1]
91 path_thumbnail = file_no_ext + ".jpg"
92 if os.path.isfile(path_thumbnail):
93 im = Image.open(path_thumbnail)
99 # cover artwork: APIC:
100 tags = mutagen.File(self.uri())
102 self.title = tags['TIT2'].text[0]
103 if 'TPE1' in tags: # artist
104 self.artist = tags['TPE1'].text[0]
108 im = Image.open(BytesIO(tags["APIC:"].data))
110 elif ext == "m4a" or ext == "m4b" or ext == "mp4" or ext == "m4p":
111 # title: ©nam (\xa9nam)
114 # cover artwork: covr
115 tags = mutagen.File(self.uri())
117 self.title = tags['©nam'][0]
118 if '©ART' in tags: # artist
119 self.artist = tags['©ART'][0]
123 im = Image.open(BytesIO(tags["covr"][0]))
126 self.thumbnail = self._prepare_thumbnail(im)
131 self.title = os.path.basename(file_no_ext)
133 def _prepare_thumbnail(self, im):
134 im.thumbnail((100, 100), Image.ANTIALIAS)
136 im = im.convert('RGB')
137 im.save(buffer, format="JPEG")
138 return base64.b64encode(buffer.getvalue()).decode('utf-8')
141 dict = super().to_dict()
142 dict['type'] = 'file'
143 dict['path'] = self.path
144 dict['title'] = self.title
145 dict['artist'] = self.artist
146 dict['thumbnail'] = self.thumbnail
149 def format_debug_string(self):
150 return "[file] {descrip} ({path})".format(
151 descrip=self.format_short_string(),
155 def format_song_string(self, user):
156 return constants.strings("file_item",
162 def format_current_playing(self, user):
163 display = constants.strings("now_playing", item=self.format_song_string(user))
165 thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
166 self.thumbnail + '"/>'
167 display += "<br />" + thumbnail_html
171 def format_short_string(self):
172 title = self.title if self.title else self.path
174 return self.artist + " - " + title
178 def display_type(self):
179 return constants.strings("file")