[GH-ISSUE #527] Query amount dependent on terminal size? #217

Closed
opened 2026-02-28 14:47:49 +03:00 by kerem · 14 comments
Owner

Originally created by @ghost on GitHub (Jul 14, 2020).
Original GitHub issue: https://github.com/Rigellute/spotify-tui/issues/527

It looks like the amount of information queried is dependent on the size of the terminal? I've tested it on both of my computers with konsole and termite.

This is the terminal size being small:

After I expand the size of my terminal, it shows that it's missing a lot of songs from the playlist, and the playlists section is missing a lot of playlists:

If I start spt with the same expanded size terminal above, this is what it looks like:

There are now more songs and playlists, but it is still missing a lot of them. The issue is more noticeable on my laptop as the screen is smaller, and I open a smaller terminal.

Originally created by @ghost on GitHub (Jul 14, 2020). Original GitHub issue: https://github.com/Rigellute/spotify-tui/issues/527 It looks like the amount of information queried is dependent on the size of the terminal? I've tested it on both of my computers with konsole and termite. This is the terminal size being small: ![](https://i.imgur.com/squKTAh.png) After I expand the size of my terminal, it shows that it's missing a lot of songs from the playlist, and the playlists section is missing a lot of playlists: ![](https://i.imgur.com/IG11zQQ.png) If I start `spt` with the same expanded size terminal above, this is what it looks like: ![](https://i.imgur.com/9QvUEW9.png) There are now more songs and playlists, but it is still missing a lot of them. The issue is more noticeable on my laptop as the screen is smaller, and I open a smaller terminal.
kerem closed this issue 2026-02-28 14:47:49 +03:00
Author
Owner

@AivreeG commented on GitHub (Jul 14, 2020):

As far as I know, this is expected behavior based on the way spt handles pagination. Ctrl+D and Ctrl+U move the viewable section down and up respectively. The displayed height is dependent on the terminal size, naturally. An alternative issue title may be Request: More Dynamic List Rendering for Changing Terminal Sizes.

<!-- gh-comment-id:658263631 --> @AivreeG commented on GitHub (Jul 14, 2020): As far as I know, this is expected behavior based on the way `spt` handles pagination. Ctrl+D and Ctrl+U move the viewable section down and up respectively. The displayed height is dependent on the terminal size, naturally. An alternative issue title may be Request: More Dynamic List Rendering for Changing Terminal Sizes.
Author
Owner

@ghost commented on GitHub (Jul 15, 2020):

@AivreeG , even the pagination isn't handled well, causing a lot of missing music. Either not enough data is being queried to be able to have multiple pages, or the sections just doesn't have pagination available to go through.

The only place I can actually use Ctrl+D & Ctrl+U is the Playlists -> Songs section:

If I search for an artist, and go to the songs section, it does not work:

This album has 25 songs, but it is only showing 15 songs. Arrow keys will just cycle through 1-15, and Ctrl+D / U does not do anything here:

<!-- gh-comment-id:658507447 --> @ghost commented on GitHub (Jul 15, 2020): @AivreeG , even the pagination isn't handled well, causing a lot of missing music. Either not enough data is being queried to be able to have multiple pages, or the sections just doesn't have pagination available to go through. The only place I can actually use Ctrl+D & Ctrl+U is the Playlists -> Songs section: ![](https://i.imgur.com/1VMDcTd.png) If I search for an artist, and go to the songs section, it does not work: ![](https://i.imgur.com/vlfTTBO.png) This album has 25 songs, but it is only showing 15 songs. Arrow keys will just cycle through 1-15, and Ctrl+D / U does not do anything here: ![](https://i.imgur.com/xOMdfQt.png)
Author
Owner

@AivreeG commented on GitHub (Jul 20, 2020):

In that case, I agree. I primarily checked in the saved Playlists and Albums section. I've found a long saved album can be simply arrowed through. This seems to be an issue with search queries specifically, then.

<!-- gh-comment-id:661107339 --> @AivreeG commented on GitHub (Jul 20, 2020): In that case, I agree. I primarily checked in the saved Playlists and Albums section. I've found a long saved album can be simply arrowed through. This seems to be an issue with search queries specifically, then.
Author
Owner

@Rigellute commented on GitHub (Jul 22, 2020):

@AivreeG is correct that terminal size defines the amount of data fetched.

The second issue is that pagination is not implemented in every view yet (this is on the roadmap)

<!-- gh-comment-id:662348825 --> @Rigellute commented on GitHub (Jul 22, 2020): @AivreeG is correct that terminal size defines the amount of data fetched. The second issue is that pagination is not implemented in every view yet (this is on the [roadmap](https://github.com/Rigellute/spotify-tui#high-level-requirements-yet-to-be-implemented))
Author
Owner

@Hugo01 commented on GitHub (Jul 22, 2020):

I wonder if there's a way to get rid of pagination and query the entire list at once
That would "solve" the problem in the "liked songs" section where you can only listen to songs on that particular page

<!-- gh-comment-id:662727600 --> @Hugo01 commented on GitHub (Jul 22, 2020): I wonder if there's a way to get rid of pagination and query the entire list at once That would "solve" the problem in the "liked songs" section where you can only listen to songs on that particular page
Author
Owner

@ghost commented on GitHub (Jul 22, 2020):

It would be nice if the application could fetch all of the data requested, regardless of terminal size, push it to a dynamic table. And each box / view would have it's own table that is fully fetched and you'd be able to even just scroll through the listings with arrow keys. And if you resize your terminal, more or less lines would automatically pop up due to the dynamic table. Page up & Page down can still be in there too.

<!-- gh-comment-id:662745971 --> @ghost commented on GitHub (Jul 22, 2020): It would be nice if the application could fetch all of the data requested, regardless of terminal size, push it to a dynamic table. And each box / view would have it's own table that is fully fetched and you'd be able to even just scroll through the listings with arrow keys. And if you resize your terminal, more or less lines would automatically pop up due to the dynamic table. Page up & Page down can still be in there too.
Author
Owner

@jcro21 commented on GitHub (Aug 18, 2020):

Just spitballin'...
A load on demand function within the TrackTable object that returns results from its tracks property and fetches additional tracks as needed would avoid retrieving and storing potentially unused data, and could be called whenever a track with index > TrackTable.tracks.len() - large_search_limit is requested which should cover terminal resizing and could also provide a more natural way of scrolling through views via the arrow keys (data is fetched and appended just in time for the user to be unaware of the offset fetching, giving a seamless scroll through the track list start to end)

Would need a way to identify a fully fetched list, something like:

struct TrackTable {
  tracks: Vec<FullTrack>,
  selected_index: usize,
  is_complete_tracklist: bool, // set true when api returns a result count < large_search_limit
  context: Option<TrackTableContext>,
}

Could maybe make it easier to locally cache more permanent user objects like Playlists and Saved/Liked tracks 🤷‍♂️

<!-- gh-comment-id:675244373 --> @jcro21 commented on GitHub (Aug 18, 2020): Just spitballin'... A load on demand function within the `TrackTable` object that returns results from its `tracks` property and fetches additional tracks as needed would avoid retrieving and storing potentially unused data, and could be called whenever a track with index > `TrackTable.tracks.len() - large_search_limit` is requested which should cover terminal resizing and could also provide a more natural way of scrolling through views via the arrow keys (data is fetched and appended just in time for the user to be unaware of the offset fetching, giving a seamless scroll through the track list start to end) Would need a way to identify a fully fetched list, something like: ``` struct TrackTable { tracks: Vec<FullTrack>, selected_index: usize, is_complete_tracklist: bool, // set true when api returns a result count < large_search_limit context: Option<TrackTableContext>, } ``` Could maybe make it easier to locally cache more permanent user objects like Playlists and Saved/Liked tracks :man_shrugging:
Author
Owner

@sputnick1124 commented on GitHub (Sep 29, 2020):

I like the idea of having an on-demand page loader. I think the current ScrollableResultPages struct is a little cumbersome to use at the moment and is causing a number of issues; possibly a redesign could not only help us resolve most of the problems we are seeing with paging at the moment, but also more easily enable new contexts to seamlessly handle paging. I was toying around with some traits to help us out and I think that something similar to the following might get us on a good start to where we want to be:

trait PageAdapter<T: Clone> {
  fn next(&self) -> Option<String>;

  fn items(&self) -> &[T];
}

pub trait Pageable {
  fn get_dispatch(next: Option<String>, offset: u32) -> Option<IoEvent>;
}

We could then impl these traits for the rspotify API types to imbue them with reliable behaviors like so:


impl<T: Clone> PageAdapter<T> for Page<T> {
  fn next(&self) -> Option<String> {
    self.next.clone()
  }

  fn items(&self) -> &[T] {
    &self.items
  }
}

impl<T: Clone> PageAdapter<T> for CursorBasedPage<T> {
  fn next(&self) -> Option<String> {
    self.cursors.after.clone()
  }

  fn items(&self) -> &[T] {
    &self.items
  }
}

impl Pageable for SavedTrack {
  fn get_dispatch(next: Option<String>, offset: u32) -> Option<IoEvent> {
    if let Some(_next_uri) = next {
      Some(IoEvent::GetCurrentSavedTracks(Some(offset)))
    } else {
      None
    }
  }
}

type SavedArtist = FullArtist;

impl Pageable for SavedArtist {
  fn get_dispatch(after: Option<String>, _offset: u32) -> Option<IoEvent> {
    if let Some(after) = after {
      Some(IoEvent::GetFollowedArtists(Some(after)))
    } else {
      None
    }
  }
}

// etc...

Finally, we can now compose these ideas together in a new ScrollableResultPage type that could look something this:

pub struct ScrollableResultPages<T> {
  pub items: Vec<T>,
  next: Option<String>,
}

impl<T: Pageable + Clone> ScrollableResultPages<T> {
  fn new() -> Self {
    ScrollableResultPages {
      items: vec![],
      next: None,
    }
  }

  fn dispatch(&self, app: &mut App) {
    if let Some(event) = T::get_dispatch(self.next.clone(), self.items.len() as u32) {
      app.dispatch(event);
    }
  }

  fn add_page(&mut self, page: &dyn PageAdapter<T>) {
    self.items.extend_from_slice(page.items());
    self.next = page.next().clone();
  }
}

and provides a common interface for anything that can be paged. When we need to page a new type of result in the future, all we should have to do is impl Pageable for it and then we're off to the races. We have a single Vec<T> which holds all of our items, so the paging can now be delegated to the UI screen size instead of the contents of the a single Page request result.

The main thing to yet be designed here is when we actually kick off getting new results. I think I like the idea of sending an IoEvent for a new page when the current selected index is too close to the end of the list, but there definitely some kinks to work out with that. Also, I'm not sure how to handle backwards scrolling from the top of the list. The user would probably expect to arrive at the end of the actual results, but we will only know about the first page. We could add the total field to the PageAdapter and reserve space for the whole list, and then do the appropriate math to start fetching pages from both ends... but "If the implementation is hard to explain, it's a bad idea".

<!-- gh-comment-id:700385162 --> @sputnick1124 commented on GitHub (Sep 29, 2020): I like the idea of having an on-demand page loader. I think the current `ScrollableResultPages` struct is a little cumbersome to use at the moment and is causing a number of issues; possibly a redesign could not only help us resolve most of the problems we are seeing with paging at the moment, but also more easily enable new contexts to seamlessly handle paging. I was toying around with some traits to help us out and I think that something similar to the following might get us on a good start to where we want to be: ```rust trait PageAdapter<T: Clone> { fn next(&self) -> Option<String>; fn items(&self) -> &[T]; } pub trait Pageable { fn get_dispatch(next: Option<String>, offset: u32) -> Option<IoEvent>; } ``` We could then `impl` these traits for the `rspotify` API types to imbue them with reliable behaviors like so: ```rust impl<T: Clone> PageAdapter<T> for Page<T> { fn next(&self) -> Option<String> { self.next.clone() } fn items(&self) -> &[T] { &self.items } } impl<T: Clone> PageAdapter<T> for CursorBasedPage<T> { fn next(&self) -> Option<String> { self.cursors.after.clone() } fn items(&self) -> &[T] { &self.items } } impl Pageable for SavedTrack { fn get_dispatch(next: Option<String>, offset: u32) -> Option<IoEvent> { if let Some(_next_uri) = next { Some(IoEvent::GetCurrentSavedTracks(Some(offset))) } else { None } } } type SavedArtist = FullArtist; impl Pageable for SavedArtist { fn get_dispatch(after: Option<String>, _offset: u32) -> Option<IoEvent> { if let Some(after) = after { Some(IoEvent::GetFollowedArtists(Some(after))) } else { None } } } // etc... ``` Finally, we can now compose these ideas together in a new `ScrollableResultPage` type that could look something this: ```rust pub struct ScrollableResultPages<T> { pub items: Vec<T>, next: Option<String>, } impl<T: Pageable + Clone> ScrollableResultPages<T> { fn new() -> Self { ScrollableResultPages { items: vec![], next: None, } } fn dispatch(&self, app: &mut App) { if let Some(event) = T::get_dispatch(self.next.clone(), self.items.len() as u32) { app.dispatch(event); } } fn add_page(&mut self, page: &dyn PageAdapter<T>) { self.items.extend_from_slice(page.items()); self.next = page.next().clone(); } } ``` and provides a common interface for anything that can be paged. When we need to page a new type of result in the future, all we should have to do is `impl Pageable` for it and then we're off to the races. We have a single `Vec<T>` which holds all of our items, so the paging can now be delegated to the UI screen size instead of the contents of the a single `Page` request result. The main thing to yet be designed here is when we actually kick off getting new results. I think I like the idea of sending an `IoEvent` for a new page when the current selected index is too close to the end of the list, but there definitely some kinks to work out with that. Also, I'm not sure how to handle backwards scrolling from the top of the list. The user would probably expect to arrive at the end of the actual results, but we will only know about the first page. We could add the `total` field to the `PageAdapter` and `reserve` space for the whole list, and then do the appropriate math to start fetching pages from both ends... but "If the implementation is hard to explain, it's a bad idea".
Author
Owner
<!-- gh-comment-id:700408204 --> @sputnick1124 commented on GitHub (Sep 29, 2020): Issues that would benefit at least a little from a better paging interface: * https://github.com/Rigellute/spotify-tui/issues/591 * https://github.com/Rigellute/spotify-tui/issues/575 * https://github.com/Rigellute/spotify-tui/issues/547 * https://github.com/Rigellute/spotify-tui/issues/383 * https://github.com/Rigellute/spotify-tui/issues/362 * https://github.com/Rigellute/spotify-tui/issues/229 * https://github.com/Rigellute/spotify-tui/issues/189 * https://github.com/Rigellute/spotify-tui/issues/116
Author
Owner

@Rigellute commented on GitHub (Sep 30, 2020):

@sputnick1124 I really like your proposal!! Pagination is one of the biggest problems in spotify-tui right now. Would love to see your solution running.

Also, thank you for collecting the other paging related issues 👍

<!-- gh-comment-id:701455143 --> @Rigellute commented on GitHub (Sep 30, 2020): @sputnick1124 I really like your proposal!! Pagination is one of the biggest problems in spotify-tui right now. Would love to see your solution running. Also, thank you for collecting the other paging related issues 👍
Author
Owner

@sputnick1124 commented on GitHub (Sep 30, 2020):

I'll try to get something up and working over the course of the next couple of weekends. If anyone else on this thread (or otherwise) would like to give it a shot, I'd also be happy to collaborate, consult, mentor, etc as well. Just let me know. Otherwise, I'll just be sure to commit and push often to a tracking branch on my fork.

<!-- gh-comment-id:701648095 --> @sputnick1124 commented on GitHub (Sep 30, 2020): I'll try to get something up and working over the course of the next couple of weekends. If anyone else on this thread (or otherwise) would like to give it a shot, I'd also be happy to collaborate, consult, mentor, etc as well. Just let me know. Otherwise, I'll just be sure to commit and push often to a tracking branch on my fork.
Author
Owner

@sputnick1124 commented on GitHub (Oct 27, 2020):

Tracking PR for pagination overhaul: https://github.com/Rigellute/spotify-tui/pull/635

<!-- gh-comment-id:716905278 --> @sputnick1124 commented on GitHub (Oct 27, 2020): Tracking PR for pagination overhaul: https://github.com/Rigellute/spotify-tui/pull/635
Author
Owner

@ghost commented on GitHub (Feb 25, 2021):

@sputnick1124 , I was wondering if you had any progress on this.

I saw in the PR draft in Nov that you've been busy.

<!-- gh-comment-id:786275805 --> @ghost commented on GitHub (Feb 25, 2021): @sputnick1124 , I was wondering if you had any progress on this. I saw in the PR draft in Nov that you've been busy.
Author
Owner

@sputnick1124 commented on GitHub (Mar 18, 2021):

@realmain, I feel bad that I have not gotten back to this lately. It is on my mind, but I have not had a chance to lend any time to this since late last year (holidays and then a major, ongoing home renovation have eaten my nights and weekends).

I think that starting in mid April, I should be able to justify taking the time needed to finish this up. It turned out that the track listings for playlists, albums, artist tracks, etc are a bit of a bugger for my initial design since they are all either FullTracks or SimplifiedTracks. This means I can't simply implement my new traits on those type directly, but rather have to wrap them as newtypes (or come up with a different design). This has complicated things a bit and will take some thought to overcome.

That said, when i left this effort, things were very nicely paging for a great number of other things (albums, podcasts, podcast episodes), so I do like where the overall objective is leading.

<!-- gh-comment-id:801599121 --> @sputnick1124 commented on GitHub (Mar 18, 2021): @realmain, I feel bad that I have not gotten back to this lately. It is on my mind, but I have not had a chance to lend any time to this since late last year (holidays and then a major, ongoing home renovation have eaten my nights and weekends). I think that starting in mid April, I should be able to justify taking the time needed to finish this up. It turned out that the track listings for playlists, albums, artist tracks, etc are a bit of a bugger for my initial design since they are all either `FullTrack`s or `SimplifiedTrack`s. This means I can't simply implement my new traits on those type directly, but rather have to wrap them as newtypes (or come up with a different design). This has complicated things a bit and will take some thought to overcome. That said, when i left this effort, things were very nicely paging for a great number of other things (albums, podcasts, podcast episodes), so I do like where the overall objective is leading.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/spotify-tui#217
No description provided.