"FULL COMBO" NPS + "AMO-RED" App Style

Symfonium v14 is now out! My NPS style makes use of many of the new features. Give it a look if you want some ideas!

:play_button: Now Playing Screen:

Full Combo NPS - Celorien - Portrait

Full Combo NPS - Celorien - Landscape

I’ve spent way too many hours on this :laughing: There is access to almost everything that Symfonium can do, as well as dynamic support for Classical music. (Some setup may be required.) No more swapping layouts when you turn on the Bach!

In Portrait, tap the Album Art to toggle “Mini Player” mode! (While in this mode, you’ll have to long-press the Album Artist name to go to their page.)

In Portrait’s “Full Player,” you can tap the bottom string to switch the displayed info.

NPS Details

There’s so many features packed into this (thanks Tolriq!) that I can’t include pictures for everything, but I’ll do my best to explain the highlights! (Or you can just try it out for yourself!)

Still here? Hope you don’t mind reading :nerd_face:

The information displayed is very dynamic, but the positioning is kept mostly fixed. My goal was to show as much useful information as possible, without having the buttons jump around.


SPECIAL FEATURES

Expand

That’s right! Everyone loves some Special Features! This is where the fun comes in:

  • Fully-Featured Queue Info!
    • See pics above for demo
    • Copy/paste version is included below!
  • Mini-Player!
    • Using the new “Toggle bool” feature, we can hide a bunch of strings with just a tap!
    • Multi-line Strings taking too much room? Just toggle them off!
  • Album Name
    • For Singles - if Album Name matches Track Name, hides Album Name
      • Avoids duplicate info
      • Only hides if the track’s Release Type is set to “single”
        • In other words, Michael Jackson’s “Thriller” album name will still display when playing the “Thriller” track
  • Disc Number and Disc Title
    • Only shown when Disc Title is present
      • Avoids useless “Disc 1” showing for your entire library
  • Album Artist vs Performing Artists
    • If they match, only displays one
    • If they don’t match, you’ll see the Album Artist (bold and underlined) on its own line, with the Performing Artists filling the line after
      • BUT
    • If the Album Artist is listed among the Performing Artists, then you’ll see them all together
      • This allows featured artists to be displayed without showing the Album Artist twice!
      • Example 1: two Performing Artists - “Gawr Gura” and “Houshou Marine” have a collaboration unit name of “GuraMarine” (which is the Album Artist)
        • You will see “GuraMarine” on the first line and “Gawr Gura, Houshou Marine” on the second line!
      • Example 2: Album Artist “Hoshimachi Suisei” has a track on her album featuring additional artist “KAF”
        • You will see “Hoshimachi Suisei, KAF” on a single line!
  • Various Artists - Be gone!
    • If the Album Artist is “Various Artists”, it will be hidden!
    • You will only see the Performing Artists
  • Cover songs
    • If an Original Artist is set, checks to see if the Album Artist is the Original Artist
    • If they don’t match, the artist line will show “Covered by: “ before the names!
    • Alternately: if you set the track’s Release Type to “covers”, this header will be shown without needing an Original Artist
  • Technical Stuff - Minimum Spacing
    • Normally, if you set a string to “At Most 2” lines and it has no content to display, it will disappear (zero lines taken)
    • I added cases which print Braille blanks (U+2800) to ensure that an “empty” string will collapse to a minimum of one line
      • This allows e.g. String 2 to maintain the one-line spacing between the Title and Ratings when empty, while still being able to increase the line count if needed to fit the content!
      • “But wait, there’s more!” This also allows me to still collapse the line completely when a bool is toggled!

Biggest Problems

Sizing

“I paid for the whole screen… and I’ma gon’ use the whole darned screen!” -Me, probably

Unfortunately this means that, while the layout fits perfectly on my screen… It might not fit so well on yours. In the post below this one, I’ll have some easy tweaks you can try to get it all to fit.


Light Mode

I hate Light Mode (in general) :laughing:

I tried to make sure it is useable, and I think I did okay. But having to support Light Mode’s colors definitely held me back in a few ways (like making me disable the Compact Player’s shadow).


Handling Classical Music

The current version is set to display data for the tags “as-is” to make things easier for y’all to edit. (Meaning “Work Name” is expected in the “Work” field, rather than in the “Album” field. Which is where I would put that info.) Since there’s no consensus on how to tag Classical stuff, you’ll probably have to edit the strings to fit your own tags.

The difference here is that I’ve handled the “Classical” genre separately from the rest, so that you can potentially use one theme for all of your music.

More details in the “Custom Strings” post below!




Screenshots

In addition to the still shots from the animation above, the “Tag Demo” shows all the fields that can be displayed.


Dark Mode


Light Mode


Tag Demo



…plus fully-featured Queue Info!

Celorien - Queue Info - Split Line

This changes to reflect: repeat, shuffle, Smart Queue, Smart Flow, Sleep Timer, and end-of-queue… And it fits all of that in a normal screen-width!

Copy/Paste Ready

Feel free to use these in your own themes! If you want to know how they work, take a peek at the Exploded View section in the post below.

Split-Line Version

This is what you’re seeing in the demo above.

Top Line:

