使用Python在Unity Scopes中实现过滤器。

很多Unity Scope在Ubuntu中无法正常工作(例如unity-scope-gmusicbrowser),因此我尝试“修正”它们以便在Dash中获得结果。
好的,我成功地做到了这一点(对于文件:/usr/share/unity-scopes/gmusicbrowser/unity_gmusicbrowser_deamon.py:已“修正”的代码:https://gist.github.com/wa4557/d6cc4ec5354bbb95042b(即使主要部分不是我写的,将其发布在这里是否可以?))。这个方法非常完美,现在gmusicbrowser的结果可以在音乐Dash中显示出来,就像我想要的那样。
但是我还有一个小问题:如何在Scope中实现可用的过滤器?我认为代码中相关的行是(第372行及之后)。
def do_get_filters(self):
    '''
    Adds filters
    '''
    fs = Unity.FilterSet.new()
    #if FILTERS:
    #
    return fs

很不幸的是,这里的一切都被注释掉了,没有严肃的文档或类似的东西。
范围内的过滤器可以让我筛选音乐,例如只选择摇滚音乐等;我想截图已经解释了我的意思(它是德语)。

enter image description here

如你所见,尽管我收藏了很多00年代的音乐,但是却没有任何结果...
编辑:我找到了一个类似的加载器(unity-gdrive-scope):https://gist.github.com/wa4557/e3a9cdef5806dc3c13c9,在那里添加了过滤器。坦率地说,我不太理解这是如何工作的。但是在do_get_filters函数中肯定有一些东西...
2个回答

我正在尝试为柑橘范围做类似的事情,我觉得我取得了一些进展。我以以下方式修改了do_get_filters函数。

    def do_get_filters(self):
        '''
        Adds filters
        '''
        fs = Unity.FilterSet.new()
        if FILTERS:
            fil = Unity.MultiRangeFilter.new(FILTERS[0]['id'], FILTERS[0]['name'],
                                             Gio.ThemedIcon.new(FILTERS[0]['icon']),
                                             FILTERS[0]['collapsed'])
            fs.add(fil)

            fil = Unity.RadioOptionFilter.new(FILTERS[1]['id'], FILTERS[1]['name'],
                                              Gio.ThemedIcon.new(FILTERS[1]['icon']),
                                              FILTERS[1]['collapsed'])
            fs.add(fil)
        return fs

定义FILTERS为之后,

f1 = {'id': 'decade',
      'name': _('Decade'),
      'icon': '',
      'collapsed': True}

f2 = {'id': 'genre',
      'name': _('Genre'),
      'icon': '',
      'collapsed': True}

FILTERS = [f1, f2]

在这一点上,你可以在MySearch类的do_run方法中做类似这样的事情。

    def do_run(self):
        '''
        Adds results to the model
        '''
        try:
            decade, genre = self.search_context.filter_state.get_filters()

            if decade.get_first_active():
                start_year = int( decade.get_first_active().get_property('id') )
            else:
                start_year = 0
            if decade.get_last_active():
                if decade.get_last_active().get_property('id') == '0':
                    end_year = 1950 + 9
                else:
                    end_year = int( decade.get_last_active().get_property('id') ) + 9
            else:
                end_year = 3000

之后

            result_set = self.search_context.result_set
            for i in search(self.search_context.search_query,
                            self.search_context.filter_state):
                if not (start_year < i['year'].get_int32() < end_year) :
                    continue
                if not 'uri' in i or not i['uri'] or i['uri'] == '':
                    continue
                if not 'icon' in i or not i['icon'] or i['icon'] == '':
                    i['icon'] = DEFAULT_RESULT_ICON
                if not 'mimetype' in i or not i['mimetype'] or i['mimetype'] == '':
                    i['mimetype'] = DEFAULT_RESULT_MIMETYPE
                if not 'result_type' in i or not i['result_type'] or i['result_type'] == '':
                    i['result_type'] = DEFAULT_RESULT_TYPE
                if not 'category' in i or not i['category'] or i['category'] == '':
                    i['category'] = 0
                if not 'title' in i or not i['title']:
                    i['title'] = ''
                if not 'comment' in i or not i['comment']:
                    i['comment'] = ''
                if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':
                    i['dnd_uri'] = i['uri']
                i['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
                result_set.add_result(**i)
        except Exception as error:
            print(error)
类型部分应该类似,不过我还没有实现。


是的,终于!太酷了,谢谢。我会尝试实施这个并报告进展情况。不幸的是,这些范围有些问题 :( - wa4557
1我很高兴能帮到你(也帮到了我自己 :-) )。我还意识到,我建议在"do_run"中实现的结果过滤可以在"search"方法中实现,因为它的"filters"参数实际上就是在"do_run"中找到的"self.search_context.filter_state"。另外,谈到一个不同的话题,在clementine范围内,我修复了专辑封面提取的问题,它调用了mutagen模块,而这个模块在Python3中不存在。你有相同的问题吗? - Antonio
是的,没错。这应该会显著加快速度,因为这意味着不需要扫描整个收藏。变异剂听起来很有趣。不过 Gmusicbrowser 对专辑艺术处理方式不同... - wa4557
我不知道你是否真的能加快速度,我认为只是在某个时间点进行过滤的问题。也许可以通过将过滤器“嵌入”到SQL查询字符串中来实际加快速度,不确定是否可行。 - Antonio
好的,看起来这就是我们范围之间的区别。Gmusicbrowser将数据库保存为纯文本,因此在我的情况下肯定会加快速度... - wa4557
很不幸的是,似乎无法实现自己的过滤器。至少我没有找到任何方法来做到这一点。 - wa4557
我认为过滤器是在音乐镜头层面上定义的,所以也许你应该修改那个来添加新的过滤器。 - Antonio

即使我们离原问题有些跑题,在clementine范围内,有一个类似的查询字符串
SEARCH_SQL = '''SELECT title, filename, artist, album, albumartist, art_automatic, year, genre, art_manual, track, length
            FROM songs
            WHERE album LIKE '%%%s%%' OR artist LIKE '%%%s%%' OR title LIKE '%%%s%%'
            ORDER BY disc, track'''

(我在原始字符串中添加了关于光盘订购的尊重),然后可以用类似以下方式调用。
tracks = get_music_from_clementine(search, search, search))

搜索是搜索词。现在我定义了一个新的搜索字符串

MY_SEARCH_SQL = '''SELECT title, filename, artist, album, albumartist, art_automatic, year, genre, art_manual, track, length
               FROM songs
               WHERE (year  >= %s AND year <= %s AND (album LIKE '%%%s%%' OR artist LIKE '%%%s%%' OR title LIKE '%%%s%%') )
               ORDER BY disc, track'''

我称之为

    tracks = get_music_from_clementine(MY_SEARCH_SQL % (str(start_year), str(end_year), search, search, search))

用这个搜索字符串,我只会从数据库查询中直接得到我感兴趣的结果,而且范围肯定更加迅速。不知道对于类型的情况是否可以做类似的处理,因为在这种情况下筛选器的数量是可变的(你可以同时选择多个类型,而不仅仅是像“年代”筛选器那样选择一个范围)。

好的,你可以这样做:"""WHERE (year >= %s AND year <= %s AND """ +s*number_of_genres + """ AND (album LIKE '%%%s%%' OR artist LIKE '%%%s%%' OR title LIKE '%%%s%%') )""",其中s=如果number_of_genre == 1: 'genre=%s' else: 'genre=%s OR '*number_of_genres[:-3]。语法明显不正确,但背后的想法应该可行。还有一些%符号缺失。完成后,你应该在Launchpad上提出合并建议。 - wa4557
我找到了一种方法来做这件事,我创建了与流派过滤器相关的部分,然后将其作为一个字符串传递给MY_SEARCH_SQL中要替换的内容。 - Antonio
你能展示一下你的加载器在任何地方都可用吗?我只是好奇你是怎么做到的... - wa4557
您可以在此处找到它:https://code.launchpad.net/~antoniomariano/unity-scope-clementine/My_USClementine,但我只推送了其中的一部分。请在 src/unity_clementine_daemon.py 的 170-177 行查看用于创建类型字符串的代码段,该字符串将作为第三个参数传递给数据库查询,例如 MY_SEARCH_SQL = '''SELECT title, filename, artist, album, albumartist, art_automatic, year, genre, art_manual, track, length FROM songs WHERE (year >= %s AND year <= %s AND %s (album LIKE '%%%s%%' OR artist LIKE '%%%s%%' OR title LIKE '%%%s%%') ) ORDER BY disc, track'''。 - Antonio