Ejemplo n.º 1
0
    def get_songs_with_any_match(name):
        name = Tracker.sparql_escape_string(
            GLib.utf8_normalize(GLib.utf8_casefold(name, -1), -1,
                                GLib.NormalizeMode.NFKD))
        query = """
            {
                SELECT DISTINCT
                    ?song
                WHERE {
                    ?song a nmm:MusicPiece .
                    BIND(tracker:normalize(nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
                    BIND(tracker:normalize(nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
                    BIND(tracker:normalize(nie:title(?song), 'nfkd') AS ?match3) .
                    FILTER (
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match1)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match1), "%(name)s") ||
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match2)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match2), "%(name)s") ||
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match3)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match3), "%(name)s")
                    )
                }
            }
            """.replace('\n', ' ').strip() % {
            'name': name
        }

        return Query.songs(query)
Ejemplo n.º 2
0
    def get_songs_with_any_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_normalize(GLib.utf8_casefold(name, -1), -1, GLib.NormalizeMode.NFKD))
        query = """
            {
                SELECT DISTINCT
                    ?song
                WHERE {
                    ?song a nmm:MusicPiece .
                    BIND(tracker:normalize(nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
                    BIND(tracker:normalize(nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
                    BIND(tracker:normalize(nie:title(?song), 'nfkd') AS ?match3) .
                    BIND(tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
                    FILTER (
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match1)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match1), "%(name)s") ||
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match2)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match2), "%(name)s") ||
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match3)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match3), "%(name)s") ||
                        CONTAINS(tracker:case-fold(tracker:unaccent(?match4)), "%(name)s") ||
                        CONTAINS(tracker:case-fold(?match4), "%(name)s")
                    )
                }
            }
            """.replace('\n', ' ').strip() % {'name': name}

        return Query.songs(query)
Ejemplo n.º 3
0
    def get_songs_with_track_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = '''
            {
                SELECT DISTINCT
                    ?song
                WHERE {
                    ?song a nmm:MusicPiece .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(?song)), "%(name)s")
                    )
                }
            }
            '''.replace('\n', ' ').strip() % {'name': name}

        return Query.songs(query)
Ejemplo n.º 4
0
    def get_artists_with_album_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = '''
            {
                SELECT DISTINCT
                    ?album
                WHERE {
                    ?album a nmm:MusicAlbum .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(?album)), "%(name)s")
                    )
                }
            }
            '''.replace('\n', ' ').strip() % {'name': name}

        return Query.artists(query)
Ejemplo n.º 5
0
    def get_artists_with_any_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = '''
            {
                SELECT DISTINCT
                    nmm:musicAlbum(?song) AS album
                WHERE {
                    ?song a nmm:MusicPiece .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(nmm:musicAlbum(?song))), "%(name)s") ||
                        fn:contains(tracker:case-fold(nmm:artistName(nmm:performer(?song))), "%(name)s") ||
                        fn:contains(tracker:case-fold(nie:title(?song)), "%(name)s")
                    )
                }
            }
            '''.replace('\n', ' ').strip() % {'name': name}

        return Query.artists(query)
Ejemplo n.º 6
0
    def get_songs_with_track_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = '''
            {
                SELECT DISTINCT
                    ?song
                WHERE {
                    ?song a nmm:MusicPiece .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(?song)), "%(name)s")
                    )
                }
            }
            '''.replace('\n', ' ').strip() % {
            'name': name
        }

        return Query.songs(query)
Ejemplo n.º 7
0
    def get_artists_with_album_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = '''
            {
                SELECT DISTINCT
                    ?album
                WHERE {
                    ?album a nmm:MusicAlbum .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(?album)), "%(name)s")
                    )
                }
            }
            '''.replace('\n', ' ').strip() % {
            'name': name
        }

        return Query.artists(query)
