예제 #1
0
    def onAppStarted(self):
        """ The module has been loaded """
        self.tree = None
        self.cfgWin = None
        self.scrolled = Gtk.ScrolledWindow()
        self.treeState = prefs.get(__name__, 'saved-states', None)

        self.scrolled.set_shadow_type(Gtk.ShadowType.IN)
        self.scrolled.set_policy(Gtk.PolicyType.AUTOMATIC,
                                 Gtk.PolicyType.AUTOMATIC)
        self.scrolled.show()

        left_vbox = prefs.getWidgetsTree().get_object('vbox3')
        left_vbox.pack_start(self.scrolled, True, True, 0)

        self.static_paths = ['/', consts.dirBaseUsr]

        self.displaying_results = False
        self.populate_tree()

        music_paths = self.get_music_paths_from_tree()
        modules.postMsg(consts.MSG_EVT_MUSIC_PATHS_CHANGED,
                        {'paths': music_paths})

        self.tree.connect('drag-begin', self.onDragBegin)
예제 #2
0
    def onAppStarted(self):
        """ Real initialization function, called when this module has been loaded """
        self.currTrackLength = 0

        # Widgets
        wTree = prefs.getWidgetsTree()
        self.btnPlay = wTree.get_object('btn-play')
        self.btnNext = wTree.get_object('btn-next')
        self.btnPrev = wTree.get_object('btn-previous')
        self.sclSeek = wTree.get_object('scl-position')

        # GTK handlers
        self.btnNext.connect(
            'clicked', lambda widget: modules.postMsg(consts.MSG_CMD_NEXT))
        self.btnPrev.connect(
            'clicked', lambda widget: modules.postMsg(consts.MSG_CMD_PREVIOUS))
        self.btnPlay.connect(
            'clicked',
            lambda widget: modules.postMsg(consts.MSG_CMD_TOGGLE_PAUSE))
        self.sclSeek.connect('change-value', self.onSeekChangingValue)
        self.sclSeek.connect('value-changed', self.onSeekValueChanged)

        self.sclSeek.hide()

        # Add preferences button.
        preferences_img = Gtk.Image.new_from_icon_name(
            'preferences-system', Gtk.IconSize.SMALL_TOOLBAR)
        preferences_button = Gtk.ToolButton.new(preferences_img, None)
        toolbar_hbox = wTree.get_object('hbox4')
        toolbar_hbox.pack_end(preferences_button, False, False, 0)
        # Move button to the right.
        toolbar_hbox.reorder_child(preferences_button, 0)
        preferences_button.connect('clicked',
                                   lambda item: modules.showPreferences())
        preferences_button.show_all()
예제 #3
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def remove(self, iter=None):
        """ Remove the given track, or the selection if iter is None """
        hadMark = self.tree.hasMark()

        iters = [iter] if iter else list(self.tree.iterSelectedRows())

        prev_iter = self.tree.get_prev_iter_or_parent(iters[0])

        # reverse list, so that we remove children before their fathers
        for iter in reversed(iters):
            track = self.tree.getTrack(iter)
            if track:
                self.playtime -= track.getLength()
            self.tree.removeRow(iter)

        self.tree.selection.unselect_all()

        if hadMark and not self.tree.hasMark():
            modules.postMsg(consts.MSG_CMD_STOP)

        # Select new track when old selected is deleted
        if prev_iter:
            self.tree.select(prev_iter)
        else:
            first_iter = self.tree.get_first_iter()
            if first_iter:
                self.tree.select(first_iter)

        self.onListModified()
예제 #4
0
파일: Search.py 프로젝트: zrqohbug/pogo
    def onSearch(self, query):
        self.should_stop = False
        self.found_something = False

        # Transform whitespace-separated query into OR-regex.
        regex = re.compile('|'.join(tools.get_pattern(word)
                                    for word in query.split()), re.IGNORECASE)

        for dir in self.get_search_paths() + [consts.dirBaseUsr]:
            # Check if search has been aborted during filtering
            if self.should_stop:
                break

            # Only search in home folder if we haven't found anything yet.
            if dir == consts.dirBaseUsr and self.found_something:
                break

            results = self.search_dir(dir, query)

            # Check if search has been aborted during searching
            if results is None or self.should_stop:
                break

            dirs, files = self.filter_results(results, dir, regex)
            if not self.should_stop and (dirs or files):
                self.found_something = True
                modules.postMsg(consts.MSG_EVT_SEARCH_APPEND,
                                {'results': (dirs, files), 'query': query})

        modules.postMsg(consts.MSG_EVT_SEARCH_END)
