87 if filename == self.get_playlist_file(idx): |
89 if filename == self.get_playlist_file(idx): |
88 return idx |
90 return idx |
89 return -1 |
91 return -1 |
90 def play_file(self, filename): |
92 def play_file(self, filename): |
91 idx = self.find_in_playlist(filename) |
93 idx = self.find_in_playlist(filename) |
92 print idx |
|
93 if idx == -1: |
94 if idx == -1: |
94 self.enqueue_and_play((filename,)) |
95 self.enqueue_and_play((filename,)) |
95 else: |
96 else: |
96 self.set_playlist_pos(idx) |
97 self.set_playlist_pos(idx) |
97 |
98 |
98 class IMMSDb: |
99 class IMMSDb: |
|
100 _dbname = os.environ['HOME'] + '/.imms/imms.db' |
|
101 # _dbname = os.environ['HOME'] + '/.imms/imms.backup.db' |
|
102 def __init__(self): |
|
103 self.cx = sqlite.connect(IMMSDb._dbname) |
|
104 def commit(self): |
|
105 self.cx.commit() |
|
106 def _get_ratings(self, min = 0, max = 250): |
|
107 cu = self.cx.cursor() |
|
108 cu.execute('''SELECT Rating.uid, Rating.rating |
|
109 FROM Rating |
|
110 WHERE Rating.rating >= %d |
|
111 AND Rating.rating <= %d |
|
112 ORDER BY Rating.rating;''' % (min, max)) |
|
113 return cu.fetchall() |
|
114 def _get_library_uid(self, uid): |
|
115 cu = self.cx.cursor() |
|
116 cu.execute('''SELECT Library.path |
|
117 FROM Library |
|
118 WHERE Library.uid = %d;''' % (uid,)) |
|
119 return cu.fetchone() |
|
120 def _get_library_by_path(self, path): |
|
121 cu = self.cx.cursor() |
|
122 cu.execute('''SELECT Library.uid, Library.sid |
|
123 FROM Library |
|
124 WHERE Library.path = '%s';''' % (path)) |
|
125 return cu.fetchone() |
|
126 def get_ratings_and_info(self): |
|
127 cu = self.cx.cursor() |
|
128 cu.execute('''SELECT Rating.uid, Rating.rating, |
|
129 Library.path, Last.last |
|
130 FROM Rating, Library, Last |
|
131 WHERE Rating.uid = Library.uid AND |
|
132 Library.sid = Last.sid |
|
133 ORDER BY Rating.rating DESC;''') |
|
134 # Better to fetch everything since locking can really mess |
|
135 # things in imms plugin. |
|
136 res = cu.fetchall() |
|
137 self.commit() |
|
138 results = [] |
|
139 for tune in res: |
|
140 try: |
|
141 tmp = {'rating' : tune[1], |
|
142 'path' : tune[2].decode('latin_1', 'replace'), |
|
143 'last' : int(tune[3])} |
|
144 results.append(tmp) |
|
145 except UnicodeDecodeError: |
|
146 print tune[2] |
|
147 return results |
|
148 |
|
149 class IMMSStore(gtk.ListStore): |
|
150 COL_RATING = 0 |
|
151 COL_PATH = 1 |
|
152 COL_LAST_STR = 2 |
|
153 COL_LAST = 3 |
|
154 COL_SELECT = 4 |
|
155 def __init__(self, db, xmms): |
|
156 gtk.ListStore.__init__(self, |
|
157 gobject.TYPE_INT, |
|
158 gobject.TYPE_STRING, |
|
159 gobject.TYPE_STRING, |
|
160 gobject.TYPE_INT, |
|
161 gobject.TYPE_BOOLEAN) |
|
162 self.db = db |
|
163 self.xmms = xmms |
|
164 def refresh(self): |
|
165 curtime = time.time() |
|
166 tunes = self.db.get_ratings_and_info() |
|
167 self.clear() |
|
168 for tune in tunes: |
|
169 iter = self.append(None) |
|
170 self.set(iter, |
|
171 IMMSStore.COL_RATING, tune['rating'], |
|
172 IMMSStore.COL_PATH, tune['path'], |
|
173 IMMSStore.COL_LAST_STR, strtime(curtime-tune['last']), |
|
174 IMMSStore.COL_LAST, tune['last'], |
|
175 IMMSStore.COL_SELECT, gtk.FALSE) |
|
176 def _check_song_path(self, path, giter, song): |
|
177 self.set(giter, 4, self.get_value(giter, 1) == song) |
|
178 def set_current_song(self): |
|
179 self.foreach(IMMSStore._check_song_path, self.xmms.get_current_file()) |
|
180 |
|
181 class IMMSView(gtk.TreeView): |
|
182 def __init__(self, model, xmms): |
|
183 gtk.TreeView.__init__(self, model) |
|
184 self.create_widgets() |
|
185 def create_widgets(self): |
|
186 renderer = gtk.CellRendererText() |
|
187 renderer.set_property('weight', 700) |
|
188 # renderer.connect('double-clicked', on_clicked) |
|
189 column = gtk.TreeViewColumn(_("Rating"), renderer, |
|
190 weight_set = IMMSStore.COL_SELECT, |
|
191 text = IMMSStore.COL_RATING) |
|
192 column.set_sort_column_id(IMMSStore.COL_RATING) |
|
193 self.append_column(column) |
|
194 column = gtk.TreeViewColumn(_("File"), renderer, |
|
195 weight_set = IMMSStore.COL_SELECT, |
|
196 text = IMMSStore.COL_PATH) |
|
197 column.set_resizable(gtk.TRUE) |
|
198 column.set_sort_column_id(IMMSStore.COL_PATH) |
|
199 column.set_clickable(gtk.TRUE) |
|
200 self.append_column(column) |
|
201 column = gtk.TreeViewColumn(_("Last"), renderer, |
|
202 weight_set = IMMSStore.COL_SELECT, |
|
203 text = IMMSStore.COL_LAST_STR) |
|
204 column.set_sort_column_id(IMMSStore.COL_LAST) |
|
205 self.append_column(column) |
|
206 self.set_search_column(IMMSStore.COL_PATH) |
|
207 self.set_headers_clickable(gtk.TRUE) |
|
208 def get_selected(self): |
|
209 model, giter = self.get_selection().get_selected() |
|
210 return model.get_value(giter, IMMSStore.COL_PATH) |
|
211 |
|
212 class IMMSToolbar(gtk.Toolbar): |
99 def __init__(self): |
213 def __init__(self): |
100 self.cx = sqlite.connect(_dbname) |
214 gtk.Toolbar.__init__(self) |
101 def commit(self): |
215 self.refresh_command = None |
102 self.cx.commit() |
216 self.select_command = None |
103 def _get_ratings(self, min = 0, max = 250): |
|
104 cu = self.cx.cursor() |
|
105 cu.execute('''SELECT Rating.uid, Rating.rating |
|
106 FROM Rating |
|
107 WHERE Rating.rating >= %d |
|
108 AND Rating.rating <= %d |
|
109 ORDER BY Rating.rating;''' % (min, max)) |
|
110 return cu.fetchall() |
|
111 def _get_library_uid(self, uid): |
|
112 cu = self.cx.cursor() |
|
113 cu.execute('''SELECT Library.path |
|
114 FROM Library |
|
115 WHERE Library.uid = %d;''' % (uid,)) |
|
116 return cu.fetchone() |
|
117 def _get_library_by_path(self, path): |
|
118 cu = self.cx.cursor() |
|
119 cu.execute('''SELECT Library.uid, Library.sid |
|
120 FROM Library |
|
121 WHERE Library.path = '%s';''' % (path)) |
|
122 def get_ratings_and_info(self): |
|
123 cu = self.cx.cursor() |
|
124 cu.execute('''SELECT Rating.uid, Rating.rating, |
|
125 Library.path, Last.last |
|
126 FROM Rating, Library, Last |
|
127 WHERE Rating.uid = Library.uid AND |
|
128 Library.sid = Last.sid |
|
129 ORDER BY Rating.rating DESC;''') |
|
130 # Better to fetch everything since locking can really mess |
|
131 # things in imms plugin. |
|
132 res = cu.fetchall() |
|
133 self.commit() |
|
134 results = [] |
|
135 for tune in res: |
|
136 tmp = {'rating' : tune[1], |
|
137 'path' : tune[2], |
|
138 'last' : int(tune[3])} |
|
139 results.append(tmp) |
|
140 return results |
|
141 |
|
142 class IMMSView(Tkinter.Frame): |
|
143 def __init__(self, xmms, db, master = None): |
|
144 Tkinter.Frame.__init__(self, master) |
|
145 self.db = db |
|
146 self.xmms = xmms |
|
147 self.create_widgets() |
217 self.create_widgets() |
148 def create_widgets(self): |
218 def create_widgets(self): |
149 lf = Tkinter.Frame(self) |
219 self.append_item(_('Refresh'), _('Refresh list'), |
150 lf.pack(expand = 1, fill = Tkinter.BOTH, side = Tkinter.LEFT) |
220 None, None, self.do_refresh) |
151 self.lb = Tkinter.Listbox(lf, relief = Tkinter.RAISED) |
221 self.append_item(_('Plot'), _('Show graph of rates'), |
152 self.lb.pack(expand = 1, side = Tkinter.TOP, fill = Tkinter.BOTH) |
222 None, None, self.plot) |
153 xsb = Tkinter.Scrollbar(lf, orient = Tkinter.HORIZONTAL) |
223 self.append_item(_('Current'), _('Get current song'), |
154 xsb.pack({'fill' : Tkinter.X, 'side' : Tkinter.BOTTOM}) |
224 None, None, self.do_get_current) |
155 ysb = Tkinter.Scrollbar(self) |
225 def plot(self, data): |
156 ysb.pack({'fill' : Tkinter.Y, 'side' : Tkinter.RIGHT}) |
226 os.system('/home/fabien/bin/immsplot &') |
157 |
227 def do_refresh(self, data): |
158 ysb['command'] = self.lb.yview |
|
159 xsb['command'] = self.lb.xview |
|
160 self.lb['yscrollcommand'] = ysb.set |
|
161 self.lb['xscrollcommand'] = xsb.set |
|
162 self.lb.bind("<Double-Button-1>", self.play_selection) |
|
163 |
|
164 self.refresh() |
|
165 |
|
166 def refresh(self): |
|
167 curtime = time.time() |
|
168 self.tunes = self.db.get_ratings_and_info() |
|
169 self.lb.delete(0,self.lb.size()) |
|
170 l = [] |
|
171 for tune in self.tunes: |
|
172 l.append("%4d: %s [%s]" % |
|
173 (tune['rating'], tune['path'], |
|
174 strtime(curtime - tune['last']))) |
|
175 apply(self.lb.insert, [0]+ l) |
|
176 self.select_current() |
|
177 def select_current(self): |
|
178 fn = self.xmms.get_current_file() |
|
179 tune = filter(lambda x: x['path'] == fn, self.tunes) |
|
180 if len(tune): |
|
181 idx = self.tunes.index(tune[0]) |
|
182 self.lb.see(idx) |
|
183 self.lb.select_set(idx) |
|
184 def play_selection(self, event): |
|
185 sel = self.lb.curselection() |
|
186 if len(sel) > 0: |
|
187 fn = self.tunes[int(sel[0])]['path'] |
|
188 self.xmms.play_file(fn) |
|
189 |
|
190 class IMMSToolbar(Tkinter.Frame): |
|
191 def __init__(self, master = None): |
|
192 Tkinter.Frame.__init__(self, master) |
|
193 self.refresh_command = None |
|
194 self.create_widgets() |
|
195 def create_widgets(self): |
|
196 button = Tkinter.Button(self, text = _('Refresh'), |
|
197 command = self.do_refresh) |
|
198 button.pack(side = Tkinter.LEFT) |
|
199 button = Tkinter.Button(self, text = _('Plot'), |
|
200 command = self.plot) |
|
201 button.pack(side = Tkinter.LEFT) |
|
202 button = Tkinter.Button(self, text = _('Current'), |
|
203 command = self.do_get_current) |
|
204 button.pack(side = Tkinter.LEFT) |
|
205 def plot(self): |
|
206 os.system('exec immsplot &') |
|
207 def do_refresh(self): |
|
208 if (self.refresh_command): |
228 if (self.refresh_command): |
209 self.refresh_command() |
229 self.refresh_command() |
210 def do_get_current(self): |
230 def do_get_current(self, data): |
211 if (self.get_current): |
231 if (self.get_current): |
212 self.get_current() |
232 self.get_current() |
213 |
233 |
214 root = Tkinter.Tk() |
234 root = gtk.Window() |
215 root.wm_title(_("IMMSview")) |
235 root.set_name(_("IMMSview")) |
216 iview = IMMSView(XMMSControl(), IMMSDb(), root) |
236 root.connect('destroy', gtk.mainquit) |
217 iview.pack(side = Tkinter.BOTTOM, expand = 1, fill = Tkinter.BOTH) |
237 vbox = gtk.VBox(spacing = 3) |
|
238 root.add(vbox) |
|
239 vbox.show() |
|
240 xmms_control = XMMSControl() |
|
241 model = IMMSStore(IMMSDb(), xmms_control) |
|
242 iview = IMMSView(model, xmms_control) |
|
243 scroll = gtk.ScrolledWindow() |
|
244 scroll.add(iview) |
|
245 vbox.pack_end(scroll) |
|
246 iview.show() |
|
247 scroll.show() |
218 toolbar = IMMSToolbar() |
248 toolbar = IMMSToolbar() |
219 toolbar.refresh_command = iview.refresh |
249 toolbar.refresh_command = model.refresh |
220 toolbar.get_current = iview.select_current |
250 toolbar.get_current = model.set_current_song |
221 toolbar.pack(side = Tkinter.TOP, fill = Tkinter.X) |
251 vbox.pack_start(toolbar, expand = gtk.FALSE) |
222 root.mainloop() |
252 toolbar.show() |
|
253 root.show() |
|
254 model.refresh() |
|
255 model.set_current_song() |
|
256 gtk.main() |