Example #1
0
    def enabled(self):
        if not self.running:
            wm = WatchManager()
            self.event_handler = LibraryEvent(app.library)

            # Choose event types to watch for
            # FIXME: watch for IN_CREATE or for some reason folder copies
            # are missed,  --nickb
            FLAGS = ['IN_DELETE', 'IN_CLOSE_WRITE',# 'IN_MODIFY',
                     'IN_MOVED_FROM', 'IN_MOVED_TO', 'IN_CREATE']
            mask = reduce(lambda x, s: x | EventsCodes.ALL_FLAGS[s], FLAGS, 0)

            if self.USE_THREADS:
                print_d("Using threaded notifier")
                self.notifier = ThreadedNotifier(wm, self.event_handler)
                # Daemonize to ensure thread dies on exit
                self.notifier.daemon = True
                self.notifier.start()
            else:
                self.notifier = Notifier(wm, self.event_handler, timeout=100)
                GLib.timeout_add(1000, self.unthreaded_callback)

            for path in get_scan_dirs():
                print_d('Watching directory %s for %s' % (path, FLAGS))
                # See https://github.com/seb-m/pyinotify/wiki/
                # Frequently-Asked-Questions
                wm.add_watch(path, mask, rec=True, auto_add=True)

            self.running = True
Example #2
0
    def __get_selection_filter(self):
        """Retuns a filter object for the current selection or None
        if nothing should be filtered"""

        selection = self.view.get_selection()
        model, rows = selection.get_selected_rows()

        filter_ = None
        for row in rows:
            type_ = model[row][self.TYPE]
            if type_ == self.TYPE_FILTER:
                key = model[row][self.KEY]
                current_filter = self.filters.query(key)
                if current_filter:
                    if filter_:
                        filter_ |= current_filter
                    else:
                        filter_ = current_filter
            elif type_ == self.TYPE_NOCAT:
                # if notcat is selected, combine all filters, negate and merge
                all_ = [self.filters.query(k) for k in self.filters.keys()]
                nocat_filter = all_ and -reduce(lambda x, y: x | y, all_)
                if nocat_filter:
                    if filter_:
                        filter_ |= nocat_filter
                    else:
                        filter_ = nocat_filter
            elif type_ == self.TYPE_ALL:
                filter_ = None
                break

        return filter_
Example #3
0
    def __get_selection_filter(self):
        """Returns a filter object for the current selection or None
        if nothing should be filtered"""

        selection = self.view.get_selection()
        model, rows = selection.get_selected_rows()

        filter_ = None
        for row in rows:
            type_ = model[row][self.TYPE]
            if type_ == self.TYPE_FILTER:
                key = model[row][self.KEY]
                current_filter = self.filters.query(key)
                if current_filter:
                    if filter_:
                        filter_ |= current_filter
                    else:
                        filter_ = current_filter
            elif type_ == self.TYPE_NOCAT:
                # if notcat is selected, combine all filters, negate and merge
                all_ = [self.filters.query(k) for k in self.filters.keys()]
                nocat_filter = all_ and -reduce(lambda x, y: x | y, all_)
                if nocat_filter:
                    if filter_:
                        filter_ |= nocat_filter
                    else:
                        filter_ = nocat_filter
            elif type_ == self.TYPE_ALL:
                filter_ = None
                break

        return filter_
Example #4
0
    def enabled(self):
        if not self.running:
            wm = WatchManager()
            self.event_handler = LibraryEvent(app.library)

            # Choose event types to watch for
            # FIXME: watch for IN_CREATE or for some reason folder copies
            # are missed,  --nickb
            FLAGS = [
                'IN_DELETE',
                'IN_CLOSE_WRITE',  # 'IN_MODIFY',
                'IN_MOVED_FROM',
                'IN_MOVED_TO',
                'IN_CREATE'
            ]
            mask = reduce(lambda x, s: x | EventsCodes.ALL_FLAGS[s], FLAGS, 0)

            if self.USE_THREADS:
                print_d("Using threaded notifier")
                self.notifier = ThreadedNotifier(wm, self.event_handler)
                # Daemonize to ensure thread dies on exit
                self.notifier.daemon = True
                self.notifier.start()
            else:
                self.notifier = Notifier(wm, self.event_handler, timeout=100)
                GLib.timeout_add(1000, self.unthreaded_callback)

            for path in get_scan_dirs():
                print_d('Watching directory %s for %s' % (path, FLAGS))
                # See https://github.com/seb-m/pyinotify/wiki/
                # Frequently-Asked-Questions
                wm.add_watch(path, mask, rec=True, auto_add=True)

            self.running = True
