New take on media player - combination of lots of cards and CSS

Im not sure if this would be of use to anyone but i really wanted to try to design something a little different in terms of a media player. I also wanted some nicer buttons to control it and a slider for volume. This is what i came up with. This is a combination of the following cards:

mini-media-player

  • used this for the media player function along with the background artwork and progress bar and favorites

button-card

  • used this for the media control buttons (play/pause, forward, back etc)

lovelace-card-mod

  • used a LOT of this to try to CSS everything into looking like one card

decluttering-card

  • made sort of a template out of the whole thing

slider-button-card

  • used this for the volume slider

There was a lot of CSS fiddling to get it looking like this. If anyone is interested in this sort of thing id be happy to post all the configuration for this on github or something.

Also certainly welcome feedback. Im still going to tweak it a bit and im sure there are bugs to work out.

Hereā€™s a few samples. Really wanted to feature artwork and make the controls sort of blend into the background.


7 Likes

That looks great! Do you mind sharing your lovelace code for the card?

Must be a huge YAMLā€¦ Iā€™d vote for sharing your code too! :smiley:
And: did you reckon how long it took you to compile this?

1 Like

Certainlyā€¦ So let me see if i can break this down properly:

Here is whatā€™s in the lovelace dashboard fileā€¦ i wanted to keep this very clean and neat.

- type: custom:decluttering-card
  template: sonos_declutter
  variables:
    - entity: media_player.toms_office

And here is what is in the declutter card template. Its a lot but at least its a template that can applied over and over. I also maintain that there are still probably bug fixes and tweaks that need to happen, but this is sort of a draft :slight_smile: Now i dont know what happens if you take out the media player short cuts or put additional ones in because i would imagine it will probably screw up the spacingā€¦ thatā€™s what im going to play with next.

