[gnome-music/wip/mschraal/core] searchview: Add albums search



commit f49425623fb7474f8bf76a0288d614bd5e56e943
Author: Marinus Schraal <mschraal gnome org>
Date:   Mon Jul 1 10:32:56 2019 +0200

    searchview: Add albums search

 gnomemusic/coregrilo.py                      |  7 ++--
 gnomemusic/coremodel.py                      |  9 ++++-
 gnomemusic/grilowrappers/grldleynasource.py  |  2 +-
 gnomemusic/grilowrappers/grltrackersource.py | 55 +++++++++++++++++++++++++++-
 gnomemusic/views/searchview.py               | 30 +++++++++++++++
 5 files changed, 97 insertions(+), 6 deletions(-)
---
diff --git a/gnomemusic/coregrilo.py b/gnomemusic/coregrilo.py
index 844f12ec..134a545a 100644
--- a/gnomemusic/coregrilo.py
+++ b/gnomemusic/coregrilo.py
@@ -13,7 +13,7 @@ class CoreGrilo(GObject.GObject):
 
     def __init__(
             self, coremodel, model, albums_model, artists_model,
-            coreselection, song_search_model):
+            coreselection, song_search_model, album_search_model):
         super().__init__()
 
         self._coremodel = coremodel
@@ -23,6 +23,7 @@ class CoreGrilo(GObject.GObject):
         self._albums_model = albums_model
         self._artists_model = artists_model
         self._song_search_model = song_search_model
+        self._album_search_model = album_search_model
 
         Grl.init(None)
 
@@ -37,12 +38,12 @@ class CoreGrilo(GObject.GObject):
             new_wrapper = GrlTrackerSource(
                 source, self._model, self._albums_model,
                 self._artists_model, self._coremodel, self._coreselection,
-                self, self._song_search_model)
+                self, self._song_search_model, self._album_search_model)
         elif source.props.source_id[:10] == "grl-dleyna":
             new_wrapper = GrlDLeynaSource(
                 source, self._model, self._albums_model,
                 self._artists_model, self._coremodel, self._coreselection,
-                self, self._song_search_model)
+                self, self._song_search_model, self._album_search_model)
 
         self._wrappers.append(new_wrapper)
         print(new_wrapper, "added")
diff --git a/gnomemusic/coremodel.py b/gnomemusic/coremodel.py
index f87225a3..055d2016 100644
--- a/gnomemusic/coremodel.py
+++ b/gnomemusic/coremodel.py
@@ -56,10 +56,14 @@ class CoreModel(GObject.GObject):
         self._song_search_model = Dazzle.ListModelFilter.new(self._model)
         self._song_search_model.set_filter_func(lambda a: False)
 
+        self._album_search_model = Dazzle.ListModelFilter.new(self._album_model)
+        self._album_search_model.set_filter_func(lambda a: False)
+
         print("PLAYLIST_MODEL", self._playlist_model)
         self._grilo = CoreGrilo(
             self, self._model, self._album_model, self._artist_model,
-            self._coreselection, self._song_search_model)
+            self._coreselection, self._song_search_model,
+            self._album_search_model)
 
     def _filter_selected(self, coresong):
         return coresong.props.selected
@@ -197,5 +201,8 @@ class CoreModel(GObject.GObject):
     def get_songs_search_model(self):
         return self._song_search_model
 
+    def get_album_search_model(self):
+        return self._album_search_model
+
     def search(self, text):
         self._grilo.search(text)
diff --git a/gnomemusic/grilowrappers/grldleynasource.py b/gnomemusic/grilowrappers/grldleynasource.py
index 248b19e9..3490d3d0 100644
--- a/gnomemusic/grilowrappers/grldleynasource.py
+++ b/gnomemusic/grilowrappers/grldleynasource.py
@@ -30,7 +30,7 @@ class GrlDLeynaSource(GObject.GObject):
 
     def __init__(
             self, source, model, albums_model, artists_model, coremodel,
-            core_selection, grilo, song_search_model):
+            core_selection, grilo, song_search_model, album_search_model):
         super().__init__()
 
         self._coremodel = coremodel
