[rhythmbox] soundcloud: use pagination to fetch more search results and tracks
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] soundcloud: use pagination to fetch more search results and tracks
- Date: Sun, 29 May 2016 09:20:37 +0000 (UTC)
commit ba24e933e9197fdc980cba504c68c5cbfab7d664
Author: Jonathan Matthew <jonathan d14n org>
Date: Sun May 29 19:15:19 2016 +1000
soundcloud: use pagination to fetch more search results and tracks
Fetch more containers when the bottom of the list is visible, and
provide a button for fetching more tracks.
plugins/soundcloud/soundcloud.py | 90 +++++++++++++++++++++++++++++++++++---
plugins/soundcloud/soundcloud.ui | 4 +-
2 files changed, 86 insertions(+), 8 deletions(-)
---
diff --git a/plugins/soundcloud/soundcloud.py b/plugins/soundcloud/soundcloud.py
index a744ee3..07834ba 100644
--- a/plugins/soundcloud/soundcloud.py
+++ b/plugins/soundcloud/soundcloud.py
@@ -87,6 +87,8 @@ class SoundCloudSource(RB.StreamingSource):
def __init__(self, **kwargs):
super(SoundCloudSource, self).__init__(kwargs)
self.loader = None
+ self.container_loader = None
+ self.container_marker_path = None
self.search_count = 1
self.search_types = {
@@ -204,6 +206,18 @@ class SoundCloudSource(RB.StreamingSource):
ct = self.container_types[k]
self.containers.append([item.get(i) for i in ct['attributes']])
+ def add_container_marker(self):
+ iter = self.containers.append(['...', None, None, None, None, None])
+ self.container_marker_path = self.containers.get_path(iter)
+
+ def remove_container_marker(self):
+ if self.container_marker_path is None:
+ return
+
+ iter = self.containers.get_iter(self.container_marker_path)
+ self.containers.remove(iter)
+ self.container_marker_path = None
+
def search_tracks_api_cb(self, data):
if data is None:
return
@@ -214,20 +228,33 @@ class SoundCloudSource(RB.StreamingSource):
data = data.decode('utf-8')
stuff = json.loads(data)
- for item in stuff:
+ for item in stuff['collection']:
self.add_track(db, entry_type, item)
+ if 'next_href' in stuff:
+ self.more_tracks_url = stuff.get('next_href')
+ self.fetch_more_button.set_sensitive(True)
+
+
def search_containers_api_cb(self, data):
if data is None:
return
+ self.remove_container_marker()
+ self.container_loader = None
+
entry_type = self.props.entry_type
data = data.decode('utf-8')
stuff = json.loads(data)
- for item in stuff:
+ for item in stuff['collection']:
self.add_container(item)
+ if 'next_href' in stuff:
+ self.add_container_marker()
+ self.more_containers_url = stuff.get('next_href')
+
+
def resolve_api_cb(self, data):
if data is None:
return
@@ -255,11 +282,15 @@ class SoundCloudSource(RB.StreamingSource):
for t in stuff['tracks']:
self.add_track(db, self.props.entry_type, t)
- def cancel_request(self):
+ def cancel_request(self, cancel_containers=False):
if self.loader:
self.loader.cancel()
self.loader = None
+ if self.container_loader and cancel_containers:
+ self.container_loader.cancel()
+ self.container_loader = None
+
def search_popup_cb(self, widget):
self.search_popup.popup(None, None, None, None, 3, Gtk.get_current_event_time())
@@ -277,12 +308,23 @@ class SoundCloudSource(RB.StreamingSource):
self.search_text = term
self.do_search()
+ def show_more_cb(self, button):
+ button.set_sensitive(False)
+ if self.more_tracks_url:
+ self.cancel_request(False)
+ print("fetching more tracks")
+ self.loader = rb.Loader()
+ self.loader.get_url(self.more_tracks_url, self.search_tracks_api_cb)
+
def do_search(self):
self.cancel_request()
base = 'https://api.soundcloud.com'
self.new_model()
self.containers.clear()
+ self.more_tracks_url = None
+ self.more_containers_url = None
+ self.fetch_more_button.set_sensitive(False)
term = self.search_text
if term.startswith('https://soundcloud.com/') or term.startswith("http://soundcloud.com/"):
@@ -302,7 +344,7 @@ class SoundCloudSource(RB.StreamingSource):
st = self.search_types[self.search_type]
self.container_view.get_column(0).set_title(st['title'])
- url = base + st['endpoint'] + '?q=' + urllib.parse.quote(term) + '&client_id=' + CLIENT_ID
+ url = base + st['endpoint'] + '?q=' + urllib.parse.quote(term) +
'&linked_partitioning=1&limit=100&client_id=' + CLIENT_ID
self.loader = rb.Loader()
if st['containers']:
self.scrolled.show()
@@ -321,13 +363,19 @@ class SoundCloudSource(RB.StreamingSource):
if aiter is None:
return
+ if self.container_marker_path is not None:
+ apath = self.containers.get_path(aiter)
+ if apath.compare(self.container_marker_path) == 0:
+ print("marker row selected")
+ return
+
[itemtype, url] = model.get(aiter, 1, 2)
if itemtype not in self.container_types:
return
print("loading %s %s" % (itemtype, url))
ct = self.container_types[itemtype]
- trackurl = url + ct['tracks-url'] + '?client_id=' + CLIENT_ID
+ trackurl = url + ct['tracks-url'] + '?linked_partitioning=1&client_id=' + CLIENT_ID
self.loader = rb.Loader()
if ct['tracks-type'] == 'playlist':
@@ -335,6 +383,26 @@ class SoundCloudSource(RB.StreamingSource):
else:
self.loader.get_url(trackurl, self.search_tracks_api_cb)
+ def maybe_more_containers(self):
+ self.more_containers_idle = 0
+ if self.container_loader is not None:
+ return False
+
+ (start, end) = self.container_view.get_visible_range()
+ if self.container_marker_path.compare(end) == 1:
+ return False
+
+ self.container_loader = rb.Loader()
+ self.container_loader.get_url(self.more_containers_url, self.search_containers_api_cb)
+ return False
+
+ def scroll_adjust_changed_cb(self, adjust):
+ if self.more_containers_url is None:
+ return
+
+ if self.more_containers_idle == 0:
+ self.more_containers_idle = GLib.idle_add(self.maybe_more_containers)
+
def sort_order_changed_cb(self, obj, pspec):
obj.resort_model()
@@ -413,9 +481,17 @@ class SoundCloudSource(RB.StreamingSource):
self.scrolled.set_no_show_all(True)
self.scrolled.hide()
+ self.more_containers_idle = 0
+ adj = self.scrolled.get_vadjustment()
+ adj.connect("changed", self.scroll_adjust_changed_cb)
+ adj.connect("value-changed", self.scroll_adjust_changed_cb)
+
self.search_entry = RB.SearchEntry(spacing=6)
self.search_entry.props.explicit_mode = True
+ self.fetch_more_button = Gtk.Button.new_with_label(_("Fetch more tracks"))
+ self.fetch_more_button.connect("clicked", self.show_more_cb)
+
action = Gio.SimpleAction.new("soundcloud-search-type", GLib.VariantType.new('s'))
action.connect("activate", self.search_type_action_cb)
shell.props.window.add_action(action)
@@ -437,8 +513,10 @@ class SoundCloudSource(RB.StreamingSource):
self.search_entry.connect("activate", self.search_entry_cb)
self.search_entry.connect("show-popup", self.search_popup_cb)
self.search_entry.set_size_request(400, -1)
- builder.get_object("search-box").pack_start(self.search_entry, False, True, 0)
+ searchbox = builder.get_object("search-box")
+ searchbox.pack_start(self.search_entry, False, True, 0)
+ searchbox.pack_start(self.fetch_more_button, False, True, 0)
self.search_popup.attach_to_widget(self.search_entry, None)
diff --git a/plugins/soundcloud/soundcloud.ui b/plugins/soundcloud/soundcloud.ui
index d6cc157..7738f3e 100644
--- a/plugins/soundcloud/soundcloud.ui
+++ b/plugins/soundcloud/soundcloud.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.18.3 -->
+<!-- Generated with glade 3.19.0 -->
<interface>
<requires lib="gtk+" version="3.6"/>
<object class="GtkListStore" id="container-store">
@@ -33,7 +33,6 @@
<property name="width_request">150</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="shadow_type">none</property>
<child>
<object class="GtkTreeView" id="containers">
<property name="visible">True</property>
@@ -69,6 +68,7 @@
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border_width">6</property>
+ <property name="spacing">6</property>
<child>
<placeholder/>
</child>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]