]> git.0d.be Git - botaradio.git/blob - media/file.py
REFACTOR: ITEM REVOLUTION #91
[botaradio.git] / media / file.py
1 import logging
2 import os
3 import re
4 from io import BytesIO
5 import base64
6 import hashlib
7 import mutagen
8 from PIL import Image
9 import json
10
11 import util
12 import variables as var
13 from media.item import BaseItem
14 import constants
15
16 '''
17 type : file
18     id
19     path
20     title
21     artist
22     duration
23     thumbnail
24     user
25 '''
26
27 class FileItem(BaseItem):
28     def __init__(self, bot, path, from_dict=None):
29         if not from_dict:
30             super().__init__(bot)
31             self.path = path
32             self.title = ""
33             self.artist = "??"
34             self.thumbnail = None
35             if self.path:
36                 self.id = hashlib.md5(path.encode()).hexdigest()
37                 if os.path.exists(self.uri()):
38                     self._get_info_from_tag()
39                     self.ready = "yes"
40         else:
41             super().__init__(bot, from_dict)
42             self.path = from_dict['path']
43             self.title = from_dict['title']
44             self.artist = from_dict['artist']
45             self.thumbnail = from_dict['thumbnail']
46             if not self.validate():
47                 self.ready = "failed"
48
49         self.type = "file"
50
51     def uri(self):
52         return var.music_folder + self.path
53
54     def is_ready(self):
55         return True
56
57     def validate(self):
58         if not os.path.exists(self.uri()):
59             self.log.info(
60                 "file: music file missed for %s" % self.format_debug_string())
61             self.send_client_message(constants.strings('file_missed', file=self.path))
62             return False
63
64         self.ready = "yes"
65         return True
66
67     def _get_info_from_tag(self):
68         match = re.search("(.+)\.(.+)", self.uri())
69         assert match is not None
70
71         file_no_ext = match[1]
72         ext = match[2]
73
74         try:
75             im = None
76             path_thumbnail = file_no_ext + ".jpg"
77             if os.path.isfile(path_thumbnail):
78                 im = Image.open(path_thumbnail)
79
80             if ext == "mp3":
81                 # title: TIT2
82                 # artist: TPE1, TPE2
83                 # album: TALB
84                 # cover artwork: APIC:
85                 tags = mutagen.File(self.uri())
86                 if 'TIT2' in tags:
87                     self.title = tags['TIT2'].text[0]
88                 if 'TPE1' in tags:  # artist
89                     self.artist = tags['TPE1'].text[0]
90
91                 if im is None:
92                     if "APIC:" in tags:
93                         im = Image.open(BytesIO(tags["APIC:"].data))
94
95             elif ext == "m4a" or ext == "m4b" or ext == "mp4" or ext == "m4p":
96                 # title: ©nam (\xa9nam)
97                 # artist: ©ART
98                 # album: ©alb
99                 # cover artwork: covr
100                 tags = mutagen.File(self.uri())
101                 if '©nam' in tags:
102                     self.title = tags['©nam'][0]
103                 if '©ART' in tags:  # artist
104                     self.artist = tags['©ART'][0]
105
106                 if im is None:
107                     if "covr" in tags:
108                         im = Image.open(BytesIO(tags["covr"][0]))
109
110             if im:
111                 self.thumbnail = self._prepare_thumbnail(im)
112         except:
113             pass
114
115         if not self.title:
116             self.title = os.path.basename(file_no_ext)
117
118     def _prepare_thumbnail(self, im):
119         im.thumbnail((100, 100), Image.ANTIALIAS)
120         buffer = BytesIO()
121         im = im.convert('RGB')
122         im.save(buffer, format="JPEG")
123         return base64.b64encode(buffer.getvalue()).decode('utf-8')
124
125     def to_dict(self):
126         dict = super().to_dict()
127         dict['type'] = 'file'
128         dict['path'] = self.path
129         dict['title'] = self.title
130         dict['artist'] = self.artist
131         dict['thumbnail'] = self.thumbnail
132         return dict
133
134     def format_debug_string(self):
135         return "[file] {artist} - {title} ({path})".format(
136             title=self.title,
137             artist=self.artist,
138             path=self.path
139         )
140
141     def format_song_string(self, user):
142         return constants.strings("file_item",
143                                     title=self.title,
144                                     artist=self.artist,
145                                     user=user
146                                     )
147
148     def format_current_playing(self, user):
149         display = constants.strings("now_playing", item=self.format_song_string(user))
150         if self.thumbnail:
151             thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
152                              self.thumbnail + '"/>'
153             display += "<br />" +  thumbnail_html
154
155         return display
156
157     def display_type(self):
158         return constants.strings("file")