diff --git a/gnomemusic/grilowrappers/grltrackersource.py b/gnomemusic/grilowrappers/grltrackersource.py
index 3c9928ae..8af63a3e 100644
--- a/gnomemusic/grilowrappers/grltrackersource.py
+++ b/gnomemusic/grilowrappers/grltrackersource.py
@@ -32,7 +32,7 @@ class GrlTrackerSource(GObject.GObject):
 
     def __init__(
             self, source, model, albums_model, artists_model, coremodel,
-            coreselection, grilo, song_search_model):
+            coreselection, grilo, song_search_model, album_search_model):
         super().__init__()
 
         self._coremodel = coremodel
@@ -45,6 +45,7 @@ class GrlTrackerSource(GObject.GObject):
         self._artists_model = artists_model
         self._hash = {}
         self._song_search_model = song_search_model
+        self._album_search_model = album_search_model
 
         self._fast_options = Grl.OperationOptions()
         self._fast_options.set_resolution_flags(
@@ -531,3 +532,55 @@ class GrlTrackerSource(GObject.GObject):
         options = self._fast_options.copy()
 
         self._source.query(query, self.METADATA_KEYS, options, search_cb)
+
+        # Album search
+
+        query = """
+        SELECT DISTINCT
+            rdf:type(nmm:musicAlbum(?song))
+            tracker:id(nmm:musicAlbum(?song)) AS ?id
+        {
+            ?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': 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)
diff --git a/gnomemusic/views/searchview.py b/gnomemusic/views/searchview.py
index 90067190..086ed91c 100644
--- a/gnomemusic/views/searchview.py
+++ b/gnomemusic/views/searchview.py
@@ -36,6 +36,7 @@ from gnomemusic.query import Query
 from gnomemusic.utils import View
 from gnomemusic.search import Search
 from gnomemusic.views.baseview import BaseView
+from gnomemusic.widgets.albumcover import AlbumCover
 from gnomemusic.widgets.headerbar import HeaderBar
 from gnomemusic.widgets.artistalbumswidget import ArtistAlbumsWidget
 from gnomemusic.widgets.songwidget import SongWidget
@@ -55,6 +56,7 @@ class SearchView(BaseView):
     def __init__(self, window, player):
         self._coremodel = window._app._coremodel
         self._model = self._coremodel.get_songs_search_model()
+        self._album_model = self._coremodel.get_album_search_model()
         super().__init__('search', None, window)
 
         # self._add_list_renderers()
@@ -98,7 +100,18 @@ class SearchView(BaseView):
         self._songs_listbox = Gtk.ListBox()
         self._songs_listbox.bind_model(self._model, self._create_song_widget)
 
+        self._album_flowbox = Gtk.FlowBox(
+            homogeneous=True, hexpand=True, halign=Gtk.Align.FILL,
+            valign=Gtk.Align.START, selection_mode=Gtk.SelectionMode.NONE,
+            margin=18, row_spacing=12, column_spacing=6,
+            min_children_per_line=1, max_children_per_line=20, visible=True)
+
+        self._album_flowbox.get_style_context().add_class('content-view')
+        self._album_flowbox.bind_model(
+            self._album_model, self._create_album_widget)
+
         self._all_results_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        self._all_results_box.pack_start(self._album_flowbox, True, True, 0)
         self._all_results_box.pack_start(self._songs_listbox, True, True, 0)
 
         # self._view = Gtk.TreeView(
@@ -146,6 +159,23 @@ class SearchView(BaseView):
 
         return song_widget
 
+    def _create_album_widget(self, corealbum):
+        album_widget = AlbumCover(corealbum)
+
+        self.bind_property(
+            "selection-mode", album_widget, "selection-mode",
+            GObject.BindingFlags.SYNC_CREATE
+            | GObject.BindingFlags.BIDIRECTIONAL)
+
+        # NOTE: Adding SYNC_CREATE here will trigger all the nested
+        # models to be created. This will slow down initial start,
+        # but will improve initial 'selecte all' speed.
+        album_widget.bind_property(
+            "selected", corealbum, "selected",
+            GObject.BindingFlags.BIDIRECTIONAL)
+
+        return album_widget
+
     def _song_activated(self, widget, event):
         mod_mask = Gtk.accelerator_get_default_mod_mask()
         if ((event.get_state() & mod_mask) == Gdk.ModifierType.CONTROL_MASK


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]