Ejemplo n.º 8
0
    def get_artists_with_any_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = '''
            {
                SELECT DISTINCT
                    nmm:musicAlbum(?song) AS album
                WHERE {
                    ?song a nmm:MusicPiece .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(nmm:musicAlbum(?song))), "%(name)s") ||
                        fn:contains(tracker:case-fold(nmm:artistName(nmm:performer(?song))), "%(name)s") ||
                        fn:contains(tracker:case-fold(nie:title(?song)), "%(name)s")
                    )
                }
            }
            '''.replace('\n', ' ').strip() % {
            'name': name
        }

        return Query.artists(query)
Ejemplo n.º 9
0
    def get_songs_with_album_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = """
            {
                SELECT DISTINCT
                    ?song
                WHERE {
                    ?song a nmm:MusicPiece .
                    FILTER (
                        fn:contains(tracker:case-fold(nie:title(nmm:musicAlbum(?song))), "%(name)s")
                    )
                }
            }
            """.replace(
            "\n", " "
        ).strip() % {
            "name": name
        }

        return Query.songs(query)
Ejemplo n.º 10
0
    def get_artists_with_artist_match(name):
        name = Tracker.sparql_escape_string(GLib.utf8_casefold(name, -1))
        query = """
            {
                SELECT DISTINCT
                    ?album
                WHERE {
                    ?album a nmm:MusicAlbum ;
                        nmm:albumArtist ?artist .
                    FILTER (
                        fn:contains(tracker:case-fold(nmm:artistName(?artist)), "%(name)s")
                    )
                }
            }
            """.replace(
            "\n", " "
        ).strip() % {
            "name": name
        }

        return Query.artists(query)
Ejemplo n.º 11
0
def string_for_search(s):
    return GLib.utf8_casefold(GLib.utf8_normalize(s, -1, GLib.NormalizeMode.ALL), -1)
Ejemplo n.º 12
0
    def search(self, text):
        # FIXME: Searches are limited to not bog down the UI with
        # widget creation ({List,Flow}Box limitations). The limit is
        # arbitrarily set to 50 and set in the Tracker query. It should
        # be possible to set it through Grilo options instead. This
        # does not work as expected and needs further investigation.
        term = Tracker.sparql_escape_string(
            GLib.utf8_normalize(GLib.utf8_casefold(text, -1), -1,
                                GLib.NormalizeMode.NFKD))

        # Artist search

        query = """
        SELECT DISTINCT
            rdf:type(?artist)
            tracker:id(?artist) AS ?id
        WHERE {
            ?song a nmm:MusicPiece ;
                    nmm:musicAlbum ?album ;
                    nmm:performer ?artist .
            BIND(tracker:normalize(
                nmm:artistName(nmm:albumArtist(?album)), 'nfkd') AS ?match1) .
            BIND(tracker:normalize(
                nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
            BIND(tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
            FILTER (
                CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match1)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match2)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match4)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match4), "%(name)s")
            )
            %(location_filter)s
        }
        LIMIT 50
        """.replace('\n', ' ').strip() % {
            'location_filter': self._location_filter(),
            'name': term
        }

        artist_filter_ids = []

        def artist_filter(coreartist):
            return coreartist.media.get_id() in artist_filter_ids

        def artist_search_cb(source, op_id, media, data, error):
            if error:
                print("ERROR", error)
                return

            if not media:
                self._artist_search_model.set_filter_func(artist_filter)
                return

            artist_filter_ids.append(media.get_id())

        options = self._fast_options.copy()
        self._source.query(query, self.METADATA_KEYS, options,
                           artist_search_cb)

        # Album search

        query = """
        SELECT DISTINCT
            rdf:type(nmm:musicAlbum(?song))
            tracker:id(nmm:musicAlbum(?song)) AS ?id
        WHERE {
            ?song a nmm:MusicPiece .
            BIND(tracker:normalize(
                nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
            BIND(tracker:normalize(
                nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
            BIND(tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
            FILTER (
                CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match1)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match2)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match4)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match4), "%(name)s")
            )
            %(location_filter)s
        }
        LIMIT 50
        """.replace('\n', ' ').strip() % {
            'location_filter': self._location_filter(),
            'name': term
        }

        album_filter_ids = []

        def album_filter(corealbum):
            return corealbum.media.get_id() in album_filter_ids

        def albums_search_cb(source, op_id, media, data, error):
            if error:
                print("ERROR", error)
                return

            if not media:
                self._album_search_model.set_filter_func(album_filter)
                return

            album_filter_ids.append(media.get_id())

        options = self._fast_options.copy()
        self._source.query(query, self.METADATA_KEYS, options,
                           albums_search_cb)

        # Song search

        query = """
        SELECT DISTINCT
            rdf:type(?song)
            tracker:id(?song) AS ?id
        WHERE {
            ?song a nmm:MusicPiece .
            BIND(tracker:normalize(
                nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
            BIND(tracker:normalize(
                nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
            BIND(tracker:normalize(
                nie:title(?song), 'nfkd') AS ?match3) .
            BIND(
                tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
            FILTER (
                CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match1)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match2)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match3)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match3), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match4)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match4), "%(name)s")
            )
            %(location_filter)s
        }
        LIMIT 50
        """.replace('\n', ' ').strip() % {
            'location_filter': self._location_filter(),
            'name': term
        }

        filter_ids = []

        def songs_filter(coresong):
            return coresong.media.get_id() in filter_ids

        def songs_search_cb(source, op_id, media, data, error):
            if error:
                print("ERROR", error)
                return

            if not media:
                self._song_search_tracker.set_filter_func(songs_filter)
                return

            filter_ids.append(media.get_id())

        options = self._fast_options.copy()

        self._source.query(query, self.METADATA_KEYS, options, songs_search_cb)
