Skip to content

Comments

feat: show cover art next to song/episode title#111

Draft
topongo wants to merge 2 commits intoLargeModGames:mainfrom
topongo:main
Draft

feat: show cover art next to song/episode title#111
topongo wants to merge 2 commits intoLargeModGames:mainfrom
topongo:main

Conversation

@topongo
Copy link

@topongo topongo commented Feb 21, 2026

Summary

i found this interesting crate called ratatui-image and thought: why not using it to add cover art support to my favourite spotify client?

i added an image fetching phase inside the get_current_playback method, that gets and caches the cover art of the currently playing song/podcast episode. during rendering, a portion of the playbar is reserved to fit the image and the image is rendered there.

Testing

IMPORTANT: this feature strongly depends on terminal that can fully display images, as kitty, iterm2, ecc... using other terminals (alacritty, konsole) will show a blocky mess produced by halfblocks (the fallback backend for the ratatui-image crate, the name is intuitive enough).

alacritty:
image
kitty:
image

i confirm i used the following without errors/warnings:

  • cargo fmt --all
  • cargo clippy --locked -- -D warnings
  • cargo test --locked (all passed)

Additional notes

please be aware that i'm not very familiar with spotatui's execution pipeline. i'm very keen to make substantial modification to best suit your model. also i plan on cleaning up my code in the next days (too many unwraps, i know...), in the meantime i wanted to know what are your thoughts about this :)

followup works:

  • consider whether to render the cover art outside of the playbar, making it bigger
  • find a better way to calculate the allocated space for the image (i currently use a semi-made-up aspect ratio, that should reflect the characted aspect ratio of the terminal/font i used, i didn't find any documentation in ratatui on how to create pixel-square Rects...)
  • decide how to handle situations with unsupported terminals: should we don't render the image? should we render the a blocky mess? add a user config for it?

supports various backends provided by the `ratatui-image` crate:
- sixels
- kitty
- iterm2
@LargeModGames
Copy link
Owner

LargeModGames commented Feb 21, 2026

I have been thinking about adding album images before but I was never sure. On one side i want to keep it as minimalistic and similar to spotify-tui as possible but on the other hand its visually very pleasing.

I tried converting the images into asci art but if you try that in a 16x16 space it looks like shit.

I think the best way to not have it displayed in unsupported terminals is by making it an optional setting users can manually change

@topongo
Copy link
Author

topongo commented Feb 21, 2026

i'm glad you like the way it looks, i think the visual result is very neat too

reagrding the terminal support, what about this?

  • we could add two settings: draw_cover_art (default = true); draw_cover_art_forced (default = false)
  • if terminal supports embedded images and draw_cover_art == true: do draw
  • if terminal doesn't support them and draw_cover_art_forced == true: do draw (blocky garbage)
  • any other case: don't draw

@topongo
Copy link
Author

topongo commented Feb 22, 2026

also, i forgot to mention motivation for which i removed a bunch of .as_ref() in src/ui/mod.rs:

turns out that spotatui-image uses the palette crate that includes a conflicting impl: [Constraint; 2]: AsRef<_>

the compiler suggests using the turbofish, but i think it could become very convoluted and either using & instead of as_ref() or moving (as i did in the end), could be much cleaner.

complete error
error[E0283]: type annotations needed
   --> src/ui/mod.rs:969:6
    |
969 |     .constraints([
    |      ^^^^^^^^^^^ cannot infer type of the type parameter `I` declared on the method `constraints`
...
972 |     ].as_ref())
    |       ------ type must be known at this point
    |
    = note: multiple `impl`s satisfying `[Constraint; 2]: AsRef<_>` found in the following crates: `core`, `palette`:
            - impl AsRef> for [::Scalar; N]
              where  as palette::cast::array::ArrayCast>::Array == [::Scalar; N], the constant `N` has type `usize`, C: palette::blend::Premultiply, palette::blend::pre_alpha::PreAlpha: palette::cast::array::ArrayCast, palette::blend::pre_alpha::PreAlpha: ?Sized;
            - impl AsRef> for [T; N]
              where  as palette::cast::array::ArrayCast>::Array == [T; N], the constant `N` has type `usize`, palette::alpha::alpha::Alpha: palette::cast::array::ArrayCast, palette::alpha::alpha::Alpha: ?Sized;
            - impl AsRef> for [T; N]
              where the constant `N` has type `usize`;
            - impl AsRef<[T]> for [T; N]
              where the constant `N` has type `usize`;
help: consider specifying the generic argument
    |
969 |     .constraints::<&T>([
    |                 ++++++

Some errors have detailed explanations: E0283, E0284.
For more information about an error, try rustc --explain E0283.

@LargeModGames
Copy link
Owner

I hope you didn't spend a lot of time on this because i have been working on a big refactor to make to code more clear and easier to contribute to

@LargeModGames
Copy link
Owner

LargeModGames commented Feb 22, 2026

@topongo idk if im doing something wrong but i cant see the banner, im using kitty so it should show right?

I didnt have time to look at the code properly yet

@LargeModGames
Copy link
Owner

ignore that last message i am stupid, just ran cargo run instead of cargo run --features cover-art

@topongo
Copy link
Author

topongo commented Feb 22, 2026

i feature gated it, it's called "cover-art"

@topongo
Copy link
Author

topongo commented Feb 22, 2026

I hope you didn't spend a lot of time on this because i have been working on a big refactor to make to code more clear and easier to contribute to

no problem, then i'll keep it up to date with the refactor branch until the feature is ready

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants