From 6ee253704ea2a9d5b5a750a2c6d246e570b7b96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Li=C5=A1ka?= Date: Thu, 20 Aug 2020 22:47:35 +0200 Subject: [PATCH 1/4] Basic mediaSession integration (media keys, notification on mobile) --- app/css/cyp.less | 1 + app/css/elements/media-handler.less | 3 ++ app/cyp.css | 2 +- app/cyp.js | 49 +++++++++++++++++++++++++++ app/index.html | 1 + app/js/cyp.js | 3 +- app/js/elements/media-handler.js | 51 +++++++++++++++++++++++++++++ 7 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 app/css/elements/media-handler.less create mode 100644 app/js/elements/media-handler.js diff --git a/app/css/cyp.less b/app/css/cyp.less index 00999ff..ba9040e 100644 --- a/app/css/cyp.less +++ b/app/css/cyp.less @@ -90,3 +90,4 @@ select { @import "elements/back.less"; @import "elements/path.less"; @import "elements/yt-result.less"; +@import "elements/media-handler.less"; diff --git a/app/css/elements/media-handler.less b/app/css/elements/media-handler.less new file mode 100644 index 0000000..8669b0d --- /dev/null +++ b/app/css/elements/media-handler.less @@ -0,0 +1,3 @@ +cyp-media-handler { + display: none; +} diff --git a/app/cyp.css b/app/cyp.css index 8fed974..74eddee 100644 --- a/app/cyp.css +++ b/app/cyp.css @@ -1 +1 @@ -*,*::before,*::after{box-sizing:inherit}html{background-color:var(--fg)}body{margin:0}main{flex:auto;overflow:auto}header,footer{flex:none;z-index:1;box-shadow:var(--box-shadow)}footer{position:relative;overflow:hidden;height:56px}@media (max-width:480px){footer{height:40px}}input,select{font:inherit}select{color:inherit}option{color:initial}button{color:inherit;font:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;flex-direction:row;align-items:center;flex:none;background-color:transparent;padding:0;border:none;line-height:1;cursor:pointer}button:not([hidden]){display:flex}select{background-color:transparent;border:1px solid var(--fg);border-radius:4px;padding:2px 4px}@font-face{font-family:"Lato";src:url("font/LatoLatin-Regular.woff2") format("woff2");font-style:normal;font-weight:normal}@font-face{font-family:"Lato";src:url("font/LatoLatin-Bold.woff2") format("woff2");font-style:normal;font-weight:bold}.icon{width:var(--icon-size);flex:none}.icon path:not([fill]),.icon polygon:not([fill]),.icon circle:not([fill]){fill:currentColor}.flex-row{flex-direction:row;align-items:center}.flex-row:not([hidden]){display:flex}.flex-column{flex-direction:column}.flex-column:not([hidden]){display:flex}.ellipsis{overflow:hidden;text-overflow:ellipsis}.font-large{font-size:18px;line-height:24px}.selectable{cursor:pointer;position:relative}.selectable.selected{color:var(--primary);background-color:var(--primary-tint)}.selectable.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}.item:not([hidden]){display:flex}.item:nth-child(odd){background-color:var(--bg-alt)}.item.selected{color:var(--primary);background-color:var(--primary-tint)}.item.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item>.icon{margin-right:var(--icon-spacing)}.item .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}.item button:first-of-type{margin-left:auto}.item button .icon{width:32px}.art{flex:none}.art .icon,.art img{display:block;width:100%}cyp-app{--icon-size:24px;--icon-spacing:4px;--primary:rgb(var(--primary-raw));--primary-tint:rgba(var(--primary-raw), .1);--box-shadow:0 0 3px #000;--border-width:4px}cyp-app[theme=light]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}cyp-app[theme=dark]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}@media (prefers-color-scheme:dark){cyp-app[theme=auto]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}}@media (prefers-color-scheme:light){cyp-app[theme=auto]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}}@media (max-width:640px),(max-height:640px){cyp-app[theme]{--text-shadow:none}}cyp-app[color=dodgerblue]{--primary-raw:30, 144, 255}cyp-app[color=darkorange]{--primary-raw:255, 140, 0}cyp-app[color=limegreen]{--primary-raw:50, 205, 50}cyp-app{flex-direction:column;box-sizing:border-box;margin:0 auto;max-width:800px;height:calc(100px * var(--vh));font-family:lato,sans-serif;font-size:16px;line-height:1.25;background-color:var(--bg);color:var(--fg);white-space:nowrap}cyp-app:not([hidden]){display:flex}cyp-menu,cyp-commands{flex-direction:row;align-items:center;height:100%}cyp-menu:not([hidden]),cyp-commands:not([hidden]){display:flex}cyp-menu button,cyp-commands button{height:100%;flex-direction:column;align-items:center;justify-content:center}cyp-menu button:not([hidden]),cyp-commands button:not([hidden]){display:flex}@media (max-width:480px){cyp-menu button,cyp-commands button{flex-direction:row}cyp-menu button span:not([id]),cyp-commands button span:not([id]){display:none}}cyp-menu button .icon+*,cyp-commands button .icon+*{margin-top:2px}cyp-menu button{flex:1 0 0;border-top:var(--border-width) solid transparent;border-bottom:var(--border-width) solid transparent}cyp-menu button .icon{margin-right:var(--icon-spacing)}cyp-menu button.active{border-top-color:var(--primary);color:var(--primary);background-color:var(--primary-tint)}cyp-commands{position:absolute;left:0;top:0;width:100%;transition:top 300ms;background-color:var(--bg)}cyp-commands[hidden]{display:flex;top:100%}cyp-commands button{flex:0 1 80px}cyp-commands button.last{order:1;margin-left:auto}cyp-song{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-song:not([hidden]){display:flex}cyp-song:nth-child(odd){background-color:var(--bg-alt)}cyp-song.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-song.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-song>.icon{margin-right:var(--icon-spacing)}cyp-song .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-song button:first-of-type{margin-left:auto}cyp-song button .icon{width:32px}cyp-song .multiline{flex-direction:column;min-width:0}cyp-song .multiline:not([hidden]){display:flex}cyp-song .multiline .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-queue cyp-song>.icon{width:32px;margin-right:8px}cyp-queue cyp-song .track{display:none}cyp-queue cyp-song:not(.playing)>.icon-play,cyp-queue cyp-song.playing>.icon-music{display:none}cyp-queue cyp-song.playing>.icon{color:var(--primary)}cyp-queue cyp-song.playing::after{content:"";position:absolute;left:0;bottom:0;background-color:var(--primary);width:calc(100% * var(--progress, 0));height:var(--border-width)}cyp-library cyp-song{padding-left:0;padding-top:0;padding-bottom:0}cyp-library cyp-song>.icon{width:64px}cyp-library cyp-song>.icon-play{display:none}cyp-player{flex-direction:row;align-items:center;align-items:stretch}cyp-player:not([hidden]){display:flex}cyp-player:not([data-state=play]) .pause{display:none}cyp-player[data-state=play] .play{display:none}cyp-player:not([data-flags~=random]) .random,cyp-player:not([data-flags~=repeat]) .repeat{opacity:.5}cyp-player[data-flags~=mute] .mute .icon-volume-high{display:none}cyp-player:not([data-flags~=mute]) .mute .icon-volume-off{display:none}cyp-player x-range{flex:auto;--elapsed-color:var(--primary)}cyp-player .art{width:96px;height:96px}cyp-player .info{flex:auto;min-width:0;flex-direction:column;justify-content:space-between;padding:0 var(--icon-spacing)}cyp-player .info:not([hidden]){display:flex}cyp-player .info .title{margin-top:8px;font-size:18px;line-height:24px;font-weight:bold}cyp-player .info .title,cyp-player .info .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-player .timeline{flex:none;height:var(--icon-size);margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .timeline:not([hidden]){display:flex}cyp-player .timeline .duration,cyp-player .timeline .elapsed{flex:none;width:5ch;text-align:center}cyp-player .controls{width:220px;min-width:0;flex-direction:column}cyp-player .controls:not([hidden]){display:flex}cyp-player .controls .playback{flex:auto;flex-direction:row;align-items:center;justify-content:space-around}cyp-player .controls .playback:not([hidden]){display:flex}cyp-player .controls .playback .icon{width:40px}cyp-player .controls .playback .icon-play,cyp-player .controls .playback .icon-pause{width:64px}cyp-player .controls .volume{flex:none;margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .controls .volume:not([hidden]){display:flex}cyp-player .controls .volume .mute{margin-right:var(--icon-spacing)}cyp-player .misc{flex:none;flex-direction:column;justify-content:space-around}cyp-player .misc:not([hidden]){display:flex}cyp-player .misc .icon{width:32px}@media (max-width:519px){cyp-player{flex-wrap:wrap;justify-content:space-between}cyp-player .info{order:1;flex-basis:100%;height:96px}}cyp-queue .current>.icon{color:var(--primary)}cyp-settings{--spacing:8px;font-size:18px;line-height:24px}cyp-settings dl{margin:var(--spacing);display:grid;grid-template-columns:max-content 1fr;align-items:center;grid-gap:var(--spacing)}cyp-settings dt{font-weight:bold}cyp-settings dd{margin:0;flex-direction:column;align-items:start}cyp-settings dd:not([hidden]){display:flex}cyp-settings label{flex-direction:row;align-items:center}cyp-settings label:not([hidden]){display:flex}cyp-settings label [type=radio],cyp-settings label [type=checkbox]{margin:0 4px 0 0}cyp-yt pre{margin:.5em .5ch;flex-grow:1;overflow:auto;white-space:pre-wrap}x-range{--thumb-size:8px;--thumb-color:#ddd;--thumb-shadow:#000;--thumb-hover-color:#fff;--track-size:4px;--track-color:#888;--track-shadow:#000;--elapsed-color:#ddd;--remaining-color:transparent;--radius:calc(var(--track-size)/2);display:inline-block;position:relative;width:192px;height:16px}x-range .-track,x-range .-elapsed,x-range .-remaining{position:absolute;top:calc(50% - var(--track-size)/2);height:var(--track-size);border-radius:var(--radius)}x-range .-track{width:100%;left:0;background-color:var(--track-color);box-shadow:0 0 1px var(--thumb-shadow)}x-range .-elapsed{left:0;background-color:var(--elapsed-color)}x-range .-remaining{right:0;background-color:var(--remaining-color)}x-range .-inner{position:absolute;left:var(--thumb-size);right:var(--thumb-size);top:0;bottom:0}x-range .-thumb{all:unset;position:absolute;top:50%;transform:translate(-50%, -50%);border-radius:50%;width:calc(2*var(--thumb-size));height:calc(2*var(--thumb-size));background-color:var(--thumb-color);box-shadow:0 0 2px var(--thumb-shadow)}x-range[disabled]{opacity:.5}x-range:not([disabled]) .-thumb:hover{background-color:var(--thumb-hover-color)}cyp-playlist{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-playlist:not([hidden]){display:flex}cyp-playlist:nth-child(odd){background-color:var(--bg-alt)}cyp-playlist.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-playlist.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-playlist>.icon{margin-right:var(--icon-spacing)}cyp-playlist .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-playlist button:first-of-type{margin-left:auto}cyp-playlist button .icon{width:32px}cyp-search form{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;align-items:stretch}cyp-search form:not([hidden]){display:flex}cyp-search form:nth-child(odd){background-color:var(--bg-alt)}cyp-search form.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-search form.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-search form>.icon{margin-right:var(--icon-spacing)}cyp-search form .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-search form button:first-of-type{margin-left:auto}cyp-search form button .icon{width:32px}cyp-search form button:first-of-type{margin-left:var(--icon-spacing)}cyp-search.pending form{background-image:linear-gradient(var(--primary), var(--primary));background-repeat:no-repeat;background-size:25% var(--border-width);animation:bar ease-in-out 3s alternate infinite}@keyframes bar{0%{background-position:0 100%}100%{background-position:100% 100%}}cyp-filter{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-filter:not([hidden]){display:flex}cyp-filter:nth-child(odd){background-color:var(--bg-alt)}cyp-filter.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-filter.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-filter>.icon{margin-right:var(--icon-spacing)}cyp-filter .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-filter button:first-of-type{margin-left:auto}cyp-filter button .icon{width:32px}cyp-filter .icon{width:32px;margin-left:var(--icon-spacing)}cyp-library nav{flex-direction:column;align-items:center}cyp-library nav:not([hidden]){display:flex}cyp-library nav button{font-size:18px;line-height:24px;width:200px;margin-top:2em;text-decoration:underline}cyp-library nav button .icon{width:32px;margin-right:var(--icon-spacing)}cyp-tag{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;padding-left:0;padding-top:0;padding-bottom:0}cyp-tag:not([hidden]){display:flex}cyp-tag:nth-child(odd){background-color:var(--bg-alt)}cyp-tag.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-tag.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-tag>.icon{margin-right:var(--icon-spacing)}cyp-tag .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-tag button:first-of-type{margin-left:auto}cyp-tag button .icon{width:32px}cyp-tag .art{margin-right:var(--icon-spacing);width:64px;height:64px}cyp-back{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-back:not([hidden]){display:flex}cyp-back:nth-child(odd){background-color:var(--bg-alt)}cyp-back.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-back.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-back>.icon{margin-right:var(--icon-spacing)}cyp-back .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-back button:first-of-type{margin-left:auto}cyp-back button .icon{width:32px}cyp-path{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-path:not([hidden]){display:flex}cyp-path:nth-child(odd){background-color:var(--bg-alt)}cyp-path.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-path.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-path>.icon{margin-right:var(--icon-spacing)}cyp-path .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-path button:first-of-type{margin-left:auto}cyp-path button .icon{width:32px}cyp-yt-result{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;cursor:default}cyp-yt-result:not([hidden]){display:flex}cyp-yt-result:nth-child(odd){background-color:var(--bg-alt)}cyp-yt-result.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-yt-result.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-yt-result>.icon{margin-right:var(--icon-spacing)}cyp-yt-result .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-yt-result button:first-of-type{margin-left:auto}cyp-yt-result button .icon{width:32px}cyp-yt-result button .icon{width:var(--icon-size)} \ No newline at end of file +*,*::before,*::after{box-sizing:inherit}html{background-color:var(--fg)}body{margin:0}main{flex:auto;overflow:auto}header,footer{flex:none;z-index:1;box-shadow:var(--box-shadow)}footer{position:relative;overflow:hidden;height:56px}@media (max-width:480px){footer{height:40px}}input,select{font:inherit}select{color:inherit}option{color:initial}button{color:inherit;font:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;flex-direction:row;align-items:center;flex:none;background-color:transparent;padding:0;border:none;line-height:1;cursor:pointer}button:not([hidden]){display:flex}select{background-color:transparent;border:1px solid var(--fg);border-radius:4px;padding:2px 4px}@font-face{font-family:"Lato";src:url("font/LatoLatin-Regular.woff2") format("woff2");font-style:normal;font-weight:normal}@font-face{font-family:"Lato";src:url("font/LatoLatin-Bold.woff2") format("woff2");font-style:normal;font-weight:bold}.icon{width:var(--icon-size);flex:none}.icon path:not([fill]),.icon polygon:not([fill]),.icon circle:not([fill]){fill:currentColor}.flex-row{flex-direction:row;align-items:center}.flex-row:not([hidden]){display:flex}.flex-column{flex-direction:column}.flex-column:not([hidden]){display:flex}.ellipsis{overflow:hidden;text-overflow:ellipsis}.font-large{font-size:18px;line-height:24px}.selectable{cursor:pointer;position:relative}.selectable.selected{color:var(--primary);background-color:var(--primary-tint)}.selectable.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}.item:not([hidden]){display:flex}.item:nth-child(odd){background-color:var(--bg-alt)}.item.selected{color:var(--primary);background-color:var(--primary-tint)}.item.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item>.icon{margin-right:var(--icon-spacing)}.item .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}.item button:first-of-type{margin-left:auto}.item button .icon{width:32px}.art{flex:none}.art .icon,.art img{display:block;width:100%}cyp-app{--icon-size:24px;--icon-spacing:4px;--primary:rgb(var(--primary-raw));--primary-tint:rgba(var(--primary-raw), .1);--box-shadow:0 0 3px #000;--border-width:4px}cyp-app[theme=light]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}cyp-app[theme=dark]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}@media (prefers-color-scheme:dark){cyp-app[theme=auto]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}}@media (prefers-color-scheme:light){cyp-app[theme=auto]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}}@media (max-width:640px),(max-height:640px){cyp-app[theme]{--text-shadow:none}}cyp-app[color=dodgerblue]{--primary-raw:30, 144, 255}cyp-app[color=darkorange]{--primary-raw:255, 140, 0}cyp-app[color=limegreen]{--primary-raw:50, 205, 50}cyp-app{flex-direction:column;box-sizing:border-box;margin:0 auto;max-width:800px;height:calc(100px * var(--vh));font-family:lato,sans-serif;font-size:16px;line-height:1.25;background-color:var(--bg);color:var(--fg);white-space:nowrap}cyp-app:not([hidden]){display:flex}cyp-menu,cyp-commands{flex-direction:row;align-items:center;height:100%}cyp-menu:not([hidden]),cyp-commands:not([hidden]){display:flex}cyp-menu button,cyp-commands button{height:100%;flex-direction:column;align-items:center;justify-content:center}cyp-menu button:not([hidden]),cyp-commands button:not([hidden]){display:flex}@media (max-width:480px){cyp-menu button,cyp-commands button{flex-direction:row}cyp-menu button span:not([id]),cyp-commands button span:not([id]){display:none}}cyp-menu button .icon+*,cyp-commands button .icon+*{margin-top:2px}cyp-menu button{flex:1 0 0;border-top:var(--border-width) solid transparent;border-bottom:var(--border-width) solid transparent}cyp-menu button .icon{margin-right:var(--icon-spacing)}cyp-menu button.active{border-top-color:var(--primary);color:var(--primary);background-color:var(--primary-tint)}cyp-commands{position:absolute;left:0;top:0;width:100%;transition:top 300ms;background-color:var(--bg)}cyp-commands[hidden]{display:flex;top:100%}cyp-commands button{flex:0 1 80px}cyp-commands button.last{order:1;margin-left:auto}cyp-song{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-song:not([hidden]){display:flex}cyp-song:nth-child(odd){background-color:var(--bg-alt)}cyp-song.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-song.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-song>.icon{margin-right:var(--icon-spacing)}cyp-song .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-song button:first-of-type{margin-left:auto}cyp-song button .icon{width:32px}cyp-song .multiline{flex-direction:column;min-width:0}cyp-song .multiline:not([hidden]){display:flex}cyp-song .multiline .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-queue cyp-song>.icon{width:32px;margin-right:8px}cyp-queue cyp-song .track{display:none}cyp-queue cyp-song:not(.playing)>.icon-play,cyp-queue cyp-song.playing>.icon-music{display:none}cyp-queue cyp-song.playing>.icon{color:var(--primary)}cyp-queue cyp-song.playing::after{content:"";position:absolute;left:0;bottom:0;background-color:var(--primary);width:calc(100% * var(--progress, 0));height:var(--border-width)}cyp-library cyp-song{padding-left:0;padding-top:0;padding-bottom:0}cyp-library cyp-song>.icon{width:64px}cyp-library cyp-song>.icon-play{display:none}cyp-player{flex-direction:row;align-items:center;align-items:stretch}cyp-player:not([hidden]){display:flex}cyp-player:not([data-state=play]) .pause{display:none}cyp-player[data-state=play] .play{display:none}cyp-player:not([data-flags~=random]) .random,cyp-player:not([data-flags~=repeat]) .repeat{opacity:.5}cyp-player[data-flags~=mute] .mute .icon-volume-high{display:none}cyp-player:not([data-flags~=mute]) .mute .icon-volume-off{display:none}cyp-player x-range{flex:auto;--elapsed-color:var(--primary)}cyp-player .art{width:96px;height:96px}cyp-player .info{flex:auto;min-width:0;flex-direction:column;justify-content:space-between;padding:0 var(--icon-spacing)}cyp-player .info:not([hidden]){display:flex}cyp-player .info .title{margin-top:8px;font-size:18px;line-height:24px;font-weight:bold}cyp-player .info .title,cyp-player .info .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-player .timeline{flex:none;height:var(--icon-size);margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .timeline:not([hidden]){display:flex}cyp-player .timeline .duration,cyp-player .timeline .elapsed{flex:none;width:5ch;text-align:center}cyp-player .controls{width:220px;min-width:0;flex-direction:column}cyp-player .controls:not([hidden]){display:flex}cyp-player .controls .playback{flex:auto;flex-direction:row;align-items:center;justify-content:space-around}cyp-player .controls .playback:not([hidden]){display:flex}cyp-player .controls .playback .icon{width:40px}cyp-player .controls .playback .icon-play,cyp-player .controls .playback .icon-pause{width:64px}cyp-player .controls .volume{flex:none;margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .controls .volume:not([hidden]){display:flex}cyp-player .controls .volume .mute{margin-right:var(--icon-spacing)}cyp-player .misc{flex:none;flex-direction:column;justify-content:space-around}cyp-player .misc:not([hidden]){display:flex}cyp-player .misc .icon{width:32px}@media (max-width:519px){cyp-player{flex-wrap:wrap;justify-content:space-between}cyp-player .info{order:1;flex-basis:100%;height:96px}}cyp-queue .current>.icon{color:var(--primary)}cyp-settings{--spacing:8px;font-size:18px;line-height:24px}cyp-settings dl{margin:var(--spacing);display:grid;grid-template-columns:max-content 1fr;align-items:center;grid-gap:var(--spacing)}cyp-settings dt{font-weight:bold}cyp-settings dd{margin:0;flex-direction:column;align-items:start}cyp-settings dd:not([hidden]){display:flex}cyp-settings label{flex-direction:row;align-items:center}cyp-settings label:not([hidden]){display:flex}cyp-settings label [type=radio],cyp-settings label [type=checkbox]{margin:0 4px 0 0}cyp-yt pre{margin:.5em .5ch;flex-grow:1;overflow:auto;white-space:pre-wrap}x-range{--thumb-size:8px;--thumb-color:#ddd;--thumb-shadow:#000;--thumb-hover-color:#fff;--track-size:4px;--track-color:#888;--track-shadow:#000;--elapsed-color:#ddd;--remaining-color:transparent;--radius:calc(var(--track-size)/2);display:inline-block;position:relative;width:192px;height:16px}x-range .-track,x-range .-elapsed,x-range .-remaining{position:absolute;top:calc(50% - var(--track-size)/2);height:var(--track-size);border-radius:var(--radius)}x-range .-track{width:100%;left:0;background-color:var(--track-color);box-shadow:0 0 1px var(--thumb-shadow)}x-range .-elapsed{left:0;background-color:var(--elapsed-color)}x-range .-remaining{right:0;background-color:var(--remaining-color)}x-range .-inner{position:absolute;left:var(--thumb-size);right:var(--thumb-size);top:0;bottom:0}x-range .-thumb{all:unset;position:absolute;top:50%;transform:translate(-50%, -50%);border-radius:50%;width:calc(2*var(--thumb-size));height:calc(2*var(--thumb-size));background-color:var(--thumb-color);box-shadow:0 0 2px var(--thumb-shadow)}x-range[disabled]{opacity:.5}x-range:not([disabled]) .-thumb:hover{background-color:var(--thumb-hover-color)}cyp-playlist{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-playlist:not([hidden]){display:flex}cyp-playlist:nth-child(odd){background-color:var(--bg-alt)}cyp-playlist.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-playlist.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-playlist>.icon{margin-right:var(--icon-spacing)}cyp-playlist .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-playlist button:first-of-type{margin-left:auto}cyp-playlist button .icon{width:32px}cyp-search form{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;align-items:stretch}cyp-search form:not([hidden]){display:flex}cyp-search form:nth-child(odd){background-color:var(--bg-alt)}cyp-search form.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-search form.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-search form>.icon{margin-right:var(--icon-spacing)}cyp-search form .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-search form button:first-of-type{margin-left:auto}cyp-search form button .icon{width:32px}cyp-search form button:first-of-type{margin-left:var(--icon-spacing)}cyp-search.pending form{background-image:linear-gradient(var(--primary), var(--primary));background-repeat:no-repeat;background-size:25% var(--border-width);animation:bar ease-in-out 3s alternate infinite}@keyframes bar{0%{background-position:0 100%}100%{background-position:100% 100%}}cyp-filter{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-filter:not([hidden]){display:flex}cyp-filter:nth-child(odd){background-color:var(--bg-alt)}cyp-filter.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-filter.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-filter>.icon{margin-right:var(--icon-spacing)}cyp-filter .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-filter button:first-of-type{margin-left:auto}cyp-filter button .icon{width:32px}cyp-filter .icon{width:32px;margin-left:var(--icon-spacing)}cyp-library nav{flex-direction:column;align-items:center}cyp-library nav:not([hidden]){display:flex}cyp-library nav button{font-size:18px;line-height:24px;width:200px;margin-top:2em;text-decoration:underline}cyp-library nav button .icon{width:32px;margin-right:var(--icon-spacing)}cyp-tag{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;padding-left:0;padding-top:0;padding-bottom:0}cyp-tag:not([hidden]){display:flex}cyp-tag:nth-child(odd){background-color:var(--bg-alt)}cyp-tag.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-tag.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-tag>.icon{margin-right:var(--icon-spacing)}cyp-tag .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-tag button:first-of-type{margin-left:auto}cyp-tag button .icon{width:32px}cyp-tag .art{margin-right:var(--icon-spacing);width:64px;height:64px}cyp-back{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-back:not([hidden]){display:flex}cyp-back:nth-child(odd){background-color:var(--bg-alt)}cyp-back.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-back.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-back>.icon{margin-right:var(--icon-spacing)}cyp-back .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-back button:first-of-type{margin-left:auto}cyp-back button .icon{width:32px}cyp-path{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-path:not([hidden]){display:flex}cyp-path:nth-child(odd){background-color:var(--bg-alt)}cyp-path.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-path.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-path>.icon{margin-right:var(--icon-spacing)}cyp-path .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-path button:first-of-type{margin-left:auto}cyp-path button .icon{width:32px}cyp-yt-result{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;cursor:default}cyp-yt-result:not([hidden]){display:flex}cyp-yt-result:nth-child(odd){background-color:var(--bg-alt)}cyp-yt-result.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-yt-result.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-yt-result>.icon{margin-right:var(--icon-spacing)}cyp-yt-result .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-yt-result button:first-of-type{margin-left:auto}cyp-yt-result button .icon{width:32px}cyp-yt-result button .icon{width:var(--icon-size)}cyp-media-handler{display:none} \ No newline at end of file diff --git a/app/cyp.js b/app/cyp.js index d364466..833ec86 100644 --- a/app/cyp.js +++ b/app/cyp.js @@ -1867,6 +1867,55 @@ class Library extends Component { customElements.define("cyp-library", Library); +class MediaHandler extends Component { + connectedCallback() { + // check support mediaSession + if (!('mediaSession' in navigator)) { + console.log('mediaSession is not supported'); + return; + } + + // DOM + const audio = node("audio", {loop: true}, "", this); + node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); + + // Init event session (play audio) on click (because restrictions by web browsers) + let mediaSessionInit = false; + window.addEventListener('click', () => { + if (!mediaSessionInit) { + audio.play(); + mediaSessionInit = true; + } + }); + + // mediaSession define metadata + navigator.mediaSession.metadata = new MediaMetadata({ + title: 'Control Your Player' + }); + + // mediaSession define action handlers + const that = this; + navigator.mediaSession.setActionHandler('play', function() { + that._mpd.command("play"); + audio.play(); + }); + navigator.mediaSession.setActionHandler('pause', function() { + that._mpd.command("pause 1"); + audio.pause(); + }); + navigator.mediaSession.setActionHandler('previoustrack', function() { + that._mpd.command("previous"); + audio.play(); + }); + navigator.mediaSession.setActionHandler('nexttrack', function() { + that._mpd.command("next"); + audio.play(); + }); + } +} + +customElements.define("cyp-media-handler", MediaHandler); + function updateSize() { document.body.style.setProperty("--vh", window.innerHeight/100); } diff --git a/app/index.html b/app/index.html index 4e9eadc..6986754 100644 --- a/app/index.html +++ b/app/index.html @@ -96,6 +96,7 @@ + diff --git a/app/js/cyp.js b/app/js/cyp.js index ff08227..9158d15 100644 --- a/app/js/cyp.js +++ b/app/js/cyp.js @@ -11,10 +11,11 @@ import "./elements/library.js"; import "./elements/tag.js"; import "./elements/back.js"; import "./elements/path.js"; +import "./elements/media-handler.js"; function updateSize() { document.body.style.setProperty("--vh", window.innerHeight/100); } window.addEventListener("resize", updateSize); -updateSize(); \ No newline at end of file +updateSize(); diff --git a/app/js/elements/media-handler.js b/app/js/elements/media-handler.js new file mode 100644 index 0000000..3cadf0a --- /dev/null +++ b/app/js/elements/media-handler.js @@ -0,0 +1,51 @@ +import Component from "../component.js"; +import * as html from "../html.js"; + +class MediaHandler extends Component { + connectedCallback() { + // check support mediaSession + if (!('mediaSession' in navigator)) { + console.log('mediaSession is not supported'); + return; + } + + // DOM (using media session controls are allowed only if there is audio/video tag) + const audio = html.node("audio", {loop: true}, "", this); + html.node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); + + // Init event session (play audio) on click (because restrictions by web browsers) + let mediaSessionInit = false; + window.addEventListener('click', () => { + if (!mediaSessionInit) { + audio.play(); + mediaSessionInit = true; + } + }); + + // mediaSession define metadata + navigator.mediaSession.metadata = new MediaMetadata({ + title: 'Control Your Player' + }); + + // mediaSession define action handlers + const that = this; + navigator.mediaSession.setActionHandler('play', function() { + that._mpd.command("play") + audio.play() + }); + navigator.mediaSession.setActionHandler('pause', function() { + that._mpd.command("pause 1") + audio.pause() + }); + navigator.mediaSession.setActionHandler('previoustrack', function() { + that._mpd.command("previous") + audio.play() + }); + navigator.mediaSession.setActionHandler('nexttrack', function() { + that._mpd.command("next") + audio.play() + }); + } +} + +customElements.define("cyp-media-handler", MediaHandler); From a440f79f42f0e3fea82a2219e697241c1464c8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Li=C5=A1ka?= Date: Mon, 21 Sep 2020 17:30:44 +0200 Subject: [PATCH 2/4] MediaSession integration moved from own custom element to class --- app/css/cyp.less | 1 - app/css/elements/media-handler.less | 3 - app/cyp.css | 2 +- app/cyp.js | 95 ++++++++++++++--------------- app/index.html | 1 - app/js/cyp.js | 1 - app/js/elements/app.js | 48 ++++++++++++++- app/js/elements/media-handler.js | 51 ---------------- 8 files changed, 94 insertions(+), 108 deletions(-) delete mode 100644 app/css/elements/media-handler.less delete mode 100644 app/js/elements/media-handler.js diff --git a/app/css/cyp.less b/app/css/cyp.less index ba9040e..00999ff 100644 --- a/app/css/cyp.less +++ b/app/css/cyp.less @@ -90,4 +90,3 @@ select { @import "elements/back.less"; @import "elements/path.less"; @import "elements/yt-result.less"; -@import "elements/media-handler.less"; diff --git a/app/css/elements/media-handler.less b/app/css/elements/media-handler.less deleted file mode 100644 index 8669b0d..0000000 --- a/app/css/elements/media-handler.less +++ /dev/null @@ -1,3 +0,0 @@ -cyp-media-handler { - display: none; -} diff --git a/app/cyp.css b/app/cyp.css index 74eddee..8fed974 100644 --- a/app/cyp.css +++ b/app/cyp.css @@ -1 +1 @@ -*,*::before,*::after{box-sizing:inherit}html{background-color:var(--fg)}body{margin:0}main{flex:auto;overflow:auto}header,footer{flex:none;z-index:1;box-shadow:var(--box-shadow)}footer{position:relative;overflow:hidden;height:56px}@media (max-width:480px){footer{height:40px}}input,select{font:inherit}select{color:inherit}option{color:initial}button{color:inherit;font:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;flex-direction:row;align-items:center;flex:none;background-color:transparent;padding:0;border:none;line-height:1;cursor:pointer}button:not([hidden]){display:flex}select{background-color:transparent;border:1px solid var(--fg);border-radius:4px;padding:2px 4px}@font-face{font-family:"Lato";src:url("font/LatoLatin-Regular.woff2") format("woff2");font-style:normal;font-weight:normal}@font-face{font-family:"Lato";src:url("font/LatoLatin-Bold.woff2") format("woff2");font-style:normal;font-weight:bold}.icon{width:var(--icon-size);flex:none}.icon path:not([fill]),.icon polygon:not([fill]),.icon circle:not([fill]){fill:currentColor}.flex-row{flex-direction:row;align-items:center}.flex-row:not([hidden]){display:flex}.flex-column{flex-direction:column}.flex-column:not([hidden]){display:flex}.ellipsis{overflow:hidden;text-overflow:ellipsis}.font-large{font-size:18px;line-height:24px}.selectable{cursor:pointer;position:relative}.selectable.selected{color:var(--primary);background-color:var(--primary-tint)}.selectable.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}.item:not([hidden]){display:flex}.item:nth-child(odd){background-color:var(--bg-alt)}.item.selected{color:var(--primary);background-color:var(--primary-tint)}.item.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item>.icon{margin-right:var(--icon-spacing)}.item .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}.item button:first-of-type{margin-left:auto}.item button .icon{width:32px}.art{flex:none}.art .icon,.art img{display:block;width:100%}cyp-app{--icon-size:24px;--icon-spacing:4px;--primary:rgb(var(--primary-raw));--primary-tint:rgba(var(--primary-raw), .1);--box-shadow:0 0 3px #000;--border-width:4px}cyp-app[theme=light]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}cyp-app[theme=dark]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}@media (prefers-color-scheme:dark){cyp-app[theme=auto]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}}@media (prefers-color-scheme:light){cyp-app[theme=auto]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}}@media (max-width:640px),(max-height:640px){cyp-app[theme]{--text-shadow:none}}cyp-app[color=dodgerblue]{--primary-raw:30, 144, 255}cyp-app[color=darkorange]{--primary-raw:255, 140, 0}cyp-app[color=limegreen]{--primary-raw:50, 205, 50}cyp-app{flex-direction:column;box-sizing:border-box;margin:0 auto;max-width:800px;height:calc(100px * var(--vh));font-family:lato,sans-serif;font-size:16px;line-height:1.25;background-color:var(--bg);color:var(--fg);white-space:nowrap}cyp-app:not([hidden]){display:flex}cyp-menu,cyp-commands{flex-direction:row;align-items:center;height:100%}cyp-menu:not([hidden]),cyp-commands:not([hidden]){display:flex}cyp-menu button,cyp-commands button{height:100%;flex-direction:column;align-items:center;justify-content:center}cyp-menu button:not([hidden]),cyp-commands button:not([hidden]){display:flex}@media (max-width:480px){cyp-menu button,cyp-commands button{flex-direction:row}cyp-menu button span:not([id]),cyp-commands button span:not([id]){display:none}}cyp-menu button .icon+*,cyp-commands button .icon+*{margin-top:2px}cyp-menu button{flex:1 0 0;border-top:var(--border-width) solid transparent;border-bottom:var(--border-width) solid transparent}cyp-menu button .icon{margin-right:var(--icon-spacing)}cyp-menu button.active{border-top-color:var(--primary);color:var(--primary);background-color:var(--primary-tint)}cyp-commands{position:absolute;left:0;top:0;width:100%;transition:top 300ms;background-color:var(--bg)}cyp-commands[hidden]{display:flex;top:100%}cyp-commands button{flex:0 1 80px}cyp-commands button.last{order:1;margin-left:auto}cyp-song{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-song:not([hidden]){display:flex}cyp-song:nth-child(odd){background-color:var(--bg-alt)}cyp-song.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-song.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-song>.icon{margin-right:var(--icon-spacing)}cyp-song .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-song button:first-of-type{margin-left:auto}cyp-song button .icon{width:32px}cyp-song .multiline{flex-direction:column;min-width:0}cyp-song .multiline:not([hidden]){display:flex}cyp-song .multiline .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-queue cyp-song>.icon{width:32px;margin-right:8px}cyp-queue cyp-song .track{display:none}cyp-queue cyp-song:not(.playing)>.icon-play,cyp-queue cyp-song.playing>.icon-music{display:none}cyp-queue cyp-song.playing>.icon{color:var(--primary)}cyp-queue cyp-song.playing::after{content:"";position:absolute;left:0;bottom:0;background-color:var(--primary);width:calc(100% * var(--progress, 0));height:var(--border-width)}cyp-library cyp-song{padding-left:0;padding-top:0;padding-bottom:0}cyp-library cyp-song>.icon{width:64px}cyp-library cyp-song>.icon-play{display:none}cyp-player{flex-direction:row;align-items:center;align-items:stretch}cyp-player:not([hidden]){display:flex}cyp-player:not([data-state=play]) .pause{display:none}cyp-player[data-state=play] .play{display:none}cyp-player:not([data-flags~=random]) .random,cyp-player:not([data-flags~=repeat]) .repeat{opacity:.5}cyp-player[data-flags~=mute] .mute .icon-volume-high{display:none}cyp-player:not([data-flags~=mute]) .mute .icon-volume-off{display:none}cyp-player x-range{flex:auto;--elapsed-color:var(--primary)}cyp-player .art{width:96px;height:96px}cyp-player .info{flex:auto;min-width:0;flex-direction:column;justify-content:space-between;padding:0 var(--icon-spacing)}cyp-player .info:not([hidden]){display:flex}cyp-player .info .title{margin-top:8px;font-size:18px;line-height:24px;font-weight:bold}cyp-player .info .title,cyp-player .info .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-player .timeline{flex:none;height:var(--icon-size);margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .timeline:not([hidden]){display:flex}cyp-player .timeline .duration,cyp-player .timeline .elapsed{flex:none;width:5ch;text-align:center}cyp-player .controls{width:220px;min-width:0;flex-direction:column}cyp-player .controls:not([hidden]){display:flex}cyp-player .controls .playback{flex:auto;flex-direction:row;align-items:center;justify-content:space-around}cyp-player .controls .playback:not([hidden]){display:flex}cyp-player .controls .playback .icon{width:40px}cyp-player .controls .playback .icon-play,cyp-player .controls .playback .icon-pause{width:64px}cyp-player .controls .volume{flex:none;margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .controls .volume:not([hidden]){display:flex}cyp-player .controls .volume .mute{margin-right:var(--icon-spacing)}cyp-player .misc{flex:none;flex-direction:column;justify-content:space-around}cyp-player .misc:not([hidden]){display:flex}cyp-player .misc .icon{width:32px}@media (max-width:519px){cyp-player{flex-wrap:wrap;justify-content:space-between}cyp-player .info{order:1;flex-basis:100%;height:96px}}cyp-queue .current>.icon{color:var(--primary)}cyp-settings{--spacing:8px;font-size:18px;line-height:24px}cyp-settings dl{margin:var(--spacing);display:grid;grid-template-columns:max-content 1fr;align-items:center;grid-gap:var(--spacing)}cyp-settings dt{font-weight:bold}cyp-settings dd{margin:0;flex-direction:column;align-items:start}cyp-settings dd:not([hidden]){display:flex}cyp-settings label{flex-direction:row;align-items:center}cyp-settings label:not([hidden]){display:flex}cyp-settings label [type=radio],cyp-settings label [type=checkbox]{margin:0 4px 0 0}cyp-yt pre{margin:.5em .5ch;flex-grow:1;overflow:auto;white-space:pre-wrap}x-range{--thumb-size:8px;--thumb-color:#ddd;--thumb-shadow:#000;--thumb-hover-color:#fff;--track-size:4px;--track-color:#888;--track-shadow:#000;--elapsed-color:#ddd;--remaining-color:transparent;--radius:calc(var(--track-size)/2);display:inline-block;position:relative;width:192px;height:16px}x-range .-track,x-range .-elapsed,x-range .-remaining{position:absolute;top:calc(50% - var(--track-size)/2);height:var(--track-size);border-radius:var(--radius)}x-range .-track{width:100%;left:0;background-color:var(--track-color);box-shadow:0 0 1px var(--thumb-shadow)}x-range .-elapsed{left:0;background-color:var(--elapsed-color)}x-range .-remaining{right:0;background-color:var(--remaining-color)}x-range .-inner{position:absolute;left:var(--thumb-size);right:var(--thumb-size);top:0;bottom:0}x-range .-thumb{all:unset;position:absolute;top:50%;transform:translate(-50%, -50%);border-radius:50%;width:calc(2*var(--thumb-size));height:calc(2*var(--thumb-size));background-color:var(--thumb-color);box-shadow:0 0 2px var(--thumb-shadow)}x-range[disabled]{opacity:.5}x-range:not([disabled]) .-thumb:hover{background-color:var(--thumb-hover-color)}cyp-playlist{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-playlist:not([hidden]){display:flex}cyp-playlist:nth-child(odd){background-color:var(--bg-alt)}cyp-playlist.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-playlist.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-playlist>.icon{margin-right:var(--icon-spacing)}cyp-playlist .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-playlist button:first-of-type{margin-left:auto}cyp-playlist button .icon{width:32px}cyp-search form{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;align-items:stretch}cyp-search form:not([hidden]){display:flex}cyp-search form:nth-child(odd){background-color:var(--bg-alt)}cyp-search form.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-search form.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-search form>.icon{margin-right:var(--icon-spacing)}cyp-search form .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-search form button:first-of-type{margin-left:auto}cyp-search form button .icon{width:32px}cyp-search form button:first-of-type{margin-left:var(--icon-spacing)}cyp-search.pending form{background-image:linear-gradient(var(--primary), var(--primary));background-repeat:no-repeat;background-size:25% var(--border-width);animation:bar ease-in-out 3s alternate infinite}@keyframes bar{0%{background-position:0 100%}100%{background-position:100% 100%}}cyp-filter{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-filter:not([hidden]){display:flex}cyp-filter:nth-child(odd){background-color:var(--bg-alt)}cyp-filter.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-filter.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-filter>.icon{margin-right:var(--icon-spacing)}cyp-filter .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-filter button:first-of-type{margin-left:auto}cyp-filter button .icon{width:32px}cyp-filter .icon{width:32px;margin-left:var(--icon-spacing)}cyp-library nav{flex-direction:column;align-items:center}cyp-library nav:not([hidden]){display:flex}cyp-library nav button{font-size:18px;line-height:24px;width:200px;margin-top:2em;text-decoration:underline}cyp-library nav button .icon{width:32px;margin-right:var(--icon-spacing)}cyp-tag{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;padding-left:0;padding-top:0;padding-bottom:0}cyp-tag:not([hidden]){display:flex}cyp-tag:nth-child(odd){background-color:var(--bg-alt)}cyp-tag.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-tag.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-tag>.icon{margin-right:var(--icon-spacing)}cyp-tag .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-tag button:first-of-type{margin-left:auto}cyp-tag button .icon{width:32px}cyp-tag .art{margin-right:var(--icon-spacing);width:64px;height:64px}cyp-back{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-back:not([hidden]){display:flex}cyp-back:nth-child(odd){background-color:var(--bg-alt)}cyp-back.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-back.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-back>.icon{margin-right:var(--icon-spacing)}cyp-back .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-back button:first-of-type{margin-left:auto}cyp-back button .icon{width:32px}cyp-path{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-path:not([hidden]){display:flex}cyp-path:nth-child(odd){background-color:var(--bg-alt)}cyp-path.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-path.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-path>.icon{margin-right:var(--icon-spacing)}cyp-path .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-path button:first-of-type{margin-left:auto}cyp-path button .icon{width:32px}cyp-yt-result{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;cursor:default}cyp-yt-result:not([hidden]){display:flex}cyp-yt-result:nth-child(odd){background-color:var(--bg-alt)}cyp-yt-result.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-yt-result.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-yt-result>.icon{margin-right:var(--icon-spacing)}cyp-yt-result .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-yt-result button:first-of-type{margin-left:auto}cyp-yt-result button .icon{width:32px}cyp-yt-result button .icon{width:var(--icon-size)}cyp-media-handler{display:none} \ No newline at end of file +*,*::before,*::after{box-sizing:inherit}html{background-color:var(--fg)}body{margin:0}main{flex:auto;overflow:auto}header,footer{flex:none;z-index:1;box-shadow:var(--box-shadow)}footer{position:relative;overflow:hidden;height:56px}@media (max-width:480px){footer{height:40px}}input,select{font:inherit}select{color:inherit}option{color:initial}button{color:inherit;font:inherit;-webkit-appearance:none;-moz-appearance:none;appearance:none;flex-direction:row;align-items:center;flex:none;background-color:transparent;padding:0;border:none;line-height:1;cursor:pointer}button:not([hidden]){display:flex}select{background-color:transparent;border:1px solid var(--fg);border-radius:4px;padding:2px 4px}@font-face{font-family:"Lato";src:url("font/LatoLatin-Regular.woff2") format("woff2");font-style:normal;font-weight:normal}@font-face{font-family:"Lato";src:url("font/LatoLatin-Bold.woff2") format("woff2");font-style:normal;font-weight:bold}.icon{width:var(--icon-size);flex:none}.icon path:not([fill]),.icon polygon:not([fill]),.icon circle:not([fill]){fill:currentColor}.flex-row{flex-direction:row;align-items:center}.flex-row:not([hidden]){display:flex}.flex-column{flex-direction:column}.flex-column:not([hidden]){display:flex}.ellipsis{overflow:hidden;text-overflow:ellipsis}.font-large{font-size:18px;line-height:24px}.selectable{cursor:pointer;position:relative}.selectable.selected{color:var(--primary);background-color:var(--primary-tint)}.selectable.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}.item:not([hidden]){display:flex}.item:nth-child(odd){background-color:var(--bg-alt)}.item.selected{color:var(--primary);background-color:var(--primary-tint)}.item.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}.item>.icon{margin-right:var(--icon-spacing)}.item .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}.item button:first-of-type{margin-left:auto}.item button .icon{width:32px}.art{flex:none}.art .icon,.art img{display:block;width:100%}cyp-app{--icon-size:24px;--icon-spacing:4px;--primary:rgb(var(--primary-raw));--primary-tint:rgba(var(--primary-raw), .1);--box-shadow:0 0 3px #000;--border-width:4px}cyp-app[theme=light]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}cyp-app[theme=dark]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}@media (prefers-color-scheme:dark){cyp-app[theme=auto]{--fg:#f0f0f0;--bg:#333;--bg-alt:#444;--text-shadow:0 1px 1px rgba(0,0,0,0.8)}}@media (prefers-color-scheme:light){cyp-app[theme=auto]{--fg:#333;--bg:#f0f0f0;--bg-alt:#e0e0e0;--text-shadow:none}}@media (max-width:640px),(max-height:640px){cyp-app[theme]{--text-shadow:none}}cyp-app[color=dodgerblue]{--primary-raw:30, 144, 255}cyp-app[color=darkorange]{--primary-raw:255, 140, 0}cyp-app[color=limegreen]{--primary-raw:50, 205, 50}cyp-app{flex-direction:column;box-sizing:border-box;margin:0 auto;max-width:800px;height:calc(100px * var(--vh));font-family:lato,sans-serif;font-size:16px;line-height:1.25;background-color:var(--bg);color:var(--fg);white-space:nowrap}cyp-app:not([hidden]){display:flex}cyp-menu,cyp-commands{flex-direction:row;align-items:center;height:100%}cyp-menu:not([hidden]),cyp-commands:not([hidden]){display:flex}cyp-menu button,cyp-commands button{height:100%;flex-direction:column;align-items:center;justify-content:center}cyp-menu button:not([hidden]),cyp-commands button:not([hidden]){display:flex}@media (max-width:480px){cyp-menu button,cyp-commands button{flex-direction:row}cyp-menu button span:not([id]),cyp-commands button span:not([id]){display:none}}cyp-menu button .icon+*,cyp-commands button .icon+*{margin-top:2px}cyp-menu button{flex:1 0 0;border-top:var(--border-width) solid transparent;border-bottom:var(--border-width) solid transparent}cyp-menu button .icon{margin-right:var(--icon-spacing)}cyp-menu button.active{border-top-color:var(--primary);color:var(--primary);background-color:var(--primary-tint)}cyp-commands{position:absolute;left:0;top:0;width:100%;transition:top 300ms;background-color:var(--bg)}cyp-commands[hidden]{display:flex;top:100%}cyp-commands button{flex:0 1 80px}cyp-commands button.last{order:1;margin-left:auto}cyp-song{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-song:not([hidden]){display:flex}cyp-song:nth-child(odd){background-color:var(--bg-alt)}cyp-song.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-song.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-song>.icon{margin-right:var(--icon-spacing)}cyp-song .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-song button:first-of-type{margin-left:auto}cyp-song button .icon{width:32px}cyp-song .multiline{flex-direction:column;min-width:0}cyp-song .multiline:not([hidden]){display:flex}cyp-song .multiline .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-queue cyp-song>.icon{width:32px;margin-right:8px}cyp-queue cyp-song .track{display:none}cyp-queue cyp-song:not(.playing)>.icon-play,cyp-queue cyp-song.playing>.icon-music{display:none}cyp-queue cyp-song.playing>.icon{color:var(--primary)}cyp-queue cyp-song.playing::after{content:"";position:absolute;left:0;bottom:0;background-color:var(--primary);width:calc(100% * var(--progress, 0));height:var(--border-width)}cyp-library cyp-song{padding-left:0;padding-top:0;padding-bottom:0}cyp-library cyp-song>.icon{width:64px}cyp-library cyp-song>.icon-play{display:none}cyp-player{flex-direction:row;align-items:center;align-items:stretch}cyp-player:not([hidden]){display:flex}cyp-player:not([data-state=play]) .pause{display:none}cyp-player[data-state=play] .play{display:none}cyp-player:not([data-flags~=random]) .random,cyp-player:not([data-flags~=repeat]) .repeat{opacity:.5}cyp-player[data-flags~=mute] .mute .icon-volume-high{display:none}cyp-player:not([data-flags~=mute]) .mute .icon-volume-off{display:none}cyp-player x-range{flex:auto;--elapsed-color:var(--primary)}cyp-player .art{width:96px;height:96px}cyp-player .info{flex:auto;min-width:0;flex-direction:column;justify-content:space-between;padding:0 var(--icon-spacing)}cyp-player .info:not([hidden]){display:flex}cyp-player .info .title{margin-top:8px;font-size:18px;line-height:24px;font-weight:bold}cyp-player .info .title,cyp-player .info .subtitle{overflow:hidden;text-overflow:ellipsis}cyp-player .timeline{flex:none;height:var(--icon-size);margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .timeline:not([hidden]){display:flex}cyp-player .timeline .duration,cyp-player .timeline .elapsed{flex:none;width:5ch;text-align:center}cyp-player .controls{width:220px;min-width:0;flex-direction:column}cyp-player .controls:not([hidden]){display:flex}cyp-player .controls .playback{flex:auto;flex-direction:row;align-items:center;justify-content:space-around}cyp-player .controls .playback:not([hidden]){display:flex}cyp-player .controls .playback .icon{width:40px}cyp-player .controls .playback .icon-play,cyp-player .controls .playback .icon-pause{width:64px}cyp-player .controls .volume{flex:none;margin-bottom:4px;flex-direction:row;align-items:center}cyp-player .controls .volume:not([hidden]){display:flex}cyp-player .controls .volume .mute{margin-right:var(--icon-spacing)}cyp-player .misc{flex:none;flex-direction:column;justify-content:space-around}cyp-player .misc:not([hidden]){display:flex}cyp-player .misc .icon{width:32px}@media (max-width:519px){cyp-player{flex-wrap:wrap;justify-content:space-between}cyp-player .info{order:1;flex-basis:100%;height:96px}}cyp-queue .current>.icon{color:var(--primary)}cyp-settings{--spacing:8px;font-size:18px;line-height:24px}cyp-settings dl{margin:var(--spacing);display:grid;grid-template-columns:max-content 1fr;align-items:center;grid-gap:var(--spacing)}cyp-settings dt{font-weight:bold}cyp-settings dd{margin:0;flex-direction:column;align-items:start}cyp-settings dd:not([hidden]){display:flex}cyp-settings label{flex-direction:row;align-items:center}cyp-settings label:not([hidden]){display:flex}cyp-settings label [type=radio],cyp-settings label [type=checkbox]{margin:0 4px 0 0}cyp-yt pre{margin:.5em .5ch;flex-grow:1;overflow:auto;white-space:pre-wrap}x-range{--thumb-size:8px;--thumb-color:#ddd;--thumb-shadow:#000;--thumb-hover-color:#fff;--track-size:4px;--track-color:#888;--track-shadow:#000;--elapsed-color:#ddd;--remaining-color:transparent;--radius:calc(var(--track-size)/2);display:inline-block;position:relative;width:192px;height:16px}x-range .-track,x-range .-elapsed,x-range .-remaining{position:absolute;top:calc(50% - var(--track-size)/2);height:var(--track-size);border-radius:var(--radius)}x-range .-track{width:100%;left:0;background-color:var(--track-color);box-shadow:0 0 1px var(--thumb-shadow)}x-range .-elapsed{left:0;background-color:var(--elapsed-color)}x-range .-remaining{right:0;background-color:var(--remaining-color)}x-range .-inner{position:absolute;left:var(--thumb-size);right:var(--thumb-size);top:0;bottom:0}x-range .-thumb{all:unset;position:absolute;top:50%;transform:translate(-50%, -50%);border-radius:50%;width:calc(2*var(--thumb-size));height:calc(2*var(--thumb-size));background-color:var(--thumb-color);box-shadow:0 0 2px var(--thumb-shadow)}x-range[disabled]{opacity:.5}x-range:not([disabled]) .-thumb:hover{background-color:var(--thumb-hover-color)}cyp-playlist{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-playlist:not([hidden]){display:flex}cyp-playlist:nth-child(odd){background-color:var(--bg-alt)}cyp-playlist.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-playlist.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-playlist>.icon{margin-right:var(--icon-spacing)}cyp-playlist .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-playlist button:first-of-type{margin-left:auto}cyp-playlist button .icon{width:32px}cyp-search form{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;align-items:stretch}cyp-search form:not([hidden]){display:flex}cyp-search form:nth-child(odd){background-color:var(--bg-alt)}cyp-search form.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-search form.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-search form>.icon{margin-right:var(--icon-spacing)}cyp-search form .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-search form button:first-of-type{margin-left:auto}cyp-search form button .icon{width:32px}cyp-search form button:first-of-type{margin-left:var(--icon-spacing)}cyp-search.pending form{background-image:linear-gradient(var(--primary), var(--primary));background-repeat:no-repeat;background-size:25% var(--border-width);animation:bar ease-in-out 3s alternate infinite}@keyframes bar{0%{background-position:0 100%}100%{background-position:100% 100%}}cyp-filter{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-filter:not([hidden]){display:flex}cyp-filter:nth-child(odd){background-color:var(--bg-alt)}cyp-filter.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-filter.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-filter>.icon{margin-right:var(--icon-spacing)}cyp-filter .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-filter button:first-of-type{margin-left:auto}cyp-filter button .icon{width:32px}cyp-filter .icon{width:32px;margin-left:var(--icon-spacing)}cyp-library nav{flex-direction:column;align-items:center}cyp-library nav:not([hidden]){display:flex}cyp-library nav button{font-size:18px;line-height:24px;width:200px;margin-top:2em;text-decoration:underline}cyp-library nav button .icon{width:32px;margin-right:var(--icon-spacing)}cyp-tag{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;padding-left:0;padding-top:0;padding-bottom:0}cyp-tag:not([hidden]){display:flex}cyp-tag:nth-child(odd){background-color:var(--bg-alt)}cyp-tag.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-tag.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-tag>.icon{margin-right:var(--icon-spacing)}cyp-tag .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-tag button:first-of-type{margin-left:auto}cyp-tag button .icon{width:32px}cyp-tag .art{margin-right:var(--icon-spacing);width:64px;height:64px}cyp-back{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-back:not([hidden]){display:flex}cyp-back:nth-child(odd){background-color:var(--bg-alt)}cyp-back.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-back.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-back>.icon{margin-right:var(--icon-spacing)}cyp-back .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-back button:first-of-type{margin-left:auto}cyp-back button .icon{width:32px}cyp-path{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px}cyp-path:not([hidden]){display:flex}cyp-path:nth-child(odd){background-color:var(--bg-alt)}cyp-path.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-path.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-path>.icon{margin-right:var(--icon-spacing)}cyp-path .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-path button:first-of-type{margin-left:auto}cyp-path button .icon{width:32px}cyp-yt-result{flex-direction:row;align-items:center;cursor:pointer;position:relative;padding:8px;cursor:default}cyp-yt-result:not([hidden]){display:flex}cyp-yt-result:nth-child(odd){background-color:var(--bg-alt)}cyp-yt-result.selected{color:var(--primary);background-color:var(--primary-tint)}cyp-yt-result.selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--border-width);background-color:var(--primary)}cyp-yt-result>.icon{margin-right:var(--icon-spacing)}cyp-yt-result .title{font-size:18px;line-height:24px;overflow:hidden;text-overflow:ellipsis;font-weight:bold;min-width:0}cyp-yt-result button:first-of-type{margin-left:auto}cyp-yt-result button .icon{width:32px}cyp-yt-result button .icon{width:var(--icon-size)} \ No newline at end of file diff --git a/app/cyp.js b/app/cyp.js index 833ec86..1811442 100644 --- a/app/cyp.js +++ b/app/cyp.js @@ -587,6 +587,9 @@ class App extends HTMLElement { await this._connect(); this.dispatchEvent(new CustomEvent("load")); + + this.mediaSessionInit = false; + this._initMediaHandler(); } attributeChangedCallback(name, oldValue, newValue) { @@ -628,6 +631,49 @@ class App extends HTMLElement { } alert(`Failed to connect to MPD after ${attempts} attempts. Please reload the page to try again.`); } + + _initMediaHandler() { + // check support mediaSession + if (!('mediaSession' in navigator)) { + console.log('mediaSession is not supported'); + return; + } + + // DOM (using media session controls are allowed only if there is audio/video tag) + const audio = node("audio", {loop: true}, "", this); + node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); + + // Init event session (play audio) on click (because restrictions by web browsers) + window.addEventListener('click', () => { + if (!this.mediaSessionInit) { + audio.play(); + this.mediaSessionInit = true; + } + }); + + // mediaSession define metadata + navigator.mediaSession.metadata = new MediaMetadata({ + title: 'Control Your Player' + }); + + // mediaSession define action handlers + navigator.mediaSession.setActionHandler('play', () => { + this.mpd.command("play"); + audio.play(); + }); + navigator.mediaSession.setActionHandler('pause', () => { + this.mpd.command("pause 1"); + audio.pause(); + }); + navigator.mediaSession.setActionHandler('previoustrack', () => { + this.mpd.command("previous"); + audio.play(); + }); + navigator.mediaSession.setActionHandler('nexttrack', () => { + this.mpd.command("next"); + audio.play(); + }); + } } customElements.define("cyp-app", App); @@ -1867,55 +1913,6 @@ class Library extends Component { customElements.define("cyp-library", Library); -class MediaHandler extends Component { - connectedCallback() { - // check support mediaSession - if (!('mediaSession' in navigator)) { - console.log('mediaSession is not supported'); - return; - } - - // DOM - const audio = node("audio", {loop: true}, "", this); - node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); - - // Init event session (play audio) on click (because restrictions by web browsers) - let mediaSessionInit = false; - window.addEventListener('click', () => { - if (!mediaSessionInit) { - audio.play(); - mediaSessionInit = true; - } - }); - - // mediaSession define metadata - navigator.mediaSession.metadata = new MediaMetadata({ - title: 'Control Your Player' - }); - - // mediaSession define action handlers - const that = this; - navigator.mediaSession.setActionHandler('play', function() { - that._mpd.command("play"); - audio.play(); - }); - navigator.mediaSession.setActionHandler('pause', function() { - that._mpd.command("pause 1"); - audio.pause(); - }); - navigator.mediaSession.setActionHandler('previoustrack', function() { - that._mpd.command("previous"); - audio.play(); - }); - navigator.mediaSession.setActionHandler('nexttrack', function() { - that._mpd.command("next"); - audio.play(); - }); - } -} - -customElements.define("cyp-media-handler", MediaHandler); - function updateSize() { document.body.style.setProperty("--vh", window.innerHeight/100); } diff --git a/app/index.html b/app/index.html index 6986754..4e9eadc 100644 --- a/app/index.html +++ b/app/index.html @@ -96,7 +96,6 @@ - diff --git a/app/js/cyp.js b/app/js/cyp.js index 9158d15..a1070f7 100644 --- a/app/js/cyp.js +++ b/app/js/cyp.js @@ -11,7 +11,6 @@ import "./elements/library.js"; import "./elements/tag.js"; import "./elements/back.js"; import "./elements/path.js"; -import "./elements/media-handler.js"; function updateSize() { document.body.style.setProperty("--vh", window.innerHeight/100); diff --git a/app/js/elements/app.js b/app/js/elements/app.js index 87382d0..c0f7d4b 100644 --- a/app/js/elements/app.js +++ b/app/js/elements/app.js @@ -26,6 +26,9 @@ class App extends HTMLElement { await this._connect(); this.dispatchEvent(new CustomEvent("load")); + + this.mediaSessionInit = false; + this._initMediaHandler(); } attributeChangedCallback(name, oldValue, newValue) { @@ -67,6 +70,49 @@ class App extends HTMLElement { } alert(`Failed to connect to MPD after ${attempts} attempts. Please reload the page to try again.`); } + + _initMediaHandler() { + // check support mediaSession + if (!('mediaSession' in navigator)) { + console.log('mediaSession is not supported'); + return; + } + + // DOM (using media session controls are allowed only if there is audio/video tag) + const audio = html.node("audio", {loop: true}, "", this); + html.node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); + + // Init event session (play audio) on click (because restrictions by web browsers) + window.addEventListener('click', () => { + if (!this.mediaSessionInit) { + audio.play(); + this.mediaSessionInit = true; + } + }); + + // mediaSession define metadata + navigator.mediaSession.metadata = new MediaMetadata({ + title: 'Control Your Player' + }); + + // mediaSession define action handlers + navigator.mediaSession.setActionHandler('play', () => { + this.mpd.command("play") + audio.play() + }); + navigator.mediaSession.setActionHandler('pause', () => { + this.mpd.command("pause 1") + audio.pause() + }); + navigator.mediaSession.setActionHandler('previoustrack', () => { + this.mpd.command("previous") + audio.play() + }); + navigator.mediaSession.setActionHandler('nexttrack', () => { + this.mpd.command("next") + audio.play() + }); + } } customElements.define("cyp-app", App); @@ -81,4 +127,4 @@ function waitForChildren(app) { const promises = [...unique].map(name => customElements.whenDefined(name)); return Promise.all(promises); -} \ No newline at end of file +} diff --git a/app/js/elements/media-handler.js b/app/js/elements/media-handler.js deleted file mode 100644 index 3cadf0a..0000000 --- a/app/js/elements/media-handler.js +++ /dev/null @@ -1,51 +0,0 @@ -import Component from "../component.js"; -import * as html from "../html.js"; - -class MediaHandler extends Component { - connectedCallback() { - // check support mediaSession - if (!('mediaSession' in navigator)) { - console.log('mediaSession is not supported'); - return; - } - - // DOM (using media session controls are allowed only if there is audio/video tag) - const audio = html.node("audio", {loop: true}, "", this); - html.node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); - - // Init event session (play audio) on click (because restrictions by web browsers) - let mediaSessionInit = false; - window.addEventListener('click', () => { - if (!mediaSessionInit) { - audio.play(); - mediaSessionInit = true; - } - }); - - // mediaSession define metadata - navigator.mediaSession.metadata = new MediaMetadata({ - title: 'Control Your Player' - }); - - // mediaSession define action handlers - const that = this; - navigator.mediaSession.setActionHandler('play', function() { - that._mpd.command("play") - audio.play() - }); - navigator.mediaSession.setActionHandler('pause', function() { - that._mpd.command("pause 1") - audio.pause() - }); - navigator.mediaSession.setActionHandler('previoustrack', function() { - that._mpd.command("previous") - audio.play() - }); - navigator.mediaSession.setActionHandler('nexttrack', function() { - that._mpd.command("next") - audio.play() - }); - } -} - -customElements.define("cyp-media-handler", MediaHandler); From cb3224592d914a08038d3bf7b790c9a8e4b03f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Li=C5=A1ka?= Date: Wed, 23 Sep 2020 10:32:43 +0200 Subject: [PATCH 3/4] Refactoring mediaSessionInit variable --- app/js/elements/app.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/js/elements/app.js b/app/js/elements/app.js index c0f7d4b..aed9997 100644 --- a/app/js/elements/app.js +++ b/app/js/elements/app.js @@ -27,7 +27,6 @@ class App extends HTMLElement { await this._connect(); this.dispatchEvent(new CustomEvent("load")); - this.mediaSessionInit = false; this._initMediaHandler(); } @@ -83,11 +82,11 @@ class App extends HTMLElement { html.node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); // Init event session (play audio) on click (because restrictions by web browsers) + let mediaSessionInit = false; window.addEventListener('click', () => { - if (!this.mediaSessionInit) { + if (mediaSessionInit) return; + mediaSessionInit = true; audio.play(); - this.mediaSessionInit = true; - } }); // mediaSession define metadata From a99621c24f95a55858e3393e0e6c3246b78a3fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Li=C5=A1ka?= Date: Wed, 23 Sep 2020 10:35:15 +0200 Subject: [PATCH 4/4] Refactoring mediaSessionInit variable (part 2) --- app/cyp.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/cyp.js b/app/cyp.js index 1811442..ac66206 100644 --- a/app/cyp.js +++ b/app/cyp.js @@ -588,7 +588,6 @@ class App extends HTMLElement { await this._connect(); this.dispatchEvent(new CustomEvent("load")); - this.mediaSessionInit = false; this._initMediaHandler(); } @@ -644,11 +643,11 @@ class App extends HTMLElement { node("source", {src: 'https://raw.githubusercontent.com/anars/blank-audio/master/10-seconds-of-silence.mp3'}, '', audio); // Init event session (play audio) on click (because restrictions by web browsers) + let mediaSessionInit = false; window.addEventListener('click', () => { - if (!this.mediaSessionInit) { + if (mediaSessionInit) return; + mediaSessionInit = true; audio.play(); - this.mediaSessionInit = true; - } }); // mediaSession define metadata