Example #5
0
    def enabled(self):
        if not self.running:
            wm = WatchManager()
            self.event_handler = LibraryEvent(library=app.library)

            FLAGS = ['IN_DELETE', 'IN_CLOSE_WRITE', # 'IN_MODIFY',
                     'IN_MOVED_FROM', 'IN_MOVED_TO', 'IN_CREATE']

            masks = [EventsCodes.FLAG_COLLECTIONS['OP_FLAGS'][s]
                     for s in FLAGS]
            mask = reduce(operator.or_, masks, 0)

            if self.USE_THREADS:
                print_d("Using threaded notifier")
                self.notifier = ThreadedNotifier(wm, self.event_handler)
                # Daemonize to ensure thread dies on exit
                self.notifier.daemon = True
                self.notifier.start()
            else:
                self.notifier = Notifier(wm, self.event_handler, timeout=100)
                GLib.timeout_add(1000, self.unthreaded_callback)

            for path in get_scan_dirs():
                real_path = os.path.realpath(path)
                print_d('Watching directory %s for %s (mask: %x)'
                        % (real_path, FLAGS, mask))
                # See https://github.com/seb-m/pyinotify/wiki/
                # Frequently-Asked-Questions
                wm.add_watch(real_path, mask, rec=True, auto_add=True)

            self.running = True
Example #6
0
def parse_time(timestr, err=object()):
    """Parse a time string in hh:mm:ss, mm:ss, or ss format."""

    if timestr[0:1] == "-":
        m = -1
        timestr = timestr[1:]
    else:
        m = 1

    try:
        return m * reduce(lambda s, a: s * 60 + int(a),
                          re.split(r":|\.", timestr), 0)
    except (ValueError, re.error):
        if err is None:
            raise
        return 0
Example #7
0
def parse_time(timestr, err=object()):
    """Parse a time string in hh:mm:ss, mm:ss, or ss format."""

    if timestr[0:1] == "-":
        m = -1
        timestr = timestr[1:]
    else:
        m = 1

    try:
        return m * reduce(lambda s, a: s * 60 + int(a),
                          re.split(r":|\.", timestr), 0)
    except (ValueError, re.error):
        if err is None:
            raise
        return 0
Example #8
0
    def enabled(self):
        if not self.running:
            wm = WatchManager()
            self.event_handler = LibraryEvent(library=app.library)

            FLAGS = [
                'IN_DELETE',
                'IN_CLOSE_WRITE',  # 'IN_MODIFY',
                'IN_MOVED_FROM',
                'IN_MOVED_TO',
                'IN_CREATE'
            ]

            masks = [
                EventsCodes.FLAG_COLLECTIONS['OP_FLAGS'][s] for s in FLAGS
            ]
            mask = reduce(operator.or_, masks, 0)

            if self.USE_THREADS:
                print_d("Using threaded notifier")
                self.notifier = ThreadedNotifier(wm, self.event_handler)
                # Daemonize to ensure thread dies on exit
                self.notifier.daemon = True
                self.notifier.start()
            else:
                self.notifier = Notifier(wm, self.event_handler, timeout=100)
                GLib.timeout_add(1000, self.unthreaded_callback)

            for path in get_scan_dirs():
                real_path = os.path.realpath(path)
                print_d('Watching directory %s for %s (mask: %x)' %
                        (real_path, FLAGS, mask))
                # See https://github.com/seb-m/pyinotify/wiki/
                # Frequently-Asked-Questions
                wm.add_watch(real_path, mask, rec=True, auto_add=True)

            self.running = True
Example #9
0
    def __update_done(self, stations):
        if not stations:
            print_w("Loading remote station list failed.")
            return

        # filter stations based on quality, listenercount
        def filter_stations(station):
            peak = station.get("~#listenerpeak", 0)
            if peak < 10:
                return False
            aac = "AAC" in station("~format")
            bitrate = station("~#bitrate", 50)
            if (aac and bitrate < 40) or (not aac and bitrate < 60):
                return False
            return True

        stations = filter(filter_stations, stations)

        # group them based on the title
        groups = {}
        for s in stations:
            key = s("~title~artist")
            groups.setdefault(key, []).append(s)

        # keep at most 2 URLs for each group
        stations = []
        for key, sub in iteritems(groups):
            sub.sort(key=lambda s: s.get("~#listenerpeak", 0), reverse=True)
            stations.extend(sub[:2])

        # only keep the ones in at least one category
        all_ = [self.filters.query(k) for k in self.filters.keys()]
        assert all_
        anycat_filter = reduce(lambda x, y: x | y, all_)
        stations = list(filter(anycat_filter.search, stations))

        # remove listenerpeak
        for s in stations:
            s.pop("~#listenerpeak", None)

        # update the libraries
        stations = dict(((s.key, s) for s in stations))
        # don't add ones that are in the fav list
        for fav in iterkeys(self.__fav_stations):
            stations.pop(fav, None)

        # separate
        o, n = set(iterkeys(self.__stations)), set(stations)
        to_add, to_change, to_remove = n - o, o & n, o - n
        del o, n

        # migrate stats
        to_change = [stations.pop(k) for k in to_change]
        for new in to_change:
            old = self.__stations[new.key]
            # clear everything except stats
            AudioFile.reload(old)
            # add new metadata except stats
            for k in (x for x in iterkeys(new) if x not in MIGRATE):
                old[k] = new[k]

        to_add = [stations.pop(k) for k in to_add]
        to_remove = [self.__stations[k] for k in to_remove]

        self.__stations.remove(to_remove)
        self.__stations.changed(to_change)
        self.__stations.add(to_add)