Ejemplo n.º 13
0
    def search(self, text):
        term = Tracker.sparql_escape_string(
            GLib.utf8_normalize(GLib.utf8_casefold(text, -1), -1,
                                GLib.NormalizeMode.NFKD))

        query = """
        SELECT DISTINCT
            rdf:type(?song)
            tracker:id(?song) AS ?id
        WHERE {
            ?song a nmm:MusicPiece .
            BIND(tracker:normalize(
                nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
            BIND(tracker:normalize(
                nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
            BIND(tracker:normalize(
                nie:title(?song), 'nfkd') AS ?match3) .
            BIND(
                tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
            FILTER (
                CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match1)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match2)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match3)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match3), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match4)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match4), "%(name)s")
            )
            %(location_filter)s
        }
        """.replace('\n', ' ').strip() % {
            'location_filter': self._location_filter(),
            'name': term
        }

        filter_ids = []

        def songs_filter(coresong):
            return coresong.media.get_id() in filter_ids

        def songs_search_cb(source, op_id, media, data, error):
            if error:
                print("ERROR", error)
                return

            if not media:
                self._song_search_tracker.set_filter_func(songs_filter)
                return

            filter_ids.append(media.get_id())

        options = self._fast_options.copy()

        self._source.query(query, self.METADATA_KEYS, options, songs_search_cb)

        # Album search

        query = """
        SELECT DISTINCT
            rdf:type(nmm:musicAlbum(?song))
            tracker:id(nmm:musicAlbum(?song)) AS ?id
        WHERE {
            ?song a nmm:MusicPiece .
            BIND(tracker:normalize(
                nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
            BIND(tracker:normalize(
                nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
            BIND(tracker:normalize(nie:title(?song), 'nfkd') AS ?match3) .
            BIND(tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
            FILTER (
                CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match1)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match2)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match3)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match3), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match4)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match4), "%(name)s")
            )
            %(location_filter)s
        }
        """.replace('\n', ' ').strip() % {
            'location_filter': self._location_filter(),
            'name': term
        }

        album_filter_ids = []

        def album_filter(corealbum):
            return corealbum.media.get_id() in album_filter_ids

        def albums_search_cb(source, op_id, media, data, error):
            if error:
                print("ERROR", error)
                return

            if not media:
                self._album_search_model.set_filter_func(album_filter)
                return

            album_filter_ids.append(media.get_id())

        options = self._fast_options.copy()
        self._source.query(query, self.METADATA_KEYS, options,
                           albums_search_cb)

        # Artist search

        query = """
        SELECT DISTINCT
            rdf:type(?artist)
            tracker:id(?artist) AS ?id
        WHERE {
            ?song a nmm:MusicPiece ;
                    nmm:musicAlbum ?album ;
                    nmm:performer ?artist .
            BIND(tracker:normalize(
                nie:title(nmm:musicAlbum(?song)), 'nfkd') AS ?match1) .
            BIND(tracker:normalize(
                nmm:artistName(nmm:performer(?song)), 'nfkd') AS ?match2) .
            BIND(tracker:normalize(nie:title(?song), 'nfkd') AS ?match3) .
            BIND(tracker:normalize(nmm:composer(?song), 'nfkd') AS ?match4) .
            FILTER (
                CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match1)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match2)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match3)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match3), "%(name)s")
                || CONTAINS(tracker:case-fold(
                    tracker:unaccent(?match4)), "%(name)s")
                || CONTAINS(tracker:case-fold(?match4), "%(name)s")
            )
            %(location_filter)s
        }
        """.replace('\n', ' ').strip() % {
            'location_filter': self._location_filter(),
            'name': term
        }

        artist_filter_ids = []

        def artist_filter(coreartist):
            return coreartist.media.get_id() in artist_filter_ids

        def artist_search_cb(source, op_id, media, data, error):
            if error:
                print("ERROR", error)
                return

            if not media:
                self._artist_search_model.set_filter_func(artist_filter)
                return

            artist_filter_ids.append(media.get_id())

        options = self._fast_options.copy()
        self._source.query(query, self.METADATA_KEYS, options,
                           artist_search_cb)
