]> git.0d.be Git - botaradio.git/blob - playlist.py
fix: ducking mode eating memory #95
[botaradio.git] / playlist.py
1 import json
2 import random
3 import hashlib
4
5 import util
6 import variables as var
7
8 """
9 FORMAT OF A MUSIC INTO THE PLAYLIST
10 type : url
11     id
12     url
13     title
14     path
15     duration
16     artist
17     thumbnail
18     user
19     ready (validation, no, downloading, yes, failed)
20     from_playlist (yes,no)
21     playlist_title
22     playlist_url
23
24 type : radio
25     id
26     url
27     name
28     current_title
29     user
30
31 type : file
32     id
33     path
34     title
35     artist
36     duration
37     thumbnail
38     user
39 """
40
41
42 class PlayList(list):
43     current_index = -1
44     version = 0 # increase by one after each change
45     mode = "one-shot" # "repeat", "random"
46
47
48     def __init__(self, *args):
49         super().__init__(*args)
50
51     def is_empty(self):
52         return True if len(self) == 0 else False
53
54     def set_mode(self, mode):
55         # modes are "one-shot", "repeat", "random"
56         self.mode = mode
57
58         if mode == "random":
59             self.randomize()
60
61         elif mode == "one-shot" and self.current_index > 0:
62             # remove items before current item
63             self.version += 1
64             for i in range(self.current_index):
65                 super().__delitem__(0)
66             self.current_index = 0
67
68     def append(self, item):
69         self.version += 1
70         item = util.attach_music_tag_info(item)
71         super().append(item)
72
73         return item
74
75     def insert(self, index, item):
76         self.version += 1
77
78         if index == -1:
79             index = self.current_index
80
81         item = util.attach_music_tag_info(item)
82         super().insert(index, item)
83
84         if index <= self.current_index:
85             self.current_index += 1
86
87         return item
88
89     def length(self):
90         return len(self)
91
92     def extend(self, items):
93         self.version += 1
94         items = list(map(
95             lambda item: util.attach_music_tag_info(item),
96             items))
97         super().extend(items)
98         return items
99
100     def next(self):
101         if len(self) == 0:
102             return False
103
104         self.version += 1
105         #logging.debug("playlist: Next into the queue")
106
107         if self.current_index < len(self) - 1:
108             if self.mode == "one-shot" and self.current_index != -1:
109                 super().__delitem__(self.current_index)
110             else:
111                 self.current_index += 1
112
113             return self[self.current_index]
114         else:
115             self.current_index = 0
116             if self.mode == "one-shot":
117                 self.clear()
118                 return False
119             elif self.mode == "repeat":
120                 return self[0]
121             elif self.mode == "random":
122                 self.randomize()
123                 return self[0]
124             else:
125                 raise TypeError("Unknown playlist mode '%s'." % self.mode)
126
127     def find(self, id):
128         for index, item in enumerate(self):
129             if item['id'] == id:
130                 return index
131         return None
132
133     def update(self, item, id):
134         self.version += 1
135         index = self.find(id)
136         if index:
137             self[index] = item
138             return True
139         return False
140
141     def __delitem__(self, key):
142         return self.remove(key)
143
144     def remove(self, index=-1):
145         self.version += 1
146         if index > len(self) - 1:
147             return False
148
149         if index == -1:
150             index = self.current_index
151
152         removed = self[index]
153         super().__delitem__(index)
154
155         if self.current_index > index:
156             self.current_index -= 1
157
158         return removed
159
160     def current_item(self):
161         if len(self) == 0:
162             return False
163
164         return self[self.current_index]
165
166     def current_item_downloading(self):
167         if len(self) == 0:
168             return False
169
170         if self[self.current_index]['type'] == 'url' and self[self.current_index]['ready'] == 'downloading':
171             return True
172         return False
173
174     def next_index(self):
175         if len(self) == 0 or (len(self) == 1 and self.mode == 'one_shot'):
176             return False
177
178         if self.current_index < len(self) - 1:
179             return self.current_index + 1
180         else:
181             return 0
182
183     def next_item(self):
184         if len(self) == 0 or (len(self) == 1 and self.mode == 'one_shot'):
185             return False
186
187         return self[self.next_index()]
188
189     def jump(self, index):
190         if self.mode == "one-shot":
191             for i in range(index):
192                 super().__delitem__(0)
193             self.current_index = 0
194         else:
195             self.current_index = index
196
197         self.version += 1
198         return self[self.current_index]
199
200     def randomize(self):
201         # current_index will lose track after shuffling, thus we take current music out before shuffling
202         #current = self.current_item()
203         #del self[self.current_index]
204
205         random.shuffle(self)
206
207         #self.insert(0, current)
208         self.current_index = -1
209         self.version += 1
210
211     def clear(self):
212         self.version += 1
213         self.current_index = -1
214         super().clear()
215
216     def save(self):
217         var.db.remove_section("playlist_item")
218         var.db.set("playlist", "current_index", self.current_index)
219
220         for index, music in enumerate(self):
221             if music['type'] == 'url' and music['ready'] == 'downloading':
222                 music['ready'] = 'no'
223
224             var.db.set("playlist_item", str(index), json.dumps(music))
225
226     def load(self):
227         current_index = var.db.getint("playlist", "current_index", fallback=-1)
228         if current_index == -1:
229             return
230
231         items = list(var.db.items("playlist_item"))
232         items.sort(key=lambda v: int(v[0]))
233         self.extend(list(map(lambda v: json.loads(v[1]), items)))
234
235         self.current_index = current_index
236
237     def _debug_print(self):
238         print("===== Playlist(%d) ====" % self.current_index)
239         for index, item in enumerate(self):
240             if index == self.current_index:
241                 print("-> %d %s" % (index, item['title']))
242             else:
243                 print("%d %s" % (index, item['title']))
244         print("=====      End     ====")