Example #10
0
    def __update_done(self, stations):
        if not stations:
            print_w("Loading remote station list failed.")
            return

        # filter stations based on quality, listenercount
        def filter_stations(station):
            peak = station.get("~#listenerpeak", 0)
            if peak < 10:
                return False
            aac = "AAC" in station("~format")
            bitrate = station("~#bitrate", 50)
            if (aac and bitrate < 40) or (not aac and bitrate < 60):
                return False
            return True
        stations = filter(filter_stations, stations)

        # group them based on the title
        groups = {}
        for s in stations:
            key = s("~title~artist")
            groups.setdefault(key, []).append(s)

        # keep at most 2 URLs for each group
        stations = []
        for key, sub in groups.iteritems():
            sub.sort(key=lambda s: s.get("~#listenerpeak", 0), reverse=True)
            stations.extend(sub[:2])

        # only keep the ones in at least one category
        all_ = [self.filters.query(k) for k in self.filters.keys()]
        assert all_
        anycat_filter = reduce(lambda x, y: x | y, all_)
        stations = filter(anycat_filter.search, stations)

        # remove listenerpeak
        for s in stations:
            s.pop("~#listenerpeak", None)

        # update the libraries
        stations = dict(((s.key, s) for s in stations))
        # don't add ones that are in the fav list
        for fav in self.__fav_stations.iterkeys():
            stations.pop(fav, None)

        # separate
        o, n = set(self.__stations.iterkeys()), set(stations)
        to_add, to_change, to_remove = n - o, o & n, o - n
        del o, n

        # migrate stats
        to_change = [stations.pop(k) for k in to_change]
        for new in to_change:
            old = self.__stations[new.key]
            # clear everything except stats
            AudioFile.reload(old)
            # add new metadata except stats
            for k in (x for x in new.iterkeys() if x not in MIGRATE):
                old[k] = new[k]

        to_add = [stations.pop(k) for k in to_add]
        to_remove = [self.__stations[k] for k in to_remove]

        self.__stations.remove(to_remove)
        self.__stations.changed(to_change)
        self.__stations.add(to_add)
Example #11
0
    def __getmenu(self, column):
        menu = Gtk.Menu()

        def selection_done_cb(menu):
            menu.destroy()

        menu.connect("selection-done", selection_done_cb)

        current = SongList.headers[:]
        current_set = set(current)

        def tag_title(tag):
            if tag.startswith("<"):
                return util.pattern(tag)
            return util.tag(tag)

        current = zip(map(tag_title, current), current)

        def add_header_toggle(menu, pair, active, column=column):
            header, tag = pair
            item = Gtk.CheckMenuItem(label=header)
            item.tag = tag
            item.set_active(active)
            item.connect("activate", self.__toggle_header_item, column)
            item.show()
            item.set_tooltip_text(tag)
            menu.append(item)

        for header in current:
            add_header_toggle(menu, header, True)

        sep = SeparatorMenuItem()
        sep.show()
        menu.append(sep)

        trackinfo = """title genre ~title~version ~#track
            ~#playcount ~#skipcount ~rating ~#length""".split()
        peopleinfo = """artist ~people performer arranger author composer
            conductor lyricist originalartist""".split()
        albuminfo = """album ~album~discsubtitle labelid ~#disc ~#discs
            ~#tracks albumartist""".split()
        dateinfo = """date originaldate recordingdate ~#laststarted
            ~#lastplayed ~#added ~#mtime""".split()
        fileinfo = """~format ~#bitrate ~#filesize ~filename ~basename ~dirname
            ~uri ~codec ~encoding""".split()
        copyinfo = """copyright organization location isrc
            contact website""".split()
        all_headers = reduce(lambda x, y: x + y, [trackinfo, peopleinfo, albuminfo, dateinfo, fileinfo, copyinfo])

        for name, group in [
            (_("All _Headers"), all_headers),
            (_("_Track Headers"), trackinfo),
            (_("_Album Headers"), albuminfo),
            (_("_People Headers"), peopleinfo),
            (_("_Date Headers"), dateinfo),
            (_("_File Headers"), fileinfo),
            (_("_Production Headers"), copyinfo),
        ]:
            item = Gtk.MenuItem(label=name, use_underline=True)
            item.show()
            menu.append(item)
            submenu = Gtk.Menu()
            item.set_submenu(submenu)
            for header in sorted(zip(map(util.tag, group), group)):
                add_header_toggle(submenu, header, header[1] in current_set)

        sep = SeparatorMenuItem()
        sep.show()
        menu.append(sep)

        custom = Gtk.MenuItem(label=_(u"_Customize Headers…"), use_underline=True)
        custom.show()
        custom.connect("activate", self.__add_custom_column)
        menu.append(custom)

        item = Gtk.CheckMenuItem(label=_("_Expand Column"), use_underline=True)
        item.set_active(column.get_expand())
        item.set_sensitive(column.get_resizable())

        def set_expand_cb(item, column):
            do_expand = item.get_active()
            if not do_expand:
                # in case we unexpand, get the current width and set it
                # so the column doesn't give up all its space
                # to the left over expanded columns
                column.set_fixed_width(column.get_width())
            else:
                # in case we expand this seems to trigger a re-distribution
                # between all expanded columns
                column.set_fixed_width(-1)
            column.set_expand(do_expand)
            self.columns_autosize()

        sep = SeparatorMenuItem()
        sep.show()
        menu.append(sep)

        item.connect("activate", set_expand_cb, column)
        item.show()
        menu.append(item)

        return menu