Ejemplo n.º 14
0
    def search(self, text):
        # FIXME: Searches are limited to not bog down the UI with
        # widget creation ({List,Flow}Box limitations). The limit is
        # arbitrarily set to 50 and set in the Tracker query. It should
        # be possible to set it through Grilo options instead. This
        # does not work as expected and needs further investigation.
        term = Tracker.sparql_escape_string(
            GLib.utf8_normalize(GLib.utf8_casefold(text, -1), -1,
                                GLib.NormalizeMode.NFKD))

        # Artist search
        self._notificationmanager.push_loading()

        query = """
        SELECT
            ?type ?id
        WHERE {
            SERVICE <dbus:%(miner_fs_busname)s> {
                GRAPH tracker:Audio {
                    SELECT DISTINCT
                        %(media_type)s AS ?type
                        COALESCE(?album_artist, ?artist) AS ?id
                    WHERE {
                        ?song a nmm:MusicPiece ;
                                nmm:musicAlbum ?album ;
                                nmm:artist ?artist .
                        OPTIONAL {
                            ?album a nmm:MusicAlbum ;
                                     nmm:albumArtist ?album_artist .
                        }
                        BIND(COALESCE(nmm:artistName(?album_artist),
                                      nmm:artistName(?artist)) AS ?artist_bind)
                        BIND(tracker:normalize(nmm:artistName(
                                 nmm:albumArtist(?artist_bind)), 'nfkd')
                             AS ?match1) .
                        BIND(tracker:normalize(
                                 nmm:artistName(nmm:artist(?song)), 'nfkd')
                             AS ?match2) .
                        BIND(tracker:normalize(nmm:composer(?song), 'nfkd')
                             AS ?match4) .
                        FILTER (
                            CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match1)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match2)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match4)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match4), "%(name)s")
                        )
                        %(location_filter)s
                    }
                    LIMIT 50
                }
            }
        }
        """.replace('\n', ' ').strip() % {
            "miner_fs_busname": self._tracker_wrapper.props.miner_fs_busname,
            "media_type": int(Grl.MediaType.AUDIO),
            'location_filter': self._tracker_wrapper.location_filter(),
            'name': term
        }

        artist_filter_ids = []

        def artist_filter(coreartist):
            return coreartist.media.get_id() in artist_filter_ids

        def artist_search_cb(source, op_id, media, remaining, error):
            if error:
                self._log.warning("Error: {}".format(error))
                self._notificationmanager.pop_loading()
                return

            if not media:
                self._artist_search_model.set_filter_func(artist_filter)
                self._notificationmanager.pop_loading()
                return

            artist_filter_ids.append(media.get_id())

        self.props.source.query(query, [Grl.METADATA_KEY_ID],
                                self._fast_options, artist_search_cb)

        # Album search
        self._notificationmanager.push_loading()

        query = """
        SELECT
            ?type ?id
        WHERE {
            SERVICE <dbus:%(miner_fs_busname)s> {
                GRAPH tracker:Audio {
                    SELECT DISTINCT
                        %(media_type)s AS ?type
                        nmm:musicAlbum(?song) AS ?id
                    WHERE {
                        ?song a nmm:MusicPiece .
                        BIND(tracker:normalize(
                                 nie:title(nmm:musicAlbum(?song)), 'nfkd')
                             AS ?match1) .
                        BIND(tracker:normalize(
                                 nmm:artistName(nmm:artist(?song)), 'nfkd')
                             AS ?match2) .
                        BIND(tracker:normalize(nmm:composer(?song), 'nfkd')
                             AS ?match4) .
                        FILTER (
                            CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match1)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match2)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match4)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match4), "%(name)s")
                        )
                        %(location_filter)s
                    }
                    LIMIT 50
                }
            }
        }
        """.replace('\n', ' ').strip() % {
            "miner_fs_busname": self._tracker_wrapper.props.miner_fs_busname,
            "media_type": int(Grl.MediaType.CONTAINER),
            'location_filter': self._tracker_wrapper.location_filter(),
            'name': term
        }

        album_filter_ids = []

        def album_filter(corealbum):
            return corealbum.media.get_id() in album_filter_ids

        def albums_search_cb(source, op_id, media, remaining, error):
            if error:
                self._log.warning("Error: {}".format(error))
                self._notificationmanager.pop_loading()
                return

            if not media:
                self._album_search_model.set_filter_func(album_filter)
                self._notificationmanager.pop_loading()
                return

            album_filter_ids.append(media.get_id())

        self.props.source.query(query, [Grl.METADATA_KEY_ID],
                                self._fast_options, albums_search_cb)

        # Song search
        self._notificationmanager.push_loading()

        query = """
        SELECT
            ?type ?id
        WHERE {
            SERVICE <dbus:%(miner_fs_busname)s> {
                GRAPH tracker:Audio {
                    SELECT DISTINCT
                        %(media_type)s AS ?type
                        ?song AS ?id
                    WHERE {
                        ?song a nmm:MusicPiece .
                        BIND(tracker:normalize(
                                 nie:title(nmm:musicAlbum(?song)), 'nfkd')
                             AS ?match1) .
                        BIND(tracker:normalize(
                                 nmm:artistName(nmm:artist(?song)), 'nfkd')
                             AS ?match2) .
                        BIND(tracker:normalize(
                            nie:title(?song), 'nfkd') AS ?match3) .
                        BIND(tracker:normalize(nmm:composer(?song), 'nfkd')
                             AS ?match4) .
                        FILTER (
                            CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match1)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match1), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match2)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match2), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match3)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match3), "%(name)s")
                            || CONTAINS(tracker:case-fold(
                                tracker:unaccent(?match4)), "%(name)s")
                            || CONTAINS(tracker:case-fold(?match4), "%(name)s")
                        )
                        %(location_filter)s
                    }
                    LIMIT 50
                }
            }
        }
        """.replace('\n', ' ').strip() % {
            "miner_fs_busname": self._tracker_wrapper.props.miner_fs_busname,
            "media_type": int(Grl.MediaType.AUDIO),
            'location_filter': self._tracker_wrapper.location_filter(),
            'name': term
        }

        filter_ids = []

        def songs_filter(coresong):
            return coresong.media.get_id() in filter_ids

        def songs_search_cb(source, op_id, media, remaining, error):
            if error:
                self._log.warning("Error: {}".format(error))
                self._notificationmanager.pop_loading()
                return

            if not media:
                self._song_search_tracker.set_filter_func(songs_filter)
                self._notificationmanager.pop_loading()
                return

            filter_ids.append(media.get_id())

        self.props.source.query(query, [Grl.METADATA_KEY_ID],
                                self._fast_options, songs_search_cb)