00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 import pygtk
00023 pygtk.require('2.0')
00024 import gtk
00025 import gobject
00026
00027
00028 import gtk.glade
00029
00030 import os
00031 import sys
00032
00033 if os.name == "posix" or os.name == "mac":
00034 sys.path.append("/usr/share/apps/pyjama")
00035 else:
00036 sys.path.append(os.path.join(os.getenv('PROGRAMFILES'), "pyjama"))
00037
00038
00039 from time import strftime, gmtime, time, sleep
00040
00041
00042 import re
00043 import hashlib
00044
00045
00046
00047 import shutil
00048 import tarfile
00049
00050
00051 import pickle
00052
00053 import clMain
00054 from clWidgets import *
00055 import clEntry
00056 import clMenu, clToolbar
00057 import functions
00058 import clLayouts
00059 from clLayouts.default_layouts import clAlbumBrowser, clAlbumLayout, clArtistLayout
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 class winGTK(gtk.Window):
00070 def __init__(self, options, parent=None):
00071 self.__alldone = False
00072 self.options = options
00073
00074 self.main = clMain.main(self, options)
00075 self.main.settings.set_value("PYJAMA", "crashed", True)
00076
00077 self.layout = {}
00078
00079
00080 self.bgcolor = "#4785C2"
00081
00082
00083 self.CellBGColor = "STANDARD"
00084 self.CellSize = 8
00085 self.markupCurPlaying = '<span foreground="blue"><i><b>__ARTIST__</b></i>\n __NUM__) __TITLE__</span>'
00086 self.markupNormalEntry ='<span>__ARTIST__\n __NUM__) __TITLE__</span>'
00087
00088 gtk.Window.__init__(self)
00089
00090
00091
00092
00093
00094 self.event_delete = self.connect('delete_event', self.quit)
00095 self.set_title("Pyjama - Python Jamendo Audiocenter")
00096 self.set_default_size(850, 600)
00097 self.set_position(gtk.WIN_POS_CENTER)
00098 self.set_icon_from_file(os.path.join(functions.install_dir(), "images", "pyjama.png"))
00099 self.set_skip_taskbar_hint(not self.main.settings.get_value("PYJAMA", "show_window_in_taskbar", False))
00100
00101 self.set_border_width(0)
00102 self.event_window_state = self.connect('window-state-event', self.window_state_event)
00103
00104 self.vbox = gtk.VBox(False, 0)
00105 self.add(self.vbox)
00106 self.vbox.set_border_width(5)
00107
00108
00109
00110
00111 self.tooltip_delay = self.main.settings.get_value("PERFORMANCE", "TOOLTIP_DELAY", 70)
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 self.vbTop = gtk.VBox()
00122 self.vbox.pack_start(self.vbTop, False, False)
00123
00124 self.hpaned = gtk.HPaned()
00125 self.vbox.pack_start(self.hpaned, True, True, 0)
00126
00127
00128
00129 self.vbMain = gtk.VBox()
00130 self.vpaned = gtk.VPaned()
00131
00132
00133 self.hpaned.pack1(self.vbMain, True, False)
00134 self.vbMedia = gtk.VBox()
00135 self.vbMain.pack_end(self.vbMedia, True, True)
00136 self.vbMedia.pack_end(self.vpaned, True, True)
00137
00138
00139
00140
00141 self.menubar = clMenu.Menu(self)
00142
00143 self.vbTop.pack_start(self.menubar, False, False)
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 self.toolbar = clToolbar.Toolbar(self)
00155
00156 self.vbTop.pack_start(self.toolbar, False, False)
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 self.scrolledwindow = gtk.ScrolledWindow()
00167 self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
00168 self.scrolledwindow.set_size_request(550, 150)
00169 self.event_scrolled_window_resize = self.scrolledwindow.connect("size-allocate", self.scrolled_window_resize)
00170
00171
00172 self.vbMainLayout = gtk.VBox()
00173 self.vbMainLayout.pack_end(self.scrolledwindow, True, True)
00174
00175
00176 self.f = gtk.Frame()
00177 self.f.set_shadow_type(gtk.SHADOW_IN)
00178 self.LayoutInfo = InfoLabel(self.main)
00179 self.f.set_label_widget(self.LayoutInfo)
00180 self.f.add(self.vbMainLayout)
00181
00182
00183
00184
00185 self.vpaned.pack1(self.f, True, True)
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 self.vbSideBar = gtk.VBox(False)
00217 self.swTreeView = gtk.ScrolledWindow()
00218 self.swTreeView.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
00219
00220 self.liststore = gtk.ListStore(gobject.TYPE_STRING)
00221
00222 self.tvPlaylist = gtk.TreeView(self.liststore)
00223 self.tvPlaylist.props.has_tooltip = True
00224 self.tooltip_timestamp = 0
00225 self.tvPlaylist.connect('query-tooltip', self.cb_query_tooltip)
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 self.tvPlaylist.connect("row_activated", self.on_tvPlaylist_row_activated)
00236 self.tvPlaylist.connect("cursor-changed", self.on_tvPlaylist_cursor_changed)
00237 self.tvPlaylist.connect("motion-notify-event", self.on_tvPlaylist_motion_notify)
00238 self.tvPlaylist.connect("enter-notify-event", self.on_tvPlaylist_enter_notify)
00239 self.tvPlaylist.connect("leave-notify-event", self.on_tvPlaylist_leave_notify)
00240 self.tvPlaylist.connect("button-press-event", self.on_tvPlaylist_button_press)
00241 self.tvPlaylist.connect("key-press-event",self.on_tvPlaylist_key_press)
00242
00243
00244 self.tvPlaylistSelection = self.tvPlaylist.get_selection()
00245 self.tvPlaylistSelection.set_mode(gtk.SELECTION_SINGLE)
00246
00247 self.cell = gtk.CellRendererText()
00248
00249
00250 self.tvColumn = gtk.TreeViewColumn('Playlist', self.cell, markup=0)
00251
00252 self.tvPlaylist.append_column(self.tvColumn)
00253
00254 self.tvPlaylist.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, [('text/plain', gtk.TARGET_SAME_APP, 0)], gtk.gdk.ACTION_MOVE)
00255 self.tvPlaylist.connect("drag-data-get", self.on_tvPlaylist_DragDataGet)
00256
00257 self.tvPlaylist.enable_model_drag_dest([('text/plain', 0, 0)], gtk.gdk.ACTION_MOVE)
00258 self.tvPlaylist.connect("drag-data-received", self.on_tvPlaylist_DragDataReceived)
00259
00260 self.tvPlaylist.connect("drag_data_delete", self.on_tvPlaylist_DragDataEnd)
00261
00262
00263
00264
00265 self.swTreeView.add(self.tvPlaylist)
00266 self.swTreeView.set_size_request(150, 100)
00267
00268
00269 self.pbSong = gtk.ProgressBar()
00270 self.pbSong.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
00271 self.pbSong.set_pulse_step(0.05)
00272 self.pbSong.set_tooltip_text("Left click: Seek the stream\nRight click: Switch time display")
00273 self.ebProgressbar = gtk.EventBox()
00274 self.ebProgressbar.add(self.pbSong)
00275 self.ebProgressbar.set_above_child(False)
00276 self.ebProgressbar.add_events (gtk.gdk.BUTTON_RELEASE)
00277 self.ebProgressbar.connect("button_release_event", self.on_pbSong_clicked)
00278 self.pbSong.ShowRemainingTime = False
00279 self.pbSong.counter = 0
00280
00281
00282 hsAdjustment = gtk.Adjustment(value=self.main.settings.get_value("SOUND", "default_vol"), lower=0, upper=self.main.settings.get_value("SOUND", "vol_max"), step_incr=10, page_incr=2, page_size=10)
00283 self.hsVolume = gtk.VolumeButton()
00284 self.hsVolume.set_value(self.main.settings.get_value("SOUND", "default_vol"))
00285 self.hsVolume.set_adjustment(hsAdjustment)
00286 self.hsVolume.connect("value-changed", self.on_sbVolume_Change)
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 self.tbControls = gtk.Table(1, 4, True)
00298
00299
00300
00301
00302
00303
00304 self.bPrev = StockButton(gtk.STOCK_MEDIA_PREVIOUS)
00305
00306 self.bPrev.connect("clicked", self.on_bPrev_clicked)
00307 self.bPrev.set_tooltip_text(_("Play previous"))
00308 self.tbControls.attach(self.bPrev, 0, 1, 0, 1)
00309
00310 self.bPlay = StockButton(gtk.STOCK_MEDIA_PLAY)
00311
00312 self.bPlay.connect("clicked", self.on_bPlay_clicked)
00313 self.bPlay.connect("button_press_event", self.on_bPlay_pressed)
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 self.bPlay.set_tooltip_text("%s\n%s" % (_("Play/pause"), _("Right click for stop")))
00325
00326 self.tbControls.attach(self.bPlay, 1, 2, 0, 1)
00327
00328
00329
00330
00331
00332
00333
00334 self.bNext = StockButton(gtk.STOCK_MEDIA_NEXT)
00335
00336 self.bNext.connect("clicked", self.on_bNext_clicked)
00337 self.bNext.set_tooltip_text(_("Play next"))
00338 self.tbControls.attach(self.bNext, 2, 3, 0, 1)
00339
00340 self.tbControls.attach(self.hsVolume, 3, 4, 0, 1)
00341
00342
00343
00344
00345
00346
00347 self.tbPlaylist = gtk.Table(1, 4, True)
00348
00349 self.bDelete = StockButton(gtk.STOCK_REMOVE)
00350 self.bDelete.connect("clicked", self.on_bDelete_clicked)
00351 self.bDelete.set_tooltip_text(_("Remove selected song from playlist"))
00352 self.tbPlaylist.attach(self.bDelete, 0, 1, 0, 1)
00353
00354 self.bClear = StockButton(gtk.STOCK_CLEAR)
00355 self.bClear.connect("clicked", self.on_bClear_clicked)
00356 self.bClear.set_tooltip_text(_("Clear playlist"))
00357 self.tbPlaylist.attach(self.bClear, 1, 2, 0, 1)
00358
00359 self.bSave = StockButton(gtk.STOCK_SAVE)
00360 self.bSave.connect("clicked", self.on_bSave_clicked)
00361 self.bSave.set_tooltip_text(_("Save Playlist"))
00362 self.tbPlaylist.attach(self.bSave, 2, 3, 0, 1)
00363
00364 self.bLoad = StockButton(gtk.STOCK_OPEN)
00365 self.bLoad.connect("clicked", self.on_bLoad_clicked)
00366 self.bLoad.set_tooltip_text(_("Load Playlist"))
00367 self.tbPlaylist.attach(self.bLoad, 3, 4, 0, 1)
00368
00369
00370
00371
00372
00373
00374
00375 SideBarFrame = gtk.Frame(_("Playlist"))
00376 SideBarFrame.set_shadow_type(gtk.SHADOW_IN)
00377 SideBarFrame.add(self.vbSideBar)
00378 self.hpaned.pack2(SideBarFrame, False, True)
00379 self.hpaned.set_position(700)
00380
00381
00382 self.vbCover = gtk.VBox()
00383 self.vbSideBar.pack_start(self.vbCover, False, True, 5)
00384 self.lbCoverArtist = gtk.Label("")
00385 self.lbCoverAlbum = gtk.Label("")
00386 self.imgCover = gtk.Image()
00387 self.imgCover.set_size_request(100,100)
00388 sep = gtk.HSeparator()
00389 self.vbCover.pack_start(self.imgCover, False, True)
00390 self.vbCover.pack_start(self.lbCoverArtist, False, True)
00391 self.vbCover.pack_start(self.lbCoverAlbum, False, True)
00392 self.vbCover.pack_end(sep, False, False, 5)
00393
00394 if True:
00395 self.imgCover.set_from_file(os.path.join(functions.install_dir(), "images", "pyjama.png"))
00396 else:
00397 animation = gtk.gdk.PixbufAnimation(os.path.join(functions.install_dir(), "images", "pyjama_anim.gif"))
00398 self.imgCover.set_from_animation(animation)
00399 self.lbCoverArtist.set_text('Pyjama')
00400 self.lbCoverAlbum.set_text('Python Jamendo Audio')
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 self.vbSideBar.pack_start(self.tbControls, False, True)
00418 self.vbSideBar.pack_start(self.ebProgressbar, False, True)
00419
00420 self.vbSideBar.pack_start(self.swTreeView, True, True)
00421
00422 self.vbSideBar.pack_start(self.tbPlaylist, False, True)
00423
00424
00425
00426 self.tvSelection = self.tvPlaylist.get_selection()
00427
00428
00429
00430
00431 self.sbStatus = StatusBar("Counter", "Info", "VarInfo", "Player")
00432 self.sbStatus.statusbars["Player"]['statusbar'].set_size_request(100,-1)
00433 self.sbStatus.set_text("Counter", _("Artists: %i, Albums: %i, Tracks: %i") % (self.main.db.artists, self.main.db.albums, self.main.db.tracks))
00434
00435 self.sbStatus.show()
00436 self.vbox.pack_start(self.sbStatus, False, True, 0)
00437
00438 self.pbWait = gtk.ProgressBar()
00439 self.vbox.pack_start(self.pbWait, False, True, 0)
00440 self.pbWait.set_pulse_step(0.02)
00441 self.pbWait.show()
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 if self.CellBGColor != "STANDARD":
00459 self.cell.set_property('cell-background', self.CellBGColor)
00460 self.cell.set_property('size-points', self.CellSize)
00461
00462
00463
00464
00465
00466
00467 self.swTVList = gtk.ScrolledWindow()
00468 self.swTVList.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
00469 self.tvList = TreeViewList()
00470 self.tvList.connect("row_activated", self.on_tvList_row_activated)
00471 self.tvList.connect("button-press-event", self.on_tvList_button_press)
00472 self.swTVList.add(self.tvList)
00473
00474
00475
00476
00477
00478 self.vpaned2 = gtk.VPaned()
00479 self.vpaned.pack2(self.vpaned2, True, True)
00480
00481
00482 self.TVListFrame = gtk.Frame(_("Tracklist"))
00483 self.TVListFrame.add(self.swTVList)
00484
00485 self.vpaned2.pack1(self.TVListFrame, True, True)
00486
00487
00488
00489
00490 self.show_all()
00491
00492
00493 chkCover = gtk.CheckMenuItem(_("Show Cover Image"))
00494 chkCover.set_active(self.main.settings.get_value("PYJAMA", "SHOW_COVER", True))
00495 view = self.menubar.get_rootmenu("View").get_submenu()
00496 view.insert(chkCover, 0)
00497 chkCover.connect("activate", self.switch_show_cover)
00498 chkCover.show()
00499 self.switch_show_cover(chkCover)
00500 sep = gtk.SeparatorMenuItem()
00501 view.insert(sep, 1)
00502 sep.show()
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 self.pbWait.hide()
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 self.main.layouts.register_layout("top", clAlbumBrowser.AlbumBrowser(self.main))
00524 self.main.layouts.register_layout("album", clAlbumLayout.AlbumLayout(self.main))
00525 self.main.layouts.register_layout("artist", clArtistLayout.ArtistLayout(self.main))
00526
00527
00528 menu = self.menubar
00529 entry = menu.append_entry(menu.get_rootmenu("Browse"), _("Albums"), "top")
00530 entry.connect("activate", self.cb_show_album_browser)
00531 menu.set_item_image(entry, os.path.join(functions.install_dir(), "images", "star.png"))
00532 menu.show()
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542 if options.update or not self.main.db.database_ok:
00543 self.main.download_database()
00544 if options.update_jamendo:
00545 self.main.download_database(force_jamendo=True)
00546
00547
00548 self.__alldone = True
00549 ev = self.main.Events
00550 ev.raise_event("alldone")
00551
00552
00553
00554 menu = self.menubar
00555 root = menu.get_rootmenu("Extras")
00556 if root:
00557 menu.append_entry(root, "---", "prefsep")
00558 mnu = menu.append_entry(root, _("Preferences"), "preferences")
00559 menu.set_item_image(mnu, gtk.STOCK_PREFERENCES)
00560 mnu.connect("activate", self.main.show_preferences)
00561
00562 self.main.jamendo.last_query_hack()
00563 self.main.go_home()
00564
00565
00566 if "check-time" in sys.argv:
00567 sys.exit()
00568
00569 self.__special_checks()
00570
00571 if self.main.plugins.blacklisted_browser:
00572 self.main.need_attention = True
00573 self.main.info("Blacklisted browser", "Pyjama probably crashed last time.\nIn most cases <b>mozplug</b> or <b>webkit-plugin</b> a responsible for that.\n\nThe browser-pluins where disabled for this reason")
00574 self.main.need_attention = False
00575
00576 self.main.need_attention = True
00577 self.main.info("Experimental!", "You are using an <b>experimental version</b> of pyjama. It was released to let you review some new features of my program.\nPlease: Report any bugs via \n\n<u>bugs.launchpad.net/pyjama</u>.\n\nThanks!")
00578 self.main.need_attention = False
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 def cb_query_tooltip(self, widget, x, y, keyboard_tip, tooltip):
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643 if self.tooltip_timestamp + self.tooltip_delay > time()*1000:
00644 return False
00645 self.tooltip_timestamp = time()*1000
00646
00647 y = y - 27
00648
00649
00650 hbox = gtk.HBox()
00651 vbox1 = gtk.VBox(True)
00652 vbox2 = gtk.VBox(True)
00653 hbox.pack_start(vbox1, False, True)
00654 hbox.pack_start(vbox2, False, True)
00655
00656 hbox.set_spacing (10)
00657 vbox1.set_spacing (10)
00658 vbox2.set_spacing (10)
00659
00660
00661
00662 l = gtk.Label()
00663 path = self.tvPlaylist.get_path_at_pos(int(x), int(y))
00664 if path:
00665
00666 track = self.main.player.playlist[path[0][0]]
00667 img_uri = self.main.get_album_image(track.album_id)
00668 if img_uri:
00669 img = gtk.Image()
00670 try:
00671 pix = gtk.gdk.pixbuf_new_from_file_at_size(img_uri, 50, 50)
00672 img.set_from_pixbuf(pix)
00673 except:
00674 img.set_from_stock(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_BUTTON)
00675 img.show()
00676 vbox1.pack_start(img, False, True)
00677
00678 l.set_markup("<b>%s</b>\n%s\n%s" % (track.artist_name[:30], track.album_name[:30], track.name[:30]))
00679 l.show()
00680 vbox2.pack_start(l, False, True)
00681
00682
00683 else:
00684 return False
00685
00686
00687 hbox.show_all()
00688
00689
00690
00691 self.main.Events.raise_event("playlist_tooltip", x, y, (vbox1, vbox2))
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706 tooltip.set_custom(hbox)
00707 return True
00708
00709 def cb_show_album_browser(self, widget):
00710 self.main.layouts.show_layout("top", 10, "ratingweek", 1, "all", who_called = "window.__init__")
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 def switch_show_cover(self, widget):
00734 show = widget.get_active()
00735 if show is True:
00736 self.vbCover.show()
00737 self.main.settings.set_value("PYJAMA", "SHOW_COVER", "True")
00738 else:
00739 self.main.settings.set_value("PYJAMA", "SHOW_COVER", "False")
00740 self.vbCover.hide()
00741
00742 def window_state_event(self, widget, event):
00743 if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
00744 self.window.visible = False
00745
00746 def show_window(self,ev):
00747 self.present()
00748
00749
00750 def on_tvPlaylist_key_press(self, widget, event):
00751 if event.keyval == 32:
00752 self.on_bPlay_clicked(None)
00753 return True
00754
00755 def on_tvPlaylist_row_activated(self, treeview, path, view_column):
00756 if path:
00757 self.on_bStop_clicked(None)
00758 self.on_bPlay_clicked(path[0])
00759
00760 def on_tvPlaylist_enter_notify(self, treeview, event):
00761 pass
00762
00763
00764
00765
00766 def on_tvPlaylist_leave_notify(self, treeview, event):
00767
00768 self.main.showInfo()
00769
00770 def on_tvPlaylist_motion_notify(self, treeview, event):
00771 ret = treeview.get_path_at_pos(int(event.x), int(event.y))
00772
00773 if ret != None:
00774 current_path, current_column = ret[:2]
00775 self.main.showInfo(current_path[0])
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 def on_tvPlaylist_cursor_changed(self, treeview):
00797 self.main.showInfo()
00798
00799 def on_pbSong_clicked(self, widget, event):
00800 if event.button == 3:
00801 self.pbSong.ShowRemainingTime = not self.pbSong.ShowRemainingTime
00802 self.main.timer_event()
00803 elif event.button == 1 and self.main.player.status == "Playing" or self.main.player.status == "paused":
00804
00805 allocation = widget.get_allocation()
00806 width = allocation[2]
00807
00808 pointer = widget.get_pointer()
00809 x = pointer[0]
00810
00811
00812 percentage = x * 100 / width
00813
00814
00815 real = long(percentage * self.main.player.duration* (10**7))
00816 self.main.player.seek(real)
00817
00818
00819 def on_tvList_DragDataGet(self, widget, drag_context, selection, info, timestamp):
00820 tvListSelection = widget.get_selection()
00821 model, iter = tvListSelection.get_selected()
00822 data = model.get_value(iter, 0)
00823 path = model.get_path(iter)
00824
00825
00826
00827
00828 data= pickle.dumps({'source':'list','data':data,'path':path})
00829 print {'source':'list','data':data,'path':path}
00830 selection.set(selection.target, 8, data)
00831 return
00832
00833 def on_tvPlaylist_DragDataGet(self, widget, drag_context, selection, info, timestamp):
00834 tvPlaylistSelection = self.tvPlaylist.get_selection()
00835 model, iter = tvPlaylistSelection.get_selected()
00836 data = model.get_value(iter, 0)
00837 path = model.get_path(iter)
00838
00839 data= pickle.dumps({'source':'playlist','data':data,'path':path})
00840
00841 selection.set(selection.target, 8, data)
00842 return
00843
00844
00845 def on_tvPlaylist_DragDataReceived(self, widget, context, x, y, selection, info, timestamp):
00846 model = widget.get_model()
00847 data = selection.data
00848 data = pickle.loads(data)
00849 source = data['source']
00850 if source == "playlist":
00851 data = [data]
00852 drop_info = widget.get_dest_row_at_pos(x, y)
00853 for datum in data:
00854 if drop_info:
00855 destpath, position = drop_info
00856 iter = model.get_iter(destpath)
00857
00858 destpath = destpath[0]
00859 sourcepath = datum['path'][0]
00860
00861 datum = datum['data']
00862 if self.main.debug_extreme:
00863 print "!", sourcepath, destpath, "!"
00864 if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
00865 if self.main.debug_extreme:
00866 print "into intoorbefore"
00867 model.insert_before(iter, [datum])
00868 self.main.move_playlist_item(sourcepath, destpath, before=True)
00869 else:
00870 if self.main.debug_extreme:
00871 print "else"
00872 self.main.move_playlist_item(sourcepath, destpath, before=False)
00873 model.insert_after(iter, [datum])
00874 else:
00875 return
00876 if context.action == gtk.gdk.ACTION_MOVE:
00877 context.finish(True, True, timestamp)
00878 return
00879
00880 def on_tvPlaylist_DragDataEnd(widget, context, data):
00881 pass
00882
00883 def on_tvPlaylist_button_press(self, widget, event):
00884 if event.button == 3:
00885
00886
00887
00888
00889
00890
00891 mnu = PlaylistMenu(self.main)
00892 mnu.popup(None, None, None, event.button, event.time)
00893 if mnu.get_children() == []:
00894 mnu.destroy()
00895
00896 def on_tvList_row_activated(self, treeview, path, view_column):
00897
00898 ret = self.tvList.get_item(path)
00899 tracknum = ret[self.tvList.COLUMN_TRACKNUM]
00900 trackid = ret[self.tvList.COLUMN_TRACKID]
00901 albumid = ret[self.tvList.COLUMN_ALBUMID]
00902 artistid = ret[self.tvList.COLUMN_ARTISTID]
00903 if trackid > -1:
00904 track = self.main.db.get_trackinfos2(trackid)
00905
00906 self.main.add2playlist(track)
00907 elif albumid > -1:
00908 print albumid
00909 albumdetails = self.main.jamendo.albuminfos(albumid)
00910 if albumdetails == None:
00911 tofast(self.window)
00912 return None
00913 elif albumdetails == -1:
00914 return None
00915 self.main.layouts.show_layout("album", albumdetails, who_called = "on_tvList_row_activated")
00916 elif artistid > -1:
00917 artist = self.main.db.artistinfos(artistid)
00918 self.main.layouts.show_layout("artist", artist, who_called = "on_tvList_row_activated")
00919
00920 def on_tvList_button_press(self, widget, event):
00921 if event.button == 3:
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 mnu = ListMenu(self.main)
00932 mnu.popup(None, None, None, event.button, event.time)
00933 if mnu.get_children() == []:
00934 mnu.destroy()
00935
00936 def on_bDelete_clicked(self, ev):
00937 liststore, markedIter = self.tvPlaylistSelection.get_selected()
00938 if markedIter:
00939 model = self.tvPlaylist.get_model()
00940 self.main.remove_item_from_playlist(model.get_path(markedIter))
00941 liststore.remove(markedIter)
00942
00943 def on_bClear_clicked(self, ev):
00944 self.main.player.clearplaylist()
00945 model = self.tvPlaylist.get_model()
00946 model.clear()
00947
00948 def on_bNext_clicked(self, ev):
00949 self.on_bStop_clicked(None)
00950 self.main.player.next()
00951 self.main.icon.menu.switch_play_button("pause")
00952
00953 def on_bPrev_clicked(self, ev):
00954 self.on_bStop_clicked(None)
00955 self.main.player.prev()
00956 self.main.icon.menu.switch_play_button("pause")
00957
00958 def on_bLoad_clicked(self, ev):
00959
00960 mnu = gtk.Menu()
00961 counter = 0
00962
00963
00964 sql = "SELECT option, value FROM settings WHERE section='playlists'"
00965 playlists = self.main.settingsdb.query(sql)
00966 if playlists:
00967 for name, ids in playlists:
00968 counter += 1
00969 playlist = gtk.ImageMenuItem(name.replace("_", "__"), False)
00970 playlist.show()
00971 mnu.append(playlist)
00972 playlist.connect("activate", self.main.playlists.cb_load_playlist, name)
00973 if counter == 0:
00974 tmp = gtk.ImageMenuItem("No playlists saved, yet.")
00975 tmp.show()
00976 tmp.set_sensitive(False)
00977 mnu.append(tmp)
00978
00979 mnu.show()
00980 mnu.popup(None, None, None, 1,0)
00981
00982
00983
00984 def on_bSave_clicked(self, ev):
00985 self.main.playlists.cb_save_playlist(None)
00986 return
00987
00988 def cb_export_playlist(self, widget):
00989 m3u = ""
00990 xspf = '''<?xml version="1.0" encoding="UTF-8"?>
00991 <playlist version="1" xmlns="http://xspf.org/ns/0/">
00992 <tracklist>
00993 '''
00994 playlist = self.main.player.playlist
00995 for track in playlist:
00996 m3u += track.stream+"\n"
00997 xspf += " <track>\n <title>%s</title>\n <creator>%s</creator>\n <location>%s</location>\n </track>\n" % (track.name, track.artist_name, track.stream)
00998 m3u = m3u[0:-1]
00999 xspf += '''\n <tracklist>
01000 </playlist>'''
01001
01002 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)
01003 dialog = gtk.FileChooserDialog(_("Save Playlist"), None, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=buttons, backend=None)
01004 filter1 = gtk.FileFilter()
01005 filter1.set_name("M3U Playlist Format")
01006 filter1.add_pattern("*.m3u")
01007 dialog.add_filter(filter1)
01008 filter2 = gtk.FileFilter()
01009 filter2.set_name("XSPF Playlist Format")
01010 filter2.add_pattern("*.xspf")
01011 dialog.add_filter(filter2)
01012
01013 dialog.set_default_response(gtk.RESPONSE_OK)
01014 dialog.set_current_folder(os.getenv("HOME"))
01015 dialog.set_current_name("pyjama-playlist")
01016
01017 response = dialog.run()
01018 dialog.hide()
01019 if response == gtk.RESPONSE_OK:
01020 filename = dialog.get_filename()
01021 if dialog.get_filter() == filter1:
01022 content = m3u
01023 if filename[-4:] != ".m3u":
01024 filename += ".m3u"
01025 else:
01026 content = xspf
01027 if filename[-5:] != ".xspf":
01028 filename += ".xspf"
01029 if self.main.debug:
01030 print "Writing to %s" % filename
01031 fh = open(filename, "w")
01032 if fh:
01033 fh.write(content)
01034 fh.close()
01035 else:
01036 print ("Error writing %s") % filename
01037
01038 def set_play(self):
01039 status = self.bPlay.tag
01040 if status == "play" or not status:
01041 status = "play"
01042
01043 if status == "pause" and self.main.player.is_playing:
01044 self.main.player.pause()
01045 self.bPlay.setimage(gtk.STOCK_MEDIA_PLAY)
01046 self.main.icon.menu.switch_play_button("play")
01047 self.bPlay.tag = "play"
01048 return "paused"
01049 elif status == "play" and self.main.player.status == "paused":
01050 self.main.player.play()
01051 self.bPlay.setimage(gtk.STOCK_MEDIA_PAUSE)
01052 self.main.icon.menu.switch_play_button("pause")
01053 self.bPlay.tag = "pause"
01054 return "continued"
01055 elif status == "play":
01056 self.bPlay.setimage(gtk.STOCK_MEDIA_PAUSE)
01057 self.main.icon.menu.switch_play_button("pause")
01058 self.bPlay.tag = "pause"
01059 return "play"
01060
01061
01062 def on_bPlay_pressed(self, widget, event):
01063 if event.button == 3:
01064 self.on_bStop_clicked(None)
01065
01066 def on_bPlay_clicked(self, ev):
01067
01068 stat = self.set_play()
01069 if stat == "paused":
01070 return
01071 elif stat == "continued":
01072 return
01073 model, tmpIter = self.tvSelection.get_selected()
01074 if tmpIter != None:
01075 path = self.liststore.get_path(tmpIter)[0]
01076 self.main.player.play(self.main.player.playlist[path], path)
01077 self.main.timer_event()
01078
01079
01080 else:
01081 model = self.tvPlaylist.get_model()
01082
01083 try:
01084 tmpIter = model.get_iter(0)
01085 except ValueError:
01086 return None
01087 path = self.liststore.get_path(tmpIter)[0]
01088 self.main.player.play(self.main.player.playlist[path], path)
01089 self.main.timer_event()
01090
01091
01092
01093
01094 def on_bStop_clicked(self, ev):
01095 self.main.icon.menu.switch_play_button("play")
01096 self.bPlay.setimage(gtk.STOCK_MEDIA_PLAY)
01097 self.bPlay.tag = "play"
01098 listview, markedIter = self.tvPlaylistSelection.get_selected()
01099
01100
01101 if markedIter != None and self.main.player.cur_playing != None:
01102 track = self.main.player.cur_playing
01103 artist_name = track.artist_name
01104 track_name = track.name
01105 track_numalbum = track.numalbum
01106 markup = self.markupNormalEntry.replace("__ARTIST__", artist_name).replace("__TITLE__", track_name).replace("__NUM__", str(track_numalbum))
01107 self.liststore.set(markedIter, 0, markup)
01108
01109 self.main.player.stop()
01110
01111 def scrolled_window_resize(self, obj, gdkrect):
01112 self.scrolledwindow_width = gdkrect[2]
01113 self.scrolledwindow_height = gdkrect[3]
01114 if self.main.allow_rearrange:
01115 self.main.allow_rearrange = False
01116 self.main.Events.raise_event("scrolled_window_resized")
01117 gobject.timeout_add(200, self.main.set_allow_rearrange)
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129 def show_about(self, widget=None):
01130 xml = gtk.glade.XML(os.path.join(functions.install_dir(), "about.glade"))
01131 about = xml.get_widget('About')
01132
01133 img = None
01134
01135 for child in about.vbox.get_children():
01136 if isinstance(child, gtk.VBox):
01137 for sub_child in child.get_children():
01138 if isinstance(sub_child, gtk.Image):
01139 img = sub_child
01140 break
01141 if img is not None:
01142 animation = gtk.gdk.PixbufAnimation(os.path.join(functions.install_dir(), "images", "pyjama_anim.gif"))
01143
01144 img.set_from_animation(animation)
01145
01146
01147
01148
01149 else:
01150 pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(functions.install_dir(), "images", "pyjama.png"))
01151 about.set_logo(pixbuf)
01152 about.run()
01153 about.destroy()
01154
01155 def get_active_text(self, combobox):
01156 model = combobox.get_model()
01157 active = combobox.get_active()
01158 if active < 0:
01159 return None
01160 return model[active][0]
01161
01162
01163 def setStatus(self, text=""):
01164 self.message_id = self.sbStatus.push(self.context_id, text)
01165
01166 def quit(self, widget, event ):
01167
01168 self.do_events()
01169 self.iconify()
01170 return True
01171
01172
01173 def really_quit(self, ev=None):
01174 if self.main.verbose:
01175 print "##########################################################"
01176 print ("Query Session Statistics:")
01177 print ("Cached Queries: %i") % self.main.jamendo.cache_counter
01178 print ("Jamendo Queries: %i") % self.main.jamendo.jamendo_counter
01179 print ("Database Queries: %i") % self.main.db.query_counter
01180 print ("Settings Database Queries: %i") % self.main.settingsdb.query_counter
01181 print "##########################################################"
01182 print ("Total Cache Statistics:")
01183 os.system("du -h %s" % os.path.join(functions.preparedirs(), "cache"))
01184 print "##########################################################"
01185 print ("Cached Queries Total:")
01186 os.system("du -a %s|wc -l" % os.path.join(functions.preparedirs(), "cache"))
01187 print "##########################################################"
01188 print ("Stored Images:")
01189 os.system("du -a %s|wc -l" % os.path.join(functions.preparedirs(), "images"))
01190 print "##########################################################"
01191 print ("Stored Images Size:")
01192 os.system("du -h %s|cut -f 1" % os.path.join(functions.preparedirs(), "images"))
01193 print "##########################################################"
01194
01195 self.main.quit()
01196 self.do_events()
01197
01198
01199 gtk.main_quit()
01200
01201
01202
01203 def on_sbVolume_Change(self, widget, value):
01204 value = int(value)
01205 if value > self.main.settings.get_value("SOUND", "vol_max"): value = self.main.settings.get_value("SOUND", "vol_max")
01206 if value < 0: value = 0
01207 self.main.player.set_volume(value)
01208
01209 def show_error_message(self, desc, tb):
01210 dia = gtk.Dialog()
01211 dia.set_size_request(400,-1)
01212 dia.set_icon_from_file(os.path.join(functions.install_dir(), "images", "pyjama.png"))
01213
01214 lbl = gtk.Label()
01215 lbl.show()
01216 lbl.set_markup(str(desc))
01217 lbl.set_line_wrap(True)
01218 lbl.set_single_line_mode(False)
01219 dia.vbox.pack_start(lbl, True, True, 10)
01220
01221 if tb.strip() != "None":
01222 expander = gtk.Expander("Show/hide details")
01223 expander.show()
01224 sw = gtk.ScrolledWindow()
01225 sw.show()
01226 expander.add(sw)
01227 dia.vbox.pack_start(expander, True, True, 10)
01228
01229 textview = gtk.TextView()
01230 textview.show()
01231 sw.add(textview)
01232 textbuffer = gtk.TextBuffer()
01233 textview.set_buffer(textbuffer)
01234 textbuffer.set_text(tb)
01235
01236
01237 dia.set_title("An Error occured")
01238 dia.add_button(gtk.STOCK_OK, -1)
01239 dia.run()
01240 dia.destroy()
01241
01242 def check_alldone(self):
01243 return self.__alldone
01244
01245 def do_events(self):
01246 i = 0
01247 try:
01248 max = self.main.settings.get_value("PERFORMANCE", "max_iterations_while_events_pending", 50)
01249 except:
01250 max = 50
01251
01252 while gtk.events_pending():
01253 if i > max:
01254 print ("To much interations, breaking events_pending() loop")
01255 break
01256 gtk.main_iteration()
01257
01258
01259 def setcolor(self, widget):
01260 if self.main.nocolor:
01261 return None
01262 style = widget.get_style()
01263 color = widget.get_colormap()
01264 bg = color.alloc_color(self.bgcolor)
01265 fg = color.alloc_color(0, 0, 0, 0)
01266 style.bg[gtk.STATE_NORMAL] = bg
01267 style.fg[gtk.STATE_NORMAL] = fg
01268 widget.set_style(style)
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282 def __special_checks(self):
01283
01284
01285
01286
01287
01288
01289
01290 if "create-imagepack" in sys.argv:
01291 ID = 0
01292 LICENSE = 1
01293 ARTIST = 2
01294 ALBUM = 3
01295 ARTIST_URL = 4
01296 sql = "SELECT albums.id, albums.license_artwork, artists.name, albums.name, artists.url FROM albums, artists WHERE albums.artist_id=artists.id"
01297 print ("Now querying the database - this will take a while")
01298 ret = self.main.db.query(sql)
01299 print ("Done - will now create the imagepack")
01300
01301 images = ""
01302 last_percentage = 0.0
01303 total = len(ret)*1.0
01304 counter = 1
01305
01306 txt = "<html><body>\nPyjama's imagepacks contains cover-images of albums that are free available @ jamendo.com<br />\n"
01307 txt += "Each image is property of it's author and comes with a own license.<br />\n"
01308 txt += "In the following table you look up informations for each image by its name in the imagepack.<br /></br>\n"
01309 txt += "<table><tr><td>MD5 Hash</td><td>Artist</td><td>Album</td><td>License</td></tr>\n"
01310
01311
01312 download_counter = 0
01313 for item in ret:
01314 album_id = item[ID]
01315 image_name = "http://api.jamendo.com/get2/image/album/redirect/?id=%s&imagesize=100" % album_id
01316 image_url = "http://imgjam.com/albums/%i/covers/1.100.jpg" % album_id
01317
01318 md5hash = hashlib.md5(image_name).hexdigest()
01319
01320 album_name = item[ALBUM]
01321 if len(item[ALBUM]) > 20:
01322 album_name = "%s[...]%s" % (item[ALBUM][:17], item[ALBUM][-3:])
01323 artist_name = item[ARTIST]
01324 if len(item[ARTIST]) > 20:
01325 artist_name = "%s[...]%s" % (item[ARTIST][:17], item[ARTIST][-3:])
01326
01327 txt += "<tr><td><a href = 'http://imgjam.com/albums/%i/covers/1.100.jpg'>%s</a></td><td><a href = '%s'>%s</a></td><td><a href='http://www.jamendo.com/album/%i'>%s</a></td><td><a href = '%s'>LICENSE</a></td></tr>\n" % (item[ID], md5hash, item[ARTIST_URL], artist_name, item[ID], album_name, item[LICENSE])
01328
01329 fh = os.path.join(self.main.home, "images", md5hash)
01330 perc = float(counter/total*100.0)
01331 if not os.path.exists(fh):
01332 try:
01333 download_counter += 1
01334 print ("Dowload #%i, Album %i - %f%%" % (download_counter, album_id, perc))
01335 urllib.urlretrieve(image_url, fh)
01336 sleep(4)
01337 except IOError:
01338 print ("Could not load image")
01339 return None
01340 else:
01341 if perc >= last_percentage + 0.3:
01342 print ("Album %i already downloaded - (%f%%)" % (album_id, perc))
01343 last_percentage = perc
01344 counter += 1
01345 print ("%i images downloaded" % download_counter)
01346 print ("Creating archive")
01347 tf = tarfile.open("imagepack.tar.gz", "w:gz")
01348 tf.add(os.path.join(self.main.home, "images"), arcname="images", recursive=True)
01349 filename = self.__info_file("create")
01350 if filename is not None:
01351 tf.add(filename, arcname="README.TXT")
01352 self.__info_file("delete")
01353 tf.close()
01354
01355 print ("Now writing license informations")
01356 txt += "</table></body></html>"
01357 fh = open("imagepack-license-infos.htm", "w")
01358 if fh:
01359 fh.write(txt)
01360 fh.close()
01361
01362 print ("Done")
01363 sys.exit(0)
01364
01365
01366
01367
01368
01369
01370
01371
01372 if "create-smart-imagepack" in sys.argv:
01373 path = os.path.join(self.main.home, "smart_image_pack")
01374 if not os.path.exists(path):
01375 os.mkdir(path)
01376 query1 = "id/album/json/?n=100&order=ratingmonth_desc"
01377 query2 = "id/album/json/?n=100&order=rating_desc"
01378 query3 = "id/album/json/?n=100&order=ratingweek_desc"
01379 query4 = "id/album/json/?n=100&order=downloaded_desc"
01380 query5 = "id/album/json/?n=100&order=listened_desc"
01381 query6 = "id/album/json/?n=100&order=stared_desc"
01382 for query in [query1, query2, query3, query4, query5, query6]:
01383 ret = self.main.jamendo.query(query)
01384 images = ""
01385 total = len(ret)*1.0
01386 counter = 1
01387 for item in ret:
01388 album_id = item
01389 image_name = "http://api.jamendo.com/get2/image/album/redirect/?id=%s&imagesize=100" % album_id
01390 image_url = "http://imgjam.com/albums/%i/covers/1.100.jpg" % album_id
01391
01392 md5hash = hashlib.md5(image_name).hexdigest()
01393 fh = os.path.join(self.main.home, "smart_image_pack", md5hash)
01394 test_image = os.path.join(self.main.home, "images", md5hash)
01395 perc = float(counter/total*100.0)
01396 if os.path.exists(fh):
01397 print ("%s alrady exists" % fh)
01398 elif os.path.exists(test_image):
01399 print ("copied %s from %s" % (fh, test_image))
01400 shutil.copy(test_image, fh)
01401 else:
01402 try:
01403 print ("Downloading", album_id, " (%f)" % perc)
01404 urllib.urlretrieve(image_url, fh)
01405 sleep(1)
01406 except IOError:
01407 print ("Could not load image")
01408 return None
01409
01410
01411 counter += 1
01412 sleep(1)
01413 print ("Creating archive")
01414 tf = tarfile.open("smart-imagepack.tar.gz", "w:gz")
01415 tf.add(path, arcname="images", recursive=True)
01416 filename = self.__info_file("create")
01417 if filename is not None:
01418 tf.add(filename, arcname="README.TXT")
01419 self.__info_file("delete")
01420 tf.close()
01421 print ("Done")
01422 sys.exit(0)
01423
01424
01425
01426
01427
01428 if "find-wrong-image-uris" in sys.argv:
01429 sql = "SELECT id FROM albums WHERE 1"
01430 ret = self.main.db.query(sql)
01431 filelist = os.listdir(os.path.join(self.main.home, "images"))
01432
01433 delete_counter = 0
01434 total = len(ret) * len(filelist)
01435 counter = 1.0
01436 for fl in filelist:
01437 print float(counter/total*100.0)
01438 for item in ret:
01439 counter += 1.0
01440 album_id = item[0]
01441 image_name = "http://imgjam.com/albums/%i/covers/1.100.jpg" % album_id
01442 md5hash = hashlib.md5(image_name).hexdigest()
01443 if fl == md5hash:
01444 if "delete-those" in sys.argv:
01445 f = os.path.join(self.main.home, "images", fl)
01446 try:
01447 os.remove(f)
01448 delete_counter +=1
01449 print("%i: Deleted %s" % (delete_counter, f))
01450 except:
01451 print("Error deleting %s" % f)
01452 else:
01453 print fl, image_name
01454
01455
01456
01457
01458
01459
01460 if "print-none-album-covers" in sys.argv:
01461 sql = "SELECT id FROM albums WHERE 1"
01462 ret = self.main.db.query(sql)
01463 filelist = os.listdir(os.path.join(self.main.home, "images"))
01464 for fl in filelist:
01465 ok = False
01466 for item in ret:
01467 counter +=1
01468 album_id = item[0]
01469 image_name = "http://api.jamendo.com/get2/image/album/redirect/?id=%s&imagesize=100" % album_id
01470 md5hash = hashlib.md5(image_name).hexdigest()
01471 if fl == md5hash:
01472 ok = True
01473 if not ok:
01474 print ("Not ok: %s" % fl)
01475
01476 if "country-check" in sys.argv:
01477 sql = "SELECT country FROM artists WHERE 1"
01478 ret = self.main.db.query(sql)
01479 cts = {}
01480 for item in ret:
01481 country = item[0]
01482 try:
01483 cts[country] +=1
01484 except:
01485 cts[country] = 1
01486 for x in cts:
01487 if cts[x] > 0:
01488 print x, cts[x]
01489 print ("Total num of countries: %s" % len(cts))
01490 sys.exit(1)
01491
01492 def __info_file(self, mode="delete"):
01493 filename = "5987635.txt"
01494 if mode != "delete":
01495 fh = open(filename, "w")
01496 if fh:
01497 fh.write("The covers in this archive belong to albums which are available for free at www.jamendo.com.\nThey are property of their artist who released them under certain licenses.\nYou can find out which cover is released under which license by calling\n\n http://xn--ngel-5qa.de/pyjama/release/imagepack-license-infos.htm\n\n On this page every cover of the imagepack is listed.")
01498 fh.close()
01499 return filename
01500 else:
01501 if os.path.exists(filename):
01502 os.remove(filename)