sonos_declutter:
  card:
    type: custom:mod-card
    style: 
      hui-vertical-stack-card:
        $: |
          #root {
            margin-bottom: -15px;
          }
      .: | 
          ha-card {
            border-radius: 8px;
            background-color: transparent;
            border: 2px solid rgba(38,38,38,1);
          }

    card:
      type: vertical-stack
      cards:
      - type: custom:mini-media-player
        artwork: material
        entity: '[[entity]]'
        hide:
          power: true
          icon: true
          volume: true
          controls: true
          runtime: false
        idle_view:
          when_idle: false
          when_paused: false
          when_standby: false
        tap_action:
          action: none
        shortcuts:
          buttons:
            - id: MSNBC
              name: MSNBC
              type: source
            - id: Jazz24
              name: Jazz24
              type: source
            - id: Jazz-FM91
              name: Jazz91
              type: source
            - id: This Is Oscar Peterson
              name: Oscar
              type: source
            - id: This Is Four80East
              name: 480East
              type: source
            - id: This Is Ramsey Lewis Trio
              name: Ramsey
              type: source     
            - id: Jazz Vibes
              name: Jazz Vibes
              type: source
            - id: Jazz-Funk
              name: Jazz Funk
              type: source     
          columns: 2
        source: icon
        group: true
        volume_stateless: true
        style:
          mmp-shortcuts:
            $: |
              .mmp-shortcuts__buttons {
                width:50%;
                padding-top: 0px;
                margin-bottom: 5px;
                margin-left: 7px;
              }
              .mmp-shortcuts__button {
                background-color: rgba(100,100,100,0.3);
                box-shadow: rgb(0 0 0 / 30%) 0px 5px 1px -2px, rgb(0 0 0 / 14%) 0px 3px 2px 0px, rgb(0 0 0 / 12%) 0px 2px 5px 0px;
              }
              span.ellipsis {
                color: white;
                mix-blend-mode: exclusion;
              }
          mmp-progress:
            $: |
              .mmp-progress__duration {
                font-size: 1.1em !important;
                padding: 0px 10px 0px 10px !important;
              }
              .mmp-progress__duration__remaining {
                opacity: 1 !important;
              }
          .: |
            ha-card.type-custom-mini-media-player {
              font-family: Sf Display, Roboto
            }
            ha-card.type-custom-mini-media-player .mmp-player{
              min-height: 400px;
            }
            ha-card.type-custom-mini-media-player .mmp-player__core {  /* background behind name, song, artist */
              padding-left: 3px;
              min-height: 73px;
              border-bottom: 2px solid rgba(38,38,38,1);
            }
            ha-card.type-custom-mini-media-player .mmp__bg { /* background behind media player */
              border-radius: 8px;
            }
            ha-card.type-custom-mini-media-player div.entity__info {  /* box that holds name, song, artist */
              padding: 8px 0px 25px 0px;
              overflow: normal;
              background: none;
              width: 80%;
            }
            ha-card.type-custom-mini-media-player div.entity__info__name { /* name of player */
              font-size: 1.4em;
            }
            ha-card.type-custom-mini-media-player span.attr__media_title { /* name of song title */
              font-size: 1.1em;
              margin-left: 2px;
              color: var(--mmp-text-color);
              display: block;
            }
            ha-card.type-custom-mini-media-player span.attr__media_artist { /* name of song artist */
              font-size: 1.1em;
              margin-left: 2px;
              color: var(--mmp-text-color);
              position: absolute;
            }
            ha-card.type-custom-mini-media-player span.attr__media_artist::before { /* remove dash between song title and artist */
              display:none;
            }
            ha-card.type-custom-mini-media-player div.cover {
              margin-top: 75px;
              border-radius: 8px;
            }

      - type: custom:mod-card
        style: |
          ha-card {
          padding: 0px 11px 0px 11px;
          margin-top: -142px;
          }
        card:
          type: horizontal-stack
          cards:

          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:volume-mute
            #color: 'var(--mmp-icon-color)'
            tap_action:
              action: call-service
              service: media_player.volume_mute
              service_data:
                entity_id: '[[entity]]'
                is_volume_muted: >
                  [[[ return states[entity].attributes.is_volume_muted == 'true' ? 'false' : 'true'; ]]]
            template: icon_only_tom

          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:volume-minus
            tap_action:
              action: call-service
              service: media_player.volume_down
              service_data:
                entity_id: entity
            template: icon_only_tom

          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:volume-plus
            tap_action:
              action: call-service
              service: media_player.volume_up
              service_data:
                entity_id: entity
            template: icon_only_tom

          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:skip-previous
            tap_action:
              action: call-service
              service: media_player.media_next_track
              service_data:
                entity_id: entity
            template: icon_only_tom

          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:play-pause
            tap_action:
              action: call-service
              service: media_player.media_play_pause
              service_data:
                entity_id: entity
            template: icon_only_tom
          
          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:stop
            tap_action:
              action: call-service
              service: media_player.media_stop
              service_data:
                entity_id: entity
            template: icon_only_tom

          - type: custom:button-card
            entity: '[[entity]]'
            icon: mdi:skip-next
            tap_action:
              action: call-service
              service: media_player.media_previous_track
              service_data:
                entity_id: entity
            template: icon_only_tom

      - type: custom:slider-button-card
        entity: '[[entity]]'
        show_name: false
        show_state: true
        compact: true
        slider:
          direction: left-right
        icon:
          show: false
        action_button:
          show: false
        style: |
          ha-card.type-custom-slider-button-card {
            border-radius: 4px;
            width: 90%;
            margin-left: 5%;
            margin-top: -93px;
            background: none;
          }
          ha-card.type-custom-slider-button-card .slider-thumb::before {
            opacity: .8;
            left: -2px;
            width: 10%;
            border-radius: 4px;
            box-shadow: rgb(0 0 0 / 30%) 0px 5px 1px -2px, rgb(0 0 0 / 14%) 0px 3px 2px 0px, rgb(0 0 0 / 12%) 0px 2px 5px 0px;
            background-color: rgba(100,100,100,0.5);
            mix-blend-mode: exclusion;
          }
          ha-card.type-custom-slider-button-card .changing .slider-thumb::before {
            opacity: .8;
            width: 10%;
            border-radius: 4px;
          }
          ha-card.type-custom-slider-button-card .slider-thumb::after {
            background-color: transparent;
          }
          ha-card.type-custom-slider-button-card .slider-thumb {
            transform:translateX(calc((var(--slider-value) * .88) - 0px));
          }
          ha-card.type-custom-slider-button-card .slider {
            background-color: rgba(100,100,100,0.3);
            box-shadow: rgb(0 0 0 / 30%) 0px 5px 1px -2px, rgb(0 0 0 / 14%) 0px 3px 2px 0px, rgb(0 0 0 / 12%) 0px 2px 5px 0px;
          }
          ha-card.type-custom-slider-button-card .slider-bg {
            background-image: none;
            background-color: transparent;
          }
          ha-card.type-custom-slider-button-card .text {
            font-size: 1.25rem;
            top: -0.35rem !important;
            height: 140% !important;
            display: block !important;
            left: .3rem !important;
            overflow: visible;
          }
          ha-card.type-custom-slider-button-card .state {
            position: absolute;
            top: 0.4rem;
            line-height: normal !important;
            color: white;
            mix-blend-mode: exclusion;
          }
          ha-card.type-custom-slider-button-card .changing .state {
            font-size: inherit;
          }

Finally there is some button-card templates that i used but i may try to pull these into the declutter template so its all in one place. Youā€™d want this added to a file and then called into your main yaml file using this:

button_card_templates: !include button_card_templates.yaml
  icon_only_tom:
    show_name: false
    aspect_ratio: 5/4
    color: white
    styles:
      icon:
        - mix-blend-mode: exclusion
      card:
        - background-color: rgba(100,100,100,0.3)
        - border-radius: 0.3em
        - box-shadow: rgb(0 0 0 / 30%) 0px 5px 1px -2px, rgb(0 0 0 / 14%) 0px 3px 2px 0px, rgb(0 0 0 / 12%) 0px 2px 5px 0px

if you come up with any mods or improvements i would love to see them. Im just going to use this for now. Would be very cool to have this all in one card module but i think that would be a little too ambitiousā€¦ Oh one thing, the mute button doesnā€™t work in this for some reasonā€¦ i can call the service manually from developer tools but when i call it here it doesnā€™t workā€¦ will have figure that out.

Just make sure you have those 5 modules listed above installed and working before you attempt this.

3 Likes

took me quite a few hours of tinkering to get all the ā€˜sub cardsā€™ to line up properly. But i like tinkering with that sort of stuff. :slight_smile:

I managed to even clean this up a bit more with a google home version as well:

1 Like

I have trouble getting mine nice and tidy. Do you embed them in some way?