[vlc-devel] [PATCH 15/15] http: add new routes & components
David Loiret
loiret.d at gmail.com
Tue Jun 23 14:42:50 CEST 2020
---
share/Makefile.am | 48 +
share/lua/http/body.html | 14 +-
share/lua/http/head.html | 2 +-
share/lua/http/index.html | 1064 +++++++++++++++--
.../album-item/album-item-grid.component.html | 20 +
.../album-item/album-item-grid.component.js | 20 +
.../album-item/album-item-list.component.html | 27 +
.../album-item/album-item-list.component.js | 16 +
.../album-item/album-item.component.scss | 17 +
.../components/albums/albums.component.html | 63 +
.../src/components/albums/albums.component.js | 41 +
.../components/albums/albums.component.scss | 23 +
.../artist-item-grid.component.html | 15 +
.../artist-item/artist-item-grid.component.js | 12 +
.../artist-item-grid.component.scss | 17 +
.../components/artists/artists.component.html | 10 +
.../components/artists/artists.component.js | 25 +
.../detail/artists-detail.component.html | 21 +
.../detail/artists-detail.component.js | 25 +
.../detail/artists-detail.component.scss | 59 +
.../continue-watching.component.html | 11 +
.../continue-watching.component.js | 13 +
.../controls/filebrowser.component.html | 18 -
.../controls/filebrowser.component.js | 83 --
.../controls/sidenav.component.html | 31 -
.../components/controls/sidenav.component.js | 26 -
.../controls/sidenav.component.scss | 50 -
.../enqueue-button.component.html | 5 +
.../enqueue-button.component.js | 14 +
.../enqueue-button.component.scss | 4 +
.../equalizer/equalizer.component.html | 2 +-
.../genre-item/genre-item-grid.component.html | 12 +
.../genre-item/genre-item-grid.component.js | 16 +
.../components/genres/genres.component.html | 10 +
.../src/components/genres/genres.component.js | 25 +
.../grid-item/grid-item.component.html | 14 +
.../grid-item/grid-item.component.js | 5 +
.../item-layout-button.component.html | 6 +
.../item-layout-button.component.js | 16 +
.../library-item/library-item.component.html | 11 +
.../library-item/library-item.component.js | 15 +
.../library-item/library-item.component.scss | 26 +
.../components/library/library.component.html | 17 +
.../components/library/library.component.js | 5 +
.../components/library/library.component.scss | 3 +
.../media-player/media-player.component.html | 66 +
.../media-player/media-player.component.js | 268 +++++
.../media-player/media-player.component.scss | 133 +++
.../play-button-secondary.component.html | 5 +
.../play-button-secondary.component.js | 15 +
.../play-button-secondary.component.scss | 12 +
.../play-button/play-button.component.html | 5 +
.../play-button/play-button.component.js | 16 +
.../play-button/play-button.component.scss | 28 +
.../components/player/player.component.scss | 19 -
.../components/player/plyr.lib.custom.scss | 758 ------------
.../src/components/player/plyr.lib.vars.scss | 71 --
.../src/components/player/plyr.methods.js | 41 -
.../playlist/buttons.playlist.component.html | 18 +-
.../playlist/buttons.playlist.component.js | 39 +-
.../playlist/buttons.playlist.component.scss | 10 +
.../playlist-audio-item.component.html | 27 +
.../playlist/playlist-audio-item.component.js | 23 +
.../playlist-audio-item.component.scss | 24 +
.../playlist-video-item.component.html | 25 +
.../playlist/playlist-video-item.component.js | 31 +
.../playlist-video-item.component.scss | 24 +
.../playlist/playlist.component.html | 36 +-
.../components/playlist/playlist.component.js | 108 +-
.../playlist/playlist.component.scss | 63 +-
.../playlists-item.component.html | 28 +
.../playlists-item.component.js | 7 +
.../playlists-item.component.scss | 10 +
.../playlists/playlists.component.html | 13 +
.../playlists/playlists.component.js | 19 +
.../sot/stream.manager.component.html | 2 +-
.../svg-icon/svg-icon.component.scss | 4 +-
.../tracksync.component.html | 2 +-
.../track-item-table.component.html | 28 +
.../track-item/track-item-table.component.js | 16 +
.../components/tracks/tracks.component.html | 25 +
.../src/components/tracks/tracks.component.js | 22 +
.../video-item/video-item-grid.component.html | 33 +
.../video-item/video-item-grid.component.js | 9 +
.../video-item/video-item-list.component.html | 20 +
.../video-item/video-item-list.component.js | 9 +
.../video-item-poster.component.html | 27 +
.../video-item/video-item-poster.component.js | 4 +
.../components/videos/videos.component.html | 90 ++
.../src/components/videos/videos.component.js | 22 +
.../src/components/vlm/vlm.component.html | 4 +-
.../http/src/components/vlm/vlm.component.js | 10 +-
.../routes/browse/browse-view.component.html | 51 +
.../routes/browse/browse-view.component.js | 19 +
.../routes/browse/browse-view.component.scss | 3 +
.../discover/discover-view.component.html | 37 +
.../discover/discover-view.component.js | 5 +
.../home/discover-home-view.component.html | 4 +
.../home/discover-home-view.component.js | 5 +
.../discover-services-view.component.html | 15 +
.../discover-services-view.component.js | 49 +
.../discover-services-view.component.scss | 33 +
.../discover-services-tv-view.component.html | 10 +
.../tv/discover-services-tv-view.component.js | 11 +
.../url/discover-url-view.component.html | 4 +
.../url/discover-url-view.component.js | 5 +
.../src/routes/main/main-view.component.html | 3 +
.../src/routes/main/main-view.component.js | 5 +
.../albums/music-albums-view.component.html | 5 +
.../albums/music-albums-view.component.js | 6 +
.../music-artists-detail-view.component.html | 5 +
.../music-artists-detail-view.component.js | 5 +
.../artists/music-artists-view.component.html | 5 +
.../artists/music-artists-view.component.js | 5 +
.../genres/music-genres-view.component.html | 5 +
.../genres/music-genres-view.component.js | 5 +
.../routes/music/music-view.component.html | 39 +
.../src/routes/music/music-view.component.js | 7 +
.../music-playlists-view.component.html | 5 +
.../music-playlists-view.component.js | 5 +
.../tracks/music-tracks-view.component.html | 5 +
.../tracks/music-tracks-view.component.js | 5 +
.../network/network-view.component.html | 31 +
.../routes/network/network-view.component.js | 4 +
.../video/all/video-all-view.component.html | 6 +
.../video/all/video-all-view.component.js | 5 +
.../movies/video-movies-view.component.html | 3 +
.../movies/video-movies-view.component.js | 5 +
.../video-playlists-view.component.html | 3 +
.../video-playlists-view.component.js | 5 +
.../tvshows/video-tvshows-view.component.html | 3 +
.../tvshows/video-tvshows-view.component.js | 5 +
.../routes/video/video-view.component.html | 38 +
.../src/routes/video/video-view.component.js | 7 +
.../routes/watch/watch-view.component.html | 36 +
.../src/routes/watch/watch-view.component.js | 7 +
share/lua/http/src/scss/components.scss | 16 +
.../http/src/services/initialize.service.js | 207 +++-
138 files changed, 3534 insertions(+), 1459 deletions(-)
create mode 100644 share/lua/http/src/components/albums/album-item/album-item-grid.component.html
create mode 100644 share/lua/http/src/components/albums/album-item/album-item-grid.component.js
create mode 100644 share/lua/http/src/components/albums/album-item/album-item-list.component.html
create mode 100644 share/lua/http/src/components/albums/album-item/album-item-list.component.js
create mode 100644 share/lua/http/src/components/albums/album-item/album-item.component.scss
create mode 100644 share/lua/http/src/components/albums/albums.component.html
create mode 100644 share/lua/http/src/components/albums/albums.component.js
create mode 100644 share/lua/http/src/components/albums/albums.component.scss
create mode 100644 share/lua/http/src/components/artists/artist-item/artist-item-grid.component.html
create mode 100644 share/lua/http/src/components/artists/artist-item/artist-item-grid.component.js
create mode 100644 share/lua/http/src/components/artists/artist-item/artist-item-grid.component.scss
create mode 100644 share/lua/http/src/components/artists/artists.component.html
create mode 100644 share/lua/http/src/components/artists/artists.component.js
create mode 100644 share/lua/http/src/components/artists/detail/artists-detail.component.html
create mode 100644 share/lua/http/src/components/artists/detail/artists-detail.component.js
create mode 100644 share/lua/http/src/components/artists/detail/artists-detail.component.scss
create mode 100644 share/lua/http/src/components/continue-watching/continue-watching.component.html
create mode 100644 share/lua/http/src/components/continue-watching/continue-watching.component.js
delete mode 100644 share/lua/http/src/components/controls/filebrowser.component.html
delete mode 100644 share/lua/http/src/components/controls/filebrowser.component.js
delete mode 100644 share/lua/http/src/components/controls/sidenav.component.html
delete mode 100644 share/lua/http/src/components/controls/sidenav.component.js
delete mode 100644 share/lua/http/src/components/controls/sidenav.component.scss
create mode 100644 share/lua/http/src/components/enqueue-button/enqueue-button.component.html
create mode 100644 share/lua/http/src/components/enqueue-button/enqueue-button.component.js
create mode 100644 share/lua/http/src/components/enqueue-button/enqueue-button.component.scss
create mode 100644 share/lua/http/src/components/genres/genre-item/genre-item-grid.component.html
create mode 100644 share/lua/http/src/components/genres/genre-item/genre-item-grid.component.js
create mode 100644 share/lua/http/src/components/genres/genres.component.html
create mode 100644 share/lua/http/src/components/genres/genres.component.js
create mode 100644 share/lua/http/src/components/grid-item/grid-item.component.html
create mode 100644 share/lua/http/src/components/grid-item/grid-item.component.js
create mode 100644 share/lua/http/src/components/item-layout-button/item-layout-button.component.html
create mode 100644 share/lua/http/src/components/item-layout-button/item-layout-button.component.js
create mode 100644 share/lua/http/src/components/library/library-item/library-item.component.html
create mode 100644 share/lua/http/src/components/library/library-item/library-item.component.js
create mode 100644 share/lua/http/src/components/library/library-item/library-item.component.scss
create mode 100644 share/lua/http/src/components/library/library.component.html
create mode 100644 share/lua/http/src/components/library/library.component.js
create mode 100644 share/lua/http/src/components/library/library.component.scss
create mode 100644 share/lua/http/src/components/media-player/media-player.component.html
create mode 100644 share/lua/http/src/components/media-player/media-player.component.js
create mode 100644 share/lua/http/src/components/media-player/media-player.component.scss
create mode 100644 share/lua/http/src/components/play-button/play-button-secondary.component.html
create mode 100644 share/lua/http/src/components/play-button/play-button-secondary.component.js
create mode 100644 share/lua/http/src/components/play-button/play-button-secondary.component.scss
create mode 100644 share/lua/http/src/components/play-button/play-button.component.html
create mode 100644 share/lua/http/src/components/play-button/play-button.component.js
create mode 100644 share/lua/http/src/components/play-button/play-button.component.scss
delete mode 100644 share/lua/http/src/components/player/player.component.scss
delete mode 100644 share/lua/http/src/components/player/plyr.lib.custom.scss
delete mode 100644 share/lua/http/src/components/player/plyr.lib.vars.scss
delete mode 100644 share/lua/http/src/components/player/plyr.methods.js
create mode 100644 share/lua/http/src/components/playlist/buttons.playlist.component.scss
create mode 100644 share/lua/http/src/components/playlist/playlist-audio-item.component.html
create mode 100644 share/lua/http/src/components/playlist/playlist-audio-item.component.js
create mode 100644 share/lua/http/src/components/playlist/playlist-audio-item.component.scss
create mode 100644 share/lua/http/src/components/playlist/playlist-video-item.component.html
create mode 100644 share/lua/http/src/components/playlist/playlist-video-item.component.js
create mode 100644 share/lua/http/src/components/playlist/playlist-video-item.component.scss
create mode 100644 share/lua/http/src/components/playlists/playlists-item/playlists-item.component.html
create mode 100644 share/lua/http/src/components/playlists/playlists-item/playlists-item.component.js
create mode 100644 share/lua/http/src/components/playlists/playlists-item/playlists-item.component.scss
create mode 100644 share/lua/http/src/components/playlists/playlists.component.html
create mode 100644 share/lua/http/src/components/playlists/playlists.component.js
create mode 100644 share/lua/http/src/components/tracks/track-item/track-item-table.component.html
create mode 100644 share/lua/http/src/components/tracks/track-item/track-item-table.component.js
create mode 100644 share/lua/http/src/components/tracks/tracks.component.html
create mode 100644 share/lua/http/src/components/tracks/tracks.component.js
create mode 100644 share/lua/http/src/components/videos/video-item/video-item-grid.component.html
create mode 100644 share/lua/http/src/components/videos/video-item/video-item-grid.component.js
create mode 100644 share/lua/http/src/components/videos/video-item/video-item-list.component.html
create mode 100644 share/lua/http/src/components/videos/video-item/video-item-list.component.js
create mode 100644 share/lua/http/src/components/videos/video-item/video-item-poster.component.html
create mode 100644 share/lua/http/src/components/videos/video-item/video-item-poster.component.js
create mode 100644 share/lua/http/src/components/videos/videos.component.html
create mode 100644 share/lua/http/src/components/videos/videos.component.js
create mode 100644 share/lua/http/src/routes/browse/browse-view.component.html
create mode 100644 share/lua/http/src/routes/browse/browse-view.component.js
create mode 100644 share/lua/http/src/routes/browse/browse-view.component.scss
create mode 100644 share/lua/http/src/routes/discover/discover-view.component.html
create mode 100644 share/lua/http/src/routes/discover/discover-view.component.js
create mode 100644 share/lua/http/src/routes/discover/home/discover-home-view.component.html
create mode 100644 share/lua/http/src/routes/discover/home/discover-home-view.component.js
create mode 100644 share/lua/http/src/routes/discover/services/discover-services-view.component.html
create mode 100644 share/lua/http/src/routes/discover/services/discover-services-view.component.js
create mode 100644 share/lua/http/src/routes/discover/services/discover-services-view.component.scss
create mode 100644 share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.html
create mode 100644 share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.js
create mode 100644 share/lua/http/src/routes/discover/url/discover-url-view.component.html
create mode 100644 share/lua/http/src/routes/discover/url/discover-url-view.component.js
create mode 100644 share/lua/http/src/routes/main/main-view.component.html
create mode 100644 share/lua/http/src/routes/main/main-view.component.js
create mode 100644 share/lua/http/src/routes/music/albums/music-albums-view.component.html
create mode 100644 share/lua/http/src/routes/music/albums/music-albums-view.component.js
create mode 100644 share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.html
create mode 100644 share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.js
create mode 100644 share/lua/http/src/routes/music/artists/music-artists-view.component.html
create mode 100644 share/lua/http/src/routes/music/artists/music-artists-view.component.js
create mode 100644 share/lua/http/src/routes/music/genres/music-genres-view.component.html
create mode 100644 share/lua/http/src/routes/music/genres/music-genres-view.component.js
create mode 100644 share/lua/http/src/routes/music/music-view.component.html
create mode 100644 share/lua/http/src/routes/music/music-view.component.js
create mode 100644 share/lua/http/src/routes/music/playlists/music-playlists-view.component.html
create mode 100644 share/lua/http/src/routes/music/playlists/music-playlists-view.component.js
create mode 100644 share/lua/http/src/routes/music/tracks/music-tracks-view.component.html
create mode 100644 share/lua/http/src/routes/music/tracks/music-tracks-view.component.js
create mode 100644 share/lua/http/src/routes/network/network-view.component.html
create mode 100644 share/lua/http/src/routes/network/network-view.component.js
create mode 100644 share/lua/http/src/routes/video/all/video-all-view.component.html
create mode 100644 share/lua/http/src/routes/video/all/video-all-view.component.js
create mode 100644 share/lua/http/src/routes/video/movies/video-movies-view.component.html
create mode 100644 share/lua/http/src/routes/video/movies/video-movies-view.component.js
create mode 100644 share/lua/http/src/routes/video/playlists/video-playlists-view.component.html
create mode 100644 share/lua/http/src/routes/video/playlists/video-playlists-view.component.js
create mode 100644 share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.html
create mode 100644 share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.js
create mode 100644 share/lua/http/src/routes/video/video-view.component.html
create mode 100644 share/lua/http/src/routes/video/video-view.component.js
create mode 100644 share/lua/http/src/routes/watch/watch-view.component.html
create mode 100644 share/lua/http/src/routes/watch/watch-view.component.js
diff --git a/share/Makefile.am b/share/Makefile.am
index d74bb86f19..b591b70baf 100644
--- a/share/Makefile.am
+++ b/share/Makefile.am
@@ -20,13 +20,61 @@ JS_TARGETS = --js $(srcdir)/lua/http/src/services/initialize.service.js \
--js $(srcdir)/lua/http/src/store/modules/playlist.js \
--js $(srcdir)/lua/http/src/store/modules/status.js \
--js $(srcdir)/lua/http/src/store/modules/vlm_cmd.js \
+--js $(srcdir)/lua/http/src/components/albums/album-item/album-item-grid.component.js \
+--js $(srcdir)/lua/http/src/components/albums/album-item/album-item-list.component.js \
+--js $(srcdir)/lua/http/src/components/artists/artist-item/artist-item-grid.component.js \
+--js $(srcdir)/lua/http/src/components/albums/albums.component.js \
+--js $(srcdir)/lua/http/src/components/artists/artists.component.js \
+--js $(srcdir)/lua/http/src/components/artists/detail/artists-detail.component.js \
+--js $(srcdir)/lua/http/src/components/continue-watching/continue-watching.component.js \
--js $(srcdir)/lua/http/src/components/playlist/playlist.component.js \
+--js $(srcdir)/lua/http/src/components/playlist/playlist-video-item.component.js \
+--js $(srcdir)/lua/http/src/components/playlist/playlist-audio-item.component.js \
--js $(srcdir)/lua/http/src/components/playlist/buttons.playlist.component.js \
+--js $(srcdir)/lua/http/src/components/playlists/playlists.component.js \
+--js $(srcdir)/lua/http/src/components/playlists/playlists-item/playlists-item.component.js \
--js $(srcdir)/lua/http/src/components/vlm/vlm.component.js \
--js $(srcdir)/lua/http/src/components/equalizer/equalizer.component.js \
+--js $(srcdir)/lua/http/src/components/genres/genres.component.js \
+--js $(srcdir)/lua/http/src/components/grid-item/grid-item.component.js \
+--js $(srcdir)/lua/http/src/components/item-layout-button/item-layout-button.component.js \
+--js $(srcdir)/lua/http/src/components/genres/genre-item/genre-item-grid.component.js \
+--js $(srcdir)/lua/http/src/components/library/library.component.js \
+--js $(srcdir)/lua/http/src/components/library/library-item/library-item.component.js \
+--js $(srcdir)/lua/http/src/components/media-player/media-player.component.js \
+--js $(srcdir)/lua/http/src/components/enqueue-button/enqueue-button.component.js \
+--js $(srcdir)/lua/http/src/components/play-button/play-button-secondary.component.js \
+--js $(srcdir)/lua/http/src/components/play-button/play-button.component.js \
+--js $(srcdir)/lua/http/src/routes/main/main-view.component.js \
+--js $(srcdir)/lua/http/src/routes/browse/browse-view.component.js \
+--js $(srcdir)/lua/http/src/routes/discover/discover-view.component.js \
+--js $(srcdir)/lua/http/src/routes/discover/home/discover-home-view.component.js \
+--js $(srcdir)/lua/http/src/routes/discover/services/discover-services-view.component.js \
+--js $(srcdir)/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.js \
+--js $(srcdir)/lua/http/src/routes/discover/url/discover-url-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/music-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/albums/music-albums-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/artists/music-artists-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/genres/music-genres-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/tracks/music-tracks-view.component.js \
+--js $(srcdir)/lua/http/src/routes/music/playlists/music-playlists-view.component.js \
+--js $(srcdir)/lua/http/src/routes/network/network-view.component.js \
+--js $(srcdir)/lua/http/src/routes/video/video-view.component.js \
+--js $(srcdir)/lua/http/src/routes/video/all/video-all-view.component.js \
+--js $(srcdir)/lua/http/src/routes/video/movies/video-movies-view.component.js \
+--js $(srcdir)/lua/http/src/routes/video/tvshows/video-tvshows-view.component.js \
+--js $(srcdir)/lua/http/src/routes/video/playlists/video-playlists-view.component.js \
+--js $(srcdir)/lua/http/src/routes/watch/watch-view.component.js \
--js $(srcdir)/lua/http/src/components/track-synchronisation/tracksync.component.js \
--js $(srcdir)/lua/http/src/components/sot/stream.manager.component.js \
--js $(srcdir)/lua/http/src/components/svg-icon/svg-icon.component.js \
+--js $(srcdir)/lua/http/src/components/tracks/tracks.component.js \
+--js $(srcdir)/lua/http/src/components/videos/video-item/video-item-grid.component.js \
+--js $(srcdir)/lua/http/src/components/videos/video-item/video-item-list.component.js \
+--js $(srcdir)/lua/http/src/components/videos/video-item/video-item-poster.component.js \
+--js $(srcdir)/lua/http/src/components/videos/videos.component.js \
+--js $(srcdir)/lua/http/src/components/tracks/track-item/track-item-table.component.js \
--js $(srcdir)/lua/http/src/assets/compiled-icons/*.js \
--js_output_file $(srcdir)/lua/http/dist/js/script.min.js
diff --git a/share/lua/http/body.html b/share/lua/http/body.html
index 908104d101..9f3667534f 100644
--- a/share/lua/http/body.html
+++ b/share/lua/http/body.html
@@ -1,18 +1,12 @@
<body>
<div id="app">
- <sidenav></sidenav>
-
- <playlist></playlist>
-
+ <!-- <sidenav></sidenav> -->
+ <main-view></main-view>
<!-- Modals -->
<div id="vlmModal" class="modal fade" role="dialog">
<vlm-modal></vlm-modal>
</div>
- <div id="fileModal" class="modal fade" role="dialog">
- <file-modal></file-modal>
- </div>
-
<div id="equalizerModal" class="modal fade" role="dialog">
<equalizer-modal></equalizer-modal>
</div>
@@ -25,8 +19,4 @@
<stream-manager-modal></stream-manager-modal>
</div>
</div>
-
- <div id="videoPlayer">
- <video></video>
- </div>
</body>
diff --git a/share/lua/http/head.html b/share/lua/http/head.html
index cb2f8e4e0d..9babc62bdf 100644
--- a/share/lua/http/head.html
+++ b/share/lua/http/head.html
@@ -10,7 +10,7 @@
<link rel="icon" type="image/png" href="dist/assets/favicons/16.png" sizes="16x16"/>
<link rel="icon" type="image/x-icon" href="dist/assets/favicons/favicon.ico"/>
<link rel="stylesheet" href="dist/css/vendors.min.css">
- <link rel="stylesheet" href="dist/css/style.min.css">
+ <link rel="stylesheet" href="dist/css/style.css">
<script src="dist/js/vendors.min.js"></script>
<script src="dist/js/script.min.js"></script>
</head>
diff --git a/share/lua/http/index.html b/share/lua/http/index.html
index 69c2438938..e54fdab9cd 100644
--- a/share/lua/http/index.html
+++ b/share/lua/http/index.html
@@ -4,28 +4,25 @@
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1">
<title>VLC media player - Web Interface</title>
- <link href="favicon.ico" type="image/x-icon" rel="shortcut icon" />
+ <link rel="apple-touch-icon" sizes="180x180" href="dist/assets/favicons/apple-touch-icon.png">
+ <link rel="apple-touch-icon-precomposed" sizes="180x180" href="dist/assets/favicons/apple-touch-icon.png">
+ <link rel="icon" type="image/png" href="dist/assets/favicons/32.png" sizes="32x32"/>
+ <link rel="icon" type="image/png" href="dist/assets/favicons/16.png" sizes="16x16"/>
+ <link rel="icon" type="image/x-icon" href="dist/assets/favicons/favicon.ico"/>
<link rel="stylesheet" href="dist/css/vendors.min.css">
- <link rel="stylesheet" href="dist/css/style.min.css">
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
+ <link rel="stylesheet" href="dist/css/style.css">
<script src="dist/js/vendors.min.js"></script>
<script src="dist/js/script.min.js"></script>
</head>
<body>
<div id="app">
- <sidenav></sidenav>
-
- <playlist></playlist>
-
+ <!-- <sidenav></sidenav> -->
+ <main-view></main-view>
<!-- Modals -->
<div id="vlmModal" class="modal fade" role="dialog">
<vlm-modal></vlm-modal>
</div>
- <div id="fileModal" class="modal fade" role="dialog">
- <file-modal></file-modal>
- </div>
-
<div id="equalizerModal" class="modal fade" role="dialog">
<equalizer-modal></equalizer-modal>
</div>
@@ -38,52 +35,144 @@
<stream-manager-modal></stream-manager-modal>
</div>
</div>
-
- <div id="videoPlayer">
- <video></video>
- </div>
</body>
+<script type="text/x-template" id="continue-watching-template">
+ <div class="continue-watching-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <album-item-list v-for="(item, index) in items" :item="item" :key="index"></album-item-list>
+ </div> -->
+ <h5 class="separator-title">Continue watching</h5>
+ <div class="row" v-if="displayMode === 'grid'">
+ <video-item-grid class="col-12 col-sm-6 col-md-4 col-lg-4" v-for="(item, index) in items" :item="item" :key="index"></video-item-grid>
+ </div>
+ </div>
+</script>
<!-- Templates -->
<!-- Playlist Template -->
<script type="text/x-template" id="playlist-template">
- <div>
- <div id="playlistNav" class="playlistNav">
- <div class="container">
- <playlist-buttons></playlist-buttons>
- <div>
- <h1 class="playlistHeader">Playlist</h1>
- </div>
- <div id="playlist">
- <ol type="1">
- <li v-for="item in this.$parent.playlistItems">
- <button v-on:click="play(item.src, item.id)" class="playlistItem">{{ item.title }}</button>
- <button v-on:click="removeItem(item.id)" type="button" class="btn-circle col-xs">
- <svg-icon name="delete"></svg-icon>
- </button>
- </li>
- </ol>
- </div>
- <div class="playlistNavMobile" id="mobilePlaylistNavButton">
- <center><svg-icon name="format-list-bulleted"></svg-icon></center>
- </div>
+ <div id="playlistNav" class="playlistNav h-100">
+ <h6 class="playlist-header">Playlist • <span class="text-muted">{{ ' ' + items.length }}{{ items.length ? ' elements' : ''}}</span></h6>
+ <div class="dropdown-divider"></div>
+ <div id="playlist">
+ <div v-for="(item, index) in items" :key="index">
+ <playlist-video-item
+ v-if="item.type === 'leaf' || item.type === 'video'"
+ :item="item"
+ :index="index">
+ </playlist-video-item>
+ <playlist-audio-item
+ v-if="item.type === 'audio'"
+ :item="item"
+ :index="index">
+ </playlist-audio-item>
</div>
</div>
+ <playlist-buttons></playlist-buttons>
</div>
</script>
<!-- Button Template -->
<script type="text/x-template" id="button-template">
- <div>
- <div class="playlistIcons">
- <div class="row">
- <button type="button" class="btn-circle col-xs" id="randomButton"><svg-icon name="shuffle-variant"></svg-icon></button>
- <button type="button" class="btn-circle col-xs" id="repeatButton"><svg-icon name="replay"></svg-icon></button>
- <button type="button" class="btn-circle col-xs" id="playButton"><svg-icon name="play-circle-outline"></svg-icon></button>
+ <div class="playlist-actions">
+ <div class="d-flex justify-content-between mx-2" :class="{ disabled: !playlist.activeItem }">
+ <button v-on:click="toggleRepeat()" type="button" class="btn-circle" id="repeatButton"><svg-icon name="repeat"></svg-icon></button>
+ <button v-on:click="toggleRandom()" type="button" class="btn-circle" id="randomButton"><svg-icon name="shuffle"></svg-icon></button>
+ <!-- <span>{{ playlist.items.length ? playlist.items.length + ' items': '' }}</span> -->
+ <button type="button" class="btn-circle" data-toggle="modal" data-target="#equalizerModal"><svg-icon name="sort"></svg-icon></button>
+ <button v-on:click="removeItem(playlist.activeItem.id)" type="button" class="btn-circle"><svg-icon name="delete_outline"></svg-icon></button>
+ </div>
+ </div>
+</script>
+<!-- Playlist item Template -->
+<script type="text/x-template" id="playlist-video-item-template">
+ <button v-on:dblclick="play(item.uri, item.id)" class="btn btn-link pl-2 playlist-video-item list-item d-flex justify-content-between align-items-start position-relative"
+ :class="{ current: item.current === 'current', active: item.active }">
+ <div class="d-flex align-items-start w-100 mr-n3">
+ <div class="item-img" v-on:click="setActiveItem(item)">
+ <img v-if="item.src" class="img-art" :src="item.src" @error="onImgError(item)">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <div class="overlay">
+ <play-button :item="item" class="item-primary-action item-action"></play-button>
+ </div>
+ </div>
+ <span class="item-duration">{{ item.duration | formatDuration }}</span>
+ <!-- <span class="item-nb">{{ index + 1 }}</span> -->
+ <div class="item-body d-flex flex-column mx-2 pt-1">
+ <router-link to="" class="item-title text-truncate">{{ item.name }}</router-link>
+ <router-link to="" class="item-subtitle text-truncate">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+ <div class="d-flex item-action pt-1">
+ <svg-icon name="more_vert"></svg-icon>
+ </div>
+ <div class="item-progress-bar" :style="{width: item.progress}"></div>
+ </button>
+</script>
+<!-- Playlist item Template -->
+<script type="text/x-template" id="playlist-audio-item-template">
+ <button v-on:dblclick="setActiveItem(item)" class="btn btn-link pl-2 playlist-audio-item list-item d-flex justify-content-between align-items-start position-relative"
+ :class="{ current: item.current === 'current', active: item.active }">
+ <div class="d-flex align-items-start w-100 mr-n3">
+ <div class="item-img" v-on:click="setActiveItem(item)">
+ <img v-if="item.src" class="img-art" :src="item.src" @error="onImgError(item)">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <div class="overlay">
+ <play-button class="item-primary-action item-action"></play-button>
+ </div>
</div>
- <div class="row">
- <button type="button" class="btn-circle col-xs" data-toggle="modal" data-target="#equalizerModal"><svg-icon name="poll"></svg-icon></button>
- <button type="button" class="btn-circle col-xs" data-toggle="modal" data-target="#fileModal"><svg-icon name="plus"></svg-icon></button>
+ <span class="item-duration">{{ item.duration | formatDuration }}</span>
+ <!-- <span class="item-nb">{{ index + 1 }}</span> -->
+ <div class="item-body d-flex flex-column mx-2 pt-1">
+ <router-link to="" class="item-title text-truncate">{{ item.name }}</router-link>
+ <!-- <span class="item-subtitle text-truncate d-flex">
+ <router-link to="/artist">{{ item.subtitle }}</router-link> • <router-link to="/album">{{ item.album }}</router-link>
+ </span> -->
</div>
</div>
+ <div class="d-flex item-action pt-1">
+ <svg-icon name="more_vert"></svg-icon>
+ </div>
+ <!-- <div class="item-progress-bar" :style="{width: item.progress}"></div> -->
+ </button>
+</script>
+<script type="text/x-template" id="playlists-template">
+ <div class="playlists-view container-fluid">
+ <div class="row">
+ <div class="playlists-item grid-item col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div class="create-item">
+ Create a playlist
+ <svg-icon name="add"></svg-icon>
+ </div>
+ </div>
+ <playlists-item v-for="item in items" :item="item"></playlists-item>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="playlists-item-template">
+ <div class="playlists-item grid-item col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div class="item-img">
+ <div>
+ <div class="d-flex">
+ <img :src="item.images[0]">
+ <img :src="item.images[1]">
+ </div>
+ <div class="d-flex">
+ <img :src="item.images[2]">
+ <img :src="item.images[3]">
+ </div>
+ </div>
+ <div class="overlay">
+ <play-button class="item-primary-action"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="/album" class="item-title text-truncate">{{ item.name }}</router-link>
+ <router-link to="/artist" class="item-subtitle text-truncate">{{ item.nbItems }} files • {{ item.duration }}</router-link>
+ </div>
</div>
</script>
<!-- equalizer modal Template -->
@@ -93,8 +182,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Equalizer</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<input type="range" name="equalizerInput" id="equalizerInput" min="-20" max="20" step="0.1"/>
@@ -106,6 +195,184 @@
</div>
</div>
</script>
+<script type="text/x-template" id="genre-item-grid-template">
+ <div class="item-people genre-item tag-item genre-item-grid-template col-12 col-sm-6 col-md-4 col-lg-3">
+ <div class="item-img">
+ <img :src="item.src">
+ <div class="item-body">
+ <span class="item-title text-truncate">{{ item.name }}</span>
+ <span class="item-subtitle text-truncate">{{ item.nbTracks }} tracks</span>
+ </div>
+ <div class="overlay"></div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="genres-template">
+ <div class="genres-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="row" v-if="layout.itemLayout === 'grid'">
+ <genre-item-grid v-for="(item, index) in music.genres" :item="item" :key="index"></genre-item-grid>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="media-player-template">
+ <div id="media-player" class="media-player">
+ <audio class="d-none" controls="false" ref="player" :src="src"></audio>
+ <div class="seek-bar">
+ <div class="seek-bar-track">
+ <div ref="progressBar" class="seek-bar-progress slider-fill"></div>
+ <div ref="bufferBar" class="seek-bar-buffer slider-fill"></div>
+ </div>
+ <input ref="scrubber" class="seek-bar-scrubber" type="range" min="0" max="1000" value="0"></input>
+ </div>
+ <div class="d-flex align-items-center justify-content-center media-player-container">
+ <div class="metadata d-flex flex-1">
+ <!-- Image + info -->
+ <img class="img" v-if="imageSrc" :src="imageSrc">
+ <svg-icon v-if="!imageSrc" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <span class="ml-2 d-flex flex-column justify-content-center">
+ <span class="title font-weight-bold">{{ status.information && status.information.category && status.information.category.meta ? status.information.category.meta.filename : '' }} </span>
+ <span class="subtitle muted-opacity"></span>
+ <span class="subtitle2 muted-opacity">{{ formattedCurrentTime }} / {{ formattedDuration }}</span>
+ </span>
+ </div>
+ <div class="primary-actions d-flex flex-1 justify-content-center">
+ <!-- Primary actions -->
+ <button v-on:click="toggleRandom()" class="btn btn-link p-0 media-action" :class="{ active: status.random }">
+ <svg-icon name="shuffle"></svg-icon>
+ </button>
+ <button class="btn btn-link p-0 media-action" v-on:click="previous()">
+ <svg-icon name="skip_previous"></svg-icon>
+ </button>
+ <button class="btn btn-link p-0 media-action play-action" v-on:click="playing ? pause() : play()">
+ <svg-icon v-if="status.state === 'playing'" name="pause"></svg-icon>
+ <svg-icon v-else name="play_arrow"></svg-icon>
+ </button>
+ <button class="btn btn-link p-0 media-action" v-on:click="next()">
+ <svg-icon name="skip_next"></svg-icon>
+ </button>
+ <button v-on:click="toggleRepeat()" class="btn btn-link p-0 media-action" :class="{ active: status.repeat }">
+ <svg-icon name="repeat"></svg-icon>
+ </button>
+ </div>
+ <div class="secondary-actions d-flex flex-1 justify-content-end">
+ <!-- Secondary actions -->
+ <div class="media-action volume-container">
+ <button class="btn btn-link p-0 media-action" v-on:click="toggleMute()">
+ <svg-icon v-if="volumeIconState === 'mute'" name="volume_off"></svg-icon>
+ <svg-icon v-if="volumeIconState === 'up'" name="volume_up"></svg-icon>
+ <svg-icon v-if="volumeIconState === 'down'" name="volume_down"></svg-icon>
+ </button>
+ <div class="volume-panel">
+ <div class="volume-slider">
+ <div class="volume-slider-track-default"></div>
+ <div ref="volumeBar" class="volume-slider-track-active"></div>
+ <input ref="volume" class="volume-slider-input" type="range">
+ </div>
+ </div>
+ </div>
+ <button v-on:click="toggleFullscreen()" class="btn btn-link p-0 media-action" :class="{ active: status.fullscreen }">
+ <svg-icon name="Icon-Fullscreen"></svg-icon>
+ </button>
+ <div class="media-action">
+ <svg-icon name="more-vertical"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="tracks-template">
+ <div class="tracks-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="row" v-if="displayMode === 'table'">
+ <table class="table table-hover table-item">
+ <thead>
+ <tr>
+ <th scope="col"></th>
+ <th scope="col">Title</th>
+ <th scope="col">Artist</th>
+ <th scope="col">Album</th>
+ <th scope="col">Duration</th>
+ <th scope="col">Track</th>
+ <th scope="col"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <track-item-table v-for="(item, index) in music.tracks" :item="item" :key="index" :index="index"></track-item-table>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="track-item-table-template">
+ <tr>
+ <th scope="row" class="d-flex justify-content-between">
+ <div class="item-img">
+ <img v-if="item.src" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <play-button class="item-primary-action item-action" :item="item"></play-button>
+ </div>
+ </th>
+ <td>
+ <router-link to="">
+ <span>{{ item.title }}</span>
+ <span></span>
+ </router-link>
+ </td>
+ <td><router-link to="">{{ item.artist }}</router-link></td>
+ <td><router-link to="">{{ item.album }}</router-link></td>
+ <td class="text-muted">{{ item.duration | formatDuration }}</td>
+ <td class="text-muted">{{ index + 1 }}</td>
+ <td class="text-muted">
+ <div class="d-flex justify-content-between">
+ <div class="item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </td>
+ </tr>
+</script><script type="text/x-template" id="library-template">
+ <div class="library-view container-fluid">
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ </div>
+</script>
+<script type="text/x-template" id="library-item-template">
+ <div class="library-item">
+ <div class="library-item-img">
+ <img src="http://images.videolan.org/images/VLC-IconSmall.png">
+ </div>
+ <div class="library-item-body">
+ <div class="library-item-name text-truncate">{{ item.name }}</div>
+ <div class="library-item-artist text-truncate">{{ item.artist }}</div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="play-button-secondary-template">
+ <button v-on:click="playItem()" class="btn btn-sm play-button-secondary">
+ <svg-icon name="play_arrow"></svg-icon> Play
+ </button>
+</script>
+<script type="text/x-template" id="play-button-template">
+ <button v-on:click="playItem()" class="btn btn-link play-button">
+ <svg-icon name="play_arrow"></svg-icon>
+ </button>
+</script>
<!-- vlm modal Template -->
<script type="text/x-template" id="vlm-modal-template">
<div>
@@ -113,8 +380,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Write your VLM commands here (seperated by new line)</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<textarea id="vlmCommand"></textarea>
@@ -123,59 +390,180 @@
</div>
</div>
<div class="modal-footer">
- <button type="button" id="vlmButton" class="btn btn-default">Submit</button>
+ <button type="button" v-on:click="executeVLM()" id="vlmButton" class="btn btn-default">Submit</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</script>
-<!-- sideNav Template -->
-<script type="text/x-template" id="sidenav-template">
- <div>
- <div id="sideNav" class="sideNav">
- <a href="javascript:void(0)" class="closebtn" id="closeNavButton">
- Menu
- </a>
- <a href="#" data-toggle="modal" data-target="#fileModal">
- Open File
- </a>
- <a href="#">
- Local Network
- </a>
- <a href="#">
- Podcast
- </a>
- <a href="#" data-toggle="modal" data-target="#streamManagerModal">
- Manage Streams
- </a>
- <a href="#" data-toggle="modal" data-target="#trackSyncModal">
- Track Synchronization
- </a>
- <a href="#" data-toggle="modal" data-target="#vlmModal">
- VLM Batch Commands
- </a>
- </div>
- <span id="openNavButton">
- <svg-icon name="menu"></svg-icon>
- </span>
- </div>
-</script>
-<!-- file modal Template -->
-<script type="text/x-template" id="file-modal-template">
- <div>
- <div class="modal-dialog">
- <!-- Modal content-->
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
- <h4 class="modal-title">Select your file</h4>
+<script type="text/x-template" id="videos-template">
+ <div class="videos-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <album-item-list v-for="(item, index) in items" :item="item" :key="index"></album-item-list>
+ </div> -->
+ <!-- <h5 class="separator-title d-flex align-items-center">
+ <span>Videos</span>
+ </h5> -->
+ <div id="collapse-group-grid" class="position-relative collapse-container" v-if="layout.itemLayout === 'grid'">
+ <!-- <div class="carousel-navigation d-flex align-items-center">
+ <svg-icon class="muted-opacity" name="keyboard_arrow_left"></svg-icon>
+ <svg-icon name="keyboard_arrow_right"></svg-icon>
+ </div> -->
+ <template v-for="(item, index) in videos">
+ <video-item-grid :key="index" data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" class="col-12 col-sm-6 col-md-4 col-lg-3 collapse-item" :item="item">
+ </video-item-grid><div class="collapse collapse-detail" v-bind:id="'collapse-' + item.id" data-parent="#collapse-group-grid">
+ <div class="d-flex ml-2">
+ <button data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button>
+ <div>
+ <img width="260" class="embed-responsive-item" :src="item.src">
+ <div class="mt-2 d-flex">
+ <play-button-secondary :item="item"></play-button-secondary>
+ <enqueue-button class="ml-2" :item="item"></enqueue-button>
+ </div>
+ </div>
+ <div class="ml-2">
+ <h4 class="title mb-0">{{ item.title }}</h4>
+ <span class="caption">{{ item.duration | formatDuration }}</span>
+ <div class="subtitle"><span class="font-weight-bold">File name:</span>{{ item.filename }}</div>
+ <div class="subtitle"><span class="font-weight-bold">Path:</span>{{ item.mrl }}</div>
+ </div>
+ </div>
</div>
- <div class="modal-body" id="file-tree">
+ </template>
+ </div>
+ <div id="collapse-group-list" class="position-relative collapse-container" v-if="layout.itemLayout === 'list'">
+ <!-- <div class="carousel-navigation d-flex align-items-center">
+ <svg-icon class="muted-opacity" name="keyboard_arrow_left"></svg-icon>
+ <svg-icon name="keyboard_arrow_right"></svg-icon>
+ </div> -->
+ <div class="tracks-view container-fluid list-table-view">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="d-flex list-header row">
+ <span class="col-2 text-muted track-img">
+ <svg-icon name="Icon-Vinyl"></svg-icon>
+ </span>
+ <span class="col-6 text-muted">Title</span>
+ <span class="col-2 text-muted text-center">
+ <svg-icon name="Icon-Time"></svg-icon>
+ </span>
</div>
- <div class="modal-footer">
+ <template v-for="(item, index) in videos">
+ <video-item-list :key="index" data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" :item="item">
+ </video-item-list><div class="collapse collapse-detail" v-bind:id="'collapse-' + item.id" data-parent="#collapse-group-list">
+ <div class="d-flex ml-2">
+ <button data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button>
+ <div>
+ <img width="260" class="embed-responsive-item" :src="item.src">
+ <div class="mt-2 d-flex">
+ <play-button-secondary :item="item"></play-button-secondary>
+ <enqueue-button class="ml-2" :item="item"></enqueue-button>
+ </div>
+ </div>
+ <div class="ml-2">
+ <h4 class="title mb-0">{{ item.title }}</h4>
+ <span class="caption">{{ item.duration | formatDuration }}</span>
+ <div class="subtitle"><span class="font-weight-bold">File name:</span>{{ item.filename }}</div>
+ <div class="subtitle"><span class="font-weight-bold">Path:</span>{{ item.mrl }}</div>
+ </div>
+ </div>
+ </div>
+ </template>
+
+ </div>
+ </div>
+ <div class="row position-relative" v-if="layout.itemLayout === 'poster'">
+ <!-- <div class="carousel-navigation d-flex align-items-center">
+ <svg-icon class="muted-opacity" name="keyboard_arrow_left"></svg-icon>
+ <svg-icon name="keyboard_arrow_right"></svg-icon>
+ </div> -->
+ <video-item-poster class="col-12 col-sm-6 col-md-4 col-lg-2" v-for="(item, index) in videos" :item="item" :key="index"></video-item-poster>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="video-item-list-template">
+ <div class="row align-items-center list-table-item">
+ <div class="d-flex justify-content-between col-2">
+ <div class="item-img img-16by9 d-flex" :style="{'background-image': `url(${item.src})`}">
+ <play-button class="item-primary-action item-action m-auto" :item="item"></play-button>
+ </div>
+ </div>
+ <div class="col-6">
+ <span>{{ item.title }}</span>
+ </div>
+ <div class="col-2 text-center">{{ item.duration | formatDuration }}</div>
+ <div class="text-muted col-2">
+ <div class="d-flex justify-content-between">
+ <div class="item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="video-item-grid-template">
+ <div class="video-item grid-item video-item-grid-template">
+ <div class="item-img embed-responsive embed-responsive-16by10">
+ <img class="embed-responsive-item" :src="item.src">
+ <div class="overlay">
+ <play-button :item="item" class="item-primary-action"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ <div v-if="item.quality" class="quality">
+ <span class="quality-tag">{{ item.quality }}</span>
+ </div>
+ <div v-if="item.user" class="user">
+ <img src="">
+ </div>
+ <div v-if="item.progress" class="item-progress-bar-container">
+ <div class="item-progress-bar" :style="{width: item.progress}"></div>
+ </div>
+ </div>
+ <div class="item-body px-2">
+ <span class="d-flex align-items-center justify-content-between">
+ <router-link to="/album" class="item-title text-truncate">
+ <span>{{ item.title }}</span>
+ </router-link>
+ <span class="item-subtitle">{{ item.duration | formatDuration }}</span>
+ </span>
+ <router-link to="/" class="item-subtitle text-truncate text-left">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="video-item-poster-template">
+ <div class="video-item grid-item poster-item video-item-poster-template">
+ <div class="item-img embed-responsive embed-responsive-4by6">
+ <img class="embed-responsive-item" :src="item.src">
+ <div class="overlay">
+ <play-button class="item-primary-action" :item="item"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
</div>
</div>
+ <div v-if="item.progress" class="item-progress-bar-container">
+ <div class="item-progress-bar" :style="{width: item.progress}"></div>
+ </div>
+ </div>
+ <div class="item-body px-2">
+ <span class="d-flex align-items-center justify-content-between">
+ <router-link to="/album" class="item-title text-truncate">
+ <span>{{ item.title }}</span>
+ </router-link>
+ <span class="item-subtitle">{{ item.duration | formatDuration }}</span>
+ </span>
+ <router-link to="/" class="item-subtitle text-truncate text-left">{{ item.subtitle }}</router-link>
</div>
</div>
</script>
@@ -186,8 +574,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Set Track Synchronization</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body" id="">
Playback Rate
@@ -208,6 +596,77 @@
</div>
</div>
</script>
+<script type="text/x-template" id="item-layout-button-template">
+ <button v-on:click="toggleItemLayout()" class="btn btn-circle active">
+ <svg-icon v-if="layout && layout.itemLayout === 'list'" name="format_list_bulleted"></svg-icon>
+ <svg-icon v-if="layout && layout.itemLayout === 'grid'" name="grid_view"></svg-icon>
+ </button>
+</script>
+<script type="text/x-template" id="grid-item-template">
+ <div class="grid-item discover-services-item-grid-template col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div :class="item.additionalClass" class="item-img embed-responsive embed-responsive-1by1 img-contain">
+ <img v-if="item.src" class="embed-responsive-item p-4" :src="item.src">
+ <div v-else="item.icon" class="embed-responsive-item" :class="item.additionalItemClass">
+ <svg-icon :name="item.icon"></svg-icon>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link :to="item.titleRoute || '/album'" class="item-title text-truncate">{{ item.title }}</router-link>
+ <router-link v-if="item.subtitle" :to="item.subtitleRoute || '/artist'" class="item-subtitle text-truncate">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="artists-template">
+ <div class="artits-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="row" v-if="layout.itemLayout === 'grid'">
+ <artist-item-grid v-for="(item, index) in music.artists" :item="item" :key="index"></artist-item-grid>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="artist-item-grid-template">
+ <router-link :to="'/music/artists/' + item.id" class="item-people artist-item grid-item artist-item-grid-template col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div class="item-img embed-responsive embed-responsive-1by1">
+ <img v-if="item.src" class="embed-responsive-item" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-artist" class="placeholder-artist-icon"></svg-icon>
+ <div class="overlay">
+ <play-button class="item-primary-action"></play-button>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="" class="item-title text-truncate">{{ item.name }}</router-link>
+ <span class="item-subtitle text-truncate">{{ item.nbTracks }} songs</span>
+ </div>
+ </router-link>
+</script>
+<script type="text/x-template" id="artists-detail-template">
+ <div class="artits-detail-view container-fluid">
+ <div class="row">
+ <div class="col-2 artists-sidebar pt-2">
+ <h5 class="font-weight-normal">Artists</h5>
+ <ul class="list-unstyled h-100">
+ <li v-for="(artist, index) in music.artists" class="artist-list-item">
+ <router-link :to="'/music/artists/' + artist.id" exact-active-class="active">
+ <img v-if="artist.src" class="embed-responsive-item artist-img" :src="artist.src">
+ <svg-icon v-if="!artist.src" name="placeholder-artist" class="placeholder-artist-icon artist-img"></svg-icon>
+ <span class="flex-1">{{ artist.name }}</span>
+ </router-link>
+ </li>
+ </ul>
+ </div>
+ <div class="col-10 pt-4">
+ <albums :artistId="$route.params.id"></albums>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="enqueue-button-template">
+ <button v-on:click="enqueueItem()" class="btn btn-sm enqueue-button">
+ <svg-icon name="playlist_add"></svg-icon> Enqueue
+ </button>
+</script>
<script type="text/x-template" id="svg-icon">
<svg version="1.1" :class="clazz" :viewBox="box" v-html="path" :style="style"></svg>
</script>
@@ -218,8 +677,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Stream Manager</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
</div>
@@ -229,4 +688,427 @@
</div>
</div>
</script>
+<script type="text/x-template" id="albums-template">
+ <div class="albums-view container-fluid">
+ <div v-if="layout.itemLayout === 'list'" class="row">
+ <!-- <album-item-list v-for="(item, index) in music.albums" :item="item" :key="index"></album-item-list> -->
+ </div>
+ <div id="album-collapse-group" class="position-relative collapse-container album-collapse-container" v-if="layout.itemLayout === 'grid'">
+ <template v-for="(item, index) in getAlbums()">
+ <album-item-grid :key="index" data-toggle="collapse" v-bind:data-target="'#collapse-album-' + item.id" aria-expanded="false" aria-controls="collapse" :item="item" class="col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2 collapse-item"></album-item-grid><div class="collapse album-collapse-detail collapse-detail" v-bind:id="'collapse-album-' + item.id" data-parent="#album-collapse-group">
+ <div class="d-flex ml-2">
+ <!-- <button data-toggle="collapse" v-bind:data-target="'#collapse-album-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button> -->
+ <div>
+ <img v-if="item.src" width="171" height="171" class="embed-responsive-item item-img" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon item-img"></svg-icon>
+ <div class="mt-2 d-flex">
+ <play-button-secondary></play-button-secondary>
+ <enqueue-button class="ml-2" :item="item"></enqueue-button>
+ </div>
+ </div>
+ <div class="ml-2 w-100">
+ <button data-toggle="collapse" v-bind:data-target="'#collapse-album-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button>
+ <h4 class="title mb-0">{{ item.title }}</h4>
+ <span class="caption">{{ item.duration | formatDuration }}</span>
+ <table class="table table-hover table-item">
+ <thead>
+ <tr>
+ <th scope="col">#</th>
+ <th scope="col">Title</th>
+ <th scope="col"></th>
+ <th scope="col"><svg-icon name="Icon-Time"></svg-icon></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="(track, index) in music.albumTracks[item.id]">
+ <td>
+ {{ index + 1 }}
+ </td>
+ <td>
+ {{ track.title }}
+ </td>
+ <td class="text-muted">
+ <div class="d-flex justify-content-between">
+ <div class="item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </td>
+ <td>
+ {{ track.duration | formatDuration }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </template>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="album-item-grid-template">
+ <div v-on:click="toggleAlbumTracks(item.id)" class="album-item grid-item album-item-grid-template">
+ <div class="item-img embed-responsive embed-responsive-1by1">
+ <img v-if="item.src" class="embed-responsive-item" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <div class="overlay">
+ <play-button class="item-primary-action"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="" class="item-title text-truncate">{{ item.title }}</router-link>
+ <router-link to="" class="item-subtitle text-truncate">{{ item.artist }}</router-link>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="album-item-list-template">
+ <div class="album-item list-item album-item-list-template col-12 col-sm-6 col-md-6 col-lg-4">
+ <div class="item-img item-border-radius">
+ <img :src="item.src">
+ <div class="overlay">
+ <play-button class="item-primary-action item-action"></play-button>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="/album" class="item-title text-truncate">{{ item.title }}</router-link>
+ <router-link to="/artist" class="item-subtitle text-truncate">{{ item.artist }}</router-link>
+ <div class="item-secondary-action">
+ <div v-on:click="toggleLiked()">
+ <div v-if="!liked" class="icon-wrapper item-action">
+ <svg-icon name="favorite_outline"></svg-icon>
+ </div>
+ <div v-if="liked" class="icon-wrapper item-action active">
+ <svg-icon name="favorite"></svg-icon>
+ </div>
+ </div>
+ <div class="icon-wrapper item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="music-view-template">
+ <div class="music-view h-100">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <item-layout-button></item-layout-button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center">
+ <router-link to="/music/albums" exact-active-class="active" class="btn btn-link">Albums</router-link>
+ <router-link to="/music/artists" active-class="active" class="btn btn-link">Artists</router-link>
+ <router-link to="/music/genres" exact-active-class="active" class="btn btn-link">Genres</router-link>
+ <router-link to="/music/tracks" exact-active-class="active" class="btn btn-link">Tracks</router-link>
+ <router-link to="/music/playlists" exact-active-class="active" class="btn btn-link">Playlists</router-link>
+ </div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="music-playlists-view-template">
+ <div class="music-playlists-view pt-4">
+ <playlists></playlists>
+ </div>
+</script>
+<script type="text/x-template" id="music-genres-view-template">
+ <div class="music-genres-view pt-4">
+ <genres></genres>
+ </div>
+</script>
+<script type="text/x-template" id="music-tracks-view-template">
+ <div class="music-tracks-view pt-4">
+ <tracks></tracks>
+ </div>
+</script>
+<script type="text/x-template" id="music-artists-detail-view-template">
+ <div class="music-artists-detail-view">
+ <artists-detail></artists-detail>
+ </div>
+</script>
+<script type="text/x-template" id="music-artists-view-template">
+ <div class="music-artists-view pt-4">
+ <artists></artists>
+ </div>
+</script>
+<script type="text/x-template" id="music-albums-view-template">
+ <div class="music-albums-view pt-4">
+ <albums></albums>
+ </div>
+</script>
+<script type="text/x-template" id="video-playlists-view-template">
+ <div class="video-playlists-view"></div>
+</script>
+<script type="text/x-template" id="video-all-view-template">
+ <div class="video-all-view">
+ <!-- <continue-watching></continue-watching> -->
+ <videos></videos>
+ </div>
+</script>
+<script type="text/x-template" id="video-tvshows-view-template">
+ <div class="video-tvshows-view"></div>
+</script>
+<script type="text/x-template" id="video-view-template">
+ <div class="video-view h-100 pt-4">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <item-layout-button></item-layout-button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center">
+ <router-link to="/video/all" exact-active-class="active" class="btn btn-link">All</router-link>
+ <router-link to="/video/movies" exact-active-class="active" class="btn btn-link">Movies</router-link>
+ <router-link to="/video/tvshows" exact-active-class="active" class="btn btn-link">Tv Shows</router-link>
+ <router-link to="/video/playlists" exact-active-class="active" class="btn btn-link">Playlists</router-link>
+ </div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="video-movies-view-template">
+ <div class="video-movies-view"></div>
+</script>
+<script type="text/x-template" id="discover-home-view-template">
+ <div class="discover-home-view">
+ </div>
+</script>
+<script type="text/x-template" id="discover-view-template">
+ <div class="discover-view h-100 pt-4">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <button v-on:click="" class="btn btn-circle"><svg-icon name="format_list_bulleted"></svg-icon></button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center">
+ <router-link to="/discover/home" active-class="active" class="btn btn-link">Home</router-link>
+ <router-link to="/discover/services" active-class="active" class="btn btn-link">Services</router-link>
+ <router-link to="/discover/url" active-class="active" class="btn btn-link">URL</router-link>
+ </div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="discover-url-view-template">
+ <div class="discover-url-view">
+ </div>
+</script>
+<script type="text/x-template" id="discover-services-view-template">
+ <div class="discover-services-view">
+ <div class="row">
+ <grid-item :item="addService"></grid-item>
+ <template v-for="service in mainServices">
+ <grid-item :item="service"></grid-item>
+ </template>
+ </div>
+ <div class="row">
+ <template v-for="service in secondaryServices">
+ <grid-item :item="service"></grid-item>
+ </template>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="discover-services-tv-view-template">
+ <div class="discover-services-tv-view container-fluid">
+ <div v-if="displayMode === 'list'" class="row">
+ <grid-list v-for="(item, index) in items" :item="item" :key="index"></grid-list>
+ </div>
+ <div class="row" v-if="displayMode === 'grid'">
+ <grid-item v-for="(item, index) in items" :item="item" :key="index"></grid-item>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="network-view-template">
+ <div class="network-view h-100 pt-4">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <button v-on:click="" class="btn btn-circle"><svg-icon name="format_list_bulleted"></svg-icon></button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center"></div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="watch-view-template">
+ <div class="watch-view h-100">
+ <div>
+ <div class="container-fluid fixed-top primary-navbar">
+ <div class="d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <router-link to="/">
+ <button class="btn btn-circle">
+ <svg-icon name="keyboard_arrow_left"></svg-icon>
+ </button>
+ </router-link>
+ </div>
+ <div class="d-flex align-items-center justify-content-center"></div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0" :class="'overlay'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col">
+ <media-player></media-player>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
+<script type="text/x-template" id="browse-view-template">
+ <div class="browse-view h-100" :class="{ 'media-player-opened': audioPlayerOpened }">
+ <div class="container-fluid fixed-top primary-navbar d-flex align-content-center align-items-center text-center justify-content-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <img width="23" height="26" src="http://images.videolan.org/images/VLC-IconSmall.png">
+ <span class="ml-2">VLC</span>
+ </div>
+ <ul class="nav d-flex align-items-center justify-content-center">
+ <li class="nav-item">
+ <router-link title="Video" active-class="active" to="/video" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="local_movies_outline"></svg-icon>
+ <span>Video</span>
+ </router-link>
+ </li>
+ <li class="nav-item">
+ <router-link title="Music" active-class="active" to="/music" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="audiotrack_outline"></svg-icon>
+ <span>Music</span>
+ </router-link>
+ </li>
+ <li class="nav-item">
+ <router-link title="Network" active-class="active" to="/network" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="wifi"></svg-icon>
+ <span>Browse</span>
+ </router-link>
+ </li>
+ <li class="nav-item">
+ <router-link title="Discover" active-class="active" to="/discover" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="explore"></svg-icon>
+ <span>Discover</span>
+ </router-link>
+ </li>
+ </ul>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <button v-on:click="" class="btn-circle mr-2"><svg-icon name="search"></svg-icon></button>
+ <button v-on:click="" class="btn-circle"><svg-icon name="more-horizontal"></svg-icon></button>
+ </div>
+ </div>
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ <transition name="slide-fade">
+ <media-player
+ v-if="audioPlayerOpened"
+ canPlay="canPlay"
+ ended="ended"
+ src="">
+ </media-player>
+ </transition>
+ </div>
+</script>
+<script type="text/x-template" id="main-view-template">
+ <router-view></router-view>
+</script>
</html>
diff --git a/share/lua/http/src/components/albums/album-item/album-item-grid.component.html b/share/lua/http/src/components/albums/album-item/album-item-grid.component.html
new file mode 100644
index 0000000000..6dd189c065
--- /dev/null
+++ b/share/lua/http/src/components/albums/album-item/album-item-grid.component.html
@@ -0,0 +1,20 @@
+<script type="text/x-template" id="album-item-grid-template">
+ <div v-on:click="toggleAlbumTracks(item.id)" class="album-item grid-item album-item-grid-template">
+ <div class="item-img embed-responsive embed-responsive-1by1">
+ <img v-if="item.src" class="embed-responsive-item" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <div class="overlay">
+ <play-button class="item-primary-action"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="" class="item-title text-truncate">{{ item.title }}</router-link>
+ <router-link to="" class="item-subtitle text-truncate">{{ item.artist }}</router-link>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/albums/album-item/album-item-grid.component.js b/share/lua/http/src/components/albums/album-item/album-item-grid.component.js
new file mode 100644
index 0000000000..13076deeaa
--- /dev/null
+++ b/share/lua/http/src/components/albums/album-item/album-item-grid.component.js
@@ -0,0 +1,20 @@
+Vue.component('album-item-grid', {
+ template: '#album-item-grid-template',
+ props: ['item'],
+ data: function() {
+ return {
+ liked: this.item.liked
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ music: state => state.music
+ }),
+ },
+ methods: {
+ toggleAlbumTracks(id) {
+ this.$store.dispatch('music/fetchAlbumTracks', id);
+ }
+ },
+ created() { }
+});
diff --git a/share/lua/http/src/components/albums/album-item/album-item-list.component.html b/share/lua/http/src/components/albums/album-item/album-item-list.component.html
new file mode 100644
index 0000000000..063644ebf5
--- /dev/null
+++ b/share/lua/http/src/components/albums/album-item/album-item-list.component.html
@@ -0,0 +1,27 @@
+<script type="text/x-template" id="album-item-list-template">
+ <div class="album-item list-item album-item-list-template col-12 col-sm-6 col-md-6 col-lg-4">
+ <div class="item-img item-border-radius">
+ <img :src="item.src">
+ <div class="overlay">
+ <play-button class="item-primary-action item-action"></play-button>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="/album" class="item-title text-truncate">{{ item.title }}</router-link>
+ <router-link to="/artist" class="item-subtitle text-truncate">{{ item.artist }}</router-link>
+ <div class="item-secondary-action">
+ <div v-on:click="toggleLiked()">
+ <div v-if="!liked" class="icon-wrapper item-action">
+ <svg-icon name="favorite_outline"></svg-icon>
+ </div>
+ <div v-if="liked" class="icon-wrapper item-action active">
+ <svg-icon name="favorite"></svg-icon>
+ </div>
+ </div>
+ <div class="icon-wrapper item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/albums/album-item/album-item-list.component.js b/share/lua/http/src/components/albums/album-item/album-item-list.component.js
new file mode 100644
index 0000000000..7eca71f703
--- /dev/null
+++ b/share/lua/http/src/components/albums/album-item/album-item-list.component.js
@@ -0,0 +1,16 @@
+Vue.component('album-item-list', {
+ template: '#album-item-list-template',
+ props: ['item'],
+ data: function() {
+ return {
+ liked: this.item.liked
+ }
+ },
+ computed: { },
+ methods: {
+ toggleLiked() {
+ this.liked = !this.liked;
+ }
+ },
+ created() { }
+});
diff --git a/share/lua/http/src/components/albums/album-item/album-item.component.scss b/share/lua/http/src/components/albums/album-item/album-item.component.scss
new file mode 100644
index 0000000000..54bdbf8403
--- /dev/null
+++ b/share/lua/http/src/components/albums/album-item/album-item.component.scss
@@ -0,0 +1,17 @@
+.album-item-grid-template.grid-item {
+ margin-bottom: 16px;
+}
+
+.album-item-list-template.list-item {
+ margin-bottom: 16px;
+ .item-img {
+ width: 90px;
+ }
+}
+
+.svg-icon {
+ &.placeholder-album-icon {
+ width: 3.5rem;
+ height: 3.5rem;
+ }
+}
diff --git a/share/lua/http/src/components/albums/albums.component.html b/share/lua/http/src/components/albums/albums.component.html
new file mode 100644
index 0000000000..441485136f
--- /dev/null
+++ b/share/lua/http/src/components/albums/albums.component.html
@@ -0,0 +1,63 @@
+<script type="text/x-template" id="albums-template">
+ <div class="albums-view container-fluid">
+ <div v-if="layout.itemLayout === 'list'" class="row">
+ <!-- <album-item-list v-for="(item, index) in music.albums" :item="item" :key="index"></album-item-list> -->
+ </div>
+ <div id="album-collapse-group" class="position-relative collapse-container album-collapse-container" v-if="layout.itemLayout === 'grid'">
+ <template v-for="(item, index) in getAlbums()">
+ <album-item-grid :key="index" data-toggle="collapse" v-bind:data-target="'#collapse-album-' + item.id" aria-expanded="false" aria-controls="collapse" :item="item" class="col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2 collapse-item"></album-item-grid><div class="collapse album-collapse-detail collapse-detail" v-bind:id="'collapse-album-' + item.id" data-parent="#album-collapse-group">
+ <div class="d-flex ml-2">
+ <!-- <button data-toggle="collapse" v-bind:data-target="'#collapse-album-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button> -->
+ <div>
+ <img v-if="item.src" width="171" height="171" class="embed-responsive-item item-img" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon item-img"></svg-icon>
+ <div class="mt-2 d-flex">
+ <play-button-secondary></play-button-secondary>
+ <enqueue-button class="ml-2" :item="item"></enqueue-button>
+ </div>
+ </div>
+ <div class="ml-2 w-100">
+ <button data-toggle="collapse" v-bind:data-target="'#collapse-album-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button>
+ <h4 class="title mb-0">{{ item.title }}</h4>
+ <span class="caption">{{ item.duration | formatDuration }}</span>
+ <table class="table table-hover table-item">
+ <thead>
+ <tr>
+ <th scope="col">#</th>
+ <th scope="col">Title</th>
+ <th scope="col"></th>
+ <th scope="col"><svg-icon name="Icon-Time"></svg-icon></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="(track, index) in music.albumTracks[item.id]">
+ <td>
+ {{ index + 1 }}
+ </td>
+ <td>
+ {{ track.title }}
+ </td>
+ <td class="text-muted">
+ <div class="d-flex justify-content-between">
+ <div class="item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </td>
+ <td>
+ {{ track.duration | formatDuration }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </template>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/albums/albums.component.js b/share/lua/http/src/components/albums/albums.component.js
new file mode 100644
index 0000000000..61e7b5c46e
--- /dev/null
+++ b/share/lua/http/src/components/albums/albums.component.js
@@ -0,0 +1,41 @@
+Vue.component('albums', {
+ template: '#albums-template',
+ props: ['artistId'],
+ watch: {
+ artistId: function(newVal, oldVal) {
+ if (newVal !== oldVal) {
+ this.fetchArtistAlbums(newVal);
+ }
+ }
+ },
+ data: function() {
+ return {
+ displayMode: 'grid'
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ music: state => state.music,
+ layout: state => state.layout
+ }),
+ },
+ methods: {
+ fetchAlbums() {
+ this.$store.dispatch('music/fetchAlbums');
+ },
+ fetchArtistAlbums(artistId) {
+ this.$store.dispatch('music/fetchArtistAlbums', artistId);
+ },
+ getAlbums() {
+ return !this.$route.params.id ? this.music.albums : this.music.artistAlbums[this.$route.params.id];
+ }
+ },
+ created() {
+ const artistId = this.$route.params.id;
+ if (artistId) {
+ this.fetchArtistAlbums(artistId);
+ } else {
+ this.fetchAlbums();
+ }
+ }
+});
diff --git a/share/lua/http/src/components/albums/albums.component.scss b/share/lua/http/src/components/albums/albums.component.scss
new file mode 100644
index 0000000000..91dd0deeb7
--- /dev/null
+++ b/share/lua/http/src/components/albums/albums.component.scss
@@ -0,0 +1,23 @@
+.albums-view {
+ ul > li {
+ display: inline-block;
+ list-style: none;
+ }
+ .expander {
+ top: auto;
+ position: absolute;
+ visibility: hidden;
+ left: 0;
+ margin-top: 20px;
+ transition: height 0.35s ease;
+ width: 100%;
+ }
+}
+.album-collapse-container {
+ .album-collapse-detail {
+ .item-img {
+ width: 171px;
+ height: 171px;
+ }
+ }
+}
diff --git a/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.html b/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.html
new file mode 100644
index 0000000000..a927d53712
--- /dev/null
+++ b/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.html
@@ -0,0 +1,15 @@
+<script type="text/x-template" id="artist-item-grid-template">
+ <router-link :to="'/music/artists/' + item.id" class="item-people artist-item grid-item artist-item-grid-template col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div class="item-img embed-responsive embed-responsive-1by1">
+ <img v-if="item.src" class="embed-responsive-item" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-artist" class="placeholder-artist-icon"></svg-icon>
+ <div class="overlay">
+ <play-button class="item-primary-action"></play-button>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="" class="item-title text-truncate">{{ item.name }}</router-link>
+ <span class="item-subtitle text-truncate">{{ item.nbTracks }} songs</span>
+ </div>
+ </router-link>
+</script>
diff --git a/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.js b/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.js
new file mode 100644
index 0000000000..8fe01f3a69
--- /dev/null
+++ b/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.js
@@ -0,0 +1,12 @@
+Vue.component('artist-item-grid', {
+ template: '#artist-item-grid-template',
+ props: ['item'],
+ data: function() {
+ return {
+ liked: this.item.liked
+ }
+ },
+ computed: { },
+ methods: { },
+ created() { }
+});
diff --git a/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.scss b/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.scss
new file mode 100644
index 0000000000..03226f6b5e
--- /dev/null
+++ b/share/lua/http/src/components/artists/artist-item/artist-item-grid.component.scss
@@ -0,0 +1,17 @@
+.artist-item-grid-template.grid-item {
+ margin-bottom: 16px;
+}
+
+.svg-icon {
+ &.placeholder-artist-icon {
+ width: 5rem;
+ height: 5rem;
+ margin-top: 1.8rem;
+ }
+}
+
+.artist-item {
+ display: block;
+ text-decoration: none;
+ color: var(--primary-text-color);
+}
diff --git a/share/lua/http/src/components/artists/artists.component.html b/share/lua/http/src/components/artists/artists.component.html
new file mode 100644
index 0000000000..0f56e8b403
--- /dev/null
+++ b/share/lua/http/src/components/artists/artists.component.html
@@ -0,0 +1,10 @@
+<script type="text/x-template" id="artists-template">
+ <div class="artits-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="row" v-if="layout.itemLayout === 'grid'">
+ <artist-item-grid v-for="(item, index) in music.artists" :item="item" :key="index"></artist-item-grid>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/artists/artists.component.js b/share/lua/http/src/components/artists/artists.component.js
new file mode 100644
index 0000000000..33b49ce48e
--- /dev/null
+++ b/share/lua/http/src/components/artists/artists.component.js
@@ -0,0 +1,25 @@
+Vue.component('artists', {
+ template: '#artists-template',
+ data: function() {
+ return {
+ displayMode: 'grid',
+ items: [
+
+ ]
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ music: state => state.music,
+ layout: state => state.layout
+ }),
+ },
+ methods: {
+ fetchArtists() {
+ this.$store.dispatch('music/fetchArtists');
+ }
+ },
+ created() {
+ this.fetchArtists();
+ }
+});
diff --git a/share/lua/http/src/components/artists/detail/artists-detail.component.html b/share/lua/http/src/components/artists/detail/artists-detail.component.html
new file mode 100644
index 0000000000..28f883c172
--- /dev/null
+++ b/share/lua/http/src/components/artists/detail/artists-detail.component.html
@@ -0,0 +1,21 @@
+<script type="text/x-template" id="artists-detail-template">
+ <div class="artits-detail-view container-fluid">
+ <div class="row">
+ <div class="col-2 artists-sidebar pt-2">
+ <h5 class="font-weight-normal">Artists</h5>
+ <ul class="list-unstyled h-100">
+ <li v-for="(artist, index) in music.artists" class="artist-list-item">
+ <router-link :to="'/music/artists/' + artist.id" exact-active-class="active">
+ <img v-if="artist.src" class="embed-responsive-item artist-img" :src="artist.src">
+ <svg-icon v-if="!artist.src" name="placeholder-artist" class="placeholder-artist-icon artist-img"></svg-icon>
+ <span class="flex-1">{{ artist.name }}</span>
+ </router-link>
+ </li>
+ </ul>
+ </div>
+ <div class="col-10 pt-4">
+ <albums :artistId="$route.params.id"></albums>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/artists/detail/artists-detail.component.js b/share/lua/http/src/components/artists/detail/artists-detail.component.js
new file mode 100644
index 0000000000..ed775f54ff
--- /dev/null
+++ b/share/lua/http/src/components/artists/detail/artists-detail.component.js
@@ -0,0 +1,25 @@
+Vue.component('artists-detail', {
+ template: '#artists-detail-template',
+ data: function() {
+ return {
+ displayMode: 'grid',
+ items: [
+
+ ]
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ music: state => state.music,
+ layout: state => state.layout
+ }),
+ },
+ methods: {
+ fetchArtists() {
+ this.$store.dispatch('music/fetchArtists');
+ }
+ },
+ created() {
+ this.fetchArtists();
+ }
+});
diff --git a/share/lua/http/src/components/artists/detail/artists-detail.component.scss b/share/lua/http/src/components/artists/detail/artists-detail.component.scss
new file mode 100644
index 0000000000..635fff7525
--- /dev/null
+++ b/share/lua/http/src/components/artists/detail/artists-detail.component.scss
@@ -0,0 +1,59 @@
+.artits-detail-view {
+ .artists-sidebar {
+ height: 100%;
+ background-color: var(--sidenav-bg-color);
+ overflow-y: auto;
+ box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);
+ position: fixed;
+ }
+ .artist-list-item a {
+ $spacing: 15px;
+ display: flex;
+ align-items: center;
+ padding: 10px 0;
+ font-size: 12px;
+ text-decoration: none;
+ margin-left: -$spacing;
+ margin-right: -$spacing;
+ padding-left: $spacing;
+ padding-right: $spacing;
+ color: var(--primary-text-color);
+ &.active {
+ background-color: var(--playlist-active-bg-color);
+ .artist-img {
+ border: 1px solid var(--highlight-color);
+ }
+ }
+ }
+ .artist-img {
+ width: 24px;
+ height: 24px;
+ margin-top: 0;
+ margin-right: 10px;
+ border-radius: 50%;
+ border: 1px solid rgb(151, 151, 151);
+ &.svg-icon {
+ padding-top: 3px;
+ }
+ }
+}
+
+.artits-detail-view {
+ .col-10 {
+ margin-left: 16.6666666667%;
+ }
+}
+.collapse {
+ .artits-detail-view {
+ .col-10 {
+ margin-left: 16.6666666667%;
+ }
+ }
+ &.show {
+ .artits-detail-view {
+ .col-10 {
+ margin-left: 20%;
+ }
+ }
+ }
+}
diff --git a/share/lua/http/src/components/continue-watching/continue-watching.component.html b/share/lua/http/src/components/continue-watching/continue-watching.component.html
new file mode 100644
index 0000000000..040b31f0d9
--- /dev/null
+++ b/share/lua/http/src/components/continue-watching/continue-watching.component.html
@@ -0,0 +1,11 @@
+<script type="text/x-template" id="continue-watching-template">
+ <div class="continue-watching-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <album-item-list v-for="(item, index) in items" :item="item" :key="index"></album-item-list>
+ </div> -->
+ <h5 class="separator-title">Continue watching</h5>
+ <div class="row" v-if="displayMode === 'grid'">
+ <video-item-grid class="col-12 col-sm-6 col-md-4 col-lg-4" v-for="(item, index) in items" :item="item" :key="index"></video-item-grid>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/continue-watching/continue-watching.component.js b/share/lua/http/src/components/continue-watching/continue-watching.component.js
new file mode 100644
index 0000000000..9df879ebf9
--- /dev/null
+++ b/share/lua/http/src/components/continue-watching/continue-watching.component.js
@@ -0,0 +1,13 @@
+Vue.component('continue-watching', {
+ template: '#continue-watching-template',
+ data: function() {
+ return {
+ displayMode: 'grid',
+ items: [
+
+ ]
+ }
+ },
+ computed: { },
+ methods: { }
+});
diff --git a/share/lua/http/src/components/controls/filebrowser.component.html b/share/lua/http/src/components/controls/filebrowser.component.html
deleted file mode 100644
index c1baa75181..0000000000
--- a/share/lua/http/src/components/controls/filebrowser.component.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!-- file modal Template -->
-<script type="text/x-template" id="file-modal-template">
- <div>
- <div class="modal-dialog">
- <!-- Modal content-->
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
- <h4 class="modal-title">Select your file</h4>
- </div>
- <div class="modal-body" id="file-tree">
- </div>
- <div class="modal-footer">
- </div>
- </div>
- </div>
- </div>
-</script>
diff --git a/share/lua/http/src/components/controls/filebrowser.component.js b/share/lua/http/src/components/controls/filebrowser.component.js
deleted file mode 100644
index a156042176..0000000000
--- a/share/lua/http/src/components/controls/filebrowser.component.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import { notifyBus } from '../../services/bus.service.js';
-import { VIDEO_TYPES, AUDIO_TYPES, PLAYLIST_TYPES } from '../../services/initialize.service.js';
-
-Vue.component('file-modal', {
- template: '#file-modal-template',
- methods: {
- populateTree() {
- $('#file-tree').jstree({
- core: {
- multiple: false,
- animation: 100,
- check_callback: true,
- html_titles: true,
- load_open: true,
- themes: {
- variant: 'medium',
- dots: false
- },
- data: {
- url: (node) => {
- if (node.id === '#') {
- return 'requests/browse.json?dir=/';
- }
- return `requests/browse.json?dir=/${node.data.path}`;
- },
- dataType: 'json',
- dataFilter(rawData) {
- const data = JSON.parse(rawData);
- const result = data.element.map((d) => {
- const res = {
- text: d.name,
- data: {
- path: d.path,
- uri: d.uri,
- type: d.type
- },
- type: d.type,
- children: true
- };
- if (d.type === 'file') {
- res.children = false;
- }
- return res;
- });
- return JSON.stringify(result);
- }
- }
- },
- types: {
- '#': {
- valid_children: ['root']
- },
- root: {
- valid_children: ['default']
- },
- default: {
- valid_children: ['default', 'file']
- }
- },
- plugins: [
- 'themes',
- 'json_data',
- 'ui',
- 'cookies',
- 'crrm',
- 'sort',
- 'types'
- ]
- });
-
- $('#file-tree').on('select_node.jstree', (e, data) => {
- node = data.instance.get_node(data.selected[0]);
- ext = (node.data.uri).substr(node.data.uri.lastIndexOf('.') + 1).toLowerCase();
- if (node.data.type === 'file' && ($.inArray(ext, VIDEO_TYPES) !== -1 || $.inArray(ext, AUDIO_TYPES) !== -1 || $.inArray(ext, PLAYLIST_TYPES) !== -1)) {
- notifyBus('addItem', [1, '', node.data.uri,node.data.uri]);
- }
- }).jstree();
- }
- },
- mounted() {
- this.populateTree();
- }
-});
diff --git a/share/lua/http/src/components/controls/sidenav.component.html b/share/lua/http/src/components/controls/sidenav.component.html
deleted file mode 100644
index acc5eca71c..0000000000
--- a/share/lua/http/src/components/controls/sidenav.component.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!-- sideNav Template -->
-<script type="text/x-template" id="sidenav-template">
- <div>
- <div id="sideNav" class="sideNav">
- <a href="javascript:void(0)" class="closebtn" id="closeNavButton">
- Menu
- </a>
- <a href="#" data-toggle="modal" data-target="#fileModal">
- Open File
- </a>
- <a href="#">
- Local Network
- </a>
- <a href="#">
- Podcast
- </a>
- <a href="#" data-toggle="modal" data-target="#streamManagerModal">
- Manage Streams
- </a>
- <a href="#" data-toggle="modal" data-target="#trackSyncModal">
- Track Synchronization
- </a>
- <a href="#" data-toggle="modal" data-target="#vlmModal">
- VLM Batch Commands
- </a>
- </div>
- <span id="openNavButton">
- <svg-icon name="menu"></svg-icon>
- </span>
- </div>
-</script>
diff --git a/share/lua/http/src/components/controls/sidenav.component.js b/share/lua/http/src/components/controls/sidenav.component.js
deleted file mode 100644
index 878388a3c9..0000000000
--- a/share/lua/http/src/components/controls/sidenav.component.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { bus } from '../../services/bus.service.js';
-
-Vue.component('sidenav', {
- template: '#sidenav-template',
- methods: {
- openNav() {
- if (window.screen.width <= 480) {
- $('#sideNav').width('60%');
- } else {
- $('#sideNav').width('20%');
- }
- },
- closeNav() {
- $('#sideNav').width('0');
- }
- },
- created() {
- bus.$on('openNav', () => {
- this.openNav();
- });
-
- bus.$on('closeNav', () => {
- this.closeNav();
- });
- }
-});
diff --git a/share/lua/http/src/components/controls/sidenav.component.scss b/share/lua/http/src/components/controls/sidenav.component.scss
deleted file mode 100644
index fc7e7d7b13..0000000000
--- a/share/lua/http/src/components/controls/sidenav.component.scss
+++ /dev/null
@@ -1,50 +0,0 @@
-/* The side navigation menu */
-.sideNav {
- height: 100%;
- width: 0;
- position: fixed;
- z-index: 5;
- top: 0;
- left: 0;
- background-color: orange;
- overflow-x: hidden;
- padding-top: 60px;
- transition: 0.5s;
-}
-
-/* The navigation menu links */
-.sideNav a {
- padding: 8px 8px 8px 32px;
- text-decoration: none;
- font-size: 25px;
- color: #111;
- display: block;
- transition: 0.3s
-}
-
-/* When you mouse over the navigation links, change their color */
-.sideNav a:hover, .offcanvas a:focus{
- color: #f1f1f1;
-}
-
-/* Position and style the close button (top right corner) */
-.sideNav .closebtn {
- position: absolute;
- top: 0;
- font-size: 36px;
-}
-
-.sideNav .closespn {
- font-size: 36px;
- margin-left: 60%;
-}
-
-/* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */
- at media screen and (max-height: 450px) {
- .sideNav {padding-top: 15px;}
- .sideNav a {font-size: 18px;}
-}
-
-#openNavButton{
- color: orange;
-}
diff --git a/share/lua/http/src/components/enqueue-button/enqueue-button.component.html b/share/lua/http/src/components/enqueue-button/enqueue-button.component.html
new file mode 100644
index 0000000000..f1b58c2cb6
--- /dev/null
+++ b/share/lua/http/src/components/enqueue-button/enqueue-button.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="enqueue-button-template">
+ <button v-on:click="enqueueItem()" class="btn btn-sm enqueue-button">
+ <svg-icon name="playlist_add"></svg-icon> Enqueue
+ </button>
+</script>
diff --git a/share/lua/http/src/components/enqueue-button/enqueue-button.component.js b/share/lua/http/src/components/enqueue-button/enqueue-button.component.js
new file mode 100644
index 0000000000..21bf28bd07
--- /dev/null
+++ b/share/lua/http/src/components/enqueue-button/enqueue-button.component.js
@@ -0,0 +1,14 @@
+Vue.component('enqueue-button', {
+ template: '#enqueue-button-template',
+ props: ['item'],
+ methods: {
+ enqueueItem() {
+ if (this.item) {
+ // Check if in playlist else add it
+ if (this.item.mrl) {
+ this.$store.dispatch('playlist/addItem', this.item.mrl);
+ }
+ }
+ }
+ }
+});
diff --git a/share/lua/http/src/components/enqueue-button/enqueue-button.component.scss b/share/lua/http/src/components/enqueue-button/enqueue-button.component.scss
new file mode 100644
index 0000000000..17be26a21c
--- /dev/null
+++ b/share/lua/http/src/components/enqueue-button/enqueue-button.component.scss
@@ -0,0 +1,4 @@
+.btn.enqueue-button {
+ display: flex;
+ align-items: center;
+}
diff --git a/share/lua/http/src/components/equalizer/equalizer.component.html b/share/lua/http/src/components/equalizer/equalizer.component.html
index 9ab4ffda7b..b825edd576 100644
--- a/share/lua/http/src/components/equalizer/equalizer.component.html
+++ b/share/lua/http/src/components/equalizer/equalizer.component.html
@@ -5,8 +5,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Equalizer</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<input type="range" name="equalizerInput" id="equalizerInput" min="-20" max="20" step="0.1"/>
diff --git a/share/lua/http/src/components/genres/genre-item/genre-item-grid.component.html b/share/lua/http/src/components/genres/genre-item/genre-item-grid.component.html
new file mode 100644
index 0000000000..a3f2d899be
--- /dev/null
+++ b/share/lua/http/src/components/genres/genre-item/genre-item-grid.component.html
@@ -0,0 +1,12 @@
+<script type="text/x-template" id="genre-item-grid-template">
+ <div class="item-people genre-item tag-item genre-item-grid-template col-12 col-sm-6 col-md-4 col-lg-3">
+ <div class="item-img">
+ <img :src="item.src">
+ <div class="item-body">
+ <span class="item-title text-truncate">{{ item.name }}</span>
+ <span class="item-subtitle text-truncate">{{ item.nbTracks }} tracks</span>
+ </div>
+ <div class="overlay"></div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/genres/genre-item/genre-item-grid.component.js b/share/lua/http/src/components/genres/genre-item/genre-item-grid.component.js
new file mode 100644
index 0000000000..c65d4d3f64
--- /dev/null
+++ b/share/lua/http/src/components/genres/genre-item/genre-item-grid.component.js
@@ -0,0 +1,16 @@
+Vue.component('genre-item-grid', {
+ template: '#genre-item-grid-template',
+ props: ['item'],
+ data: function() {
+ return {
+ liked: this.item.liked
+ }
+ },
+ computed: { },
+ methods: {
+ toggleLiked() {
+ this.liked = !this.liked;
+ }
+ },
+ created() { }
+});
diff --git a/share/lua/http/src/components/genres/genres.component.html b/share/lua/http/src/components/genres/genres.component.html
new file mode 100644
index 0000000000..7b14a5eae9
--- /dev/null
+++ b/share/lua/http/src/components/genres/genres.component.html
@@ -0,0 +1,10 @@
+<script type="text/x-template" id="genres-template">
+ <div class="genres-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="row" v-if="layout.itemLayout === 'grid'">
+ <genre-item-grid v-for="(item, index) in music.genres" :item="item" :key="index"></genre-item-grid>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/genres/genres.component.js b/share/lua/http/src/components/genres/genres.component.js
new file mode 100644
index 0000000000..b10f5af8e5
--- /dev/null
+++ b/share/lua/http/src/components/genres/genres.component.js
@@ -0,0 +1,25 @@
+Vue.component('genres', {
+ template: '#genres-template',
+ data: function() {
+ return {
+ displayMode: 'grid',
+ items: [
+
+ ]
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ music: state => state.music,
+ layout: state => state.layout
+ }),
+ },
+ methods: {
+ fetchGenres() {
+ this.$store.dispatch('music/fetchGenres');
+ }
+ },
+ created() {
+ this.fetchGenres();
+ }
+});
diff --git a/share/lua/http/src/components/grid-item/grid-item.component.html b/share/lua/http/src/components/grid-item/grid-item.component.html
new file mode 100644
index 0000000000..d54b507924
--- /dev/null
+++ b/share/lua/http/src/components/grid-item/grid-item.component.html
@@ -0,0 +1,14 @@
+<script type="text/x-template" id="grid-item-template">
+ <div class="grid-item discover-services-item-grid-template col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div :class="item.additionalClass" class="item-img embed-responsive embed-responsive-1by1 img-contain">
+ <img v-if="item.src" class="embed-responsive-item p-4" :src="item.src">
+ <div v-else="item.icon" class="embed-responsive-item" :class="item.additionalItemClass">
+ <svg-icon :name="item.icon"></svg-icon>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link :to="item.titleRoute || '/album'" class="item-title text-truncate">{{ item.title }}</router-link>
+ <router-link v-if="item.subtitle" :to="item.subtitleRoute || '/artist'" class="item-subtitle text-truncate">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/grid-item/grid-item.component.js b/share/lua/http/src/components/grid-item/grid-item.component.js
new file mode 100644
index 0000000000..c8a06c8193
--- /dev/null
+++ b/share/lua/http/src/components/grid-item/grid-item.component.js
@@ -0,0 +1,5 @@
+Vue.component('grid-item', {
+ template: '#grid-item-template',
+ props: ['item'],
+ created() { }
+});
diff --git a/share/lua/http/src/components/item-layout-button/item-layout-button.component.html b/share/lua/http/src/components/item-layout-button/item-layout-button.component.html
new file mode 100644
index 0000000000..75f07346d9
--- /dev/null
+++ b/share/lua/http/src/components/item-layout-button/item-layout-button.component.html
@@ -0,0 +1,6 @@
+<script type="text/x-template" id="item-layout-button-template">
+ <button v-on:click="toggleItemLayout()" class="btn btn-circle active">
+ <svg-icon v-if="layout && layout.itemLayout === 'list'" name="format_list_bulleted"></svg-icon>
+ <svg-icon v-if="layout && layout.itemLayout === 'grid'" name="grid_view"></svg-icon>
+ </button>
+</script>
diff --git a/share/lua/http/src/components/item-layout-button/item-layout-button.component.js b/share/lua/http/src/components/item-layout-button/item-layout-button.component.js
new file mode 100644
index 0000000000..c58b5cb5b2
--- /dev/null
+++ b/share/lua/http/src/components/item-layout-button/item-layout-button.component.js
@@ -0,0 +1,16 @@
+Vue.component('item-layout-button', {
+ template: '#item-layout-button-template',
+ computed: {
+ ...Vuex.mapState({
+ layout: state => state.layout
+ }),
+ },
+ created() {
+ document.body.style['overflow-y'] = 'auto';
+ },
+ methods: {
+ toggleItemLayout() {
+ this.$store.dispatch('layout/toggleItemLayout');
+ }
+ }
+});
diff --git a/share/lua/http/src/components/library/library-item/library-item.component.html b/share/lua/http/src/components/library/library-item/library-item.component.html
new file mode 100644
index 0000000000..1ccde89882
--- /dev/null
+++ b/share/lua/http/src/components/library/library-item/library-item.component.html
@@ -0,0 +1,11 @@
+<script type="text/x-template" id="library-item-template">
+ <div class="library-item">
+ <div class="library-item-img">
+ <img src="http://images.videolan.org/images/VLC-IconSmall.png">
+ </div>
+ <div class="library-item-body">
+ <div class="library-item-name text-truncate">{{ item.name }}</div>
+ <div class="library-item-artist text-truncate">{{ item.artist }}</div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/library/library-item/library-item.component.js b/share/lua/http/src/components/library/library-item/library-item.component.js
new file mode 100644
index 0000000000..6737b2db93
--- /dev/null
+++ b/share/lua/http/src/components/library/library-item/library-item.component.js
@@ -0,0 +1,15 @@
+Vue.component('library-item', {
+ template: '#library-item-template',
+ computed: {
+
+ },
+ methods: {
+
+ },
+ created() {
+ this.item = {
+ name: 'Some name',
+ artist: 'Some artist'
+ }
+ }
+});
diff --git a/share/lua/http/src/components/library/library-item/library-item.component.scss b/share/lua/http/src/components/library/library-item/library-item.component.scss
new file mode 100644
index 0000000000..6ad6a56902
--- /dev/null
+++ b/share/lua/http/src/components/library/library-item/library-item.component.scss
@@ -0,0 +1,26 @@
+.library-item {
+ display: inline-block;
+ width: 150px;
+ margin: 10px;
+ .library-item-img {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--library-item-bg-color);
+ height: 150px;
+ }
+ .library-item-body {
+ text-align: center;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin-top: 5px;
+ .library-item-name {
+ font-weight: bold;
+ }
+ .library-item-artist {
+ font-weight: normal;
+ color: var(--secondary-text-color);
+ font-size: 0.8rem;
+ }
+ }
+}
\ No newline at end of file
diff --git a/share/lua/http/src/components/library/library.component.html b/share/lua/http/src/components/library/library.component.html
new file mode 100644
index 0000000000..12ca97ec88
--- /dev/null
+++ b/share/lua/http/src/components/library/library.component.html
@@ -0,0 +1,17 @@
+<script type="text/x-template" id="library-template">
+ <div class="library-view container-fluid">
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ <library-item></library-item>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/library/library.component.js b/share/lua/http/src/components/library/library.component.js
new file mode 100644
index 0000000000..87dc6ea235
--- /dev/null
+++ b/share/lua/http/src/components/library/library.component.js
@@ -0,0 +1,5 @@
+Vue.component('library', {
+ template: '#library-template',
+ computed: { },
+ methods: { }
+});
diff --git a/share/lua/http/src/components/library/library.component.scss b/share/lua/http/src/components/library/library.component.scss
new file mode 100644
index 0000000000..823aa363f4
--- /dev/null
+++ b/share/lua/http/src/components/library/library.component.scss
@@ -0,0 +1,3 @@
+.library-view {
+ margin: 90px 20px 20px 8px;
+}
diff --git a/share/lua/http/src/components/media-player/media-player.component.html b/share/lua/http/src/components/media-player/media-player.component.html
new file mode 100644
index 0000000000..5260d59cc8
--- /dev/null
+++ b/share/lua/http/src/components/media-player/media-player.component.html
@@ -0,0 +1,66 @@
+<script type="text/x-template" id="media-player-template">
+ <div id="media-player" class="media-player">
+ <audio class="d-none" controls="false" ref="player" :src="src"></audio>
+ <div class="seek-bar">
+ <div class="seek-bar-track">
+ <div ref="progressBar" class="seek-bar-progress slider-fill"></div>
+ <div ref="bufferBar" class="seek-bar-buffer slider-fill"></div>
+ </div>
+ <input ref="scrubber" class="seek-bar-scrubber" type="range" min="0" max="1000" value="0"></input>
+ </div>
+ <div class="d-flex align-items-center justify-content-center media-player-container">
+ <div class="metadata d-flex flex-1">
+ <!-- Image + info -->
+ <img class="img" v-if="imageSrc" :src="imageSrc">
+ <svg-icon v-if="!imageSrc" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <span class="ml-2 d-flex flex-column justify-content-center">
+ <span class="title font-weight-bold">{{ status.information && status.information.category && status.information.category.meta ? status.information.category.meta.filename : '' }} </span>
+ <span class="subtitle muted-opacity"></span>
+ <span class="subtitle2 muted-opacity">{{ formattedCurrentTime }} / {{ formattedDuration }}</span>
+ </span>
+ </div>
+ <div class="primary-actions d-flex flex-1 justify-content-center">
+ <!-- Primary actions -->
+ <button v-on:click="toggleRandom()" class="btn btn-link p-0 media-action" :class="{ active: status.random }">
+ <svg-icon name="shuffle"></svg-icon>
+ </button>
+ <button class="btn btn-link p-0 media-action" v-on:click="previous()">
+ <svg-icon name="skip_previous"></svg-icon>
+ </button>
+ <button class="btn btn-link p-0 media-action play-action" v-on:click="playing ? pause() : play()">
+ <svg-icon v-if="status.state === 'playing'" name="pause"></svg-icon>
+ <svg-icon v-else name="play_arrow"></svg-icon>
+ </button>
+ <button class="btn btn-link p-0 media-action" v-on:click="next()">
+ <svg-icon name="skip_next"></svg-icon>
+ </button>
+ <button v-on:click="toggleRepeat()" class="btn btn-link p-0 media-action" :class="{ active: status.repeat }">
+ <svg-icon name="repeat"></svg-icon>
+ </button>
+ </div>
+ <div class="secondary-actions d-flex flex-1 justify-content-end">
+ <!-- Secondary actions -->
+ <div class="media-action volume-container">
+ <button class="btn btn-link p-0 media-action" v-on:click="toggleMute()">
+ <svg-icon v-if="volumeIconState === 'mute'" name="volume_off"></svg-icon>
+ <svg-icon v-if="volumeIconState === 'up'" name="volume_up"></svg-icon>
+ <svg-icon v-if="volumeIconState === 'down'" name="volume_down"></svg-icon>
+ </button>
+ <div class="volume-panel">
+ <div class="volume-slider">
+ <div class="volume-slider-track-default"></div>
+ <div ref="volumeBar" class="volume-slider-track-active"></div>
+ <input ref="volume" class="volume-slider-input" type="range">
+ </div>
+ </div>
+ </div>
+ <button v-on:click="toggleFullscreen()" class="btn btn-link p-0 media-action" :class="{ active: status.fullscreen }">
+ <svg-icon name="Icon-Fullscreen"></svg-icon>
+ </button>
+ <div class="media-action">
+ <svg-icon name="more-vertical"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/media-player/media-player.component.js b/share/lua/http/src/components/media-player/media-player.component.js
new file mode 100644
index 0000000000..c753c10b96
--- /dev/null
+++ b/share/lua/http/src/components/media-player/media-player.component.js
@@ -0,0 +1,268 @@
+const formatTime = second => new Date(second * 1000).toISOString().substr(11, 8);
+Vue.component('media-player', {
+ template: '#media-player-template',
+ props: ['src', 'autoPlay', 'ended', 'canPlay'],
+ computed: {
+ ...Vuex.mapState({
+ activeItem: state => state.playlist.activeItem,
+ status: state => state.status.data
+ }),
+ },
+ data() {
+ return {
+ firstPlay: true,
+ isMuted: false,
+ loaded: false,
+ playing: false,
+ paused: false,
+ percentage: 0,
+ currentTime: '00:00:00',
+ audio: undefined,
+ totalDuration: 0,
+ duration: 0,
+ volumeIconState: 'up',
+ formattedDuration: formatTime(0),
+ formattedCurrentTime: formatTime(0),
+ imageSrc
+ }
+ },
+ methods: {
+ init: function() {
+ this.player.addEventListener('loadeddata', this._handleLoaded);
+ this.player.addEventListener('pause', this._handlePlayPause);
+ this.player.addEventListener('play', this._handlePlayPause);
+ this.player.addEventListener('seeked', this._handleSeeked);
+ this.player.addEventListener('progress', this._handleProgress);
+ this.player.addEventListener('timeupdate', this._handleTimeUpdate);
+ this.player.addEventListener('ended', this._handleEnded);
+ this.player.volume = 0.5;
+
+ this.scrubber.addEventListener('input', this._handleScrubberChange);
+ this.volume.addEventListener('input', this._handleVolumeChange);
+ this._handleVolumeChange();
+ },
+ fetchStatus() {
+ this.$store.dispatch('status/fetchStatus');
+ },
+ refreshStatus() {
+ if (this.interval) {
+ clearTimeout(this.interval);
+ this.interval = null;
+ }
+ this.fetchStatus();
+ this.interval = setInterval(() => {
+ this.fetchStatus();
+ }, 1000);
+ },
+ play(dispatch = true) {
+ this.previousState = null;
+ if (this.playing) {
+ return;
+ }
+ this.paused = false;
+ if (this.src) {
+ this.player.play().then(() => {
+ this.playing = true;
+ });
+ } else {
+ this.playing = true;
+ }
+ if (dispatch) {
+ this.$store.dispatch('status/play', this.status.currentplid);
+ }
+ },
+ pause(dispatch = true) {
+ this.previousState = null;
+ this.paused = !this.paused;
+ if (this.src) {
+ this.paused ? this.player.pause() : this.player.play();
+ }
+ if (dispatch) {
+ this.$store.dispatch('status/pause', this.status.currentplid);
+ }
+ },
+ stop(dispatch = true) {
+ this.previousState = null;
+ this.paused = this.playing = false;
+ if (this.src) {
+ this.player.pause();
+ }
+ this.player.currentTime = 0;
+ if (dispatch) {
+ this.$store.dispatch('status/stop', this.status.currentplid);
+ }
+ },
+ setPosition() {
+ this.player.currentTime = parseInt(this.player.duration / 100 * this.percentage);
+ },
+ next() {
+ this.$store.dispatch('status/next');
+ },
+ previous() {
+ this.$store.dispatch('status/previous');
+ },
+ toggleRandom() {
+ this.$store.dispatch('status/toggleRandom');
+ },
+ toggleRepeat() {
+ this.$store.dispatch('status/toggleRepeat');
+ },
+ toggleFullscreen() {
+ this.$store.dispatch('status/toggleFullscreen');
+ },
+ toggleMute() {
+ if (parseInt(this.volume.value)) {
+ this.previousVolume = this.volume.value;
+ this.volume.value = 0;
+ } else {
+ this.volume.value = this.previousVolume;
+ }
+ this._handleVolumeChange();
+ },
+ handleState(state) {
+ if (this.previousState && this.previousState == state) {
+ return;
+ }
+ this.previousState = state;
+ switch (state) {
+ case 'playing':
+ this.play(false);
+ break;
+ case 'paused':
+ this.pause(false);
+ break;
+ case 'stopped':
+ this.stop(false);
+ break;
+ }
+ },
+ handleVolume(volume) {
+ this.volume.value = volume / 255 * 100;
+ this._handleVolumeChange(false);
+ },
+ handleCurrentTime(currentTime) {
+ this.player.currentTime = currentTime;
+ this._handleTimeUpdate();
+ },
+ _handleSeeked() {
+ },
+ _handleProgress: function() {
+ let duration = this.player.duration;
+ if (duration > 0) {
+ for (let i = 0; i < this.player.buffered.length; i++) {
+ if (this.player.buffered.start(this.player.buffered - 1 - i) < this.player.currentTime) {
+ let scaleX = this.player.buffered.end(this.player.buffered.length - 1 - i) / duration;
+ this.bufferBar.style.transform = `scaleX(${scaleX})`;
+ break;
+ }
+ }
+ }
+ },
+ _handleTimeUpdate: function() {
+ this.duration = this.status.length * 1000;
+ const currentTime = this.status.time * 1000;
+ this.percentage = currentTime / this.duration * 100
+ this.formattedCurrentTime = formatTime(currentTime / 1000);
+ this.formattedDuration = formatTime(this.duration / 1000);
+ if (this.duration > 0) {
+ let scaleX = currentTime / this.duration;
+ this.progressBar.style.transform = `scaleX(${scaleX})`;
+ // Update scrubber
+ this.scrubber.value = scaleX * 1000;
+ }
+ },
+ _handleEnded() {
+ this.paused = this.playing = false;
+ },
+ _handlePlayPause: function(e) {
+ if (e.type === 'play' && this.firstPlay) {
+ this.player.currentTime = 0;
+ if (this.firstPlay) {
+ this.firstPlay = false;
+ }
+ }
+ if (e.type === 'pause' && this.paused === false && this.playing === false) {
+ this.formattedCurrentTime = formatTime(0);
+ }
+ },
+ _handleLoaded: function() {
+ if (this.player.readyState >= 2) {
+ if (this.player.duration === Infinity) {
+ this.player.currentTime = 1e101;
+ this.player.ontimeupdate = () => {
+ this.player.ontimeupdate = () => {}
+ this.player.currentTime = 0
+ this.totalDuration = parseInt(this.player.duration)
+ this.loaded = true;
+ }
+ } else {
+ this.totalDuration = parseInt(this.player.duration);
+ this.loaded = true;
+ }
+ // this.duration = formatTime(this.totalDuration);
+ if (this.autoPlay) {
+ this.player.play();
+ }
+ } else {
+ throw new Error('Failed to load sound file')
+ }
+ },
+ _handleScrubberChange: function(e) {
+ this.progressBar.style.transition = 'none;';
+ this.progressBar.style.transform = `scaleX(${this.scrubber.value / 1000})`;
+ this.progressBar.style.transition = 'transform .1s;';
+ const cTime = this.scrubber.value / 1000 * (this.duration);
+ this.player.currentTime = cTime;
+ this.$store.dispatch('status/seek', (this.player.currentTime / 1000).toFixed());
+ },
+ _handleVolumeChange: function(dispatch = true) {
+ this.volumeBar.style.width = `${this.volume.value}%`;
+ this.player.volume = this.volume.value / 100;
+ if (dispatch) {
+ this.$store.dispatch('status/updateVolume', this.player.volume * 255);
+ }
+ if (this.volume.value >= 50) {
+ this.volumeIconState = 'up';
+ } else if (this.volume.value < 50 && this.volume.value > 0) {
+ this.volumeIconState = 'down';
+ } else {
+ this.volumeIconState = 'mute';
+ }
+ }
+ },
+ mounted() {
+ this.player = this.$refs.player;
+ this.scrubber = this.$refs.scrubber;
+ this.volume = this.$refs.volume;
+ this.progressBar = this.$refs.progressBar;
+ this.volumeBar = this.$refs.volumeBar;
+ this.bufferBar = this.$refs.bufferBar;
+ this.init();
+ this.$store.subscribe((mutation, payload) => {
+ switch (mutation.type) {
+ case 'status/setStatus':
+ this.handleCurrentTime(payload.status.data.time);
+ this.handleState(payload.status.data.state);
+ this.handleVolume(payload.status.data.volume);
+ break;
+ // case 'playlist/activeItem':
+ }
+ });
+ },
+ created() {
+ this.refreshStatus();
+ },
+ beforeDestroy() {
+ this.player.removeEventListener('loadeddata', this._handleLoaded);
+ this.player.removeEventListener('pause', this._handlePlayPause);
+ this.player.removeEventListener('play', this._handlePlayPause);
+ this.player.removeEventListener('seeked', this._handleSeeked);
+ this.player.removeEventListener('progress', this._handleProgress);
+ this.player.removeEventListener('timeupdate', this._handleTimeUpdate);
+ this.player.removeEventListener('ended', this._handleEnded);
+
+ this.scrubber.removeEventListener('input', this._handleScrubberChange);
+ this.volume.removeEventListener('input', this._handleVolumeChange);
+ clearTimeout(this.interval);
+ }
+});
diff --git a/share/lua/http/src/components/media-player/media-player.component.scss b/share/lua/http/src/components/media-player/media-player.component.scss
new file mode 100644
index 0000000000..b01d464101
--- /dev/null
+++ b/share/lua/http/src/components/media-player/media-player.component.scss
@@ -0,0 +1,133 @@
+.media-player {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 86px;
+ background-color: var(--media-player-bg-color);
+ backdrop-filter: blur(10px);
+ z-index: 9999;
+ .img {
+ width: 70px;
+ height: 70px;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
+ border-radius: 3px;
+ overflow: hidden;
+ }
+ .seek-bar {
+ position: absolute;
+ width: 100%;
+ top: 0;
+ }
+ .media-player-container {
+ margin: 15px 10px 10px 10px;
+ }
+ .seek-bar-track {
+ height: 4px;
+ position: relative;
+ &::before {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ content: '';
+ background-color: rgba(0, 0, 0, 0.6);
+ transition: background-color .6s;
+ transition-delay: .2s;
+ }
+ }
+ .slider-fill {
+ position: absolute;
+ transition: transform .1s;
+ transform-origin: center left;
+ width: 100%;
+ height: 4px;
+ }
+ .seek-bar-progress {
+ background-color: var(--highlight-color);
+ transform: scaleX(0);
+ }
+ .seek-bar-buffer {
+ background-color: rgba(244, 139, 0, 0.45);
+ top: 0;
+ transform: scaleX(0);
+ }
+ input[type=range]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ border: none;
+ height: 16px;
+ width: 16px;
+ border-radius: 50%;
+ background: #ffffff;
+ cursor: pointer;
+ box-shadow: 0.5px 0.5px 0.5px #000000, 0px 0px 0.5px #0d0d0d;
+ }
+ .seek-bar-scrubber {
+ -webkit-appearance: none;
+ background: transparent;
+ cursor: pointer;
+ height: 8px;
+ right: 0;
+ position: absolute;
+ top: -2px;
+ width: 100%;
+ outline: none;
+ }
+ .media-action {
+ width: 2rem;
+ height: 2rem;
+ margin: 0 5px;
+ }
+ .volume-container {
+ display: flex;
+ align-items: center;
+ width: 100px;
+ .volume-panel {
+ position: relative;
+ height: 6px;
+ }
+ .volume-slider {
+ width: 70px;
+ }
+ .volume-slider-track-default {
+ position: absolute;
+ border-radius: 4px;
+ left: 0;
+ background-color: rgba(0, 0, 0, 0.6);
+ height: 6px;
+ width: 100%;
+ }
+ .volume-slider-track-active {
+ background-color: var(--highlight-color);
+ position: absolute;
+ height: 6px;
+ width: 50%;
+ }
+ .volume-slider-input {
+ -webkit-appearance: none;
+ background: rgba(0,0,0,0);
+ cursor: pointer;
+ height: 6px;
+ position: absolute;
+ width: 100%;
+ outline: none;
+ }
+ }
+ .media-action.play-action {
+ border-radius: 50%;
+ background: rgba(0, 0, 0, 0.7);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ .svg-icon {
+ color: #fff;
+ }
+ }
+ .subtitle {
+ font-size: 0.8rem;
+ }
+ .subtitle2 {
+ font-size: 0.8rem;
+ }
+}
diff --git a/share/lua/http/src/components/play-button/play-button-secondary.component.html b/share/lua/http/src/components/play-button/play-button-secondary.component.html
new file mode 100644
index 0000000000..68ee5face0
--- /dev/null
+++ b/share/lua/http/src/components/play-button/play-button-secondary.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="play-button-secondary-template">
+ <button v-on:click="playItem()" class="btn btn-sm play-button-secondary">
+ <svg-icon name="play_arrow"></svg-icon> Play
+ </button>
+</script>
diff --git a/share/lua/http/src/components/play-button/play-button-secondary.component.js b/share/lua/http/src/components/play-button/play-button-secondary.component.js
new file mode 100644
index 0000000000..94d1953c0b
--- /dev/null
+++ b/share/lua/http/src/components/play-button/play-button-secondary.component.js
@@ -0,0 +1,15 @@
+Vue.component('play-button-secondary', {
+ template: '#play-button-secondary-template',
+ props: ['item'],
+ methods: {
+ playItem() {
+ if (this.item) {
+ // Check if in playlist else add it
+ if (this.item.mrl) {
+ this.$store.dispatch('playlist/addItem', this.item.mrl);
+ }
+ this.$store.dispatch('status/play', this.item.id);
+ }
+ }
+ }
+});
diff --git a/share/lua/http/src/components/play-button/play-button-secondary.component.scss b/share/lua/http/src/components/play-button/play-button-secondary.component.scss
new file mode 100644
index 0000000000..0e58647cee
--- /dev/null
+++ b/share/lua/http/src/components/play-button/play-button-secondary.component.scss
@@ -0,0 +1,12 @@
+.btn.play-button-secondary {
+ background-color: var(--highlight-color);
+ color: #fff;
+ display: flex;
+ align-items: center;
+ .svg-icon {
+ color: #fff;
+ }
+ &:hover, &:active, &:focus {
+ color: #fff;
+ }
+}
diff --git a/share/lua/http/src/components/play-button/play-button.component.html b/share/lua/http/src/components/play-button/play-button.component.html
new file mode 100644
index 0000000000..883d3f84a2
--- /dev/null
+++ b/share/lua/http/src/components/play-button/play-button.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="play-button-template">
+ <button v-on:click="playItem()" class="btn btn-link play-button">
+ <svg-icon name="play_arrow"></svg-icon>
+ </button>
+</script>
diff --git a/share/lua/http/src/components/play-button/play-button.component.js b/share/lua/http/src/components/play-button/play-button.component.js
new file mode 100644
index 0000000000..6810eb9a2e
--- /dev/null
+++ b/share/lua/http/src/components/play-button/play-button.component.js
@@ -0,0 +1,16 @@
+Vue.component('play-button', {
+ template: '#play-button-template',
+ props: ['item'],
+ methods: {
+ playItem() {
+ if (this.item) {
+ // Check if in playlist else add it
+ // Don't add if already added
+ if (this.item.mrl) {
+ this.$store.dispatch('playlist/addItem', this.item.mrl);
+ }
+ this.$store.dispatch('status/play', this.item.id);
+ }
+ }
+ }
+});
diff --git a/share/lua/http/src/components/play-button/play-button.component.scss b/share/lua/http/src/components/play-button/play-button.component.scss
new file mode 100644
index 0000000000..ce8158dd81
--- /dev/null
+++ b/share/lua/http/src/components/play-button/play-button.component.scss
@@ -0,0 +1,28 @@
+.play-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ transition: opacity 0.2s ease, visibility 0.2s, transform 0.2s;
+ border: none;
+ padding: 0;
+ margin: 0;
+ transition: opacity 0.2s ease, visibility 0.2s, transform 0.2s;
+ background: rgba(0, 0, 0, 0.4);
+ border: 2px solid #fff;
+ .svg-icon {
+ color: #fff;
+ &:hover,
+ &:focus {
+ color: #fff;
+ }
+ }
+ &:hover {
+ transform: scale3d(1.2,1.2,1.2);
+ -webkit-transform: scale3d(1.2,1.2,1.2);
+ }
+ &:active {
+ transform: scaleX(1);
+ -webkit-transform: scaleX(1);
+ }
+}
\ No newline at end of file
diff --git a/share/lua/http/src/components/player/player.component.scss b/share/lua/http/src/components/player/player.component.scss
deleted file mode 100644
index 753348e9c7..0000000000
--- a/share/lua/http/src/components/player/player.component.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-#videoPlayer {
- padding-right: 12%;
- padding-left: 2%;
- left:0;
- top:0;
- margin:0;
- width:90%;
-}
-
- at media screen and (min-device-width: 320px) and (max-device-width: 480px) {
- #videoPlayer {
- padding-right: 12%;
- padding-left: 2%;
- top: initial;
- left: initial;
- margin:0 auto;
- width:100%;
- }
-}
diff --git a/share/lua/http/src/components/player/plyr.lib.custom.scss b/share/lua/http/src/components/player/plyr.lib.custom.scss
deleted file mode 100644
index 931e45c46b..0000000000
--- a/share/lua/http/src/components/player/plyr.lib.custom.scss
+++ /dev/null
@@ -1,758 +0,0 @@
-// ==========================================================================
-// Plyr styles
-// https://github.com/selz/plyr
-// ==========================================================================
-
- at import "plyr.lib.vars.scss";
- at import "../../scss/mixins.util.scss";
-
-// Animation
-// ---------------------------------------
- at keyframes plyr-progress {
- to { background-position: $plyr-progress-loading-size 0; }
-}
-
-// Styles
-// -------------------------------
-// Base
-.plyr {
- position: relative;
- max-width: 100%;
- min-width: 200px;
- font-family: $plyr-font-family;
- direction: ltr;
-
- @if $plyr-border-box == true {
- // border-box everything
- // http://paulirish.com/2012/box-sizing-border-box-ftw/
- &,
- *,
- *::after,
- *::before {
- box-sizing: border-box;
- }
- }
-
- @if $plyr-touch-action == true {
- // Fix 300ms delay
- a, button, input, label {
- touch-action: manipulation;
- }
- }
-
- // Focus
- &:focus {
- outline: 0;
- }
-
- // Media elements
- video,
- audio {
- width: 100%;
- height: auto;
- vertical-align: middle;
- border-radius: inherit;
- }
-
- // Range inputs
- // Specificity is for bootstrap compatibility
- input[type='range'] {
- display: block;
- height: ($plyr-range-thumb-height * $plyr-range-thumb-active-scale);
- width: 100%;
- margin: 0;
- padding: 0;
- vertical-align: middle;
-
- @include prefix(appearance, none);
- cursor: pointer;
- border: none;
- background: transparent;
-
- // WebKit
- &::-webkit-slider-runnable-track {
- @include plyr-range-track();
- }
- &::-webkit-slider-thumb {
- @include prefix(appearance, none);
- margin-top: -(($plyr-range-thumb-height - $plyr-range-track-height) / 2);
- @include plyr-range-thumb();
- }
-
- // Mozilla
- &::-moz-range-track {
- @include plyr-range-track();
- }
- &::-moz-range-thumb {
- @include plyr-range-thumb();
- }
-
- // Microsoft
- &::-ms-track {
- height: $plyr-range-track-height;
- background: transparent;
- border: 0;
- color: transparent;
- }
- &::-ms-fill-upper {
- @include plyr-range-track();
- }
- &::-ms-fill-lower {
- @include plyr-range-track();
- background: $plyr-range-selected-bg;
- }
- &::-ms-thumb {
- @include plyr-range-thumb();
- // For some reason, Edge uses the -webkit margin above
- margin-top: 0;
- }
- &::-ms-tooltip {
- display: none;
- }
-
- // Focus styles
- &:focus {
- outline: 0;
- }
- &::-moz-focus-outer {
- border: 0;
- }
- &.tab-focus:focus {
- outline-offset: 3px;
- }
-
- // Pressed styles
- &:active {
- &::-webkit-slider-thumb {
- @include plyr-range-thumb-active();
- }
- &::-moz-range-thumb {
- @include plyr-range-thumb-active();
- }
- &::-ms-thumb {
- @include plyr-range-thumb-active();
- }
- }
- }
-}
-
-// Video range inputs
-.plyr--video input[type='range'].tab-focus:focus {
- outline: 1px dotted transparentize($plyr-video-control-color, .5);
-}
-
-// Audio range inputs
-.plyr--audio input[type='range'].tab-focus:focus {
- outline: 1px dotted transparentize($plyr-audio-control-color, .5);
-}
-
-// Screen reader only elements
-.plyr__sr-only {
- clip: rect(1px, 1px, 1px, 1px);
- overflow: hidden;
-
- // !important is not always needed
- @if $plyr-sr-only-important == true {
- position: absolute !important;
- padding: 0 !important;
- border: 0 !important;
- height: 1px !important;
- width: 1px !important;
- } @else {
- position: absolute;
- padding: 0;
- border: 0;
- height: 1px;
- width: 1px;
- }
-}
-
-// Video
-.plyr__video-wrapper {
- position: relative;
- background: #000;
- border-radius: inherit;
-}
-
-// Container for embeds
-.plyr__video-embed {
- padding-bottom: 56.25%; /* 16:9 */
- height: 0;
- border-radius: inherit;
-
- // Require overflow and z-index to force border-radius
- overflow: hidden;
- z-index: 0;
-
- iframe {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- border: 0;
- user-select: none;
- }
-
- // Vimeo hack
- > div {
- position: relative;
- padding-bottom: 200%;
- @include prefix(transform, translateY(-35.95%));
- }
-}
-// To allow mouse events to be captured if full support
-.plyr .plyr__video-embed iframe {
- pointer-events: none;
-}
-
-// Captions
-// --------------------------------------------------------------
-// Hide default captions
-.plyr video::-webkit-media-text-track-container {
- display: none;
-}
-.plyr__captions {
- display: none;
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- padding: ($plyr-control-spacing * 2);
- @include prefix(transform, translateY(-($plyr-control-spacing * 6)));
- transition: transform .3s ease;
- color: $plyr-captions-color;
- font-size: $plyr-font-size-captions-base;
- text-align: center;
- font-weight: 400;
-
- span {
- border-radius: 2px;
- padding: floor($plyr-control-spacing / 3) $plyr-control-spacing;
- background: $plyr-captions-bg;
- box-decoration-break: clone;
- line-height: 150%;
- }
- span:empty {
- display: none;
- }
-
- @media (min-width: $plyr-bp-screen-md) {
- font-size: $plyr-font-size-captions-medium;
- }
-}
-.plyr--captions-active .plyr__captions {
- display: block;
-}
-.plyr--hide-controls .plyr__captions {
- @include prefix(transform, translateY(-($plyr-control-spacing * 2)));
-}
-// Large captions in full screen on larger screens
- at media (min-width: $plyr-bp-screen-lg) {
- .plyr--fullscreen-active .plyr__captions {
- font-size: $plyr-font-size-captions-large;
- }
-}
-
-// Controls
-// --------------------------------------------------------------
-// Hide native controls
-.plyr ::-webkit-media-controls {
- display: none;
-}
-
-// Playback controls
-.plyr__controls {
- display: flex;
- align-items: center;
- line-height: 1;
- text-align: center;
-
- // Spacing
- > button,
- .plyr__progress,
- .plyr__time {
- margin-left: ($plyr-control-spacing / 2);
-
- &:first-child {
- margin-left: 0;
- }
- }
- .plyr__volume {
- margin-left: ($plyr-control-spacing / 2);
- }
- [data-plyr="pause"] {
- margin-left: 0;
- }
-
- // Buttons
- button {
- position: relative;
- display: inline-block;
- flex-shrink: 0;
- overflow: visible; // IE11
- vertical-align: middle;
- padding: ($plyr-control-spacing * .7);
- border: 0;
- background: transparent;
- border-radius: 3px;
- cursor: pointer;
- transition: background .3s ease, color .3s ease, opacity .3s ease;
- color: inherit;
-
- svg {
- width: $plyr-control-icon-size;
- height: $plyr-control-icon-size;
- display: block;
- fill: currentColor;
- }
-
- // Default focus
- &:focus {
- outline: 0;
- }
- }
-
- // Hide toggle icons by default
- .icon--exit-fullscreen,
- .icon--muted,
- .icon--captions-on {
- display: none;
- }
-
- @media (min-width: $plyr-bp-screen-sm) {
- > button,
- .plyr__progress,
- .plyr__time {
- margin-left: $plyr-control-spacing;
- }
- }
-}
-// Hide controls
-.plyr--hide-controls .plyr__controls {
- opacity: 0;
- pointer-events: none;
-}
-
-// Video controls
-.plyr--video .plyr__controls {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- padding: ($plyr-control-spacing * 5) $plyr-control-spacing $plyr-control-spacing;
- background: linear-gradient(transparentize($plyr-video-controls-bg, 1), transparentize($plyr-video-controls-bg, .5));
- border-bottom-left-radius: inherit;
- border-bottom-right-radius: inherit;
- color: $plyr-video-control-color;
- transition: opacity .3s ease;
-
- button {
- // Hover and tab focus
- &.tab-focus:focus,
- &:hover {
- background: $plyr-video-control-bg-hover;
- color: $plyr-video-control-color-hover;
- }
- }
-}
-
-// Audio controls
-.plyr--audio .plyr__controls {
- padding: $plyr-control-spacing;
- border-radius: inherit;
- background: $plyr-audio-controls-bg;
- border: $plyr-audio-controls-border;
- color: $plyr-audio-control-color;
-
- button {
- // Hover and tab focus
- &.tab-focus:focus,
- &:hover {
- background: $plyr-audio-control-bg-hover;
- color: $plyr-audio-control-color-hover;
- }
- }
-}
-
-// Large play button (video only)
-.plyr__play-large {
- display: none;
- position: absolute;
- z-index: 1;
- top: 50%;
- left: 50%;
- @include prefix(transform, translate(-50%, -50%));
- padding: $plyr-control-spacing;
- background: $plyr-video-control-bg-hover;
- border: 4px solid currentColor;
- border-radius: 100%;
- box-shadow: 0 1px 1px transparentize(#000, .85);
- color: $plyr-video-control-color;
- transition: all .3s ease;
-
- svg {
- position: relative;
- left: 2px;
- width: 20px;
- height: 20px;
- display: block;
- fill: currentColor;
- }
-
- &:focus {
- outline: 1px dotted transparentize($plyr-video-control-color, .5);
- }
-}
-.plyr .plyr__play-large {
- display: inline-block;
-}
-.plyr--audio .plyr__play-large {
- display: none;
-}
-.plyr--playing .plyr__play-large {
- opacity: 0;
- visibility: hidden;
-}
-
-// States
-.plyr__controls [data-plyr='pause'],
-.plyr--playing .plyr__controls [data-plyr='play'] {
- display: none;
-}
-.plyr--playing .plyr__controls [data-plyr='pause'] {
- display: inline-block;
-}
-
-// Change icons on state change
-.plyr--fullscreen-active .icon--exit-fullscreen,
-.plyr--muted .plyr__controls .icon--muted,
-.plyr--captions-active .plyr__controls .icon--captions-on {
- display: block;
-
- & + svg {
- display: none;
- }
-}
-
-// Some options are hidden by default
-.plyr [data-plyr='captions'],
-.plyr [data-plyr='fullscreen'] {
- display: none;
-}
-.plyr--captions-enabled [data-plyr='captions'],
-.plyr--fullscreen-enabled [data-plyr='fullscreen'] {
- display: inline-block;
-}
-
-// Tooltips
-// --------------------------------------------------------------
-.plyr__tooltip {
- position: absolute;
- z-index: 2;
- bottom: 100%;
- margin-bottom: ($plyr-tooltip-padding * 2);
- padding: $plyr-tooltip-padding ($plyr-tooltip-padding * 1.5);
- pointer-events: none;
-
- opacity: 0;
- background: $plyr-tooltip-bg;
- border-radius: $plyr-tooltip-radius;
-
- color: $plyr-tooltip-color;
- font-size: $plyr-font-size-small;
- line-height: 1.3;
-
- @include prefix(transform, translate(-50%, 10px) scale(.8));
- transform-origin: 50% 100%;
- transition: transform .2s .1s ease, opacity .2s .1s ease;
-
- &::before {
- // Arrows
- content: '';
- position: absolute;
- width: 0;
- height: 0;
- left: 50%;
- @include prefix(transform, translateX(-50%));
-
- // The background triangle
- bottom: -$plyr-tooltip-arrow-size;
- border-right: $plyr-tooltip-arrow-size solid transparent;
- border-top: $plyr-tooltip-arrow-size solid $plyr-tooltip-bg;
- border-left: $plyr-tooltip-arrow-size solid transparent;
- z-index: 2;
- }
-}
-.plyr button:hover .plyr__tooltip,
-.plyr button.tab-focus:focus .plyr__tooltip,
-.plyr__tooltip--visible {
- opacity: 1;
- @include prefix(transform, translate(-50%, 0) scale(1));
-}
-.plyr button:hover .plyr__tooltip {
- z-index: 3;
-}
-
-// First tooltip
-.plyr__controls button:first-child .plyr__tooltip {
- left: 0;
- @include prefix(transform, translate(0, 10px) scale(.8));
- transform-origin: 0 100%;
-
- &::before {
- left: ($plyr-control-icon-size / 2) + $plyr-control-padding;
- }
-}
-
-// Last tooltip
-.plyr__controls button:last-child .plyr__tooltip {
- right: 0;
- @include prefix(transform, translate(0, 10px) scale(.8));
- transform-origin: 100% 100%;
-
- &::before {
- left: auto;
- right: ($plyr-control-icon-size / 2) + $plyr-control-padding;
- @include prefix(transform, translateX(50%));
- }
-}
-
-.plyr__controls button:first-child,
-.plyr__controls button:last-child {
- &:hover .plyr__tooltip,
- &.tab-focus:focus .plyr__tooltip,
- .plyr__tooltip--visible {
- @include prefix(transform, translate(0, 0) scale(1));
- }
-}
-
-// Playback progress
-// --------------------------------------------------------------
-// <progress> element
-.plyr__progress {
- display: none;
- position: relative;
- flex: 1;
-
- input[type="range"] {
- position: relative;
- z-index: 2;
-
- &::-webkit-slider-runnable-track {
- background: transparent;
- }
- &::-moz-range-track {
- background: transparent;
- }
- &::-ms-fill-upper {
- background: transparent;
- }
- }
-
- // Seek tooltip to show time
- .plyr__tooltip {
- left: 0;
- }
-}
-.plyr .plyr__progress {
- display: inline-block;
-}
-
-.plyr__progress--buffer,
-.plyr__progress--played,
-.plyr__volume--display {
- position: absolute;
- left: 0;
- top: 50%;
- width: 100%;
- height: $plyr-range-track-height;
- margin: -($plyr-range-track-height / 2) 0 0;
- padding: 0;
- vertical-align: top;
- @include prefix(appearance, none);
- border: none;
- border-radius: 100px;
-
- &::-webkit-progress-bar {
- background: transparent;
- }
- &::-webkit-progress-value {
- background: currentColor;
- border-radius: 100px;
- min-width: $plyr-range-track-height;
- }
- &::-moz-progress-bar {
- background: currentColor;
- border-radius: 100px;
- min-width: $plyr-range-track-height;
- }
- &::-ms-fill {
- border-radius: 100px;
- }
-}
-.plyr__progress--played,
-.plyr__volume--display {
- z-index: 1;
- color: $plyr-range-selected-bg;
- background: transparent;
- transition: none;
-
- &::-webkit-progress-value {
- min-width: $plyr-range-track-height;
- max-width: 99%;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- transition: none;
- }
- &::-moz-progress-bar {
- min-width: $plyr-range-track-height;
- max-width: 99%;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- transition: none;
- }
- &::-ms-fill {
- display: none;
- }
-}
-.plyr__progress--buffer {
- &::-webkit-progress-value {
- transition: width .2s ease;
- }
- &::-moz-progress-bar {
- transition: width .2s ease;
- }
- &::-ms-fill {
- transition: width .2s ease;
- }
-}
-.plyr--video .plyr__progress--buffer,
-.plyr--video .plyr__volume--display {
- background: $plyr-video-range-track-bg;
-}
-.plyr--video .plyr__progress--buffer {
- color: $plyr-video-progress-buffered-bg;
-}
-.plyr--audio .plyr__progress--buffer,
-.plyr--audio .plyr__volume--display {
- background: $plyr-audio-range-track-bg;
-}
-.plyr--audio .plyr__progress--buffer {
- color: $plyr-audio-progress-buffered-bg;
-}
-
-// Loading state
-.plyr--loading .plyr__progress--buffer {
- animation: plyr-progress 1s linear infinite;
- background-size: $plyr-progress-loading-size $plyr-progress-loading-size;
- background-repeat: repeat-x;
- background-image: linear-gradient(
- -45deg,
- $plyr-progress-loading-bg 25%,
- transparent 25%,
- transparent 50%,
- $plyr-progress-loading-bg 50%,
- $plyr-progress-loading-bg 75%,
- transparent 75%,
- transparent);
- color: transparent;
-}
-.plyr--video.plyr--loading .plyr__progress--buffer {
- background-color: $plyr-video-progress-buffered-bg;
-}
-.plyr--audio.plyr--loading .plyr__progress--buffer {
- background-color: $plyr-audio-progress-buffered-bg;
-}
-
-// Time
-// --------------------------------------------------------------
-.plyr__time {
- display: inline-block;
- vertical-align: middle;
- font-size: $plyr-font-size-small;
-}
-// Media duration hidden on small screens
-.plyr__time + .plyr__time {
- display: none;
-
- @media (min-width: $plyr-bp-screen-md) {
- display: inline-block;
- }
-
- // Add a slash in before
- &::before {
- content: '\2044';
- margin-right: $plyr-control-spacing;
- }
-}
-
-// Volume
-// --------------------------------------------------------------
-.plyr__volume {
- display: none;
-}
-.plyr .plyr__volume {
- flex: 1;
- position: relative;
-
- input[type="range"] {
- position: relative;
- z-index: 2;
- }
- @media (min-width: $plyr-bp-screen-sm) {
- display: block;
- max-width: 60px;
- }
- @media (min-width: $plyr-bp-screen-md) {
- max-width: 100px;
- }
-}
-
-// Hide sound controls on iOS
-// It's not supported to change volume using JavaScript:
-// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
-.plyr--is-ios .plyr__volume,
-.plyr--is-ios [data-plyr='mute'] {
- display: none !important;
-}
-
-// Fullscreen
-// --------------------------------------------------------------
-.plyr--fullscreen-active {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- height: 100%;
- width: 100%;
- z-index: 10000000;
- background: #000;
- border-radius: 0 !important;
-
- video {
- height: 100%;
- }
- .plyr__video-wrapper {
- height: 100%;
- width: 100%;
- }
- .plyr__video-embed {
- // Revert overflow change
- overflow: visible;
- }
- .plyr__controls {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- }
-
- // Vimeo requires some different styling
- &.plyr--vimeo .plyr__video-wrapper {
- height: 0;
- top: 50%;
- @include prefix(transform, translateY(-50%));
- }
-}
diff --git a/share/lua/http/src/components/player/plyr.lib.vars.scss b/share/lua/http/src/components/player/plyr.lib.vars.scss
deleted file mode 100644
index e8a3415f1c..0000000000
--- a/share/lua/http/src/components/player/plyr.lib.vars.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-// ==========================================================================
-// Plyr variables
-// ==========================================================================
-
-// Settings
-$plyr-border-box: true !default;
-$plyr-touch-action: true !default;
-$plyr-sr-only-important: true !default;
-
-// Colors
-$plyr-color-main: #FFA500 !default;
-
-// Font sizes
-$plyr-font-family: Avenir, 'Avenir Next', 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif !default;
-$plyr-font-size-small: 14px !default;
-$plyr-font-size-base: 16px !default;
-
-// Captions
-$plyr-captions-bg: transparentize(#000, .3) !default;
-$plyr-captions-color: #fff !default;
-$plyr-font-size-captions-base: $plyr-font-size-base !default;
-$plyr-font-size-captions-medium: ceil($plyr-font-size-base * 1.5) !default;
-$plyr-font-size-captions-large: ($plyr-font-size-base * 2) !default;
-
-// Controls
-$plyr-control-icon-size: 18px !default;
-$plyr-control-spacing: 10px !default;
-$plyr-control-padding: ($plyr-control-spacing * .7) !default;
-$plyr-video-controls-bg: #000 !default;
-$plyr-video-control-color: #fff !default;
-$plyr-video-control-color-hover: #fff !default;
-$plyr-video-control-bg-hover: $plyr-color-main !default;
-$plyr-audio-controls-bg: #fff !default;
-$plyr-audio-controls-border: 1px solid #dbe3e8 !default;
-$plyr-audio-control-color: #565D64 !default;
-$plyr-audio-control-color-hover: #fff !default;
-$plyr-audio-control-bg-hover: $plyr-color-main;
-
-// Tooltips
-$plyr-tooltip-bg: transparentize(#000, .3) !default;
-$plyr-tooltip-color: #fff !default;
-$plyr-tooltip-padding: ($plyr-control-spacing / 2) !default;
-$plyr-tooltip-arrow-size: 4px !default;
-$plyr-tooltip-radius: 3px !default;
-
-// Progress
-$plyr-progress-loading-size: 25px !default;
-$plyr-progress-loading-bg: transparentize(#000, .85) !default;
-$plyr-video-progress-bg: transparentize(#fff, .75) !default;
-$plyr-video-progress-buffered-bg: $plyr-video-progress-bg !default;
-$plyr-audio-progress-bg: transparentize(#C6D6DB, .33) !default;
-$plyr-audio-progress-buffered-bg: $plyr-audio-progress-bg !default;
-
-// Range sliders
-$plyr-range-track-height: 8px !default;
-$plyr-range-thumb-height: floor($plyr-range-track-height * 2) !default;
-$plyr-range-thumb-width: floor($plyr-range-track-height * 2) !default;
-$plyr-range-thumb-bg: #fff !default;
-$plyr-range-thumb-border: 2px solid transparent !default;
-$plyr-range-thumb-shadow: 0 1px 1px transparentize($plyr-video-controls-bg, .85), 0 0 0 1px transparentize(#000, .85) !default;
-$plyr-range-thumb-active-border-color: #fff !default;
-$plyr-range-thumb-active-bg: $plyr-video-control-bg-hover !default;
-$plyr-range-thumb-active-scale: 1.25 !default;
-$plyr-video-range-track-bg: $plyr-video-progress-buffered-bg !default;
-$plyr-audio-range-track-bg: $plyr-audio-progress-buffered-bg !default;
-$plyr-range-selected-bg: $plyr-color-main !default;
-
-// Breakpoints
-$plyr-bp-screen-sm: 480px !default;
-$plyr-bp-screen-md: 768px !default;
-$plyr-bp-screen-lg: 1024px !default;
diff --git a/share/lua/http/src/components/player/plyr.methods.js b/share/lua/http/src/components/player/plyr.methods.js
deleted file mode 100644
index b41d2dad39..0000000000
--- a/share/lua/http/src/components/player/plyr.methods.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { sendCommand } from '../../services/command.service.js';
-
-let player;
-
-export function plyrInit() {
- player = plyr.setup({
- showPosterOnEnd: true
- });
- // setVideo('S6IP_6HG2QE','youtube');
- player[0].on('pause', () => {
- sendCommand(0, 'command=pl_pause');
- });
-
- player[0].on('play', () => {
- sendCommand(0, 'command=pl_play');
- });
-
- player[0].on('volumechange', (event) => {
- const cmd = `command=volume&val=${event.detail.plyr.getVolume() * 255}`;
- sendCommand(0, cmd);
- });
- return true;
-}
-
-export function setVideo(videoSrc, type) {
- player[0].source({
- type: 'video',
- title: '',
- sources: [{
- src: videoSrc,
- type
- }],
- poster: 'assets/vlc-icons/256x256/vlc.png'
- });
-}
-
-export function playItem(src, id) {
- setVideo(src, 'video/mp4', id);
- player[0].play();
- sendCommand(0, `command=pl_play&id=${id}`);
-}
diff --git a/share/lua/http/src/components/playlist/buttons.playlist.component.html b/share/lua/http/src/components/playlist/buttons.playlist.component.html
index fc0dae59d0..66c2a1e6ae 100644
--- a/share/lua/http/src/components/playlist/buttons.playlist.component.html
+++ b/share/lua/http/src/components/playlist/buttons.playlist.component.html
@@ -1,16 +1,12 @@
<!-- Button Template -->
<script type="text/x-template" id="button-template">
- <div>
- <div class="playlistIcons">
- <div class="row">
- <button type="button" class="btn-circle col-xs" id="randomButton"><svg-icon name="shuffle-variant"></svg-icon></button>
- <button type="button" class="btn-circle col-xs" id="repeatButton"><svg-icon name="replay"></svg-icon></button>
- <button type="button" class="btn-circle col-xs" id="playButton"><svg-icon name="play-circle-outline"></svg-icon></button>
- </div>
- <div class="row">
- <button type="button" class="btn-circle col-xs" data-toggle="modal" data-target="#equalizerModal"><svg-icon name="poll"></svg-icon></button>
- <button type="button" class="btn-circle col-xs" data-toggle="modal" data-target="#fileModal"><svg-icon name="plus"></svg-icon></button>
- </div>
+ <div class="playlist-actions">
+ <div class="d-flex justify-content-between mx-2" :class="{ disabled: !playlist.activeItem }">
+ <button v-on:click="toggleRepeat()" type="button" class="btn-circle" id="repeatButton"><svg-icon name="repeat"></svg-icon></button>
+ <button v-on:click="toggleRandom()" type="button" class="btn-circle" id="randomButton"><svg-icon name="shuffle"></svg-icon></button>
+ <!-- <span>{{ playlist.items.length ? playlist.items.length + ' items': '' }}</span> -->
+ <button type="button" class="btn-circle" data-toggle="modal" data-target="#equalizerModal"><svg-icon name="sort"></svg-icon></button>
+ <button v-on:click="removeItem(playlist.activeItem.id)" type="button" class="btn-circle"><svg-icon name="delete_outline"></svg-icon></button>
</div>
</div>
</script>
diff --git a/share/lua/http/src/components/playlist/buttons.playlist.component.js b/share/lua/http/src/components/playlist/buttons.playlist.component.js
index d5609d7424..e1256289e6 100644
--- a/share/lua/http/src/components/playlist/buttons.playlist.component.js
+++ b/share/lua/http/src/components/playlist/buttons.playlist.component.js
@@ -1,35 +1,26 @@
-import { bus, notifyBus } from '../../services/bus.service.js';
-import { sendCommand } from '../../services/command.service.js';
-
-let playlistItems;
-
Vue.component('playlist-buttons', {
template: '#button-template',
+ computed: {
+ ...Vuex.mapState({
+ status: state => state.status.data,
+ playlist: state => state.playlist
+ }),
+ ...Vuex.mapGetters('playlist', {
+ currentItem: 'getCurrentItem'
+ })
+ },
methods: {
toggleRepeat() {
- sendCommand(0, 'command=pl_repeat');
+ this.$store.dispatch('status/toggleRepeat');
},
startPlaylist() {
- playlistItems = this.$parent.$parent.$data.playlistItems;
- if (playlistItems[0]) {
- notifyBus('play', playlistItems[0].src,playlistItems[0].id);
- }
+ this.$store.dispatch('status/play', this.status.currentplid);
},
toggleRandom() {
- sendCommand(0, 'command=pl_random');
+ this.$store.dispatch('status/toggleRandom');
+ },
+ removeItem(id) {
+ this.$store.dispatch('playlist/removeItem', id);
}
- },
- created() {
- bus.$on('toggleRepeat', () => {
- this.toggleRepeat();
- });
-
- bus.$on('startPlaylist', () => {
- this.startPlaylist();
- });
-
- bus.$on('toggleRandom', () => {
- this.toggleRandom();
- });
}
});
diff --git a/share/lua/http/src/components/playlist/buttons.playlist.component.scss b/share/lua/http/src/components/playlist/buttons.playlist.component.scss
new file mode 100644
index 0000000000..5e44e510a3
--- /dev/null
+++ b/share/lua/http/src/components/playlist/buttons.playlist.component.scss
@@ -0,0 +1,10 @@
+.playlist-actions {
+ padding: 5px 8px;
+ background-color: var(--playlist-action-bg-color);
+ .disabled {
+ color: var(--playlist-action-text-color);
+ .svg-icon {
+ color: var(--playlist-action-text-color);
+ }
+ }
+}
\ No newline at end of file
diff --git a/share/lua/http/src/components/playlist/playlist-audio-item.component.html b/share/lua/http/src/components/playlist/playlist-audio-item.component.html
new file mode 100644
index 0000000000..72f240de4f
--- /dev/null
+++ b/share/lua/http/src/components/playlist/playlist-audio-item.component.html
@@ -0,0 +1,27 @@
+<!-- Playlist item Template -->
+<script type="text/x-template" id="playlist-audio-item-template">
+ <button v-on:dblclick="setActiveItem(item)" class="btn btn-link pl-2 playlist-audio-item list-item d-flex justify-content-between align-items-start position-relative"
+ :class="{ current: item.current === 'current', active: item.active }">
+ <div class="d-flex align-items-start w-100 mr-n3">
+ <div class="item-img" v-on:click="setActiveItem(item)">
+ <img v-if="item.src" class="img-art" :src="item.src" @error="onImgError(item)">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <div class="overlay">
+ <play-button class="item-primary-action item-action"></play-button>
+ </div>
+ </div>
+ <span class="item-duration">{{ item.duration | formatDuration }}</span>
+ <!-- <span class="item-nb">{{ index + 1 }}</span> -->
+ <div class="item-body d-flex flex-column mx-2 pt-1">
+ <router-link to="" class="item-title text-truncate">{{ item.name }}</router-link>
+ <!-- <span class="item-subtitle text-truncate d-flex">
+ <router-link to="/artist">{{ item.subtitle }}</router-link> • <router-link to="/album">{{ item.album }}</router-link>
+ </span> -->
+ </div>
+ </div>
+ <div class="d-flex item-action pt-1">
+ <svg-icon name="more_vert"></svg-icon>
+ </div>
+ <!-- <div class="item-progress-bar" :style="{width: item.progress}"></div> -->
+ </button>
+</script>
diff --git a/share/lua/http/src/components/playlist/playlist-audio-item.component.js b/share/lua/http/src/components/playlist/playlist-audio-item.component.js
new file mode 100644
index 0000000000..de82597d11
--- /dev/null
+++ b/share/lua/http/src/components/playlist/playlist-audio-item.component.js
@@ -0,0 +1,23 @@
+Vue.component('playlist-audio-item', {
+ template: '#playlist-audio-item-template',
+ props: ['item', 'index'],
+ methods: {
+ addItem(mode, id, title, src) {
+ this.$store.dispatch('playlist/addItem', src);
+ },
+ play(src, id) {
+ this.$store.dispatch('layout/openAudioPlayer');
+ this.$store.dispatch('status/play', id);
+ },
+ onImgError(item) {
+ item.src = '';
+ },
+ setActiveItem(item) {
+ this.$store.dispatch('layout/openAudioPlayer');
+ this.$store.dispatch('playlist/setActiveItem', item);
+ }
+ },
+ created() {
+
+ }
+});
diff --git a/share/lua/http/src/components/playlist/playlist-audio-item.component.scss b/share/lua/http/src/components/playlist/playlist-audio-item.component.scss
new file mode 100644
index 0000000000..7625d63a0e
--- /dev/null
+++ b/share/lua/http/src/components/playlist/playlist-audio-item.component.scss
@@ -0,0 +1,24 @@
+.playlist-audio-item.list-item {
+ text-align: center;
+ border: 0;
+ border-radius: 0;
+ margin-bottom: 8px;
+ width: 100%;
+ &.active {
+ background-color: var(--playlist-active-bg-color);
+ color: var(--playlist-active-color);
+ }
+ &:focus,
+ &:hover {
+ text-decoration: none;
+ }
+ .item-img {
+ width: 52px;
+ height: 52px;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+ .item-duration {
+ bottom: 3px;
+ }
+}
diff --git a/share/lua/http/src/components/playlist/playlist-video-item.component.html b/share/lua/http/src/components/playlist/playlist-video-item.component.html
new file mode 100644
index 0000000000..7cd5b02121
--- /dev/null
+++ b/share/lua/http/src/components/playlist/playlist-video-item.component.html
@@ -0,0 +1,25 @@
+<!-- Playlist item Template -->
+<script type="text/x-template" id="playlist-video-item-template">
+ <button v-on:dblclick="play(item.uri, item.id)" class="btn btn-link pl-2 playlist-video-item list-item d-flex justify-content-between align-items-start position-relative"
+ :class="{ current: item.current === 'current', active: item.active }">
+ <div class="d-flex align-items-start w-100 mr-n3">
+ <div class="item-img" v-on:click="setActiveItem(item)">
+ <img v-if="item.src" class="img-art" :src="item.src" @error="onImgError(item)">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <div class="overlay">
+ <play-button :item="item" class="item-primary-action item-action"></play-button>
+ </div>
+ </div>
+ <span class="item-duration">{{ item.duration | formatDuration }}</span>
+ <!-- <span class="item-nb">{{ index + 1 }}</span> -->
+ <div class="item-body d-flex flex-column mx-2 pt-1">
+ <router-link to="" class="item-title text-truncate">{{ item.name }}</router-link>
+ <router-link to="" class="item-subtitle text-truncate">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+ <div class="d-flex item-action pt-1">
+ <svg-icon name="more_vert"></svg-icon>
+ </div>
+ <div class="item-progress-bar" :style="{width: item.progress}"></div>
+ </button>
+</script>
diff --git a/share/lua/http/src/components/playlist/playlist-video-item.component.js b/share/lua/http/src/components/playlist/playlist-video-item.component.js
new file mode 100644
index 0000000000..7bef7bc539
--- /dev/null
+++ b/share/lua/http/src/components/playlist/playlist-video-item.component.js
@@ -0,0 +1,31 @@
+Vue.component('playlist-video-item', {
+ template: '#playlist-video-item-template',
+ props: ['item', 'index'],
+ computed: {
+ ...Vuex.mapState({
+ playlist: state => state.playlist
+ }),
+ },
+ methods: {
+ addItem(mode, id, title, src) {
+ this.$store.dispatch('playlist/addItem', src);
+ },
+ play(src, id) {
+ this.$store.dispatch('status/play', id);
+ },
+ onImgError(item) {
+ item.src = '';
+ },
+ setActiveItem(item) {
+ const path = '/watch'
+ if (this.$route.path !== path) {
+ this.$router.push(path);
+ }
+ this.$store.dispatch('layout/closeAudioPlayer');
+ this.$store.dispatch('playlist/setActiveItem', item);
+ }
+ },
+ created() {
+
+ }
+});
diff --git a/share/lua/http/src/components/playlist/playlist-video-item.component.scss b/share/lua/http/src/components/playlist/playlist-video-item.component.scss
new file mode 100644
index 0000000000..e37f18394f
--- /dev/null
+++ b/share/lua/http/src/components/playlist/playlist-video-item.component.scss
@@ -0,0 +1,24 @@
+.playlist-video-item {
+ text-align: center;
+ border: 0;
+ border-radius: 0;
+ margin-bottom: 8px;
+ width: 100%;
+ &.current {
+ // font-weight: bold;
+ }
+ &.active {
+ background-color: var(--playlist-active-bg-color);
+ color: var(--playlist-active-color);
+ }
+ &:focus,
+ &:hover {
+ text-decoration: none;
+ color: #fff;
+ }
+ .item-img {
+ width: 120px;
+ height: 70px;
+ object-fit: cover;
+ }
+}
diff --git a/share/lua/http/src/components/playlist/playlist.component.html b/share/lua/http/src/components/playlist/playlist.component.html
index 86137bf985..7b65192713 100644
--- a/share/lua/http/src/components/playlist/playlist.component.html
+++ b/share/lua/http/src/components/playlist/playlist.component.html
@@ -1,27 +1,23 @@
<!-- Templates -->
<!-- Playlist Template -->
<script type="text/x-template" id="playlist-template">
- <div>
- <div id="playlistNav" class="playlistNav">
- <div class="container">
- <playlist-buttons></playlist-buttons>
- <div>
- <h1 class="playlistHeader">Playlist</h1>
- </div>
- <div id="playlist">
- <ol type="1">
- <li v-for="item in this.$parent.playlistItems">
- <button v-on:click="play(item.src, item.id)" class="playlistItem">{{ item.title }}</button>
- <button v-on:click="removeItem(item.id)" type="button" class="btn-circle col-xs">
- <svg-icon name="delete"></svg-icon>
- </button>
- </li>
- </ol>
- </div>
- <div class="playlistNavMobile" id="mobilePlaylistNavButton">
- <center><svg-icon name="format-list-bulleted"></svg-icon></center>
- </div>
+ <div id="playlistNav" class="playlistNav h-100">
+ <h6 class="playlist-header">Playlist • <span class="text-muted">{{ ' ' + items.length }}{{ items.length ? ' elements' : ''}}</span></h6>
+ <div class="dropdown-divider"></div>
+ <div id="playlist">
+ <div v-for="(item, index) in items" :key="index">
+ <playlist-video-item
+ v-if="item.type === 'leaf' || item.type === 'video'"
+ :item="item"
+ :index="index">
+ </playlist-video-item>
+ <playlist-audio-item
+ v-if="item.type === 'audio'"
+ :item="item"
+ :index="index">
+ </playlist-audio-item>
</div>
</div>
+ <playlist-buttons></playlist-buttons>
</div>
</script>
diff --git a/share/lua/http/src/components/playlist/playlist.component.js b/share/lua/http/src/components/playlist/playlist.component.js
index 7733d40eca..3a928d7a15 100644
--- a/share/lua/http/src/components/playlist/playlist.component.js
+++ b/share/lua/http/src/components/playlist/playlist.component.js
@@ -1,102 +1,36 @@
-import { bus } from '../../services/bus.service.js';
-import { sendCommand } from '../../services/command.service.js';
-import { playItem } from '../player/plyr.methods.js';
-
Vue.component('playlist', {
template: '#playlist-template',
+ computed: {
+ ...Vuex.mapState({
+ items: state => state.playlist.items,
+ }),
+ },
methods: {
- addItem(mode, id, title, src) {
- if (mode === 0) {
- this.$parent.playlistItems.push({
- id,
- title,
- src
- });
- } else if (mode === 1) {
- sendCommand(0, `command=in_enqueue&input=${src}`);
- this.clearPlaylist();
- bus.$emit('refreshPlaylist');
- }
- },
- removeItem(id) {
- sendCommand(0, `command=pl_delete&id=${id}`);
- this.$parent.playlistItems.splice({
- id
- });
- sendCommand(1);
- },
- openPlaylist() {
- $('#playlistNav').width('60%');
- $('#mobilePlaylistNavButton').width('0%');
- },
- closePlaylist() {
- $('#playlistNav').width('0%');
- $('#mobilePlaylistNavButton').width('10%');
- },
- populatePlaylist(playlistData) {
- if (!playlistData) {
- return;
- }
- this.$parent.playlistItems = [];
- for (let i = 0; i < playlistData.children[0].children.length; i++) {
- this.addItem(
- 0,
- playlistData.children[0].children[i].id,
- playlistData.children[0].children[i].name,
- playlistData.children[0].children[i].uri
- );
- }
- },
fetchPlaylist() {
- sendCommand(1)
- .then(data => this.populatePlaylist(data));
+ this.$store.dispatch('playlist/fetchPlaylist');
},
refreshPlaylist() {
+ if (this.interval) {
+ clearTimeout(this.interval);
+ this.interval = null;
+ }
this.fetchPlaylist();
- setInterval(() => {
+ this.interval = setInterval(() => {
this.fetchPlaylist();
- }, 5000);
- },
- clearPlaylist() {
- this.$parent.playlistItems = [];
- },
- play(src, id) {
- playItem(src,id);
+ }, 30000);
}
},
created() {
- bus.$on('openPlaylist', () => {
- this.openPlaylist();
- });
-
- bus.$on('closePlaylist', () => {
- this.closePlaylist();
- });
-
- bus.$on('addItem', (params) => {
- this.addItem(params[0], params[1], params[2], params[3]);
- });
-
- bus.$on('removeItem', (id) => {
- this.removeItem(id);
- });
-
- bus.$on('refreshPlaylist', () => {
- this.refreshPlaylist();
- });
-
- bus.$on('play', (arg) => {
- this.play(arg[0], arg[1]);
+ this.$store.subscribeAction((mutation) => {
+ switch (mutation.type) {
+ case 'layout/openPlaylist':
+ this.openPlaylist();
+ break;
+ case 'layout/closePlaylist':
+ this.closePlaylist();
+ break;
+ }
});
-
this.refreshPlaylist();
}
});
-
-$(document).click((e) => {
- const container = $('#playlistNav');
-
- if ($(window).width() <= 480 && !container.is(e.target) && container.has(e.target).length === 0 && container.css('width') !== '0px') {
- bus.$emit('closePlaylist');
- }
-});
diff --git a/share/lua/http/src/components/playlist/playlist.component.scss b/share/lua/http/src/components/playlist/playlist.component.scss
index 6ae49d3cfe..3b4772f548 100644
--- a/share/lua/http/src/components/playlist/playlist.component.scss
+++ b/share/lua/http/src/components/playlist/playlist.component.scss
@@ -1,43 +1,19 @@
.playlistNav {
- right: 0;
- width: 20%;
- height: 100%;
- position: fixed;
- z-index: 5;
- top: 0;
- background-color: orange;
- overflow-x: hidden;
- padding-top: 2%;
- transition: 0.5s;
-}
-
-.playlistIcons {
- font-size: 2em;
- padding-left: 4%;
-}
-
-.playlistNavMobile {
- visibility: hidden;
- right: 0;
- width: 10%;
- height: 100%;
- position: fixed;
- z-index: 5;
- top: 0;
- background-color: orange;
- overflow-x: hidden;
- padding-top: 2%;
+ overflow: hidden;
transition: 0.5s;
}
.btn-circle {
- width: 30px;
- height: 30px;
text-align: center;
- padding: 6px 0;
+ padding: 0;
border-radius: 15px;
border: 0;
- background-color: orange;
+ background-color: transparent;
+ line-height: 0;
+ .svg-icon {
+ width: 1.5rem;
+ height: 1.5rem;
+ }
}
.btn-circle.btn-lg {
@@ -56,23 +32,20 @@
border-radius: 35px;
}
-.playlistItem {
- text-align: center;
- border: 0;
- margin-bottom: 0.2em;
- background-color: white;
+#playlistNav {
+ background-color: var(--sidenav-bg-color);
}
-.playlistHeader{
- color: black;
- padding-left: 5%;
- padding-right: 5%;
+#playlist {
+ // max-height: calc(100% - 120px);
+ height: calc(100% - 160px);
+ overflow-y: auto;
+ overflow-x: hidden;
}
-#playlist {
- width:21.5%;
- height: 100%;
- background-color: white;
+.playlist-header {
+ margin: 8px 8px;
+ font-size: 13px;
}
@media screen and (min-device-width : 320px) and (max-device-width : 480px) {
diff --git a/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.html b/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.html
new file mode 100644
index 0000000000..a733a239ef
--- /dev/null
+++ b/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.html
@@ -0,0 +1,28 @@
+<script type="text/x-template" id="playlists-item-template">
+ <div class="playlists-item grid-item col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div class="item-img">
+ <div>
+ <div class="d-flex">
+ <img :src="item.images[0]">
+ <img :src="item.images[1]">
+ </div>
+ <div class="d-flex">
+ <img :src="item.images[2]">
+ <img :src="item.images[3]">
+ </div>
+ </div>
+ <div class="overlay">
+ <play-button class="item-primary-action"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="item-body">
+ <router-link to="/album" class="item-title text-truncate">{{ item.name }}</router-link>
+ <router-link to="/artist" class="item-subtitle text-truncate">{{ item.nbItems }} files • {{ item.duration }}</router-link>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.js b/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.js
new file mode 100644
index 0000000000..8022d6ca9c
--- /dev/null
+++ b/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.js
@@ -0,0 +1,7 @@
+Vue.component('playlists-item', {
+ template: '#playlists-item-template',
+ props: ['item'],
+ computed: { },
+ methods: { },
+ created() { }
+});
diff --git a/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.scss b/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.scss
new file mode 100644
index 0000000000..d7cc3e1b80
--- /dev/null
+++ b/share/lua/http/src/components/playlists/playlists-item/playlists-item.component.scss
@@ -0,0 +1,10 @@
+.playlists-item.grid-item {
+ margin-bottom: 16px;
+ img {
+ width: 50%;
+ height: 50%;
+ }
+ .item-img {
+ display: block;
+ }
+}
diff --git a/share/lua/http/src/components/playlists/playlists.component.html b/share/lua/http/src/components/playlists/playlists.component.html
new file mode 100644
index 0000000000..5e848f6bf5
--- /dev/null
+++ b/share/lua/http/src/components/playlists/playlists.component.html
@@ -0,0 +1,13 @@
+<script type="text/x-template" id="playlists-template">
+ <div class="playlists-view container-fluid">
+ <div class="row">
+ <div class="playlists-item grid-item col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
+ <div class="create-item">
+ Create a playlist
+ <svg-icon name="add"></svg-icon>
+ </div>
+ </div>
+ <playlists-item v-for="item in items" :item="item"></playlists-item>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/playlists/playlists.component.js b/share/lua/http/src/components/playlists/playlists.component.js
new file mode 100644
index 0000000000..4ac085299b
--- /dev/null
+++ b/share/lua/http/src/components/playlists/playlists.component.js
@@ -0,0 +1,19 @@
+Vue.component('playlists', {
+ template: '#playlists-template',
+ data: function() {
+ return {
+ items: [
+
+ ]
+ }
+ },
+ computed: {
+
+ },
+ methods: {
+
+ },
+ created() {
+
+ }
+});
diff --git a/share/lua/http/src/components/sot/stream.manager.component.html b/share/lua/http/src/components/sot/stream.manager.component.html
index 9813fe2f65..3619de0633 100644
--- a/share/lua/http/src/components/sot/stream.manager.component.html
+++ b/share/lua/http/src/components/sot/stream.manager.component.html
@@ -5,8 +5,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Stream Manager</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
</div>
diff --git a/share/lua/http/src/components/svg-icon/svg-icon.component.scss b/share/lua/http/src/components/svg-icon/svg-icon.component.scss
index 0c6710d4b2..2761b95125 100644
--- a/share/lua/http/src/components/svg-icon/svg-icon.component.scss
+++ b/share/lua/http/src/components/svg-icon/svg-icon.component.scss
@@ -1,7 +1,7 @@
.svg-icon {
display: inline-block;
- width: 2.5rem;
- height: 2.5rem;
+ width: 1.5rem;
+ height: 1.5rem;
color: inherit;
vertical-align: middle;
fill: none;
diff --git a/share/lua/http/src/components/track-synchronisation/tracksync.component.html b/share/lua/http/src/components/track-synchronisation/tracksync.component.html
index 4ae724b99f..f66d4387b2 100644
--- a/share/lua/http/src/components/track-synchronisation/tracksync.component.html
+++ b/share/lua/http/src/components/track-synchronisation/tracksync.component.html
@@ -5,8 +5,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Set Track Synchronization</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body" id="">
Playback Rate
diff --git a/share/lua/http/src/components/tracks/track-item/track-item-table.component.html b/share/lua/http/src/components/tracks/track-item/track-item-table.component.html
new file mode 100644
index 0000000000..82502ded40
--- /dev/null
+++ b/share/lua/http/src/components/tracks/track-item/track-item-table.component.html
@@ -0,0 +1,28 @@
+<script type="text/x-template" id="track-item-table-template">
+ <tr>
+ <th scope="row" class="d-flex justify-content-between">
+ <div class="item-img">
+ <img v-if="item.src" :src="item.src">
+ <svg-icon v-if="!item.src" name="placeholder-album" class="placeholder-album-icon"></svg-icon>
+ <play-button class="item-primary-action item-action" :item="item"></play-button>
+ </div>
+ </th>
+ <td>
+ <router-link to="">
+ <span>{{ item.title }}</span>
+ <span></span>
+ </router-link>
+ </td>
+ <td><router-link to="">{{ item.artist }}</router-link></td>
+ <td><router-link to="">{{ item.album }}</router-link></td>
+ <td class="text-muted">{{ item.duration | formatDuration }}</td>
+ <td class="text-muted">{{ index + 1 }}</td>
+ <td class="text-muted">
+ <div class="d-flex justify-content-between">
+ <div class="item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </td>
+ </tr>
+</script>
\ No newline at end of file
diff --git a/share/lua/http/src/components/tracks/track-item/track-item-table.component.js b/share/lua/http/src/components/tracks/track-item/track-item-table.component.js
new file mode 100644
index 0000000000..ebc8d4bf50
--- /dev/null
+++ b/share/lua/http/src/components/tracks/track-item/track-item-table.component.js
@@ -0,0 +1,16 @@
+Vue.component('track-item-table', {
+ template: '#track-item-table-template',
+ props: ['item', 'index'],
+ data: function() {
+ return {
+ liked: this.item.liked
+ }
+ },
+ computed: { },
+ methods: {
+ toggleLiked() {
+ this.liked = !this.liked;
+ }
+ },
+ created() { }
+});
diff --git a/share/lua/http/src/components/tracks/tracks.component.html b/share/lua/http/src/components/tracks/tracks.component.html
new file mode 100644
index 0000000000..fe8a5e5bd0
--- /dev/null
+++ b/share/lua/http/src/components/tracks/tracks.component.html
@@ -0,0 +1,25 @@
+<script type="text/x-template" id="tracks-template">
+ <div class="tracks-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="row" v-if="displayMode === 'table'">
+ <table class="table table-hover table-item">
+ <thead>
+ <tr>
+ <th scope="col"></th>
+ <th scope="col">Title</th>
+ <th scope="col">Artist</th>
+ <th scope="col">Album</th>
+ <th scope="col">Duration</th>
+ <th scope="col">Track</th>
+ <th scope="col"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <track-item-table v-for="(item, index) in music.tracks" :item="item" :key="index" :index="index"></track-item-table>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/tracks/tracks.component.js b/share/lua/http/src/components/tracks/tracks.component.js
new file mode 100644
index 0000000000..60ea02514a
--- /dev/null
+++ b/share/lua/http/src/components/tracks/tracks.component.js
@@ -0,0 +1,22 @@
+Vue.component('tracks', {
+ template: '#tracks-template',
+ props: ['item'],
+ data: function() {
+ return {
+ displayMode: 'table'
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ music: state => state.music,
+ }),
+ },
+ methods: {
+ fetchTracks() {
+ this.$store.dispatch('music/fetchTracks');
+ }
+ },
+ created() {
+ this.fetchTracks();
+ }
+});
diff --git a/share/lua/http/src/components/videos/video-item/video-item-grid.component.html b/share/lua/http/src/components/videos/video-item/video-item-grid.component.html
new file mode 100644
index 0000000000..becf714748
--- /dev/null
+++ b/share/lua/http/src/components/videos/video-item/video-item-grid.component.html
@@ -0,0 +1,33 @@
+<script type="text/x-template" id="video-item-grid-template">
+ <div class="video-item grid-item video-item-grid-template">
+ <div class="item-img embed-responsive embed-responsive-16by10">
+ <img class="embed-responsive-item" :src="item.src">
+ <div class="overlay">
+ <play-button :item="item" class="item-primary-action"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ <div v-if="item.quality" class="quality">
+ <span class="quality-tag">{{ item.quality }}</span>
+ </div>
+ <div v-if="item.user" class="user">
+ <img src="">
+ </div>
+ <div v-if="item.progress" class="item-progress-bar-container">
+ <div class="item-progress-bar" :style="{width: item.progress}"></div>
+ </div>
+ </div>
+ <div class="item-body px-2">
+ <span class="d-flex align-items-center justify-content-between">
+ <router-link to="/album" class="item-title text-truncate">
+ <span>{{ item.title }}</span>
+ </router-link>
+ <span class="item-subtitle">{{ item.duration | formatDuration }}</span>
+ </span>
+ <router-link to="/" class="item-subtitle text-truncate text-left">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/videos/video-item/video-item-grid.component.js b/share/lua/http/src/components/videos/video-item/video-item-grid.component.js
new file mode 100644
index 0000000000..ef710235dd
--- /dev/null
+++ b/share/lua/http/src/components/videos/video-item/video-item-grid.component.js
@@ -0,0 +1,9 @@
+Vue.component('video-item-grid', {
+ template: '#video-item-grid-template',
+ props: ['item'],
+ methods: {
+ toggleLiked() {
+ this.liked = !this.liked;
+ }
+ }
+});
diff --git a/share/lua/http/src/components/videos/video-item/video-item-list.component.html b/share/lua/http/src/components/videos/video-item/video-item-list.component.html
new file mode 100644
index 0000000000..e1a029c0b8
--- /dev/null
+++ b/share/lua/http/src/components/videos/video-item/video-item-list.component.html
@@ -0,0 +1,20 @@
+<script type="text/x-template" id="video-item-list-template">
+ <div class="row align-items-center list-table-item">
+ <div class="d-flex justify-content-between col-2">
+ <div class="item-img img-16by9 d-flex" :style="{'background-image': `url(${item.src})`}">
+ <play-button class="item-primary-action item-action m-auto" :item="item"></play-button>
+ </div>
+ </div>
+ <div class="col-6">
+ <span>{{ item.title }}</span>
+ </div>
+ <div class="col-2 text-center">{{ item.duration | formatDuration }}</div>
+ <div class="text-muted col-2">
+ <div class="d-flex justify-content-between">
+ <div class="item-action">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/videos/video-item/video-item-list.component.js b/share/lua/http/src/components/videos/video-item/video-item-list.component.js
new file mode 100644
index 0000000000..629bee7f52
--- /dev/null
+++ b/share/lua/http/src/components/videos/video-item/video-item-list.component.js
@@ -0,0 +1,9 @@
+Vue.component('video-item-list', {
+ template: '#video-item-list-template',
+ props: ['item'],
+ methods: {
+ toggleLiked() {
+ this.liked = !this.liked;
+ }
+ }
+});
diff --git a/share/lua/http/src/components/videos/video-item/video-item-poster.component.html b/share/lua/http/src/components/videos/video-item/video-item-poster.component.html
new file mode 100644
index 0000000000..5b4c51227e
--- /dev/null
+++ b/share/lua/http/src/components/videos/video-item/video-item-poster.component.html
@@ -0,0 +1,27 @@
+<script type="text/x-template" id="video-item-poster-template">
+ <div class="video-item grid-item poster-item video-item-poster-template">
+ <div class="item-img embed-responsive embed-responsive-4by6">
+ <img class="embed-responsive-item" :src="item.src">
+ <div class="overlay">
+ <play-button class="item-primary-action" :item="item"></play-button>
+ <div class="item-secondary-action">
+ <div class="icon-wrapper">
+ <svg-icon name="more-horizontal"></svg-icon>
+ </div>
+ </div>
+ </div>
+ <div v-if="item.progress" class="item-progress-bar-container">
+ <div class="item-progress-bar" :style="{width: item.progress}"></div>
+ </div>
+ </div>
+ <div class="item-body px-2">
+ <span class="d-flex align-items-center justify-content-between">
+ <router-link to="/album" class="item-title text-truncate">
+ <span>{{ item.title }}</span>
+ </router-link>
+ <span class="item-subtitle">{{ item.duration | formatDuration }}</span>
+ </span>
+ <router-link to="/" class="item-subtitle text-truncate text-left">{{ item.subtitle }}</router-link>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/videos/video-item/video-item-poster.component.js b/share/lua/http/src/components/videos/video-item/video-item-poster.component.js
new file mode 100644
index 0000000000..febb7d4c1c
--- /dev/null
+++ b/share/lua/http/src/components/videos/video-item/video-item-poster.component.js
@@ -0,0 +1,4 @@
+Vue.component('video-item-poster', {
+ template: '#video-item-poster-template',
+ props: ['item']
+});
diff --git a/share/lua/http/src/components/videos/videos.component.html b/share/lua/http/src/components/videos/videos.component.html
new file mode 100644
index 0000000000..4109de8f78
--- /dev/null
+++ b/share/lua/http/src/components/videos/videos.component.html
@@ -0,0 +1,90 @@
+<script type="text/x-template" id="videos-template">
+ <div class="videos-view container-fluid">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <album-item-list v-for="(item, index) in items" :item="item" :key="index"></album-item-list>
+ </div> -->
+ <!-- <h5 class="separator-title d-flex align-items-center">
+ <span>Videos</span>
+ </h5> -->
+ <div id="collapse-group-grid" class="position-relative collapse-container" v-if="layout.itemLayout === 'grid'">
+ <!-- <div class="carousel-navigation d-flex align-items-center">
+ <svg-icon class="muted-opacity" name="keyboard_arrow_left"></svg-icon>
+ <svg-icon name="keyboard_arrow_right"></svg-icon>
+ </div> -->
+ <template v-for="(item, index) in videos">
+ <video-item-grid :key="index" data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" class="col-12 col-sm-6 col-md-4 col-lg-3 collapse-item" :item="item">
+ </video-item-grid><div class="collapse collapse-detail" v-bind:id="'collapse-' + item.id" data-parent="#collapse-group-grid">
+ <div class="d-flex ml-2">
+ <button data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button>
+ <div>
+ <img width="260" class="embed-responsive-item" :src="item.src">
+ <div class="mt-2 d-flex">
+ <play-button-secondary :item="item"></play-button-secondary>
+ <enqueue-button class="ml-2" :item="item"></enqueue-button>
+ </div>
+ </div>
+ <div class="ml-2">
+ <h4 class="title mb-0">{{ item.title }}</h4>
+ <span class="caption">{{ item.duration | formatDuration }}</span>
+ <div class="subtitle"><span class="font-weight-bold">File name:</span>{{ item.filename }}</div>
+ <div class="subtitle"><span class="font-weight-bold">Path:</span>{{ item.mrl }}</div>
+ </div>
+ </div>
+ </div>
+ </template>
+ </div>
+ <div id="collapse-group-list" class="position-relative collapse-container" v-if="layout.itemLayout === 'list'">
+ <!-- <div class="carousel-navigation d-flex align-items-center">
+ <svg-icon class="muted-opacity" name="keyboard_arrow_left"></svg-icon>
+ <svg-icon name="keyboard_arrow_right"></svg-icon>
+ </div> -->
+ <div class="tracks-view container-fluid list-table-view">
+ <!-- <div v-if="displayMode === 'list'" class="row">
+ <artist-item-list v-for="item in items" :item="item"></artist-item-list>
+ </div> -->
+ <div class="d-flex list-header row">
+ <span class="col-2 text-muted track-img">
+ <svg-icon name="Icon-Vinyl"></svg-icon>
+ </span>
+ <span class="col-6 text-muted">Title</span>
+ <span class="col-2 text-muted text-center">
+ <svg-icon name="Icon-Time"></svg-icon>
+ </span>
+ </div>
+ <template v-for="(item, index) in videos">
+ <video-item-list :key="index" data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" :item="item">
+ </video-item-list><div class="collapse collapse-detail" v-bind:id="'collapse-' + item.id" data-parent="#collapse-group-list">
+ <div class="d-flex ml-2">
+ <button data-toggle="collapse" v-bind:data-target="'#collapse-' + item.id" aria-expanded="false" aria-controls="collapse" class="close">
+ <svg-icon name="add"></svg-icon>
+ </button>
+ <div>
+ <img width="260" class="embed-responsive-item" :src="item.src">
+ <div class="mt-2 d-flex">
+ <play-button-secondary :item="item"></play-button-secondary>
+ <enqueue-button class="ml-2" :item="item"></enqueue-button>
+ </div>
+ </div>
+ <div class="ml-2">
+ <h4 class="title mb-0">{{ item.title }}</h4>
+ <span class="caption">{{ item.duration | formatDuration }}</span>
+ <div class="subtitle"><span class="font-weight-bold">File name:</span>{{ item.filename }}</div>
+ <div class="subtitle"><span class="font-weight-bold">Path:</span>{{ item.mrl }}</div>
+ </div>
+ </div>
+ </div>
+ </template>
+
+ </div>
+ </div>
+ <div class="row position-relative" v-if="layout.itemLayout === 'poster'">
+ <!-- <div class="carousel-navigation d-flex align-items-center">
+ <svg-icon class="muted-opacity" name="keyboard_arrow_left"></svg-icon>
+ <svg-icon name="keyboard_arrow_right"></svg-icon>
+ </div> -->
+ <video-item-poster class="col-12 col-sm-6 col-md-4 col-lg-2" v-for="(item, index) in videos" :item="item" :key="index"></video-item-poster>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/components/videos/videos.component.js b/share/lua/http/src/components/videos/videos.component.js
new file mode 100644
index 0000000000..1e756194f3
--- /dev/null
+++ b/share/lua/http/src/components/videos/videos.component.js
@@ -0,0 +1,22 @@
+Vue.component('videos', {
+ template: '#videos-template',
+ data: function() {
+ return {
+ displayMode: 'grid'
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ videos: state => state.video.videos,
+ layout: state => state.layout
+ }),
+ },
+ methods: {
+ fetchVideos() {
+ this.$store.dispatch('video/fetchVideos');
+ }
+ },
+ created() {
+ this.fetchVideos();
+ }
+});
diff --git a/share/lua/http/src/components/vlm/vlm.component.html b/share/lua/http/src/components/vlm/vlm.component.html
index 222c7ae2c9..905f0b04b4 100644
--- a/share/lua/http/src/components/vlm/vlm.component.html
+++ b/share/lua/http/src/components/vlm/vlm.component.html
@@ -5,8 +5,8 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
- <button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Write your VLM commands here (seperated by new line)</h4>
+ <button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<textarea id="vlmCommand"></textarea>
@@ -15,7 +15,7 @@
</div>
</div>
<div class="modal-footer">
- <button type="button" id="vlmButton" class="btn btn-default">Submit</button>
+ <button type="button" v-on:click="executeVLM()" id="vlmButton" class="btn btn-default">Submit</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
diff --git a/share/lua/http/src/components/vlm/vlm.component.js b/share/lua/http/src/components/vlm/vlm.component.js
index c7da5b49d1..e6569b6bab 100644
--- a/share/lua/http/src/components/vlm/vlm.component.js
+++ b/share/lua/http/src/components/vlm/vlm.component.js
@@ -1,17 +1,9 @@
-import { bus } from '../../services/bus.service.js';
-import { sendCommand } from '../../services/command.service.js';
-
Vue.component('vlm-modal', {
template: '#vlm-modal-template',
methods: {
executeVLM() {
const cmd = $('#vlmCommand').val();
- sendCommand(2, `?command=${cmd}`);
+ this.$store.dispatch('vlmCmd/postCmd', cmd);
}
- },
- created() {
- bus.$on('executeVLM', () => {
- this.executeVLM();
- });
}
});
diff --git a/share/lua/http/src/routes/browse/browse-view.component.html b/share/lua/http/src/routes/browse/browse-view.component.html
new file mode 100644
index 0000000000..2f05444c6a
--- /dev/null
+++ b/share/lua/http/src/routes/browse/browse-view.component.html
@@ -0,0 +1,51 @@
+<script type="text/x-template" id="browse-view-template">
+ <div class="browse-view h-100" :class="{ 'media-player-opened': audioPlayerOpened }">
+ <div class="container-fluid fixed-top primary-navbar d-flex align-content-center align-items-center text-center justify-content-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <img width="23" height="26" src="http://images.videolan.org/images/VLC-IconSmall.png">
+ <span class="ml-2">VLC</span>
+ </div>
+ <ul class="nav d-flex align-items-center justify-content-center">
+ <li class="nav-item">
+ <router-link title="Video" active-class="active" to="/video" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="local_movies_outline"></svg-icon>
+ <span>Video</span>
+ </router-link>
+ </li>
+ <li class="nav-item">
+ <router-link title="Music" active-class="active" to="/music" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="audiotrack_outline"></svg-icon>
+ <span>Music</span>
+ </router-link>
+ </li>
+ <li class="nav-item">
+ <router-link title="Network" active-class="active" to="/network" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="wifi"></svg-icon>
+ <span>Browse</span>
+ </router-link>
+ </li>
+ <li class="nav-item">
+ <router-link title="Discover" active-class="active" to="/discover" class="btn btn-icon btn-link d-flex flex-column">
+ <svg-icon name="explore"></svg-icon>
+ <span>Discover</span>
+ </router-link>
+ </li>
+ </ul>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <button v-on:click="" class="btn-circle mr-2"><svg-icon name="search"></svg-icon></button>
+ <button v-on:click="" class="btn-circle"><svg-icon name="more-horizontal"></svg-icon></button>
+ </div>
+ </div>
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ <transition name="slide-fade">
+ <media-player
+ v-if="audioPlayerOpened"
+ canPlay="canPlay"
+ ended="ended"
+ src="">
+ </media-player>
+ </transition>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/browse/browse-view.component.js b/share/lua/http/src/routes/browse/browse-view.component.js
new file mode 100644
index 0000000000..102c5f5497
--- /dev/null
+++ b/share/lua/http/src/routes/browse/browse-view.component.js
@@ -0,0 +1,19 @@
+export default BrowseViewComponent = {
+ template: '#browse-view-template',
+ methods: {
+ canPlay: function() {
+ console.log('canPlay');
+ },
+ ended: function() {
+ console.log('ended');
+ }
+ },
+ computed: {
+ ...Vuex.mapState({
+ audioPlayerOpened: state => state.layout.audioPlayerOpened
+ }),
+ },
+ created() {
+ document.body.style['overflow-y'] = 'auto';
+ }
+};
diff --git a/share/lua/http/src/routes/browse/browse-view.component.scss b/share/lua/http/src/routes/browse/browse-view.component.scss
new file mode 100644
index 0000000000..b2c50dd613
--- /dev/null
+++ b/share/lua/http/src/routes/browse/browse-view.component.scss
@@ -0,0 +1,3 @@
+.browse-view {
+ margin: 86px 0 20px 0px;
+}
diff --git a/share/lua/http/src/routes/discover/discover-view.component.html b/share/lua/http/src/routes/discover/discover-view.component.html
new file mode 100644
index 0000000000..7d0b7f1be1
--- /dev/null
+++ b/share/lua/http/src/routes/discover/discover-view.component.html
@@ -0,0 +1,37 @@
+<script type="text/x-template" id="discover-view-template">
+ <div class="discover-view h-100 pt-4">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <button v-on:click="" class="btn btn-circle"><svg-icon name="format_list_bulleted"></svg-icon></button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center">
+ <router-link to="/discover/home" active-class="active" class="btn btn-link">Home</router-link>
+ <router-link to="/discover/services" active-class="active" class="btn btn-link">Services</router-link>
+ <router-link to="/discover/url" active-class="active" class="btn btn-link">URL</router-link>
+ </div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/discover/discover-view.component.js b/share/lua/http/src/routes/discover/discover-view.component.js
new file mode 100644
index 0000000000..4540e4ff26
--- /dev/null
+++ b/share/lua/http/src/routes/discover/discover-view.component.js
@@ -0,0 +1,5 @@
+export default DiscoverViewComponent = {
+ template: '#discover-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/discover/home/discover-home-view.component.html b/share/lua/http/src/routes/discover/home/discover-home-view.component.html
new file mode 100644
index 0000000000..f0e06d0390
--- /dev/null
+++ b/share/lua/http/src/routes/discover/home/discover-home-view.component.html
@@ -0,0 +1,4 @@
+<script type="text/x-template" id="discover-home-view-template">
+ <div class="discover-home-view">
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/discover/home/discover-home-view.component.js b/share/lua/http/src/routes/discover/home/discover-home-view.component.js
new file mode 100644
index 0000000000..36e0295e52
--- /dev/null
+++ b/share/lua/http/src/routes/discover/home/discover-home-view.component.js
@@ -0,0 +1,5 @@
+export default DiscoverHomeViewComponent = {
+ template: '#discover-home-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/discover/services/discover-services-view.component.html b/share/lua/http/src/routes/discover/services/discover-services-view.component.html
new file mode 100644
index 0000000000..6b4e9d1391
--- /dev/null
+++ b/share/lua/http/src/routes/discover/services/discover-services-view.component.html
@@ -0,0 +1,15 @@
+<script type="text/x-template" id="discover-services-view-template">
+ <div class="discover-services-view">
+ <div class="row">
+ <grid-item :item="addService"></grid-item>
+ <template v-for="service in mainServices">
+ <grid-item :item="service"></grid-item>
+ </template>
+ </div>
+ <div class="row">
+ <template v-for="service in secondaryServices">
+ <grid-item :item="service"></grid-item>
+ </template>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/discover/services/discover-services-view.component.js b/share/lua/http/src/routes/discover/services/discover-services-view.component.js
new file mode 100644
index 0000000000..a762738050
--- /dev/null
+++ b/share/lua/http/src/routes/discover/services/discover-services-view.component.js
@@ -0,0 +1,49 @@
+export default DiscoverServicesViewComponent = {
+ template: '#discover-services-view-template',
+ methods: { },
+ created() { },
+ data: function() {
+ return {
+ addService: {
+ icon: 'add',
+ title: 'Add a service',
+ additionalItemClass: 'create-item'
+ },
+ mainServices: [
+ {
+ icon: 'display',
+ title: 'TV',
+ additionalItemClass: 'tv-service',
+ titleRoute: 'services/tv'
+ },
+ {
+ icon: 'feed',
+ title: 'Radio',
+ additionalItemClass: 'radio-service'
+ },
+ {
+ icon: 'mic',
+ title: 'Podcast',
+ additionalItemClass: 'podcast-service'
+ },
+ {
+ icon: 'headphones',
+ title: 'Audio Book',
+ additionalItemClass: 'audiobook-service'
+ },
+ ],
+ secondaryServices: [
+ {
+ icon: 'youtube',
+ title: 'Youtube',
+ additionalItemClass: 'youtube-service'
+ },
+ {
+ icon: 'twitch',
+ title: 'Twitch',
+ additionalItemClass: 'twitch-service'
+ }
+ ]
+ }
+ }
+};
diff --git a/share/lua/http/src/routes/discover/services/discover-services-view.component.scss b/share/lua/http/src/routes/discover/services/discover-services-view.component.scss
new file mode 100644
index 0000000000..3f7ea6fc8b
--- /dev/null
+++ b/share/lua/http/src/routes/discover/services/discover-services-view.component.scss
@@ -0,0 +1,33 @@
+.create-item {
+ .svg-icon {
+ color: var(--highlight-color) !important;
+ }
+}
+.tv-service {
+ background-color: #7b5398;
+}
+.radio-service {
+ background-color: #fb610b;
+}
+.podcast-service {
+ background-color: #c1428d;
+}
+.audiobook-service {
+ background-color: #c1428d;
+}
+.youtube-service {
+ background-color: #fb0001;
+}
+.twitch-service {
+ background-color: #9146ff;
+}
+.discover-service-item {
+ .svg-icon {
+ width: 2.8rem;
+ height: 2.8rem;
+ color: #fff;
+ &:hover, &:focus {
+ color: #fff;
+ }
+ }
+}
\ No newline at end of file
diff --git a/share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.html b/share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.html
new file mode 100644
index 0000000000..f59478788d
--- /dev/null
+++ b/share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.html
@@ -0,0 +1,10 @@
+<script type="text/x-template" id="discover-services-tv-view-template">
+ <div class="discover-services-tv-view container-fluid">
+ <div v-if="displayMode === 'list'" class="row">
+ <grid-list v-for="(item, index) in items" :item="item" :key="index"></grid-list>
+ </div>
+ <div class="row" v-if="displayMode === 'grid'">
+ <grid-item v-for="(item, index) in items" :item="item" :key="index"></grid-item>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.js b/share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.js
new file mode 100644
index 0000000000..4fd88b9641
--- /dev/null
+++ b/share/lua/http/src/routes/discover/services/tv/discover-services-tv-view.component.js
@@ -0,0 +1,11 @@
+export default DiscoverServicesTvViewComponent = {
+ template: '#discover-services-tv-view-template',
+ data: function() {
+ return {
+ displayMode: 'grid',
+ items: [
+
+ ]
+ }
+ },
+};
diff --git a/share/lua/http/src/routes/discover/url/discover-url-view.component.html b/share/lua/http/src/routes/discover/url/discover-url-view.component.html
new file mode 100644
index 0000000000..e0802f38f5
--- /dev/null
+++ b/share/lua/http/src/routes/discover/url/discover-url-view.component.html
@@ -0,0 +1,4 @@
+<script type="text/x-template" id="discover-url-view-template">
+ <div class="discover-url-view">
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/discover/url/discover-url-view.component.js b/share/lua/http/src/routes/discover/url/discover-url-view.component.js
new file mode 100644
index 0000000000..cf004c11cf
--- /dev/null
+++ b/share/lua/http/src/routes/discover/url/discover-url-view.component.js
@@ -0,0 +1,5 @@
+export default DiscoverUrlViewComponent = {
+ template: '#discover-url-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/main/main-view.component.html b/share/lua/http/src/routes/main/main-view.component.html
new file mode 100644
index 0000000000..626e395980
--- /dev/null
+++ b/share/lua/http/src/routes/main/main-view.component.html
@@ -0,0 +1,3 @@
+<script type="text/x-template" id="main-view-template">
+ <router-view></router-view>
+</script>
diff --git a/share/lua/http/src/routes/main/main-view.component.js b/share/lua/http/src/routes/main/main-view.component.js
new file mode 100644
index 0000000000..eb9c51c386
--- /dev/null
+++ b/share/lua/http/src/routes/main/main-view.component.js
@@ -0,0 +1,5 @@
+Vue.component('main-view', {
+ template: '#main-view-template',
+ methods: { },
+ created() { }
+});
diff --git a/share/lua/http/src/routes/music/albums/music-albums-view.component.html b/share/lua/http/src/routes/music/albums/music-albums-view.component.html
new file mode 100644
index 0000000000..464f931cac
--- /dev/null
+++ b/share/lua/http/src/routes/music/albums/music-albums-view.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="music-albums-view-template">
+ <div class="music-albums-view pt-4">
+ <albums></albums>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/albums/music-albums-view.component.js b/share/lua/http/src/routes/music/albums/music-albums-view.component.js
new file mode 100644
index 0000000000..59a8b70ada
--- /dev/null
+++ b/share/lua/http/src/routes/music/albums/music-albums-view.component.js
@@ -0,0 +1,6 @@
+export default MusicAlbumsViewComponent = {
+ template: '#music-albums-view-template',
+ methods: { },
+ created() {
+ }
+};
diff --git a/share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.html b/share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.html
new file mode 100644
index 0000000000..c91773be0a
--- /dev/null
+++ b/share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="music-artists-detail-view-template">
+ <div class="music-artists-detail-view">
+ <artists-detail></artists-detail>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.js b/share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.js
new file mode 100644
index 0000000000..f7705cd5d1
--- /dev/null
+++ b/share/lua/http/src/routes/music/artists/detail/music-artists-detail-view.component.js
@@ -0,0 +1,5 @@
+export default MusicArtistsDetailViewComponent = {
+ template: '#music-artists-detail-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/music/artists/music-artists-view.component.html b/share/lua/http/src/routes/music/artists/music-artists-view.component.html
new file mode 100644
index 0000000000..d3c75e838a
--- /dev/null
+++ b/share/lua/http/src/routes/music/artists/music-artists-view.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="music-artists-view-template">
+ <div class="music-artists-view pt-4">
+ <artists></artists>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/artists/music-artists-view.component.js b/share/lua/http/src/routes/music/artists/music-artists-view.component.js
new file mode 100644
index 0000000000..536ad5a359
--- /dev/null
+++ b/share/lua/http/src/routes/music/artists/music-artists-view.component.js
@@ -0,0 +1,5 @@
+export default MusicArtistsViewComponent = {
+ template: '#music-artists-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/music/genres/music-genres-view.component.html b/share/lua/http/src/routes/music/genres/music-genres-view.component.html
new file mode 100644
index 0000000000..1d3b5c2b3b
--- /dev/null
+++ b/share/lua/http/src/routes/music/genres/music-genres-view.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="music-genres-view-template">
+ <div class="music-genres-view pt-4">
+ <genres></genres>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/genres/music-genres-view.component.js b/share/lua/http/src/routes/music/genres/music-genres-view.component.js
new file mode 100644
index 0000000000..1b53befaf9
--- /dev/null
+++ b/share/lua/http/src/routes/music/genres/music-genres-view.component.js
@@ -0,0 +1,5 @@
+export default MusicGenresViewComponent = {
+ template: '#music-genres-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/music/music-view.component.html b/share/lua/http/src/routes/music/music-view.component.html
new file mode 100644
index 0000000000..b0c6d0d7f2
--- /dev/null
+++ b/share/lua/http/src/routes/music/music-view.component.html
@@ -0,0 +1,39 @@
+<script type="text/x-template" id="music-view-template">
+ <div class="music-view h-100">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <item-layout-button></item-layout-button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center">
+ <router-link to="/music/albums" exact-active-class="active" class="btn btn-link">Albums</router-link>
+ <router-link to="/music/artists" active-class="active" class="btn btn-link">Artists</router-link>
+ <router-link to="/music/genres" exact-active-class="active" class="btn btn-link">Genres</router-link>
+ <router-link to="/music/tracks" exact-active-class="active" class="btn btn-link">Tracks</router-link>
+ <router-link to="/music/playlists" exact-active-class="active" class="btn btn-link">Playlists</router-link>
+ </div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/music-view.component.js b/share/lua/http/src/routes/music/music-view.component.js
new file mode 100644
index 0000000000..0739f843d9
--- /dev/null
+++ b/share/lua/http/src/routes/music/music-view.component.js
@@ -0,0 +1,7 @@
+export default MusicViewComponent = {
+ template: '#music-view-template',
+ methods: { },
+ created() {
+ document.body.style['overflow-y'] = 'auto';
+ }
+};
diff --git a/share/lua/http/src/routes/music/playlists/music-playlists-view.component.html b/share/lua/http/src/routes/music/playlists/music-playlists-view.component.html
new file mode 100644
index 0000000000..5871a89a5d
--- /dev/null
+++ b/share/lua/http/src/routes/music/playlists/music-playlists-view.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="music-playlists-view-template">
+ <div class="music-playlists-view pt-4">
+ <playlists></playlists>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/playlists/music-playlists-view.component.js b/share/lua/http/src/routes/music/playlists/music-playlists-view.component.js
new file mode 100644
index 0000000000..0c12f51716
--- /dev/null
+++ b/share/lua/http/src/routes/music/playlists/music-playlists-view.component.js
@@ -0,0 +1,5 @@
+export default MusicPlaylistsViewComponent = {
+ template: '#music-playlists-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/music/tracks/music-tracks-view.component.html b/share/lua/http/src/routes/music/tracks/music-tracks-view.component.html
new file mode 100644
index 0000000000..181d747384
--- /dev/null
+++ b/share/lua/http/src/routes/music/tracks/music-tracks-view.component.html
@@ -0,0 +1,5 @@
+<script type="text/x-template" id="music-tracks-view-template">
+ <div class="music-tracks-view pt-4">
+ <tracks></tracks>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/music/tracks/music-tracks-view.component.js b/share/lua/http/src/routes/music/tracks/music-tracks-view.component.js
new file mode 100644
index 0000000000..f8d8b6a351
--- /dev/null
+++ b/share/lua/http/src/routes/music/tracks/music-tracks-view.component.js
@@ -0,0 +1,5 @@
+export default MusicTracksViewComponent = {
+ template: '#music-tracks-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/network/network-view.component.html b/share/lua/http/src/routes/network/network-view.component.html
new file mode 100644
index 0000000000..0e0d4e2217
--- /dev/null
+++ b/share/lua/http/src/routes/network/network-view.component.html
@@ -0,0 +1,31 @@
+<script type="text/x-template" id="network-view-template">
+ <div class="network-view h-100 pt-4">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <button v-on:click="" class="btn btn-circle"><svg-icon name="format_list_bulleted"></svg-icon></button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center"></div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/network/network-view.component.js b/share/lua/http/src/routes/network/network-view.component.js
new file mode 100644
index 0000000000..8fdf022613
--- /dev/null
+++ b/share/lua/http/src/routes/network/network-view.component.js
@@ -0,0 +1,4 @@
+export default NetworkViewComponent = {
+ template: '#network-view-template',
+ methods: { }
+};
diff --git a/share/lua/http/src/routes/video/all/video-all-view.component.html b/share/lua/http/src/routes/video/all/video-all-view.component.html
new file mode 100644
index 0000000000..4adbb62c86
--- /dev/null
+++ b/share/lua/http/src/routes/video/all/video-all-view.component.html
@@ -0,0 +1,6 @@
+<script type="text/x-template" id="video-all-view-template">
+ <div class="video-all-view">
+ <!-- <continue-watching></continue-watching> -->
+ <videos></videos>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/video/all/video-all-view.component.js b/share/lua/http/src/routes/video/all/video-all-view.component.js
new file mode 100644
index 0000000000..9e550b0cd7
--- /dev/null
+++ b/share/lua/http/src/routes/video/all/video-all-view.component.js
@@ -0,0 +1,5 @@
+export default VideoAllViewComponent = {
+ template: '#video-all-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/video/movies/video-movies-view.component.html b/share/lua/http/src/routes/video/movies/video-movies-view.component.html
new file mode 100644
index 0000000000..03a5ba5543
--- /dev/null
+++ b/share/lua/http/src/routes/video/movies/video-movies-view.component.html
@@ -0,0 +1,3 @@
+<script type="text/x-template" id="video-movies-view-template">
+ <div class="video-movies-view"></div>
+</script>
diff --git a/share/lua/http/src/routes/video/movies/video-movies-view.component.js b/share/lua/http/src/routes/video/movies/video-movies-view.component.js
new file mode 100644
index 0000000000..79ecdfd1c4
--- /dev/null
+++ b/share/lua/http/src/routes/video/movies/video-movies-view.component.js
@@ -0,0 +1,5 @@
+export default VideoMoviesViewComponent = {
+ template: '#video-movies-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/video/playlists/video-playlists-view.component.html b/share/lua/http/src/routes/video/playlists/video-playlists-view.component.html
new file mode 100644
index 0000000000..62c40e5b87
--- /dev/null
+++ b/share/lua/http/src/routes/video/playlists/video-playlists-view.component.html
@@ -0,0 +1,3 @@
+<script type="text/x-template" id="video-playlists-view-template">
+ <div class="video-playlists-view"></div>
+</script>
diff --git a/share/lua/http/src/routes/video/playlists/video-playlists-view.component.js b/share/lua/http/src/routes/video/playlists/video-playlists-view.component.js
new file mode 100644
index 0000000000..172ab20a3f
--- /dev/null
+++ b/share/lua/http/src/routes/video/playlists/video-playlists-view.component.js
@@ -0,0 +1,5 @@
+export default VideoPlaylistsViewComponent = {
+ template: '#video-playlists-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.html b/share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.html
new file mode 100644
index 0000000000..6ea9529936
--- /dev/null
+++ b/share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.html
@@ -0,0 +1,3 @@
+<script type="text/x-template" id="video-tvshows-view-template">
+ <div class="video-tvshows-view"></div>
+</script>
diff --git a/share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.js b/share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.js
new file mode 100644
index 0000000000..604c98d5c5
--- /dev/null
+++ b/share/lua/http/src/routes/video/tvshows/video-tvshows-view.component.js
@@ -0,0 +1,5 @@
+export default VideoTvShowsViewComponent = {
+ template: '#video-tvshows-view-template',
+ methods: { },
+ created() { }
+};
diff --git a/share/lua/http/src/routes/video/video-view.component.html b/share/lua/http/src/routes/video/video-view.component.html
new file mode 100644
index 0000000000..db2127b27c
--- /dev/null
+++ b/share/lua/http/src/routes/video/video-view.component.html
@@ -0,0 +1,38 @@
+<script type="text/x-template" id="video-view-template">
+ <div class="video-view h-100 pt-4">
+ <div class="fixed-top secondary-navbar">
+ <div class="container-fluid d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <item-layout-button></item-layout-button>
+ <button v-on:click="" class="btn btn-circle ml-2"><svg-icon name="sort"></svg-icon></button>
+ </div>
+ <div class="d-flex align-items-center justify-content-center">
+ <router-link to="/video/all" exact-active-class="active" class="btn btn-link">All</router-link>
+ <router-link to="/video/movies" exact-active-class="active" class="btn btn-link">Movies</router-link>
+ <router-link to="/video/tvshows" exact-active-class="active" class="btn btn-link">Tv Shows</router-link>
+ <router-link to="/video/playlists" exact-active-class="active" class="btn btn-link">Playlists</router-link>
+ </div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0 h-100" :class="'push'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col container-view">
+ <transition name="fade" mode="out-in">
+ <router-view></router-view>
+ </transition>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/video/video-view.component.js b/share/lua/http/src/routes/video/video-view.component.js
new file mode 100644
index 0000000000..27c60d0eb5
--- /dev/null
+++ b/share/lua/http/src/routes/video/video-view.component.js
@@ -0,0 +1,7 @@
+export default VideoViewComponent = {
+ template: '#video-view-template',
+ methods: { },
+ created() {
+ document.body.style['overflow-y'] = 'auto';
+ }
+};
diff --git a/share/lua/http/src/routes/watch/watch-view.component.html b/share/lua/http/src/routes/watch/watch-view.component.html
new file mode 100644
index 0000000000..0546e71483
--- /dev/null
+++ b/share/lua/http/src/routes/watch/watch-view.component.html
@@ -0,0 +1,36 @@
+<script type="text/x-template" id="watch-view-template">
+ <div class="watch-view h-100">
+ <div>
+ <div class="container-fluid fixed-top primary-navbar">
+ <div class="d-flex h-100 position-relative show collapse justify-content-between align-items-center">
+ <div class="d-flex align-items-center flex-1 justify-content-start">
+ <router-link to="/">
+ <button class="btn btn-circle">
+ <svg-icon name="keyboard_arrow_left"></svg-icon>
+ </button>
+ </router-link>
+ </div>
+ <div class="d-flex align-items-center justify-content-center"></div>
+ <div class="d-flex flex-1 justify-content-end h-100">
+ <a data-toggle="collapse" href="#" data-target=".collapse" role="button" class="text-white toggler px-2 d-flex align-items-center">
+ <svg-icon name="playlist_play"></svg-icon>
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="container-fluid px-0" :class="'overlay'">
+ <div class="row collapse show no-gutters d-flex h-100 position-relative">
+ <div class="col">
+ <media-player></media-player>
+ </div>
+ <div class="col-3 p-0 h-100 w-sidebar navbar-collapse collapse d-flex sidebar show">
+ <!-- fixed sidebar -->
+ <div class="navbar-dark align-self-start w-sidebar w-sidebar-content">
+ <playlist></playlist>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</script>
diff --git a/share/lua/http/src/routes/watch/watch-view.component.js b/share/lua/http/src/routes/watch/watch-view.component.js
new file mode 100644
index 0000000000..ba86388f28
--- /dev/null
+++ b/share/lua/http/src/routes/watch/watch-view.component.js
@@ -0,0 +1,7 @@
+export default WatchViewComponent = {
+ template: '#watch-view-template',
+ methods: { },
+ created() {
+ document.body.style['overflow-y'] = 'hidden';
+ }
+};
diff --git a/share/lua/http/src/scss/components.scss b/share/lua/http/src/scss/components.scss
index ea5d6eb9e0..336c0f0df1 100644
--- a/share/lua/http/src/scss/components.scss
+++ b/share/lua/http/src/scss/components.scss
@@ -1,9 +1,25 @@
// components.scss
+ at import '../components/albums/albums.component.scss';
+ at import '../components/albums/album-item/album-item.component.scss';
+ at import '../components/artists/artist-item/artist-item-grid.component.scss';
+ at import '../components/artists/detail/artists-detail.component.scss';
+ at import '../components/library/library.component.scss';
+ at import '../components/library/library-item/library-item.component.scss';
+ at import '../components/media-player/media-player.component.scss';
+ at import '../components/enqueue-button/enqueue-button.component.scss';
+ at import '../components/play-button/play-button-secondary.component.scss';
+ at import '../components/play-button/play-button.component.scss';
@import '../components/playlist/playlist.component.scss';
+ at import '../components/playlist/playlist-video-item.component.scss';
+ at import '../components/playlist/playlist-audio-item.component.scss';
+ at import '../components/playlist/buttons.playlist.component.scss';
+ at import '../components/playlists/playlists-item/playlists-item.component.scss';
@import '../components/vlm/vlm.component.scss';
@import '../components/svg-icon/svg-icon.component.scss';
+ at import '../routes/browse/browse-view.component.scss';
+ at import '../routes/discover/services/discover-services-view.component.scss';
@import './collapse.scss';
@import './grid-item.scss';
@import './list-item.scss';
diff --git a/share/lua/http/src/services/initialize.service.js b/share/lua/http/src/services/initialize.service.js
index 4185306342..6eb4c8ad3f 100644
--- a/share/lua/http/src/services/initialize.service.js
+++ b/share/lua/http/src/services/initialize.service.js
@@ -1,79 +1,176 @@
-import { plyrInit } from '../components/player/plyr.methods.js';
-import { notifyBus } from './bus.service.js';
import { svgIcon } from '../components/svg-icon/svg-icon.component.js';
+import BrowseViewComponent from '../routes/browse/browse-view.component.js';
+import VideoViewComponent from '../routes/video/video-view.component.js';
+import WatchViewComponent from '../routes/watch/watch-view.component.js';
-export const VIDEO_TYPES = [
- 'asf', 'avi', 'bik', 'bin', 'divx', 'drc', 'dv', 'f4v', 'flv', 'gxf', 'iso',
- 'm1v', 'm2v', 'm2t', 'm2ts', 'm4v', 'mkv', 'mov',
- 'mp2', 'mp4', 'mpeg', 'mpeg1',
- 'mpeg2', 'mpeg4', 'mpg', 'mts', 'mtv', 'mxf', 'mxg', 'nuv',
- 'ogg', 'ogm', 'ogv', 'ogx', 'ps',
- 'rec', 'rm', 'rmvb', 'rpl', 'thp', 'ts', 'txd', 'vob', 'wmv', 'xesc'
-];
+import store from '../store/index.js';
+import MusicViewComponent from '../routes/music/music-view.component.js';
+import DiscoverViewComponent from '../routes/discover/discover-view.component.js';
+import DiscoverHomeViewComponent from '../routes/discover/home/discover-home-view.component.js';
+import DiscoverServicesViewComponent from '../routes/discover/services/discover-services-view.component.js';
+import DiscoverServicesTvViewComponent from '../routes/discover/services/tv/discover-services-tv-view.component.js';
+import DiscoverUrlViewComponent from '../routes/discover/url/discover-url-view.component.js';
-export const AUDIO_TYPES = [
- '3ga', 'a52', 'aac', 'ac3', 'ape', 'awb', 'dts', 'flac', 'it',
- 'm4a', 'm4p', 'mka', 'mlp', 'mod', 'mp1', 'mp2', 'mp3',
- 'oga', 'ogg', 'oma', 's3m', 'spx', 'thd', 'tta',
- 'wav', 'wma', 'wv', 'xm'
-];
+import MusicAlbumsViewComponent from '../routes/music/albums/music-albums-view.component.js';
+import MusicArtistsViewComponent from '../routes/music/artists/music-artists-view.component.js';
+import MusicArtistsDetailViewComponent from '../routes/music/artists/detail/music-artists-detail-view.component.js';
+import MusicGenresViewComponent from '../routes/music/genres/music-genres-view.component.js';
+import MusicTracksViewComponent from '../routes/music/tracks/music-tracks-view.component.js';
+
+import NetworkViewComponent from '../routes/network/network-view.component.js';
+import VideoMoviesComponent from '../routes/video/movies/video-movies-view.component.js';
+import VideoTvshowsComponent from '../routes/video/tvshows/video-tvshows-view.component.js';
+import VideoAllComponent from '../routes/video/all/video-all-view.component.js';
+import MusicPlaylistsViewComponent from '../routes/music/playlists/music-playlists-view.component.js';
+import VideoPlaylistsComponent from '../routes/video/playlists/video-playlists-view.component.js';
+
+const routes = [
-export const PLAYLIST_TYPES = [
- 'asx', 'b4s', 'cue', 'ifo', 'm3u', 'm3u8', 'pls', 'ram', 'rar',
- 'sdp', 'vlc', 'xspf', 'zip', 'conf'
+ {
+ path: '/',
+ component: BrowseViewComponent,
+ redirect: '/video',
+ children: [
+ {
+ path: 'music',
+ component: MusicViewComponent,
+ redirect: 'music/albums',
+ children: [
+ {
+ path: 'albums',
+ component: MusicAlbumsViewComponent
+ },
+ {
+ path: 'artists',
+ component: MusicArtistsViewComponent,
+ },
+ {
+ path: 'artists/:id',
+ component: MusicArtistsDetailViewComponent
+ },
+ {
+ path: 'genres',
+ component: MusicGenresViewComponent
+ },
+ {
+ path: 'tracks',
+ component: MusicTracksViewComponent
+ },
+ {
+ path: 'playlists',
+ component: MusicPlaylistsViewComponent
+ }
+ ]
+ },
+ {
+ path: 'video',
+ component: VideoViewComponent,
+ redirect: 'video/all',
+ children: [
+ {
+ path: 'all',
+ component: VideoAllComponent
+ },
+ {
+ path: 'movies',
+ component: VideoMoviesComponent
+ },
+ {
+ path: 'tvshows',
+ component: VideoTvshowsComponent
+ },
+ {
+ path: 'playlists',
+ component: VideoPlaylistsComponent
+ }
+ ]
+ },
+ {
+ path: 'network',
+ component: NetworkViewComponent
+ },
+ {
+ path: 'discover',
+ component: DiscoverViewComponent,
+ redirect: 'discover/home',
+ children: [
+ {
+ path: 'home',
+ component: DiscoverHomeViewComponent
+ },
+ {
+ path: 'services',
+ component: DiscoverServicesViewComponent
+ },
+ {
+ path: 'services/tv',
+ component: DiscoverServicesTvViewComponent
+ },
+ {
+ path: 'url',
+ component: DiscoverUrlViewComponent
+ }
+ ]
+ }
+ ]
+ },
+ {
+ path: '/watch',
+ component: WatchViewComponent
+ }
];
+const router = new VueRouter({
+ routes
+})
+
function vueInit() {
+ Vue.use(svgIcon, {
+ tagName: 'svg-icon'
+ });
return new Vue({
+ router,
el: '#app',
data: {
playlistItems: []
- }
+ },
+ store,
+ mounted() { }
});
}
$(() => {
- plyrInit();
- Vue.use(svgIcon, {
- tagName: 'svg-icon'
- });
vueInit();
+ let didScroll;
+ let lastScrollTop = 0;
+ const delta = 5;
+ const navbarHeight = $('.fixed-top.secondary-navbar').outerHeight();
- $('#openNavButton').on('click', () => {
- if ($(window).width() <= 480 && $('#playlistNav').css('width') === '60%') {
- notifyBus('closePlaylist');
- notifyBus('openNav');
- } else {
- notifyBus('openNav');
- }
- });
-
- $('#closeNavButton').on('click', () => {
- notifyBus('closeNav');
- });
-
- $('#vlmButton').on('click', () => {
- notifyBus('executeVLM');
- });
-
- $('#repeatButton').on('click', () => {
- notifyBus('toggleRepeat');
+ $(window).scroll(() => {
+ didScroll = true;
});
- $('#playButton').on('click', () => {
- notifyBus('startPlaylist');
- });
+ setInterval(() => {
+ if (didScroll) {
+ hasScrolled();
+ didScroll = false;
+ }
+ }, 250);
- $('#randomButton').on('click', () => {
- notifyBus('toggleRandom');
- });
+ function hasScrolled() {
+ const sValue = $(this).scrollTop();
+ const secondaryNavbar = $('.fixed-top.secondary-navbar');
+ if (Math.abs(lastScrollTop - sValue) <= delta) {
+ return;
+ }
- $('#mobilePlaylistNavButton').on('click', () => {
- if ($(window).width() <= 480 && $('#sideNav').width() === '60%') {
- notifyBus('closeNav');
- notifyBus('openPlaylist');
+ if (sValue > lastScrollTop && sValue > navbarHeight) {
+ secondaryNavbar.removeClass('nav-down').addClass('nav-up');
} else {
- notifyBus('openPlaylist');
+ if (sValue + $(window).height() < $(document).height()) {
+ secondaryNavbar.removeClass('nav-up').addClass('nav-down');
+ }
}
- });
+ lastScrollTop = sValue;
+ }
});
--
2.18.0
More information about the vlc-devel
mailing list