{⠀String by Celorien⠀%|!=%}{--------------------%|!=%}{# Headers%|!=%}{    %|!=%}{## Standard%|!=%}{𝄚𝄞𝄚⠀%|providername==empty || queue.position!=queue.size || player.repeat.mode=="One"%}{    %|!=%}{## End-of-Queue%|!=%}{𝄚𝄚𝄂⠀%|providername!=empty && queue.position==queue.size && player.repeat.mode!="One"%}{--------------------%|!=%}{# Sleep Timer%|!=%}{    %|!=%}{## Immediate Stop%|!=%}{⎅ %sleep.timer|sleep.timer.eos=="false" && sleep.timer.seconds>"0"%}{    %|!=%}{## Finish Track before Stop%|!=%}{⏲ %sleep.timer|sleep.timer.eos=="true" && sleep.timer.seconds>"0"%}{    %|!=%}{## Waiting to Stop%|!=%}{⚠⠀Ending playback⠀⚠%|sleep.timer.seconds=="0"%}{    %|!=%}{## Separator%|!=%}{ • %|sleep.timer.seconds>"0" && (providername!=empty && next.title!=empty)%}{--------------------%|!=%}{# Repeat All enabled, End-of-Queue reached%|!=%}{Restarting Queue%|(providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}{    %|!=%}{## If set, show Queue Name; else ellipsis%|!=%}{: "%queue.name|(queue.name!=empty && queue.name!="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%"}{...%|(queue.name==empty || queue.name=="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}{--------------------%|!=%}{# Queue Position%|!=%}{    %|!=%}{## Standard%|!=%}{Playing %queue.position|(smartqueue=="Disabled" && smartflow=="Disabled" && sleep.timer.seconds!="0") && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}{ / %queue.size|(smartqueue=="Disabled" && smartflow=="Disabled" && sleep.timer.seconds!="0") && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}{    %|!=%}{## Condensed - single-digit values padded to two digits%|!=%}{### Used when Smart Queue/Flow or Sleep Timer are enabled%|!=%}{▶ 0%queue.position|queue.position<"10" && ((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds!="0") && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}{▶ %queue.position|queue.position>"9" && ((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds!="0") && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}{--------------------%|!=%}{# Smart Queue and Flow Indicators%|!=%}{## Condensed indicators used when Sleep Timer is enabled%|!=%}{ • Smart %|((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}{    %|!=%}{Queue%|(smartqueue!="Disabled" && sleep.timer.seconds=="-1") && (providername!=empty && next.title!=empty)%}{[Q]%|(smartqueue!="Disabled" && sleep.timer.seconds>"0") && (providername!=empty && next.title!=empty)%}{    %|!=%}{ & %|((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds=="-1") && (providername!=empty && next.title!=empty)%}{    %|!=%}{Flow%|(smartflow!="Disabled" && sleep.timer.seconds=="-1") && (providername!=empty && next.title!=empty)%}{[F]%|(smartflow!="Disabled" && sleep.timer.seconds>"0") && (providername!=empty && next.title!=empty)%}{--------------------%|!=%}

Bottom Line:

{⠀String by Celorien⠀%|!=%}{--------------------%|!=%}{# Headers%|!=%}{    %|!=%}{## Standard%|!=%}{Up Next:⠀%|(player.repeat.mode!="One" && player.shuffle.mode=="false") && (providername!=empty && next.title!=empty)%}{    %|!=%}{## Shuffle or Unknown Provider (e.g. Internet Radio)%|!=%}{⠀?????%|(player.repeat.mode!="One" && player.shuffle.mode=="true") && (providername!=empty && next.title!=empty)%}{⠀?????%|providername==empty%⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀}{    %|!=%}{## Repeat One%|!=%}{Repeat:⠀%|player.repeat.mode=="One" && (providername!=empty && next.title!=empty)%}{    %|!=%}{## End-of-Queue%|!=%}{⠀FIN%|queue.position==queue.size && (providername!=empty && next.title==empty)%}{--------------------%|!=%}{#!# EDIT BELOW to fit your tags%|!=%}{# Classical Genre%|!=%}{    %|!=%}{## Show Composer name (only if different from current)%|!=%}{%next.composer|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (next.composer!=empty && next.composer!=composer)%'s }{    %|!=%}{## Show Work name (only if different from current)%|!=%}{%next.work|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && ((next.composer!=empty && next.composer!=composer) || ((next.composer!=empty && next.composer==composer) && next.work!=work))%}{    %|!=%}{## Show Movement Number as a Roman numeral (only if Movement name is set and Work matches current)%|!=%}{%next.movement.number.roman|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (((next.composer!=empty && next.composer==composer) && next.work==work) && next.movement.number!=empty && next.movement.name!=empty)%. }{    %|!=%}{## Show Movement name (only if Work matches current%|!=%}{%next.movement.name|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && ((next.composer!=empty && next.composer==composer) && next.work==work)%}{    %|!=%}{## Show Title (only if Work matches but Movement name is empty%|!=%}{%next.title|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (((next.composer!=empty && next.composer==composer) && next.work==work) && next.movement.name==empty)%}{#!# END OF EDIT ZONE%|!=%}{--------------------%|!=%}{# Other Genres%|!=%}{    %|!=%}{## Show Work name if set, else show Title%|!=%}{%next.work|(providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.work!=empty%}{%next.title|(providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.work==empty%}{    %|!=%}{## Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}{ • %next.albumartist|(providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.albumartist!="Various Artists"%}{ • %next.artist|(providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.albumartist=="Various Artists"%}{--------------------%|!=%}

Single-Line Version

This version is used at the bottom of my Landscape layout. It’s not as pretty, but it shows the same info.

{⠀String by Celorien⠀%|!=%}{--------------------%|!=%}{⠀Mode and Position  %|!=%}{--------------------%|!=%}{# Sleep Timer%|!=%}{    %|!=%}{## Immediate Stop%|!=%}{⎅ %sleep.timer|sleep.timer.eos=="false" && sleep.timer.seconds>"0"%}{    %|!=%}{## Finish Track before Stop%|!=%}{⏲ %sleep.timer|sleep.timer.eos=="true" && sleep.timer.seconds>"0"%}{    %|!=%}{## Waiting to Stop%|!=%}{⚠⠀Ending playback⠀⚠%|sleep.timer.seconds=="0"%}{    %|!=%}{## Separator%|!=%}{ • %|sleep.timer.seconds>"0" && (providername!=empty && next.title!=empty)%}{--------------------%|!=%}{# Repeat All enabled, End-of-Queue reached%|!=%}{Restarting Queue%|(providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}{    %|!=%}{## If set, show Queue Name; else ellipsis%|!=%}{: "%queue.name|(queue.name!=empty && queue.name!="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%"}{...%|(queue.name==empty || queue.name=="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}{--------------------%|!=%}{# Queue Position%|!=%}{    %|!=%}{## Condensed - single-digit values padded to two digits%|!=%}{### Used when Smart Queue/Flow or Sleep Timer are enabled%|!=%}{▶ 0%queue.position|sleep.timer.seconds!="0" && queue.position<"10" && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}{▶ %queue.position|sleep.timer.seconds!="0" && queue.position>"9" && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}{--------------------%|!=%}{# Smart Queue and Flow Indicators%|!=%}{## Always uses condensed indicators%|!=%}{ • %|((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}{[Q]%|(smartqueue!="Disabled" && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}{[F]%|(smartflow!="Disabled" && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}{--------------------%|!=%}{⠀Next Track Info    %|!=%}{--------------------%|!=%}{# Headers%|!=%}{    %|!=%}{## Standard%|!=%}{ • Up Next:%|sleep.timer.seconds!="0" && player.repeat.mode!="One" && (providername!=empty && next.title!=empty)%}{    %|!=%}{## Shuffle%|!=%}{⠀?????%|sleep.timer.seconds!="0" && ((player.repeat.mode!="One" && player.shuffle.mode=="true") && providername!=empty && next.title!=empty)%}{    %|!=%}{## Repeat One%|!=%}{ • Repeat:%|(sleep.timer.seconds!="0" && player.repeat.mode=="One" && providername!=empty && next.title!=empty)%}{    %|!=%}{## End-of-Queue%|!=%}{### Bullet Spacer shows when Sleep Timer active%|!=%}{### Split string "\t" keeps Header position fixed when Marquee enabled%|!=%}{ • %|queue.position==queue.size && (providername!=empty && next.title==empty) && sleep.timer.seconds>"0"%}{FIN%|queue.position==queue.size && (providername!=empty && next.title==empty) && sleep.timer.seconds!="0"%}\t{### Blanks extend tap region%|!=%}{⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀%|queue.position==queue.size && (providername!=empty && next.title==empty) && sleep.timer.seconds!="0"%}{--------------------%|!=%}{#!# EDIT BELOW to fit your tags%|!=%}{# Classical Genre%|!=%}{    %|!=%}{## Show Composer name (only if different from current)%|!=%}{%next.composer|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (next.composer!=empty && next.composer!=composer)%'s }{    %|!=%}{## Show Work name (only if different from current)%|!=%}{%next.work|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && ((next.composer!=empty && next.composer!=composer) || ((next.composer!=empty && next.composer==composer) && next.work!=work))%}{    %|!=%}{## Show Movement Number as a Roman numeral (only if Movement name is set and Work matches current)%|!=%}{%next.movement.number.roman|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (((next.composer!=empty && next.composer==composer) && next.work==work) && next.movement.number!=empty && next.movement.name!=empty)%. }{    %|!=%}{## Show Movement name (only if Work matches current%|!=%}{%next.movement.name|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && ((next.composer!=empty && next.composer==composer) && next.work==work)%}{    %|!=%}{## Show Title (only if Work matches but Movement name is empty%|!=%}{%next.title|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (((next.composer!=empty && next.composer==composer) && next.work==work) && next.movement.name==empty)%}{#!# END OF EDIT ZONE%|!=%}{--------------------%|!=%}{# Other Genres%|!=%}{    %|!=%}{## Show Work name if set, else show Title%|!=%}{%next.work|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.work!=empty%}{%next.title|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.work==empty%}{    %|!=%}{## Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}{ • %next.albumartist|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.albumartist!="Various Artists"%}{ • %next.artist|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.albumartist=="Various Artists"%}{--------------------%|!=%}



:house: App Style

App Style Details

I know the theme is called “AMO-RED,” but all the red parts will actually change color once you start playing music!

Suggested Music - Uses two Smart Playlists to help you pick something to listen to. Check the “Playlist Setup” section below to get this set up.

Dark is the new Black - Make sure not to “Black” mode, as it overrides some of my colors. “Dark” mode has fully black backgrounds in this theme anyway.

Designed as a 2-3 page layout - I left some gaps to hide my phone’s camera cutout, but you’ll probably need to adjust the spacing a bit to suit your phone. Fortunately, the app now makes that pretty easy to do!

Minimal design - I only use the Home Page as a landing screen, so I didn’t want too much on it. There are quick shortcuts to most media options, but the Library tab is where I do my browsing.

Newly-added music page will pop in at the top if you add some new music. If you use my Playlist settings below, the page will also go away once you’ve listened to the new stuff.

Scrollable previews:

Expand

No, the “Recently Added” section isn’t cut off. It scrolls horizontally. (These pictures don’t, of course.)


Media Overviews:

Here we have: Artist, Album, Playlist, and Genre views! The durations on the Artist and Album pages use my localized strings to show a prettier estimate instead of the exact duration.

Dark Mode

Light Mode

Playlist Setup:

For both Recents and Suggested sections

To get you started, I enabled the default “Recently Added” categories. I strongly recommend replacing them with your own Smart Playlists, using the following settings:

Playlist Settings

Same info, however you want to see it.
“Max Item count” can be whatever you prefer.

Text
  • Recently Added Albums
    • (Date Added: within 14)
      • AND
    • (Play Count: less than 1)
      • AND
    • (Track count: greater than 1).
    • Sort by “Date added” with the arrow pointing UP
    • Inherit providers
  • Recently Added Tracks:
    • (Date Added: within 14)
      • AND
    • (Play Count: is 0)
    • Sort by “Date added” with the arrow pointing UP
    • Inherit providers
  • Suggested Albums:
    • GROUP: (Last Played: is missing) OR (Last Played: over 30)
      • AND
    • (Track Count: greater than 1)
    • Sort by “Random”
    • Inherit providers
  • Suggested Tracks:
    • (Last Played: is missing)
      • OR
    • (Last Played: over 30)
    • Sort by “Random”
    • Inherit providers

Images

Once you have your playlists added to the Home page, you can just copy the layout from the existing Recents rows. (There’s new buttons at the bottom, when editing the Home page rows.) Easy!

For the Suggested Albums/Tracks, you can instead use the new “Change Playlist” button to replace the empty section with your newly-created playlist.

This setup for Recents let you customize how many days new songs will stay in the list, but more importantly it will remove a song from the Recents list once you have listened to it. (Get that list cleared! :laughing: )



:file_folder: Downloads

Expand

Final version is now available! Full-size version available here:

NPS_FULL COMBO v1.0P.json (63.5 KB)

NavBar version is scaled down for those that have shorter screens than me. Hopefully it’s not too tiny.

NPS_FULL COMBO (NavBar) v1.0P.json (63.5 KB)


App Style: APPSTYLE_AMO-RED v1.0P.json (123.1 KB)


Color theme only: COLORS_AMO-RED.json (2.7 KB)

Careful to import the right file, since I failed to come up with a separate name for App Style vs Color Theme :stuck_out_tongue:


Version Archive

Expand

Posted: 2026-02-24 at 05:00 UTC

Standalone NPS: nps-Full Combo v0.10 (14B6) (67.1 KB)

Mostly just small tweaks to the strings. Added a STOP button to landscape’s Bottom Bar (replaces Details button)


Posted: 2026-02-20 at 01:00 UTC

Standalone NPS: nps-Full Combo v0.9 (14B5)-20260220_171047-symfonium.json (67.1 KB)

Huge makeover for Portrait! Screenshots will be updated in the coming days…


Posted 2026-02-13 at 05:00 UTC

Standalone NPS: nps-Full Combo v0.5 (14B1) (61.4 KB)

Added Mini Player mode! (Toggle by long-pressing Ratings)
Misc. bug fixes


Posted 2026-02-12 at 05:20 UTC

Full App Style: as-AMO-RED v0.3 (14B1) (113.0 KB)

Standalone NPS: nps-Full Combo v0.3 (14B1) (58.1 KB)

Color theme only: AMO-RED (2.7 KB)




Image credits:

Screenshot frames sourced from MockUPhone.com
Text-art created by CoolText.com

11 Likes

Known problems:

Expand

Actual bugs:

None

Not bugs:

  • No way to access “Composers” when playing Classical music in Landscape!
    • Trade-offs were made. It’s normally accessed by tapping String 6, but this was replaced by queue info since I didn’t have room to fit the Top Bar
  • Tapping Artist’s name in Mini-Player mode takes me to the album!
    • Use Long-press instead to go to Artist
    • I can change the text but not the tap actions. This is still using the Album’s “string slot” since I couldn’t collapse that one
  • If Top Bar string is too long to fit or if marquee is enabled, treble clef header gets height-cropped
    • The character is actually taller than single-line height, and gets cropped to fit. So don’t add too many buttons!
    • I did my best to keep the text length short. “It works on mine” :stuck_out_tongue:
  • Artists don’t display if Album Artist line is long
    • Just how it works, they’re both inside a single string
    • Tweak the font sizing if you need to
  • If NPS adaptive color picks white, you can’t see the state of Repeat/Shuffle buttons
    • Just white on white. I could change to non-colored buttons but this issue is uncommon and I prefer the colored style
  • Not friendly to shorter aspect ratios, since most of the layout has fixed vertical sizing
    • Mini-Player helps with this! (Tap the Album Art to toggle)
  • The “Covered by” header doesn’t show on this cover of XYZ!
    • Either you don’t have “Original Artist” tag set or it has multiple values
    • If you add “covers” as a Release Type, it’ll work 100% of the time

NPS gets cut off on your screen?

Expand

Did you try the “NavBar” version of my NPS? I already pre-shrank a bunch of stuff there, so you can make things bigger from there.

Otherwise, try these easy tweaks:

  • Set Top Bar size to “Small”
  • Set Progress Bar “Scale Factor” to 1.0
  • Shrink the Play button (Control buttons, icon 4) to size 40
    • Go even smaller? Set icons 3-5 to size 32, and icons 2 & 6 to size 22

Still doesn’t fit? Try these tweaks to the strings:

  • Don’t use Movement Name?
    • Disable String 2
  • Don’t use Disc Title?
    • Change “String 4 line count” to “2 (At most)”
  • Don’t mind buttons moving?
    • Change String 4 & 5 “line count” to “2 (At most)”

As a last resort, scale down all of the strings by 0.1 at a time until you’ve made enough room.


When the spacing is just right, you’ll see the corners of the album art are rounded in the Full Player. (Mini Player doesn’t have rounded corners in my version.)

If you set the “Cover art style” to “Visible” instead of Fill size, the art will always be rounded. (But this will also move the Rating Bar for the Mini Player on top of the art. Can’t be helped.)

1 Like

Custom Strings :nerd_face:

All of my NPS’s custom strings will be added here, for ease-of-use by the community. These will be exploded into multiple lines for readability.

If you plan to edit these strings, I would strongly recommend doing so in a proper text editor. You can easily expand the flat versions by using Find } and Replace }\n

HUGE thanks to Tolriq for adding mixed operator support! Some of these strings were 3x longer before the update (imagine that lol).


Note for Classical listeners:

Expand

Most of these strings have special cases to handle the “Classical” genre vs everything else. All relevant portions have been marked! Simply use your text editor to search for #!# and you will jump straight to the parts to be edited.

The comments will tell you what information should be displayed by a given line, helping you to replace the tag field with the one you use to hold that info.


These should be up-to-date with the latest version of my Portrait theme. (Landscape versions simply drop the bool5 conditions.)

Exploded View

Do not copy and paste these directly into Symfonium–they will not work.

Everything inside a sub-header is part of the same string.

If you’re not familiar with coding, the lines that start with a {# are my “Comments” that explain what the stuff below is doing. Lines like {⠀String by Celorien⠀%|!=%} will never be visible. These are all safe to leave in, just remember to flatten to one line!


Queue Info

Expand

This section has the longest strings by far, so buckle your seat belts. Read the comments for an explanation of what’s happening. If you have any questions, feel free to ask below!

The two split strings are the original format and the Single-Line version is trimmed and reorganized from those.

Mode and Position

Used for the first line of my Top Bar in portrait.

{# Headers%|!=%}

{## Standard%|!=%}
{𝄚𝄞𝄚⠀%|providername==empty || queue.position!=queue.size || player.repeat.mode=="One"%}

{## End-of-Queue%|!=%}
{𝄚𝄚𝄂⠀%|providername!=empty && queue.position==queue.size && player.repeat.mode!="One"%}
{# Sleep Timer%|!=%}

{## Immediate Stop%|!=%}
{⎅ %sleep.timer|sleep.timer.eos=="false" && sleep.timer.seconds>"0"%}

{## Finish Track before Stop%|!=%}
{⏲ %sleep.timer|sleep.timer.eos=="true" && sleep.timer.seconds>"0"%}

{## Waiting to Stop%|!=%}
{⚠⠀Ending playback⠀⚠%|sleep.timer.seconds=="0"%}

{## Separator%|!=%}
{ • %|sleep.timer.seconds>"0" && (providername!=empty && next.title!=empty)%}

{# Repeat All enabled, End-of-Queue reached%|!=%}
{Restarting Queue%|(providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}

{## If set, show Queue Name; else ellipsis%|!=%}
{: "%queue.name|(queue.name!=empty && queue.name!="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%"}

{...%|(queue.name==empty || queue.name=="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}
{# Queue Position%|!=%}

{## Standard%|!=%}
{Playing %queue.position|(smartqueue=="Disabled" && smartflow=="Disabled" &&
    sleep.timer.seconds!="0") &&
    providername!=empty &&
    (queue.position!=queue.size || 
        (queue.position==queue.size && player.repeat.mode=="One"))%}
{ / %queue.size|(smartqueue=="Disabled" && smartflow=="Disabled" &&
    sleep.timer.seconds!="0") && providername!=empty &&
    (queue.position!=queue.size || 
        (queue.position==queue.size && player.repeat.mode=="One"))%}
{## Condensed - single-digit values padded to two digits%|!=%}
{### Used when Smart Queue/Flow or Sleep Timer are enabled%|!=%}
{▶ 0%queue.position|queue.position<"10" &&
    ((smartqueue!="Disabled" || smartflow!="Disabled") &&
    sleep.timer.seconds!="0") && providername!=empty &&
    (queue.position!=queue.size ||
        (queue.position==queue.size && player.repeat.mode=="One"))%}
{▶ %queue.position|queue.position>"9" &&
    ((smartqueue!="Disabled" || smartflow!="Disabled") &&
    sleep.timer.seconds!="0") && providername!=empty &&
    (queue.position!=queue.size ||
        (queue.position==queue.size && player.repeat.mode=="One"))%}
{# Smart Queue and Flow Indicators%|!=%}
{## Condensed indicators used when Sleep Timer is enabled%|!=%}
{ • Smart %|((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}

{Queue%|(smartqueue!="Disabled" && sleep.timer.seconds=="-1") && (providername!=empty && next.title!=empty)%}
{[Q]%|(smartqueue!="Disabled" && sleep.timer.seconds>"0") && (providername!=empty && next.title!=empty)%}

{ & %|((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds=="-1") && (providername!=empty && next.title!=empty)%}

{Flow%|(smartflow!="Disabled" && sleep.timer.seconds=="-1") && (providername!=empty && next.title!=empty)%}
{[F]%|(smartflow!="Disabled" && sleep.timer.seconds>"0") && (providername!=empty && next.title!=empty)%}

Next Track Info

Used for the second line of my Top Bar in portrait.

{# Headers%|!=%}

{## Standard%|!=%}
{Up Next:⠀%|(player.repeat.mode!="One" && player.shuffle.mode=="false") &&
    (providername!=empty && next.title!=empty)%}

{## Shuffle or Unknown Provider (e.g. Internet Radio)%|!=%}
{⠀?????%|(player.repeat.mode!="One" && player.shuffle.mode=="true") &&
    (providername!=empty && next.title!=empty)%}
{⠀?????%|providername==empty%⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀}

{## Repeat One%|!=%}
{Repeat:⠀%|player.repeat.mode=="One" && (providername!=empty && next.title!=empty)%}

{## End-of-Queue%|!=%}
{⠀FIN%|queue.position==queue.size && (providername!=empty && next.title==empty)%}
{#!# EDIT BELOW to fit your tags%|!=%}
{# Classical Genre%|!=%}

{## Show Composer name (only if different from current)%|!=%}
{%next.composer|(providername!=empty && next.genre+="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    (next.composer!=empty && next.composer!=composer)%'s }
{'%|!=%}

{# Show Work name (only if different from current)%|!=%}
{%next.work|(providername!=empty && next.genre+="Classical") && 
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
            ((next.composer!=empty && next.composer!=composer) ||
    ((next.composer!=empty && next.composer==composer) &&
        next.work!=work))%}
{## Show Movement Number as a Roman numeral (only if Movement name is set and Work matches current)%|!=%}
{%next.movement.number.roman|(providername!=empty && next.genre+="Classical") && 
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    (((next.composer!=empty && next.composer==composer) &&
        next.work==work) &&
        next.movement.number!=empty &&
        next.movement.name!=empty)%. }
{## Show Movement name (only if Work matches current%|!=%}
{%next.movement.name|(providername!=empty && next.genre+="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    ((next.composer!=empty && next.composer==composer) &&
        next.work==work)%}
{## Show Title (only if Work matches but Movement Name is empty%|!=%}
{%next.title|(providername!=empty && next.genre+="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    (((next.composer!=empty && next.composer==composer) &&
        next.work==work) && next.movement.name==empty)%}
{#!# END OF EDIT ZONE%|!=%}
{# Other Genres%|!=%}

{## Show Work name if set, else show Title%|!=%}
{%next.work|(providername!=empty && next.genre-="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    next.work!=empty%}
{%next.title|(providername!=empty && next.genre-="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    next.work==empty%}
{## Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}
{ • %next.albumartist|(providername!=empty && next.genre-="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    next.albumartist!="Various Artists"%}
{ • %next.artist|(providername!=empty && next.genre-="Classical") &&
    (player.shuffle.mode=="false" ||
        (player.shuffle.mode=="true" && player.repeat.mode=="One")) &&
    next.albumartist=="Various Artists"%}

Single-Line

Used as String 6 in landscape. I won’t break it down beyond the build instructions, since almost everything is copied from the two above this.

Building from Split-Line Version
Modes and Position
------------------
Insert blank before "FIN" when sleep timer is running
Queue position - Condensed only, drop Smart Genre/Flow checks
Smart Queue/Flow - Condensed only, drop ampersand
    change condition {sleep.timer.seconds>"0"} to {sleep.timer.seconds!="0"}

Next Track Info
---------------
Drop shuffle condition from "Up Next: " header
Drop trailing space from "Up Next: " and "Repeat: "
Add spaced bullet (" • ") before "Up Next:" and "Repeat:"
Drop "?????" case for empty providername
Drop trailing blanks from shuffle header (remaining "?????" header)
Split leading blank from "FIN" header and swap to spaced bullet (" • ")
    Only show leading blank when 'Sleep Timer + FIN'
Add trailing blanks after "FIN" header and split-operator
    ("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀" 15 Braille blanks)

(!!!) Add {sleep.timer.seconds!="0" && } condition to start of ALL lines
    (Except the split blank from FIN, which is already covered)
(!!!) Add "\t" after Headers section (but before trailing blanks)

Remainder is direct copy


End Result
{⠀String by Celorien⠀%|!=%}
{--------------------%|!=%}
{⠀Mode and Position  %|!=%}
{--------------------%|!=%}
{# Sleep Timer%|!=%}
{    %|!=%}
{## Immediate Stop%|!=%}
{⎅ %sleep.timer|sleep.timer.eos=="false" && sleep.timer.seconds>"0"%}
{    %|!=%}
{## Finish Track before Stop%|!=%}
{⏲ %sleep.timer|sleep.timer.eos=="true" && sleep.timer.seconds>"0"%}
{    %|!=%}
{## Waiting to Stop%|!=%}
{⚠⠀Ending playback⠀⚠%|sleep.timer.seconds=="0"%}
{    %|!=%}
{## Separator%|!=%}
{ • %|sleep.timer.seconds>"0" && (providername!=empty && next.title!=empty)%}
{--------------------%|!=%}
{# Repeat All enabled, End-of-Queue reached%|!=%}
{Restarting Queue%|(providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}
{    %|!=%}
{## If set, show Queue Name; else ellipsis%|!=%}
{: "%queue.name|(queue.name!=empty && queue.name!="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%"}
{...%|(queue.name==empty || queue.name=="No name") && (providername!=empty && queue.position==queue.size && player.repeat.mode=="All")%}
{--------------------%|!=%}
{# Queue Position%|!=%}
{    %|!=%}
{## Condensed - single-digit values padded to two digits%|!=%}
{### Used when Smart Queue/Flow or Sleep Timer are enabled%|!=%}
{▶ 0%queue.position|sleep.timer.seconds!="0" && queue.position<"10" && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}
{▶ %queue.position|sleep.timer.seconds!="0" && queue.position>"9" && providername!=empty && (queue.position!=queue.size || (queue.position==queue.size && player.repeat.mode=="One"))%}
{--------------------%|!=%}
{# Smart Queue and Flow Indicators%|!=%}
{## Always uses condensed indicators%|!=%}
{ • %|((smartqueue!="Disabled" || smartflow!="Disabled") && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}
{[Q]%|(smartqueue!="Disabled" && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}
{[F]%|(smartflow!="Disabled" && sleep.timer.seconds!="0") && (providername!=empty && next.title!=empty)%}
{--------------------%|!=%}
{⠀Next Track Info    %|!=%}
{--------------------%|!=%}
{# Headers%|!=%}
{    %|!=%}
{## Standard%|!=%}
{ • Up Next:%|sleep.timer.seconds!="0" && player.repeat.mode!="One" && (providername!=empty && next.title!=empty)%}
{    %|!=%}
{## Shuffle%|!=%}
{⠀?????%|sleep.timer.seconds!="0" && ((player.repeat.mode!="One" && player.shuffle.mode=="true") && providername!=empty && next.title!=empty)%}
{    %|!=%}
{## Repeat One%|!=%}
{ • Repeat:%|(sleep.timer.seconds!="0" && player.repeat.mode=="One" && providername!=empty && next.title!=empty)%}
{    %|!=%}
{## End-of-Queue%|!=%}
{### Bullet Spacer shows when Sleep Timer active%|!=%}
{### Split string "\t" keeps Header position fixed when Marquee enabled%|!=%}
{ • %|queue.position==queue.size && (providername!=empty && next.title==empty) && sleep.timer.seconds>"0"%}
{FIN%|queue.position==queue.size && (providername!=empty && next.title==empty) && sleep.timer.seconds!="0"%}
\t{### Blanks extend tap region%|!=%}
{⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀%|queue.position==queue.size && (providername!=empty && next.title==empty) && sleep.timer.seconds!="0"%}
{--------------------%|!=%}
{#!# EDIT BELOW to fit your tags%|!=%}
{# Classical Genre%|!=%}
{    %|!=%}
{## Show Composer name (only if different from current)%|!=%}
{%next.composer|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (next.composer!=empty && next.composer!=composer)%'s }
{'    %|!=%}
{## Show Work name (only if different from current)%|!=%}
{%next.work|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && ((next.composer!=empty && next.composer!=composer) || ((next.composer!=empty && next.composer==composer) && next.work!=work))%}
{    %|!=%}
{## Show Movement Number as a Roman numeral (only if Movement name is set and Work matches current)%|!=%}
{%next.movement.number.roman|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (((next.composer!=empty && next.composer==composer) && next.work==work) && next.movement.number!=empty && next.movement.name!=empty)%. }
{    %|!=%}
{## Show Movement name (only if Work matches current%|!=%}
{%next.movement.name|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && ((next.composer!=empty && next.composer==composer) && next.work==work)%}
{    %|!=%}
{## Show Title (only if Work matches but Movement name is empty%|!=%}
{%next.title|(providername!=empty && next.genre+="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && (((next.composer!=empty && next.composer==composer) && next.work==work) && next.movement.name==empty)%}
{#!# END OF EDIT ZONE%|!=%}
{--------------------%|!=%}
{# Other Genres%|!=%}
{    %|!=%}
{## Show Work name if set, else show Title%|!=%}
{%next.work|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.work!=empty%}
{%next.title|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.work==empty%}
{    %|!=%}
{## Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}
{ • %next.albumartist|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.albumartist!="Various Artists"%}
{ • %next.artist|sleep.timer.seconds!="0" && (providername!=empty && next.genre-="Classical") && (player.shuffle.mode=="false" || (player.shuffle.mode=="true" && player.repeat.mode=="One")) && next.albumartist=="Various Artists"%}
{--------------------%|!=%}


Main Info Panel

Expand

This is the heart of the Now Playing Screen.

Main Title

Explicit tag shows here if a Movement Name is not set.

{# Shows Work name (if present) or Title (if not)%|!=%}
{%explicit|explicit!=empty && work!=empty && ((movement.name==empty && bool5=="false") || bool5=="true")%⠀}
{%work|genre-="Classical" && work!=empty%}
{⠀%|genre-="Classical" && work==empty && movement.name!=empty%}
{%title|genre-="Classical" && work==empty && movement.name==empty%}
{#!# ---EDIT BELOW to fit your tags---%|!=%}
{# Classical Genre%|!=%}

{## Shows Work Name%|!=%}
{%work|genre+="Classical"%}
{#!# ---END OF EDIT ZONE---%|!=%}
{# Mini Player: Alt-Text%|!=%}
{    %|!=%}
{## Spacer%|!=%}
{\n%|bool5=="true"%}

Subtitle

Not much of interest here. It’s just movement info, or a Braille blank for spacing. Explicit tag is shown here if Movement Name is set, otherwise it shows on the Main Title.

{%explicit|explicit!=empty && movement.name!=empty && bool5=="false"%⠀}
{__%movement.number.roman|movement.number!=empty && movement.name!=empty && bool5=="false"%.__}
{⠀%|movement.number!=empty && movement.name!=empty && bool5=="false"%}
{%movement.name|bool5=="false"%}
{⠀%|movement.name==empty && bool5=="false"%}

Custom Rating Bar

Not an original idea, this has been done in several other themes on the forum here. My additions: an “Icon Bank” at the top (useful when switching fonts) and the bool5 stuff so that I can hide the string when toggled.

{⬤◐●◉⦿◎◯◑○★☆⭒%|!=% Alt Icons}
{《 %| bool5=="false"%}
{○○○○○%|userrating.5=="0" && bool5=="false"%}
{◉○○○○%|userrating.5=="0.5" && bool5=="false"%}
{●○○○○%|userrating.5=="1" && bool5=="false"%}
{●◉○○○%|userrating.5=="1.5" && bool5=="false"%}
{●●○○○%|userrating.5=="2" && bool5=="false"%}
{●●◉○○%|userrating.5=="2.5" && bool5=="false"%}
{●●●○○%|userrating.5=="3" && bool5=="false"%}
{●●●◉○%|userrating.5=="3.5" && bool5=="false"%}
{●●●●○%|userrating.5=="4" && bool5=="false"%}
{●●●●◉%|userrating.5=="4.5" && bool5=="false"%}
{●●●●●%|userrating.5=="5" && bool5=="false"%}
{ 》%|bool5=="false"%}

Album Details
{# Album Name and Version%|!=%}
{## IF ReleaseType is NOT "single" or "covers", always show%|!=%}
{## ELSE show only if Album name doesn't match Work/Title%|!=%}

{**%album.raw|genre-="Classical" && ((album.type!="single" && album.type-="covers") || ((album.type=="single" || album.type+="covers") && ((work!=empty && album.raw!=work) || (work==empty && album.raw!=title)))) && bool5=="false"%**}
{ • **%album.version|genre-="Classical" && album.version!=empty && ((album.type!="single" && album.type-="covers") || ((album.type=="single" || album.type+="covers") && ((work!=empty && album.raw!=work) || (work==empty && album.raw!=title)))) && bool5=="false"%**}

{# Disc Number and Title%|!=%}
{## Shown only if Disc Title not empty%|!=%}
{## Pad Disc Number to two digits%|!=%}

{\nDisc #--%|genre-="Classical" && disc==empty && disctitle!=empty && bool5=="false"%: }
{\nDisc #0%disc|genre-="Classical" && (disc!=empty && disc<"10") && disctitle!=empty && bool5=="false"%: }
{\nDisc #%disc|genre-="Classical" && disc>"9" && disctitle!=empty && bool5=="false"%: }
{%disctitle|genre-="Classical" && bool5=="false"%}
{#!# ---EDIT BELOW to fit your tags---%|!=%}
{# Classical Genre%|!=%}

{## Show Album/Release Name and Release Date%|!=%}
{%album|genre+="Classical" && bool5=="false"%}
{    %|!=%}
{## Show Release Year after Album/Release Name, only if different from "Year" tag%|!=%}
{### Toggle bool4 to display full Release DATE instead of Release YEAR%|!=%}
{ (%releasedate.year|(genre+="Classical" && releasedate!=empty && releasedate.year!=year) && disctitle!=empty && bool4=="false" && bool5=="false"%)}
{ (%releasedate|(genre+="Classical" && releasedate!=empty) && disctitle!=empty && bool4=="true" && bool5=="false"%)}
{#!# ---END OF EDIT ZONE---%|!=%}
{# Mini Player: Alt-Text%|!=%}

{## Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}
{### Show Performing Artists instead if Album Artist is included%|!=%}
{**%albumartist|genre-="Classical" && albumartist!="Various Artists" && bool5=="true"%**}
{**%artist|genre-="Classical" && (albumartist=="Various Artists" || albumartist==empty) && bool5=="true"%**}
{#!# ---EDIT BELOW to fit your tags---%|!=%}
{# Classical genre%|!=%}
{## Shows Composer's name%|!=%}
{**%composer|genre+="Classical" && bool5=="true"%**}
{#!# ---END OF EDIT ZONE---%|!=%

All Artists
{# Show label for song covers (aka songs not performed by the original artist)%|!=%}
{## Based on ReleaseType (guaranteed, no errors) or comparison to original artist (reliable but not perfect)%|!=%}

{//Covered by: %|album.type+="covers" && bool5=="false"%//}
{//Covered by: %|album.type-="covers" && genre-="Classical" && original.artist!=empty && albumartist!=original.artist && bool5=="false"%//}

{# Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}
{## Show Performing Artists instead if Album Artist is included%|!=%}
{## The newline after Artist is there to force two-line minimum spacing for the string%|!=%}

{**__%albumartist|genre-="Classical" && artist-=albumartist && albumartist!="Various Artists" && bool5=="false"%__**\n}
{%artist|genre-="Classical" && bool5=="false"%\n}
{#!# ---EDIT BELOW to fit your tags---%|!=%}
{# Classical Genre%|!=%}

{## Shows Composer on first line followed by Performing Artists on second line%|!=%}
{**__%composer|genre+="Classical" && bool5=="false"%__**\n}
{%artist|genre+="Classical" && bool5=="false"%}
{#!# ---END OF EDIT ZONE---%|!=%}

Composer and Extras
{# Mode 1: Year, Mode 2: Release Date%|!=%}
{# Classical Mode 1: Year, Mode 2: Original Date%|!=%}

{**%year|bool4=="false" && bool5=="false"%**}
{%releasedate|genre-="Classical" && bool4=="true" && bool5=="false"%}
{**%originaldate|genre+="Classical" && bool4=="true" && bool5=="false"%**}

\t

{# Mode 1: Composer, Mode 2: File Info%|!=%}
{## Classical Genre - File Info only%|!=%}

{//Composed by: %|genre-="Classical" && composer!=empty && bool4=="false" && bool5=="false"%//}
{%composer|genre-="Classical" && composer!=empty && bool4=="false" && bool5=="false"%}
{**%format|genre-="Classical" && bool4=="true" && format!="Unknown" && bool5=="false"%**}
{%format|genre+="Classical" && format!="Unknown" && bool5=="false"%}
{//Loading track info...%|(genre+="Classical" || bool4=="true") && format=="Unknown" && bool5=="false"%//}

\t

{# Mode 1: Equalizer indicator, Mode 2: Provider Name%|!=%}
{## Classical Genre - Same info, just Bold%|!=%}

{**☐ EQ%|eq.config=="Disabled" && bool4=="false" && bool5=="false"%**}
{**☑ EQ%|eq.config!="Disabled" && bool4=="false" && bool5=="false"%**}
{%providername|genre-="Classical" && bool4=="true" && bool5=="false"%}
{**%providername|genre+="Classical" && bool4=="true" && bool5=="false"%**}


Compact Player

Expand

Can’t forget about this guy! There’s nothing too special here, it’s just a few snippets from the main NPS.

Top String

Pulls from “Main Title” string for non-Classical vs from “Subtitle” for Classical genre.

{# Shows Work name (if present) or Title (if not)%|!=%}
{%explicit|genre-="Classical" && explicit!=empty && work!=empty%⠀}
{%work|genre-="Classical" && work!=empty%}
{%title|genre-="Classical" && work==empty%}
{#!# ---EDIT BELOW to fit your tags---%|!=%}
{# Classical Genre%|!=%}

{## Shows Movement info (if present) or Title (if not)%|!=%}
{%explicit|genre+="Classical" && explicit!=empty%⠀}
{%movement.number.roman|movement.number!=empty && movement.name!=empty%.⠀}
{%movement.name|genre+="Classical"%}
{%title|genre+="Classical" && movement.name==empty%}
{#!# ---END OF EDIT ZONE---%|!=%}

Bottom String

For non-Classical: copies “All Artists” string, but without the “Covered by” stuff

For Classical: copies relevant portion of “Main Title” string

{# Show Album Artist if not set to "Various Artists", else show Performing Artists%|!=%}
{## Show Performing Artists instead if Album Artist is included%|!=%}

{%albumartist|genre-="Classical" && (artist-=albumartist && albumartist!="Various Artists")%}
{%artist|genre-="Classical" && (artist+=albumartist || albumartist=="Various Artists")%}
{#!# ---EDIT BELOW to fit your tags---%|!=%}
{# Classical Genre%|!=%}

{## Show Composer's name%|!=%}
{%composer|genre+="Classical"%'s }

{## Show Work name%|!=%}
{%work|genre+="Classical"%}
{#!# ---END OF EDIT ZONE---%|!=%}



Flattened

Ex... Expand?

Y’know, cuz it’s flattened… You don’t want to expand the fl–ANYWAY :rofl:

I hit the character limit and can’t attach *.txt files so… Just copy them from inside the app after you apply the theme.

My Queue Info strings are available pre-flattened in the main post. Feel free to use them in your own themes!


This is so cool. Not really my style but showcases so many cool tricks I had no idea Symfonium could do and gives me so many ideas for ways to make my own theme more dynamic. I’m curious, how are you doing the rating as circles rather than stars? Is it just a conditional string translating each possible rating to a corresponding set of unicode characters?

2 Likes

That’s exactly it! I’ll update the third post with the full string later but it’s just:

{●●◉○○%|userrating.5=="2.5"%}

For each step from 0 to 5

Also, I wanted to use stars but my phone somehow doesn’t support the Unicode for half-stars lol. So I had to find a replacement.

Makes sense. I actually like the dots, especially since I prefer to use them not as a true rating system but as a sort of “how often am I willing to have this come up in my playlist?” thing. So I may “borrow” that for my setup.

Final release of my themes are now out for use with the new app version. I don’t expect to change much about it, but let me know if you run into any problems.

1 Like

hi & thanks for the dedication. this is exactly what i was expecting when i browsing for a theme, and it’s a beautiful one with that.

that said, i was able to import the “APPSTYLE_AMO-RED v1 OP” but got “Invalid style detected!” with any other file (v.1.0 ,v0.10, v0.9, NavBar, etc.).

I was wondering if maybe you were on the beta and i am not (beta is full so i can’t join anymore), or if you had any leads about why i may get that error.

with care

Sounds like the NPS styles are the issue? The “FULL COMBO” files?

There’s a separate Import button for those. Go to Settings > Interface > Now Playing Screens and use the Import button there.

Lmk if that still doesn’t work.

1 Like

haha yup that was it. you’re the best!

1 Like