示例#1
0
文件: player.py 项目: nadako/myplay
    def __init__(self, idle_callback=None):
        super(Player, self).__init__()
        
        self._tag_scanner = TagScanner(self._on_tag_scanned)
        self._tags = {}
        
        data_dir = os.path.join(glib.get_user_data_dir(), 'myplay')
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        
        self._playlist_path = os.path.join(data_dir, 'playlist')

        self._init_playlist()
        if self._playlist:
            self._tag_scanner.add(self._playlist)
        
        self._player = gst.element_factory_make('playbin2', 'player')
        self._player.set_property('flags', GST_PLAY_FLAG_AUDIO)
        player_bus = self._player.get_bus()
        player_bus.add_signal_watch()
        player_bus.connect('message', self._on_player_message)

        self._state = STATE_READY
        self._idle_callback = idle_callback
        self.idle = True
示例#2
0
文件: player.py 项目: nadako/myplay
class Player(dbus.service.Object):
    
    @dbus.service.method(OBJECT_IFACE, out_signature='a(sa{ss})')
    def List(self):
        res = []
        for uri in self._playlist:
            res.append((uri, self._tags.get(uri, {})))
        return tuple(res)
    
    @dbus.service.method(OBJECT_IFACE, in_signature='asu')
    def Add(self, uris, position):
        if not uris:
            raise EmptySequence
        if position < 0 or position > len(self._playlist):
            raise InvalidPosition(position)

        uris = [str(uri) for uri in uris]
        self._playlist[position:position] = uris
        self._save_playlist()
        
        add_info = [(uri, self._tags.get(uri, {})) for uri in uris]
        self.Added(add_info, position)

        no_tags = [uri for uri, tag in add_info if not tag]
        if no_tags:
            self._tag_scanner.add(no_tags)
    
    @dbus.service.method(OBJECT_IFACE, in_signature='au')
    def Remove(self, positions):
        if not positions:
            raise EmptySequence
        playlist_len = len(self._playlist)
        for pos in positions:
            if pos < 0 or pos >= playlist_len:
                raise InvalidPosition(pos)

        self._playlist[:] = [uri for i, uri in enumerate(self._playlist) if i not in positions]
        self._save_playlist()
        self.Removed(positions)

        if self._current in positions:
            self.SetCurrent(CURRENT_UNSET)
    
    @dbus.service.method(OBJECT_IFACE)
    def Clear(self):
        self._playlist[:] = []
        self._save_playlist()
        self.Cleared()
        self.SetCurrent(CURRENT_UNSET)
    
    @dbus.service.method(OBJECT_IFACE, in_signature='au')
    def Reorder(self, positions):
        if not positions:
            raise EmptySequence
        playlist_len = len(self._playlist)
        if len(positions) != playlist_len:
            raise InvalidLength(self._playlist)

        new_playlist = []
        for pos in positions:
            if pos < 0 or pos >= playlist_len:
                raise InvalidPosition(pos)
            new_playlist.append(self._playlist[pos])

        self._playlist[:] = new_playlist
        self._save_playlist()

        self.Reordered(positions)
    
        if self._current != CURRENT_UNSET:
            self._change_current(positions.index(self._current), True)

    @dbus.service.method(OBJECT_IFACE, out_signature='i')
    def GetCurrent(self):
        return self._current

    @dbus.service.method(OBJECT_IFACE, in_signature='ib')
    def SetCurrent(self, position, play=False):
        if position < 0 or position >= len(self._playlist):
            if not (position == CURRENT_UNSET and not play):
                raise InvalidPosition()
        self._change_current(int(position))
        if play:
            self.Play()

    @dbus.service.method(OBJECT_IFACE)
    def Next(self):
        if self._current != CURRENT_UNSET and not self._current_is_last():
            self._change_current(self._current + 1)
    
    @dbus.service.method(OBJECT_IFACE)
    def Previous(self):
        if self._current != CURRENT_UNSET and not self._current_is_first():
            self._change_current(self._current - 1)
    
    @dbus.service.method(OBJECT_IFACE)
    def Play(self):
        if self._state != STATE_PLAYING:
            if self._current == CURRENT_UNSET:
                if self._playlist:
                    self._change_current(0)
                else:
                    return
            if self._state == STATE_READY:
                self._player.set_property('uri', self._playlist[self._current])
            self._player.set_state(gst.STATE_PLAYING)
            self._change_state(STATE_PLAYING)

    @dbus.service.method(OBJECT_IFACE)
    def Pause(self):
        if self._state == STATE_PLAYING:
            self._player.set_state(gst.STATE_PAUSED)
            self._change_state(STATE_PAUSED)
    
    @dbus.service.method(OBJECT_IFACE)
    def Stop(self):
        if self._state != STATE_READY:
            self._player.set_state(gst.STATE_NULL)
            self._player.set_property('uri', '')
            self._change_state(STATE_READY)

    @dbus.service.method(OBJECT_IFACE, out_signature='u')
    def GetState(self):
        return self._state

    @dbus.service.signal(OBJECT_IFACE, signature='a(sa{ss})i')
    def Added(self, tracks, position):
        pass
    
    @dbus.service.signal(OBJECT_IFACE, signature='au')
    def Removed(self, positions):
        pass
    
    @dbus.service.signal(OBJECT_IFACE)
    def Cleared(self):
        pass
    
    @dbus.service.signal(OBJECT_IFACE, signature='au')
    def Reordered(self, positions):
        pass
    
    @dbus.service.signal(OBJECT_IFACE, signature='ii')
    def CurrentChanged(self, old_position, new_position):
        pass
    
    @dbus.service.signal(OBJECT_IFACE, signature='uu')
    def StateChanged(self, old_state, new_state):
        pass

    @dbus.service.signal(OBJECT_IFACE, signature='sa{ss}')
    def TagChanged(self, uri, tag_dict):
        pass

    def __init__(self, idle_callback=None):
        super(Player, self).__init__()
        
        self._tag_scanner = TagScanner(self._on_tag_scanned)
        self._tags = {}
        
        data_dir = os.path.join(glib.get_user_data_dir(), 'myplay')
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        
        self._playlist_path = os.path.join(data_dir, 'playlist')

        self._init_playlist()
        if self._playlist:
            self._tag_scanner.add(self._playlist)
        
        self._player = gst.element_factory_make('playbin2', 'player')
        self._player.set_property('flags', GST_PLAY_FLAG_AUDIO)
        player_bus = self._player.get_bus()
        player_bus.add_signal_watch()
        player_bus.connect('message', self._on_player_message)

        self._state = STATE_READY
        self._idle_callback = idle_callback
        self.idle = True

    @apply
    def idle():
        def fget(self):
            return getattr(self, '_idle', False)
        def fset(self, value):
            setattr(self, '_idle', value)
            if self._idle_callback is not None:
                self._idle_callback(self, value)
        return property(fget, fset)

    def _current_is_last(self):
        if not self._playlist:
            # check so this function won't return True on empty playlist 
            return False
        return self._current == (len(self._playlist) - 1)

    def _current_is_first(self):
        return self._current == 0
    
    def _on_player_message(self, element, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            if not self._current_is_last():
                self.Next()
            else:
                self.Stop()

    def _on_tag_scanned(self, uri, tag):
        if not (uri in self._tags and self._tags[uri] == tag):
            self._tags[uri] = tag
            self.TagChanged(uri, tag)
    
    def _init_playlist(self):
        self._playlist = []
        self._current = CURRENT_UNSET
        if os.path.exists(self._playlist_path):
            try:
                data = pickle.load(open(self._playlist_path, 'rb'))
                self._playlist = data['playlist']
                self._current = data['current']
            except:
                pass
    
    def _save_playlist(self):
        if self._playlist:
            data = {'playlist': self._playlist, 'current': self._current}
            pickle.dump(data, open(self._playlist_path, 'wb'))
        elif os.path.exists(self._playlist_path):
            os.unlink(self._playlist_path)

    def _change_state(self, new):
        old = self._state
        if new != old:
            self._state = new
            self.StateChanged(old, new)
            if new == STATE_READY:
                self.idle = True
            else:
                self.idle = False

    def _change_current(self, new, reorder=False):
        old = self._current
        if old != new:
            self._current = new
            self._save_playlist()
            self.CurrentChanged(old, new)
            if not reorder:
                if self._state == STATE_PAUSED or new == CURRENT_UNSET:
                    self.Stop()
                elif self._state == STATE_PLAYING:
                    # reset player without changing player state
                    self._player.set_state(gst.STATE_NULL)
                    self._player.set_property('uri', self._playlist[new])
                    self._player.set_state(gst.STATE_PLAYING)