00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 import pygtk
00027 pygtk.require('2.0')
00028
00029 import sys, os
00030
00031 import gobject
00032
00033 import pygst
00034 pygst.require('0.10')
00035 import gst
00036 import gst.interfaces
00037 import gtk
00038 import random
00039
00040
00041
00042 import copy
00043
00044
00045 from time import strftime, gmtime, time
00046
00047 import functions
00048
00049
00050
00051
00052 def sec2time(seconds):
00053 try:
00054 time_string = strftime("%M:%S", gmtime(seconds))
00055 except ValueError:
00056 return "00:00"
00057 return time_string
00058
00059
00060
00061 class Track:
00062 def __init__(self):
00063 self.name = None
00064 self.duration = None
00065 self.numalbum = None
00066 self.id = None
00067 self.license = None
00068 self.id3genre = None
00069
00070 self.album_id = None
00071 self.album_name = None
00072
00073 self.artist_name = None
00074 self.artist_id = None
00075
00076 self.stream = None
00077 self.uid = None
00078
00079 self.position_in_playlist = None
00080
00081
00082
00083
00084 def __getitem__(self, item):
00085 print ""
00086 print "The track object now no longer is a dictionary"
00087 print "You can easily switch to the new track-object"
00088 print "by simply replacing track['%s'] through" % str(item)
00089 print "track.%s." % str(item)
00090 print ""
00091 print "Using a track object as a dictionary is deprecated!"
00092 return self.__dict__[item]
00093
00094
00095 def print_info(self):
00096
00097 ret = ""
00098 for item in self.__dict__:
00099 ret += "%s: %s\n" % (item, str(self.__dict__[item]))
00100 return ret
00101
00102 __call__ = print_info
00103 __str__ = print_info
00104
00105 class TrackError(Exception):
00106 pass
00107
00108
00109
00110
00111
00112 class Player:
00113 def __init__(self, parent, sink="pulsesink"):
00114 parent.Events.add_event("player-status")
00115 parent.Events.add_event('end_of_playlist')
00116
00117
00118 self.playing = False
00119
00120
00121 self.buffer = 0
00122
00123 BIN_TO_USE = "new"
00124 if "oldbin" in sys.argv: BIN_TO_USE = "old"
00125
00126 self.equalizer_available = False
00127 self.equalizer_bands = 10
00128
00129
00130 if BIN_TO_USE == "new":
00131 self.player = gst.element_factory_make("playbin", "player")
00132
00133
00134 pipe = "audioresample ! audioamplify amplification=1.0 ! equalizer-10bands ! %s" % sink
00135 pipe = pipe.split(" ")
00136
00137
00138 self.bin = gst.Bin('my-bin')
00139 audioconvert = gst.element_factory_make('audioconvert')
00140 self.bin.add(audioconvert)
00141 pad = audioconvert.get_pad("sink")
00142 ghostpad = gst.GhostPad("sink", pad)
00143 self.bin.add_pad(ghostpad)
00144
00145
00146 next_is_pipe_element=True
00147 pipeel=None
00148 els=[audioconvert]
00149 i=0
00150 while len(pipe)>i:
00151 el=pipe[i]
00152 i+=1
00153 if el.strip()!="":
00154 if el=="!":
00155 next_is_pipe_element=True
00156 else:
00157 if next_is_pipe_element:
00158 if parent.debug:
00159 print ("pipe element: %s"%el)
00160 if el.startswith('equalizer'):
00161 pipeel = gst.element_factory_make(el)
00162 self.eq=pipeel
00163 self.bin.add(pipeel)
00164 els.append(pipeel)
00165 elif el.startswith('audioamplify'):
00166 pipeel = gst.element_factory_make(el)
00167 self.amp=pipeel
00168 self.bin.add(pipeel)
00169 els.append(pipeel)
00170 elif el.startswith('audioresample'):
00171 pipeel = gst.element_factory_make(el)
00172 self.resample=pipeel
00173 self.bin.add(pipeel)
00174 els.append(pipeel)
00175 elif el.startswith('audio/x-raw-int'):
00176 caps = gst.Caps(el)
00177 filter = gst.element_factory_make("capsfilter", "filter")
00178 self.bin.add(filter)
00179 filter.set_property("caps", caps)
00180 els.append(filter)
00181 else:
00182 pipeel = gst.element_factory_make(el)
00183 self.bin.add(pipeel)
00184 els.append(pipeel)
00185
00186 next_is_pipe_element=False
00187 else:
00188 data=el.split("=")
00189 if parent.debug:
00190 print ("\tproperty %s = %s"%(data[0],data[1]))
00191 try:
00192 if data[1].isdigit():
00193 val=int(data[1])
00194 else:
00195 val=float(data[1])
00196 except:
00197 val=data[1]
00198 pipeel.set_property(data[0],val)
00199
00200
00201
00202
00203 gst.element_link_many(*els)
00204 fakesink = gst.element_factory_make('fakesink', "my-fakesink")
00205
00206 self.player.set_property("audio-sink", self.bin)
00207
00208
00209
00210
00211
00212
00213
00214 self.src = self.player
00215 self.volume = self.player
00216
00217 self.equalizer_available = True
00218
00219 elif BIN_TO_USE == "old":
00220 self.player = gst.element_factory_make("playbin", "player")
00221 self.src = self.player
00222 self.volume = self.player
00223 else:
00224 self.player = gst.Pipeline("pyjama_player")
00225
00226 self.src = gst.element_factory_make("uridecodebin", "src")
00227 self.player.add(self.src)
00228
00229 self.volume_bin = gst.element_factory_make("volume", "volume")
00230 self.player.add(self.volume_bin)
00231
00232 self.equalizer_bin = gst.element_factory_make("equalizer-10bands", "equalizer")
00233 self.player.add(self.equalizer_bin)
00234
00235 self.pulse_bin = gst.element_factory_make("pulsesink", "pulse")
00236 self.player.add(self.pulse_bin)
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 self.EOS = False
00261
00262 bus = self.player.get_bus()
00263 bus.enable_sync_message_emission()
00264 bus.add_signal_watch()
00265 bus.connect('sync-message::element', self.on_sync_message)
00266 bus.connect('message', self.on_message)
00267
00268
00269
00270
00271
00272 self.pyjama = parent
00273
00274 self.cur_playing = None
00275
00276 self.last_played = None
00277
00278 self.connection_tries = 0
00279
00280
00281 self.artist_counter = {}
00282
00283 self.album_counter = {}
00284
00285 self.track_counter = {}
00286
00287
00288 self.playlist = []
00289
00290 self.playlist_track_uids = []
00291
00292
00293 self.percentage = None
00294 self.text = None
00295
00296 self.status = None
00297
00298 self.cursec = None
00299
00300 self.duration = None
00301
00302 self.togo = None
00303
00304 self.artist_name = None
00305
00306 self.track_name = None
00307
00308 self.numalbum = None
00309
00310
00311 if self.equalizer_available:
00312 bands = []
00313 for i in range(self.equalizer_bands):
00314 val = self.pyjama.settings.get_value("SOUND", "band%i" % i, 0.0, float)
00315 bands.append(val)
00316 self.set_equalizer(bands)
00317
00318
00319
00320
00321 def set_equalizer(self, bands):
00322 i = 0
00323 for band in bands:
00324 self.eq.set_property("band%i" % i, float(band))
00325 i += 1
00326
00327
00328
00329
00330
00331
00332 def add2playlist(self, track):
00333 if isinstance(track, Track):
00334 for pl_track in self.playlist:
00335 if track is pl_track:
00336 if self.pyjama.verbose:
00337 print ("Track #%i in playlist and the track you added are identical. Will now create a copy." % pl_track.position_in_playlist)
00338 track = copy.deepcopy(track)
00339 count = len(self.playlist)
00340
00341 track.uid = random.random()
00342 track.position_in_playlist = count
00343 self.playlist.append(track)
00344 self.playlist_track_uids.append(track.uid)
00345 else:
00346 print "No valid track object was given"
00347 raise TrackError
00348
00349
00350
00351
00352
00353
00354 def move_item(self, source, dest, before):
00355
00356
00357
00358
00359 if dest > source:
00360 if before:
00361 before = -1
00362 else:
00363 before = 0
00364 else:
00365 if before:
00366 before = 0
00367 else:
00368 before = 1
00369 dest = dest + before
00370
00371 old = self.playlist.pop(source)
00372 self.playlist.insert(dest, old)
00373 old.position_in_playlist = dest
00374 print ("new pos in playlist:", dest)
00375
00376 old = self.playlist_track_uids.pop(source)
00377 self.playlist_track_uids.insert(dest, old)
00378
00379 if self.pyjama.debug_extreme:
00380 for track in self.playlist:
00381 print track.id
00382
00383
00384
00385
00386
00387
00388 def remove(self, items):
00389 for item in items:
00390 track = self.playlist.pop(item)
00391 self.playlist_track_uids.remove(track.uid)
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 def clearplaylist(self):
00409 self.cur_playing = None
00410 self.last_played = None
00411 self.playlist = []
00412 self.playlist_track_uids = []
00413
00414
00415
00416
00417
00418
00419 def set_volume(self, volume):
00420
00421 volume = volume / 100.0
00422
00423 self.volume.set_property('volume', volume)
00424
00425
00426
00427
00428
00429
00430
00431 def check_status(self):
00432 if self.status == "paused":
00433 self.pyjama.Events.raise_event("player-status", "paused")
00434 return "paused"
00435 if self.status == "End":
00436 self.pyjama.Events.raise_event("player-status", "end")
00437 return None
00438 if self.cur_playing == None:
00439 self.pyjama.Events.raise_event("player-status", "end")
00440 self.status = "End"
00441 else:
00442 ret = self.get_state
00443
00444
00445
00446 self.status = "Playing"
00447 position, duration = self.query_position()
00448 self.cursec = position / (10**9)
00449 self.duration = int(self.cur_playing.duration)
00450 self.percentage = (1.0 / self.duration) * self.cursec
00451 if self.percentage > 1: self.percentage = 0
00452 self.togo = self.cursec - self.duration
00453 self.artist_name = self.cur_playing.artist_name
00454 self.track_name = self.cur_playing.name
00455 self.numalbum = self.cur_playing.numalbum
00456 self.text = "%s:%s: %s / %s - %s" % (self.cur_playing.artist_name ,self.cur_playing.name, sec2time(self.cursec), sec2time(self.duration), sec2time(self.togo*-1))
00457 self.pyjama.Events.raise_event("player-status", "playing", self.cursec, self.duration)
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 def on_eos(self):
00469 self.EOS = False
00470
00471
00472 self.next()
00473
00474
00475
00476 def on_sync_message(self, bus, message):
00477 if message.structure is None:
00478 return
00479 if message.structure.get_name() == 'prepare-xwindow-id':
00480 self.videowidget.set_sink(message.src)
00481 message.src.set_property('force-aspect-ratio', True)
00482
00483 def on_message(self, bus, message):
00484 t = message.type
00485 if t == gst.MESSAGE_ERROR:
00486 err, debug = message.parse_error()
00487 print "GstError: %s" % err, debug
00488 print 99*"-"
00489 print self.cur_playing.stream
00490 print self.src.get_property('uri')
00491
00492 if self.EOS:
00493 self.on_eos()
00494 else:
00495 self.next()
00496 elif t == gst.MESSAGE_EOS:
00497 self.EOS = True
00498 self.on_eos()
00499 elif t == gst.MESSAGE_BUFFERING:
00500 percentage = message.parse_buffering()
00501 self.buffer = percentage
00502
00503 def set_location(self, location):
00504
00505 self.src.set_property('uri', location)
00506
00507 def query_position(self):
00508 "Returns a (position, duration) tuple"
00509 try:
00510 position, format = self.src.query_position(gst.FORMAT_TIME)
00511 except:
00512
00513 position = gst.CLOCK_TIME_NONE
00514
00515 try:
00516 duration, format = self.src.query_duration(gst.FORMAT_TIME)
00517 except:
00518
00519 duration = gst.CLOCK_TIME_NONE
00520
00521 return (position, duration)
00522
00523
00524
00525
00526
00527
00528
00529
00530 def seek(self, location):
00531 gst.debug("seeking to %r" % location)
00532 event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
00533 gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
00534 gst.SEEK_TYPE_SET, location,
00535 gst.SEEK_TYPE_NONE, 0)
00536
00537 res = self.src.send_event(event)
00538 if res:
00539 gst.info("setting new stream time to 0")
00540 self.src.set_new_stream_time(0L)
00541 return True
00542 else:
00543 gst.error("seek to %r failed" % location)
00544 return False
00545
00546
00547 def pause(self):
00548 gst.info("pausing player")
00549 self.status = "paused"
00550 self.src.set_state(gst.STATE_PAUSED)
00551 self.playing = False
00552
00553
00554
00555
00556
00557
00558 def increment_counter(self, array, key):
00559 if array.has_key(key):
00560 array[key] += 1
00561 else:
00562 array[key] = 1
00563
00564
00565
00566
00567
00568
00569
00570 def play(self, track=None, activate_item=-1):
00571
00572
00573 if self.status == "paused" and track == None:
00574 track = self.cur_playing
00575 self.increment_counter(self.artist_counter, track.artist_id)
00576 self.increment_counter(self.album_counter, track.album_id)
00577 self.increment_counter(self.track_counter, track.id)
00578 if track.stream == "query":
00579 track.stream = self.pyjama.jamendo.stream(track.id)
00580 if track.duration == 0:
00581
00582 track.duration = 60*59
00583
00584 self.last_played = self.cur_playing
00585 self.cur_playing = track
00586
00587 if self.status != "paused":
00588 self.stop()
00589
00590 try:
00591 self.set_location(track.stream)
00592 except Exception, inst:
00593 print ("error: %s" % inst)
00594 gst.info("playing player")
00595 self.src.set_state(gst.STATE_PLAYING)
00596 self.playing = True
00597 self.status = "Playing"
00598
00599 if activate_item > -1:
00600 track.position_in_playlist = activate_item
00601
00602 ev = self.pyjama.Events
00603 ev.raise_event('nowplaying', track)
00604
00605
00606
00607 if activate_item > -1:
00608 self.pyjama.setplaylist(activate_item)
00609
00610
00611
00612
00613
00614
00615
00616 def stop(self):
00617 self.percentage = None
00618 self.text = None
00619 self.cursec = None
00620 self.duration = None
00621 self.togo = None
00622 self.artist_name = None
00623 self.track_name = None
00624 self.numalbum = None
00625 self.status = "End"
00626 self.src.set_state(gst.STATE_NULL)
00627 gst.info("stopped player")
00628
00629
00630
00631
00632
00633
00634
00635
00636 def next(self):
00637 if self.cur_playing is not None:
00638 uid = self.cur_playing.uid
00639 if uid in self.playlist_track_uids:
00640 pos = self.playlist_track_uids.index(uid)
00641 if len(self.playlist)> pos+1:
00642 self.play(self.playlist[pos+1], pos+1)
00643 else:
00644 self.status = "End"
00645 self.pyjama.Events.raise_event('end_of_playlist')
00646
00647
00648
00649
00650
00651
00652 def prev(self):
00653 if self.cur_playing is not None:
00654 uid = self.cur_playing.uid
00655 if uid in self.playlist_track_uids:
00656 pos = self.playlist_track_uids.index(uid)
00657 if pos-1 >= 0:
00658 self.play(self.playlist[pos-1], pos-1)
00659
00660 def get_state(self, timeout=1):
00661 print "getstate"
00662 return self.src.get_state(timeout=timeout)
00663
00664 def is_playing(self):
00665 return self.playing