예제 #5
0
    def __onTrackEnded(self, error):
        """ Called to signal eos and errors """
        self.nextURI = None

        if error:
            modules.postMsg(consts.MSG_EVT_TRACK_ENDED_ERROR)
        else:
            modules.postMsg(consts.MSG_EVT_TRACK_ENDED_OK)
예제 #6
0
파일: Search.py 프로젝트: zrqohbug/pogo
 def on_searchbox_activate(self, _entry):
     self.stop_searches()
     query = self.searchbox.get_text().strip()
     if len(query) < MIN_CHARS:
         msg = 'Search term has to have at least %d characters' % MIN_CHARS
         logging.info(msg)
         return
     query = self.searchbox.get_text()
     logging.info('Query: %s' % query)
     modules.postMsg(consts.MSG_EVT_SEARCH_START, {'query': query})
예제 #7
0
    def onStop(self):
        """ Stop playing """
        self.__stopUpdateTimer()
        self.player.stop()
        self.nextURI = None

        if self.playbackTimer is not None:
            GObject.source_remove(self.playbackTimer)

        modules.postMsg(consts.MSG_EVT_STOPPED)
예제 #8
0
    def updateTimerHandler(self):
        """ Regularly called during playback (can be paused) """
        if self.player.isPlaying():
            position = self.player.getPosition()
            remaining = self.player.getDuration() - position

            modules.postMsg(consts.MSG_EVT_TRACK_POSITION, {'seconds': int(position // 1000000000)})

            if remaining < 5000000000 and self.nextURI is None:
                modules.postMsg(consts.MSG_EVT_NEED_BUFFER)

        return True
예제 #9
0
    def play(self, path=None):
        """
            Replace/extend the tracklist
            If 'path' is None, use the current selection
        """
        if path is None:
            track_paths = [
                row[ROW_FULLPATH] for row in self.tree.getSelectedRows()
            ]
        else:
            track_paths = [self.tree.getRow(path)[ROW_FULLPATH]]

        modules.postMsg(consts.MSG_EVT_LOAD_TRACKS, {'paths': track_paths})
예제 #10
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def onListModified(self):
        """ Some rows have been added/removed/moved """
        # Getting the trackdir takes virtually no time, so we can do it on every
        # paylist change
        tracks = self.getTrackDir()
        self.playtime = tracks.get_playtime()

        modules.postMsg(
            consts.MSG_EVT_NEW_TRACKLIST,
            {'tracks': tracks, 'playtime': self.playtime})

        if self.tree.hasMark():
            modules.postMsg(
                consts.MSG_EVT_TRACK_MOVED,
                {'hasPrevious': self.__hasPreviousTrack(), 'hasNext': self.__hasNextTrack()})
예제 #11
0
    def onTogglePause(self):
        """ Switch between play/pause """
        if self.player.isPaused():
            if self.queuedSeek is not None:
                self.player.seek(self.queuedSeek * 1000000000)
                self.queuedSeek = None
            self.player.play()
            modules.postMsg(consts.MSG_EVT_UNPAUSED)
        elif self.player.isPlaying():

            if self.playbackTimer is not None:
                GObject.source_remove(self.playbackTimer)

            self.player.pause()
            modules.postMsg(consts.MSG_EVT_PAUSED)
예제 #12
0
    def onScaleValueChanged(self, scale, idx):
        """ The user has moved one of the scales """
        # Add a 'custom' entry to the presets if needed
        if self.preset is not None:
            self.preset = None
            prefs.set(__name__, 'preset', self.preset)
            self.combo.handler_block_by_func(self.onPresetChanged)
            self.comboStore.insert(0, (False, _('Custom'), None))
            self.comboStore.insert(1, (True, '', None))
            self.combo.set_active(0)
            self.combo.handler_unblock_by_func(self.onPresetChanged)

        self.lvls[idx] = scale.get_value()
        prefs.set(__name__, 'levels', self.lvls)
        modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls})
예제 #13
0
    def onDragBegin(self, tree, context):
        """ A drag'n'drop operation has begun.

        Pass the paths to the track tree to let it decide whether to
        collapse directories.

        """
        paths = [row[ROW_FULLPATH] for row in tree.getSelectedRows()]
        modules.postMsg(consts.MSG_CMD_FILE_EXPLORER_DRAG_BEGIN,
                        {'paths': paths})

        # Preload the tracks to speedup their addition to the playlist.
        import threading
        crawler = threading.Thread(target=media.preloadTracks, args=(paths, ))
        crawler.start()
예제 #14
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def onShowPopupMenu(self, tree, button, time, path):
        # Keep reference after method exits.
        self.popup_menu = Gtk.Menu()

        # Remove
        remove = Gtk.MenuItem.new_with_label(_('Remove'))
        self.popup_menu.append(remove)
        if path is None:
            remove.set_sensitive(False)
        else:
            remove.connect('activate', lambda item: self.remove())

        # Clear
        clear = Gtk.MenuItem.new_with_label(_('Clear Playlist'))
        self.popup_menu.append(clear)

        # Save to m3u
        export_m3u = Gtk.MenuItem.new_with_label(_('Export playlist to file'))
        self.popup_menu.append(export_m3u)

        # Save to dir
        export_dir = Gtk.MenuItem.new_with_label(_('Export playlist to directory'))
        self.popup_menu.append(export_dir)

        if len(tree.store) == 0:
            clear.set_sensitive(False)
            export_m3u.set_sensitive(False)
            export_dir.set_sensitive(False)
        else:
            clear.connect('activate', lambda item: modules.postMsg(consts.MSG_CMD_TRACKLIST_CLR))
            export_m3u.connect('activate', lambda item: self.export_playlist_to_m3u())
            export_dir.connect('activate', lambda item: self.export_playlist_to_dir())

        self.popup_menu.show_all()
        self.popup_menu.popup(None, None, None, None, button, time)
예제 #15
0
 def onMediaKey(self, appName, action):
     """ A media key has been pressed """
     if action == 'Stop':
         modules.postMsg(consts.MSG_CMD_STOP)
     elif action == 'Next':
         modules.postMsg(consts.MSG_CMD_NEXT)
     elif action == 'Previous':
         modules.postMsg(consts.MSG_CMD_PREVIOUS)
     elif action in ['Play', 'Pause']:
         modules.postMsg(consts.MSG_CMD_TOGGLE_PAUSE)
예제 #16
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def set(self, tracks, playNow):
        """ Replace the tracklist, clear it if tracks is None """
        self.playtime = 0

        if type(tracks) == list:
            trackdir = media.TrackDir(None, flat=True)
            trackdir.tracks = tracks
            tracks = trackdir

        if self.tree.hasMark() and ((not playNow) or (tracks is None) or tracks.empty()):
            modules.postMsg(consts.MSG_CMD_STOP)

        self.tree.clear()

        if tracks is not None and not tracks.empty():
            self.insert(tracks, playNow=playNow)

        self.tree.collapse_all()

        self.onListModified()
예제 #17
0
파일: Covers.py 프로젝트: zrqohbug/pogo
    def onModUnloaded(self):
        """ The module has been unloaded """
        if self.currTrack is not None:
            modules.postMsg(
                consts.MSG_CMD_SET_COVER, {
                    'track': self.currTrack,
                    'pathThumbnail': None,
                    'pathFullSize': None
                })

        # Delete covers that have been generated by this module
        for covers in self.coverMap.values():
            if os.path.exists(covers[CVR_THUMB]):
                os.remove(covers[CVR_THUMB])
            if os.path.exists(covers[CVR_FULL]):
                os.remove(covers[CVR_FULL])
        self.coverMap = None

        # Delete blacklist
        self.coverBlacklist = None
예제 #18
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def onTrackEnded(self, withError):
        """ The current track has ended, jump to the next one if any """
        current_iter = self.tree.getMark()

        # If an error occurred with the current track, flag it as such
        if withError and current_iter:
            self.tree.setItem(current_iter, ROW_ICO, icons.errorMenuIcon())

        # Find the next 'playable' track (not already flagged)
        next = self.__getNextTrackIter()
        if next:
            send_play_msg = True
            if current_iter:
                track_name = self.tree.getTrack(current_iter).getURI()
                send_play_msg = (track_name != self.bufferedTrack)
            self.jumpTo(next, sendPlayMsg=send_play_msg, forced=False)
            self.bufferedTrack = None
            return

        self.bufferedTrack = None
        modules.postMsg(consts.MSG_CMD_STOP)
예제 #19
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def jumpTo(self, iter, sendPlayMsg=True, forced=True):
        """ Jump to the track located at the given iter """
        if not iter:
            return

        mark = self.tree.getMark()
        if mark:
            self.set_track_playing(mark, False)

        self.tree.setMark(iter)
        self.tree.scroll(iter)

        # Check track
        track = self.tree.getTrack(iter)
        if not track:
            # Row may be a directory
            self.jumpTo(self.__getNextTrackIter())
            return

        self.set_track_playing(iter, True)
        self.paused = False

        if sendPlayMsg:
            modules.postMsg(consts.MSG_CMD_PLAY, {'uri': track.getURI(), 'forced': forced})

        modules.postMsg(consts.MSG_EVT_NEW_TRACK, {'track': track})
        modules.postMsg(consts.MSG_EVT_TRACK_MOVED, {'hasPrevious': self.__hasPreviousTrack(), 'hasNext': self.__hasNextTrack()})
예제 #20
0
    def on_add_dir(self, widget):
        parent = prefs.getWidgetsTree().get_object('win-main')
        path = fileChooser.openDirectory(parent, _('Choose a directory'))
        if path is None:
            return

        if os.path.isdir(path):
            if path in self.static_paths:
                errorMsgBox(
                    None, _('Invalid Folder'),
                    _('You cannot add your root or home folder to the music directories'
                      ))
                return
            self.add_dir(path)
            music_paths = self.get_music_paths_from_tree()
            modules.postMsg(consts.MSG_EVT_MUSIC_PATHS_CHANGED,
                            {'paths': music_paths})
            self.set_info_text()
        else:
            errorMsgBox(
                None, _('This path does not exist'),
                '"%s"\n' % path + _('Please select an existing directory.'))
예제 #21
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def onKeyboard(self, list, event):
        """ Keyboard shortcuts """
        keyname = Gdk.keyval_name(event.keyval)

        if keyname == 'Delete':
            self.remove()
        elif keyname == 'Return':
            self.jumpTo(self.tree.getFirstSelectedRow())
        elif keyname == 'space':
            modules.postMsg(consts.MSG_CMD_TOGGLE_PAUSE)
        elif keyname == 'Escape':
            modules.postMsg(consts.MSG_CMD_STOP)
        elif keyname == 'Left':
            modules.postMsg(consts.MSG_CMD_STEP, {'seconds': -5})
        elif keyname == 'Right':
            modules.postMsg(consts.MSG_CMD_STEP, {'seconds': 5})
예제 #22
0
    def timerFunc(self):
        """ Move a bit the scales to their target value """
        isFinished = True

        # Move the scales a bit
        for i in range(10):
            currLvl = self.scales[i].get_value()
            targetLvl = self.targetLvls[i]
            difference = targetLvl - currLvl

            if abs(difference) <= 0.25:
                newLvl = targetLvl
            else:
                newLvl = currLvl + (difference / 8.0)
                isFinished = False

            self.lvls[i] = newLvl
            self.scales[i].set_value(newLvl)

        # Set the equalizer to the new levels
        modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls})

        if isFinished:
            self.timer = None
            prefs.set(__name__, 'levels', self.lvls)

            # Make sure labels are up to date (sometimes they aren't when we're done with the animation)
            # Also unblock the handlers
            for i in range(10):
                self.scales[i].queue_draw()
                self.scales[i].handler_unblock_by_func(
                    self.onScaleValueChanged)

            return False

        return True