Example #12
0
    def __getmenu(self, column):
        menu = Gtk.Menu()

        def selection_done_cb(menu):
            menu.destroy()

        menu.connect('selection-done', selection_done_cb)

        current = SongList.headers[:]
        current_set = set(current)

        def tag_title(tag):
            if tag.startswith("<"):
                return util.pattern(tag)
            return util.tag(tag)

        current = zip(map(tag_title, current), current)

        def add_header_toggle(menu, pair, active, column=column):
            header, tag = pair
            item = Gtk.CheckMenuItem(label=header)
            item.tag = tag
            item.set_active(active)
            item.connect('activate', self.__toggle_header_item, column)
            item.show()
            item.set_tooltip_text(tag)
            menu.append(item)

        for header in current:
            add_header_toggle(menu, header, True)

        sep = SeparatorMenuItem()
        sep.show()
        menu.append(sep)

        trackinfo = """title genre ~title~version ~#track
            ~#playcount ~#skipcount ~rating ~#length""".split()
        peopleinfo = """artist ~people performer arranger author composer
            conductor lyricist originalartist""".split()
        albuminfo = """album ~album~discsubtitle labelid ~#disc ~#discs
            ~#tracks albumartist""".split()
        dateinfo = """date originaldate recordingdate ~#laststarted
            ~#lastplayed ~#added ~#mtime""".split()
        fileinfo = """~format ~#bitrate ~#filesize ~filename ~basename ~dirname
            ~uri ~codec ~encoding""".split()
        copyinfo = """copyright organization location isrc
            contact website""".split()
        all_headers = reduce(
            lambda x, y: x + y,
            [trackinfo, peopleinfo, albuminfo, dateinfo, fileinfo, copyinfo])

        for name, group in [
            (_("All _Headers"), all_headers),
            (_("_Track Headers"), trackinfo),
            (_("_Album Headers"), albuminfo),
            (_("_People Headers"), peopleinfo),
            (_("_Date Headers"), dateinfo),
            (_("_File Headers"), fileinfo),
            (_("_Production Headers"), copyinfo),
        ]:
            item = Gtk.MenuItem(label=name, use_underline=True)
            item.show()
            menu.append(item)
            submenu = Gtk.Menu()
            item.set_submenu(submenu)
            for header in sorted(zip(map(util.tag, group), group)):
                add_header_toggle(submenu, header, header[1] in current_set)

        sep = SeparatorMenuItem()
        sep.show()
        menu.append(sep)

        custom = Gtk.MenuItem(label=_(u"_Customize Headers…"),
                              use_underline=True)
        custom.show()
        custom.connect('activate', self.__add_custom_column)
        menu.append(custom)

        item = Gtk.CheckMenuItem(label=_("_Expand Column"), use_underline=True)
        item.set_active(column.get_expand())
        item.set_sensitive(column.get_resizable())

        def set_expand_cb(item, column):
            do_expand = item.get_active()
            if not do_expand:
                # in case we unexpand, get the current width and set it
                # so the column doesn't give up all its space
                # to the left over expanded columns
                column.set_fixed_width(column.get_width())
            else:
                # in case we expand this seems to trigger a re-distribution
                # between all expanded columns
                column.set_fixed_width(-1)
            column.set_expand(do_expand)
            self.columns_autosize()

        sep = SeparatorMenuItem()
        sep.show()
        menu.append(sep)

        item.connect('activate', set_expand_cb, column)
        item.show()
        menu.append(item)

        return menu