예제 #23
0
 def onSkipTrack(self, _notification, _action):
     """ The user wants to skip the current track """
     if self.hasNext:
         modules.postMsg(consts.MSG_CMD_NEXT)
     else:
         modules.postMsg(consts.MSG_CMD_STOP)
예제 #24
0
 def onAppStarted(self):
     """ The application has started """
     self.modInit()
     modules.postMsg(consts.MSG_CMD_ENABLE_EQZ)
     modules.postMsg(consts.MSG_CMD_SET_EQZ_LVLS, {'lvls': self.lvls})
예제 #25
0
 def onLoadTracks(self, paths):
     modules.postMsg(consts.MSG_CMD_TRACKLIST_ADD, {
         'tracks': media.getTracks(paths),
         'playNow': True
     })
예제 #26
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
    def onAppStarted(self):
        """ This is the real initialization function, called when the module has been loaded """
        wTree = tools.prefs.getWidgetsTree()
        self.playtime = 0
        self.bufferedTrack = None
        # Retrieve widgets
        self.window = wTree.get_object('win-main')

        columns = (('', [(Gtk.CellRendererPixbuf(), GdkPixbuf.Pixbuf), (Gtk.CellRendererText(), GObject.TYPE_STRING)], True),
                   (None, [(None, GObject.TYPE_PYOBJECT)], False),
                   )

        self.tree = TrackTreeView(columns, use_markup=True)

        self.tree.enableDNDReordering()
        target = Gtk.TargetEntry.new(*DND_INTERNAL_TARGET)
        targets = Gtk.TargetList.new([target])
        self.tree.setDNDSources(targets)

        wTree.get_object('scrolled-tracklist').add(self.tree)

        # GTK handlers
        self.tree.connect('exttreeview-button-pressed', self.onMouseButton)
        self.tree.connect('tracktreeview-dnd', self.onDND)
        self.tree.connect('key-press-event', self.onKeyboard)
        self.tree.get_model().connect('row-deleted', self.onRowDeleted)

        _options, args = prefs.getCmdLine()

        self.savedPlaylist = os.path.join(consts.dirCfg, 'saved-playlist')
        self.paused = False

        # Populate the playlist with the saved playlist
        dump = None
        if os.path.exists(self.savedPlaylist):
            try:
                dump = pickleLoad(self.savedPlaylist)
            except (EOFError, ImportError, IOError):
                msg = '[%s] Unable to restore playlist from %s\n\n%s'
                log.logger.error(msg % (MOD_INFO[modules.MODINFO_NAME],
                                        self.savedPlaylist, traceback.format_exc()))

        if dump:
            self.restoreTreeDump(dump)
            log.logger.info('[%s] Restored playlist' % MOD_INFO[modules.MODINFO_NAME])
            self.tree.collapse_all()
            self.select_last_played_track()
            self.onListModified()

        commands, args = tools.separate_commands_and_tracks(args)

        # Add commandline tracks to the playlist
        if args:
            log.logger.info('[%s] Filling playlist with files given on command line' % MOD_INFO[modules.MODINFO_NAME])
            tracks = media.getTracks([os.path.abspath(arg) for arg in args])
            playNow = 'stop' not in commands and 'pause' not in commands
            modules.postMsg(consts.MSG_CMD_TRACKLIST_ADD, {'tracks': tracks, 'playNow': playNow})
        elif 'play' in commands:
            modules.postMsg(consts.MSG_CMD_TOGGLE_PAUSE)

        # Automatically save the content at regular intervals
        GObject.timeout_add_seconds(SAVE_INTERVAL, self.save_track_tree)
예제 #27
0
파일: Tracktree.py 프로젝트: zrqohbug/pogo
 def onBufferingNeeded(self):
     """ The current track is close to its end, so we try to buffer the next one to avoid gaps """
     where = self.__getNextTrackIter()
     if where:
         self.bufferedTrack = self.tree.getItem(where, ROW_TRK).getURI()
         modules.postMsg(consts.MSG_CMD_BUFFER, {'uri': self.bufferedTrack})
예제 #28
0
 def onSeekValueChanged(self, range):
     """ The user has moved the seek slider """
     modules.postMsg(consts.MSG_CMD_SEEK,
                     {'seconds': int(range.get_value())})
예제 #29
0
파일: Search.py 프로젝트: zrqohbug/pogo
 def on_searchbox_changed(self, _entry):
     if self.searchbox.get_text().strip() == '':
         self.stop_searches()
         modules.postMsg(consts.MSG_EVT_SEARCH_RESET, {})
예제 #30
0
 def on_remove_dir(self, widget, path):
     self.tree.removeRow(path)
     music_paths = self.get_music_paths_from_tree()
     modules.postMsg(consts.MSG_EVT_MUSIC_PATHS_CHANGED,
                     {'paths': music_paths})
     self.set_info_text()