@ -1 +1,23 @@ |
|||
node_modules |
|||
.DS_Store |
|||
node_modules |
|||
/dist |
|||
|
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
|
|||
@ -0,0 +1,24 @@ |
|||
# vue-css |
|||
|
|||
## Project setup |
|||
``` |
|||
npm install |
|||
``` |
|||
|
|||
### Compiles and hot-reloads for development |
|||
``` |
|||
npm run serve |
|||
``` |
|||
|
|||
### Compiles and minifies for production |
|||
``` |
|||
npm run build |
|||
``` |
|||
|
|||
### Lints and fixes files |
|||
``` |
|||
npm run lint |
|||
``` |
|||
|
|||
### Customize configuration |
|||
See [Configuration Reference](https://cli.vuejs.org/config/). |
|||
@ -1,28 +0,0 @@ |
|||
<!-- |
|||
- ************************************************************************* |
|||
- log_template-mat.html.temp |
|||
- ************************************************************************** |
|||
- Copyright © 2022 VLC authors and VideoLAN |
|||
- Author: Nicolas POMEPUY |
|||
- This program is free software; you can redistribute it and/or modify |
|||
- it under the terms of the GNU General Public License as published by |
|||
- the Free Software Foundation; either version 2 of the License, or |
|||
- (at your option) any later version. |
|||
- |
|||
- This program is distributed in the hope that it will be useful, |
|||
- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
- GNU General Public License for more details. |
|||
- |
|||
- You should have received a copy of the GNU General Public License |
|||
- along with this program; if not, write to the Free Software |
|||
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
- *************************************************************************** |
|||
- |
|||
- |
|||
--> |
|||
|
|||
<tr class="mdc-data-table__row"> |
|||
<th class="mdc-data-table__cell" scope="row">%%FILE_NAME_SHORT%%</th> |
|||
<td class="mdc-data-table__cell"><a href="download?file=%%FILE_NAME%%"><button class="material-icons mdc-icon-button" aria-label="download">download</button></a></td> |
|||
</tr> |
|||
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
presets: [ |
|||
'@vue/cli-plugin-babel/preset' |
|||
] |
|||
} |
|||
@ -1,158 +0,0 @@ |
|||
<!-- |
|||
~ ************************************************************************* |
|||
~ index.html |
|||
~ ************************************************************************** |
|||
~ Copyright © 2022 VLC authors and VideoLAN |
|||
~ Author: Nicolas POMEPUY |
|||
~ This program is free software; you can redistribute it and/or modify |
|||
~ it under the terms of the GNU General Public License as published by |
|||
~ the Free Software Foundation; either version 2 of the License, or |
|||
~ (at your option) any later version. |
|||
~ |
|||
~ This program is distributed in the hope that it will be useful, |
|||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
~ GNU General Public License for more details. |
|||
~ |
|||
~ You should have received a copy of the GNU General Public License |
|||
~ along with this program; if not, write to the Free Software |
|||
~ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
~ *************************************************************************** |
|||
~ |
|||
~ |
|||
--> |
|||
|
|||
<!doctype html> |
|||
<html lang="en"> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<title>{%ns_network_sharing%}</title> |
|||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> |
|||
|
|||
<link rel="apple-touch-icon" sizes="180x180" href="images/apple-touch-icon.png"> |
|||
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png"> |
|||
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png"> |
|||
<link rel="manifest" href="/site.webmanifest"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"/> |
|||
</head> |
|||
|
|||
<body> |
|||
<main> |
|||
|
|||
<header class="mdc-top-app-bar"> |
|||
<div class="mdc-top-app-bar__row"> |
|||
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start"> |
|||
<button class="material-icons mdc-top-app-bar__navigation-icon mdc-icon-button" aria-label="Open navigation menu"> |
|||
<div class="mdc-icon-button__ripple"></div> |
|||
menu |
|||
</button> |
|||
<a href="http://www.videolan.org" target="_blank"> |
|||
<img class="mdc-top-app-bar__navigation-icon" aria-label="Open navigation menu" |
|||
src="images/icon.png" /> |
|||
</a> |
|||
<span class="mdc-top-app-bar__title">{%ns_network_sharing%}</span> |
|||
</section> |
|||
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-end" role="toolbar"> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" |
|||
aria-label="Options"><div class="mdc-icon-button__ripple"></div>more_vert |
|||
</button> |
|||
</section> |
|||
</div> |
|||
</header> |
|||
<main class="mdc-top-app-bar--fixed-adjust"> |
|||
|
|||
<div class="mdc-layout-grid"> |
|||
<div class="mdc-layout-grid__inner"> |
|||
<div class="mdc-layout-grid__cell"></div> |
|||
<div class="mdc-layout-grid__cell"> |
|||
<div class="mdc-data-table"> |
|||
<div class="mdc-data-table__table-container"> |
|||
<table class="mdc-data-table__table" aria-label="Dessert calories"> |
|||
<thead> |
|||
<tr class="mdc-data-table__header-row"> |
|||
<th class="mdc-data-table__header-cell" role="columnheader" scope="col"> |
|||
{%ns_log_file%} |
|||
</th> |
|||
<th class="mdc-data-table__header-cell mdc-data-table__header-cell--numeric" |
|||
role="columnheader" scope="col">{%download_on_device%} |
|||
</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="mdc-data-table__content"> |
|||
{*logs*} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="mdc-layout-grid__cell"></div> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
<footer class="footer"> |
|||
<div class="footer__content"> |
|||
<p class="mdc-typography--body1">VLC for Android is free, open-source software published by |
|||
<a href="http://www.videolan.org" target="_blank">VideoLAN</a>. <br />Modification |
|||
and redistribution is subject to both the <a href="http://opensource.org/licenses/GPL-2.0" |
|||
target="_blank">GPLv2 (or |
|||
later)</a> and the <a href="http://opensource.org/licenses/MPL-2.0" target="_blank">MPLv2</a> as |
|||
well as further rights |
|||
reserved by the VideoLAN non-profit organization.<br />You can find more information |
|||
about licensing in the About dialog within the app.<br />VideoLAN, VLC and VLC media |
|||
player are internationally registered trademarks of the <a href="http://www.videolan.org/videolan/" |
|||
target="_blank">VideoLAN non-profit |
|||
organization</a>. |
|||
</p> |
|||
</div> |
|||
</footer> |
|||
</main> |
|||
<div id="player"> |
|||
<img id="player_artwork" width="48px" height="48px"> |
|||
<div class="player_info"> |
|||
<p id="title"/> |
|||
<p id="artist"/> |
|||
</div> |
|||
<div class="player_controls"> |
|||
<div> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_shuffle" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>shuffle |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_previous" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>skip_previous |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_previous_10" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>replay_10 |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_play" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>play_circle |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_pause" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>pause_circle |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_next_10" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>forward_10 |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_next" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>skip_next |
|||
</button> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" id="player_repeat" |
|||
aria-label="play"><div class="mdc-icon-button__ripple"></div>repeat |
|||
</button> |
|||
</div> |
|||
<div id="player_controls_progress"> |
|||
<p id="time"/> |
|||
<div id="progress_bar"></div> |
|||
<p id="duration"/> |
|||
</div> |
|||
</div> |
|||
<div class="player_right"> |
|||
</div> |
|||
|
|||
</div> |
|||
<link rel="stylesheet" href="bundle.css"> |
|||
<script src="style-bundle.js"></script> |
|||
|
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,91 +0,0 @@ |
|||
import {MDCRipple} from '@material/ripple'; |
|||
import {MDCTopAppBar} from '@material/top-app-bar'; |
|||
import {MDCDataTable} from '@material/data-table'; |
|||
|
|||
|
|||
import icon from "../asset/resource/icon.png" |
|||
import android_chrome_192 from "../asset/resource/android-chrome-192x192.png" |
|||
import android_chrome_512 from "../asset/resource/android-chrome-512x512.png" |
|||
import favicon from "../asset/resource/favicon.ico" |
|||
import favicon_16 from "../asset/resource/favicon-16x16.png" |
|||
import favicon_32 from "../asset/resource/favicon-32x32.png" |
|||
import index from "../html/index.html" |
|||
|
|||
|
|||
//const playerWS = new WebSocket("wss://"+window.location.origin+"/echo", "protocolOne");
|
|||
const playerWS = new WebSocket("ws://"+location.host+"/echo", "player"); |
|||
playerWS.onopen = (event) => { |
|||
}; |
|||
|
|||
|
|||
export const msecToTime = ms => { |
|||
const seconds = Math.floor((ms / 1000) % 60) |
|||
const minutes = Math.floor((ms / (60 * 1000)) % 60) |
|||
const hours = Math.floor((ms / (3600 * 1000)) % 3600) |
|||
return `${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}:${ |
|||
seconds < 10 ? '0' + seconds : seconds |
|||
}` |
|||
} |
|||
const play = document.getElementById("player_play"); |
|||
const pause = document.getElementById("player_pause"); |
|||
const previous = document.getElementById("player_previous"); |
|||
const next = document.getElementById("player_next"); |
|||
const shuffle = document.getElementById("player_shuffle"); |
|||
const repeat = document.getElementById("player_repeat"); |
|||
const previous10 = document.getElementById("player_previous_10"); |
|||
const next10 = document.getElementById("player_next_10"); |
|||
|
|||
play.addEventListener('click', (event) => { |
|||
playerWS.send("play"); |
|||
}); |
|||
pause.addEventListener('click', (event) => { |
|||
playerWS.send("pause"); |
|||
}); |
|||
previous.addEventListener('click', (event) => { |
|||
playerWS.send("previous"); |
|||
}); |
|||
next.addEventListener('click', (event) => { |
|||
playerWS.send("next"); |
|||
}); |
|||
shuffle.addEventListener('click', (event) => { |
|||
playerWS.send("shuffle"); |
|||
}); |
|||
repeat.addEventListener('click', (event) => { |
|||
playerWS.send("repeat"); |
|||
}); |
|||
previous10.addEventListener('click', (event) => { |
|||
playerWS.send("previous10"); |
|||
}); |
|||
next10.addEventListener('click', (event) => { |
|||
playerWS.send("next10"); |
|||
}); |
|||
|
|||
var lastLoadedMediaUri = "" |
|||
|
|||
playerWS.onmessage = (event) => { |
|||
console.log(event.data); |
|||
const player = document.getElementById("player"); |
|||
const title = document.getElementById("title"); |
|||
const artist = document.getElementById("artist"); |
|||
const time = document.getElementById("time"); |
|||
const duration = document.getElementById("duration"); |
|||
const artwork = document.getElementById("player_artwork"); |
|||
const msg = JSON.parse(event.data); |
|||
title.textContent = msg.title |
|||
artist.textContent = msg.artist |
|||
time.textContent = msecToTime(new Date(msg.progress)) |
|||
duration.textContent = msecToTime(new Date(msg.duration)) |
|||
if (lastLoadedMediaUri != msg.uri) { |
|||
artwork.src = "http://"+location.host+"/artwork?randomizer="+Date.now() |
|||
lastLoadedMediaUri = msg.uri |
|||
} |
|||
|
|||
if (msg.playing) { |
|||
play.style.display = "none"; |
|||
pause.style.display = "inline-block"; |
|||
} else { |
|||
play.style.display = "inline-block"; |
|||
pause.style.display = "none"; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"target": "es5", |
|||
"module": "esnext", |
|||
"baseUrl": "./", |
|||
"moduleResolution": "node", |
|||
"paths": { |
|||
"@/*": [ |
|||
"src/*" |
|||
] |
|||
}, |
|||
"lib": [ |
|||
"esnext", |
|||
"dom", |
|||
"dom.iterable", |
|||
"scripthost" |
|||
] |
|||
} |
|||
} |
|||
@ -1,32 +1,53 @@ |
|||
{ |
|||
"name": "vlc-android-network-sharing-server", |
|||
"version": "1.0.0", |
|||
"description": "VLC for Android network sharing server", |
|||
"main": "index.js", |
|||
"author": "VideoLAN", |
|||
"license": "LGPL-3.0-or-later", |
|||
"scripts": { |
|||
"build": "webpack", |
|||
"start": "webpack-dev-server" |
|||
}, |
|||
"devDependencies": { |
|||
"copy-webpack-plugin": "^11.0.0", |
|||
"css-loader": "^6.7.1", |
|||
"extract-loader": "^5.1.0", |
|||
"file-loader": "^6.2.0", |
|||
"html-loader": "^4.2.0", |
|||
"sass": "^1.53.0", |
|||
"sass-loader": "^13.0.2", |
|||
"webpack": "^5.74.0", |
|||
"webpack-cli": "^4.10.0", |
|||
"webpack-dev-server": "^4.11.1" |
|||
}, |
|||
"dependencies": { |
|||
"@material/button": "^14.0.0", |
|||
"@material/data-table": "^14.0.0", |
|||
"@material/icon-button": "^14.0.0", |
|||
"@material/layout-grid": "^14.0.0", |
|||
"@material/top-app-bar": "^14.0.0", |
|||
"@material/typography": "^14.0.0" |
|||
} |
|||
} |
|||
"name": "vue-css", |
|||
"version": "0.1.0", |
|||
"private": true, |
|||
"scripts": { |
|||
"serve": "export VUE_APP_DEVICE_IP=$(adb shell ifconfig wlan0 | awk '/inet addr/ {gsub(\"addr:\", \"\", $2); print $2}') && vue-cli-service serve", |
|||
"build": "vue-cli-service build", |
|||
"lint": "vue-cli-service lint" |
|||
}, |
|||
"dependencies": { |
|||
"@material/button": "^14.0.0", |
|||
"@material/data-table": "^14.0.0", |
|||
"@material/icon-button": "^14.0.0", |
|||
"@material/layout-grid": "^14.0.0", |
|||
"@material/top-app-bar": "^14.0.0", |
|||
"@material/typography": "^14.0.0", |
|||
"axios": "^1.3.4", |
|||
"core-js": "^3.8.3", |
|||
"vue": "^3.2.13", |
|||
"vue-router": "^4.1.6" |
|||
}, |
|||
"devDependencies": { |
|||
"@babel/core": "^7.12.16", |
|||
"@babel/eslint-parser": "^7.12.16", |
|||
"@vue/cli-plugin-babel": "~5.0.0", |
|||
"@vue/cli-plugin-eslint": "~5.0.0", |
|||
"@vue/cli-service": "~5.0.0", |
|||
"eslint": "^7.32.0", |
|||
"eslint-plugin-vue": "^8.0.3", |
|||
"sass": "^1.59.3", |
|||
"sass-loader": "^13.2.1" |
|||
}, |
|||
"eslintConfig": { |
|||
"root": true, |
|||
"env": { |
|||
"node": true |
|||
}, |
|||
"extends": [ |
|||
"plugin:vue/vue3-essential", |
|||
"eslint:recommended" |
|||
], |
|||
"parserOptions": { |
|||
"parser": "@babel/eslint-parser" |
|||
}, |
|||
"rules": {} |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions", |
|||
"not dead", |
|||
"not ie 11" |
|||
] |
|||
} |
|||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,25 @@ |
|||
<!DOCTYPE html> |
|||
<html lang=""> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<title>VLC-Android</title> |
|||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> |
|||
|
|||
<link rel="apple-touch-icon" sizes="180x180" href="../src/assets/resources/apple-touch-icon.png"> |
|||
<link rel="icon" type="image/png" sizes="32x32" href="../src/assets/resources/favicon-32x32.png"> |
|||
<link rel="icon" type="image/png" sizes="16x16" href="../src/assets/resources/favicon-16x16.png"> |
|||
<link rel="manifest" href="/site.webmanifest"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|||
</head> |
|||
|
|||
<body> |
|||
<noscript> |
|||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. |
|||
Please enable it to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -0,0 +1,25 @@ |
|||
<template> |
|||
<AppHeader /> |
|||
<PageDownloads /> |
|||
<MiniPlayer /> |
|||
<!-- <AppFooter /> --> |
|||
</template> |
|||
|
|||
<script> |
|||
import AppHeader from './components/AppHeader.vue' |
|||
// import AppFooter from './components/AppFooter.vue' |
|||
import MiniPlayer from './components/MiniPlayer.vue' |
|||
import PageDownloads from './pages/PageDownloads.vue' |
|||
|
|||
export default { |
|||
name: 'App', |
|||
components: { |
|||
PageDownloads, |
|||
AppHeader, |
|||
// AppFooter, |
|||
MiniPlayer, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style></style> |
|||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 603 B After Width: | Height: | Size: 603 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,28 @@ |
|||
<template> |
|||
<footer class="footer"> |
|||
<div class="footer__content"> |
|||
<p class="mdc-typography--body1">VLC for Android is free, open-source software published by |
|||
<a href="http://www.videolan.org" target="_blank">VideoLAN</a>. <br />Modification |
|||
and redistribution is subject to both the <a href="http://opensource.org/licenses/GPL-2.0" |
|||
target="_blank">GPLv2 (or |
|||
later)</a> and the <a href="http://opensource.org/licenses/MPL-2.0" target="_blank">MPLv2</a> as |
|||
well as further rights |
|||
reserved by the VideoLAN non-profit organization.<br />You can find more information |
|||
about licensing in the About dialog within the app.<br />VideoLAN, VLC and VLC media |
|||
player are internationally registered trademarks of the <a href="http://www.videolan.org/videolan/" |
|||
target="_blank">VideoLAN non-profit |
|||
organization</a>. |
|||
</p> |
|||
</div> |
|||
</footer> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -0,0 +1,30 @@ |
|||
<template> |
|||
<header class="mdc-top-app-bar"> |
|||
<div class="mdc-top-app-bar__row"> |
|||
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start"> |
|||
<button class="material-icons mdc-top-app-bar__navigation-icon mdc-icon-button" aria-label="Open navigation menu"> |
|||
<div class="mdc-icon-button__ripple"></div> |
|||
menu |
|||
</button> |
|||
<a href="http://www.videolan.org" target="_blank"> |
|||
<img class="mdc-top-app-bar__navigation-icon" aria-label="Open navigation menu" |
|||
src="../assets/resources/icon.png" /> |
|||
</a> |
|||
<span class="mdc-top-app-bar__title">VLC-Android's web server</span> |
|||
</section> |
|||
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-end" role="toolbar"> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" aria-label="Options"> |
|||
<div class="mdc-icon-button__ripple"></div>more_vert |
|||
</button> |
|||
</section> |
|||
</div> |
|||
</header> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style></style> |
|||
@ -0,0 +1,11 @@ |
|||
<template> |
|||
<main class="mdc-top-app-bar--fixed-adjust"> |
|||
<h1>This is empty</h1> |
|||
</main> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
|
|||
} |
|||
</script> |
|||
@ -0,0 +1,30 @@ |
|||
<template> |
|||
<tr class="mdc-data-table__row"> |
|||
<th class="mdc-data-table__cell" scope="row">{{ logfile.date }}</th> |
|||
<td class="mdc-data-table__cell"> |
|||
<a :href="href"> |
|||
<button class="material-icons mdc-icon-button" aria-label="download"> |
|||
download |
|||
</button> |
|||
</a> |
|||
</td> |
|||
</tr> |
|||
</template> |
|||
|
|||
<script> |
|||
import { API_CONFIG } from '@/config'; |
|||
export default { |
|||
props: { |
|||
logfile: Object |
|||
}, |
|||
computed: { |
|||
href: function () { |
|||
return `${API_CONFIG.DOWNLOAD_LOGFILE}` + this.logfile.path |
|||
} |
|||
}, |
|||
mounted: function () { |
|||
console.log(this.logfile.date + " -> " + this.logfile.path) |
|||
console.log(this.href) |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,48 @@ |
|||
<template> |
|||
<main class="mdc-top-app-bar--fixed-adjust"> |
|||
|
|||
<div class="mdc-layout-grid"> |
|||
<div class="mdc-layout-grid__inner"> |
|||
<div class="mdc-layout-grid__cell"></div> |
|||
<div class="mdc-layout-grid__cell"> |
|||
<div class="mdc-data-table"> |
|||
<div class="mdc-data-table__table-container"> |
|||
<table class="mdc-data-table__table" aria-label="Dessert calories"> |
|||
<thead> |
|||
<tr class="mdc-data-table__header-row"> |
|||
<th class="mdc-data-table__header-cell" role="columnheader" scope="col"> |
|||
Log Files |
|||
</th> |
|||
<th class="mdc-data-table__header-cell mdc-data-table__header-cell--numeric" role="columnheader" |
|||
scope="col">Download |
|||
</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="mdc-data-table__content"> |
|||
<div v-for="logfile in logs" :key="logfile.path"> |
|||
<LogItem :logfile="logfile" /> |
|||
</div> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="mdc-layout-grid__cell"></div> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
</template> |
|||
|
|||
<script> |
|||
import LogItem from './LogItem.vue' |
|||
|
|||
export default { |
|||
components: { |
|||
LogItem, |
|||
}, |
|||
props: { |
|||
logs: [] |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
@ -0,0 +1,42 @@ |
|||
<template> |
|||
<div id="player"> |
|||
<img id="player_artwork" width="48px" height="48px"> |
|||
<div class="player_info"> |
|||
<p id="title"/> |
|||
<p id="artist"/> |
|||
</div> |
|||
<div class="player_controls"> |
|||
<div> |
|||
<PlayerButton type="shuffle" id="player_shuffle"/> |
|||
<PlayerButton type="skip_previous" id="player_previous"/> |
|||
<PlayerButton type="replay_10" id="player_previous_10"/> |
|||
<PlayerButton type="play_circle" id="player_play"/> |
|||
<PlayerButton type="pause_circle" id="player_pause"/> |
|||
<PlayerButton type="forward_10" id="player_next_10"/> |
|||
<PlayerButton type="skip_next" id="player_next"/> |
|||
<PlayerButton type="repeat" id="player_repeat"/> |
|||
</div> |
|||
<div id="player_controls_progress"> |
|||
<p id="time"/> |
|||
<div id="progress_bar"></div> |
|||
<p id="duration"/> |
|||
</div> |
|||
</div> |
|||
<div class="player_right"> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import PlayerButton from './PlayerButton.vue' |
|||
|
|||
export default { |
|||
components: { |
|||
PlayerButton |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -0,0 +1,16 @@ |
|||
<template> |
|||
<button class="material-icons mdc-top-app-bar__action-item mdc-icon-button" |
|||
aria-label="play"> |
|||
<div class="mdc-icon-button__ripple"> |
|||
</div> |
|||
{{type}} |
|||
</button> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
type: String |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,8 @@ |
|||
const API_PORT = "8080" |
|||
export const API_IP = process.env.NODE_ENV === 'development' ? `${process.env.VUE_APP_DEVICE_IP}:${API_PORT}` : `${location.host}:${API_PORT}` |
|||
export const API_URL = `http://${API_IP}/`; |
|||
|
|||
export const API_CONFIG = { |
|||
LIST_LOGFILES: `${API_URL}list-logfiles`, |
|||
DOWNLOAD_LOGFILE: `${API_URL}download-logfile?file=`, |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
import { createApp } from 'vue' |
|||
import App from './App.vue' |
|||
import './assets/scss/app.scss' |
|||
import { API_IP, API_URL } from './config.js' |
|||
|
|||
createApp(App).mount('#app') |
|||
|
|||
//const playerWS = new WebSocket("wss://"+window.location.origin+"/echo", "protocolOne");
|
|||
const playerWS = new WebSocket("ws://" + API_IP + "/echo", "player"); |
|||
// playerWS.onopen = (event) => {
|
|||
// };
|
|||
|
|||
|
|||
export const msecToTime = ms => { |
|||
const seconds = Math.floor((ms / 1000) % 60) |
|||
const minutes = Math.floor((ms / (60 * 1000)) % 60) |
|||
const hours = Math.floor((ms / (3600 * 1000)) % 3600) |
|||
return `${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}:${seconds < 10 ? '0' + seconds : seconds |
|||
}` |
|||
} |
|||
const play = document.getElementById("player_play"); |
|||
const pause = document.getElementById("player_pause"); |
|||
const previous = document.getElementById("player_previous"); |
|||
const next = document.getElementById("player_next"); |
|||
const shuffle = document.getElementById("player_shuffle"); |
|||
const repeat = document.getElementById("player_repeat"); |
|||
const previous10 = document.getElementById("player_previous_10"); |
|||
const next10 = document.getElementById("player_next_10"); |
|||
|
|||
play.addEventListener('click', () => { |
|||
playerWS.send("play"); |
|||
}); |
|||
pause.addEventListener('click', () => { |
|||
playerWS.send("pause"); |
|||
}); |
|||
previous.addEventListener('click', () => { |
|||
playerWS.send("previous"); |
|||
}); |
|||
next.addEventListener('click', () => { |
|||
playerWS.send("next"); |
|||
}); |
|||
shuffle.addEventListener('click', () => { |
|||
playerWS.send("shuffle"); |
|||
}); |
|||
repeat.addEventListener('click', () => { |
|||
playerWS.send("repeat"); |
|||
}); |
|||
previous10.addEventListener('click', () => { |
|||
playerWS.send("previous10"); |
|||
}); |
|||
next10.addEventListener('click', () => { |
|||
playerWS.send("next10"); |
|||
}); |
|||
|
|||
var lastLoadedMediaUri = "" |
|||
|
|||
playerWS.onmessage = (event) => { |
|||
console.log(event.data); |
|||
// const player = document.getElementById("player");
|
|||
const title = document.getElementById("title"); |
|||
const artist = document.getElementById("artist"); |
|||
const time = document.getElementById("time"); |
|||
const duration = document.getElementById("duration"); |
|||
const artwork = document.getElementById("player_artwork"); |
|||
const msg = JSON.parse(event.data); |
|||
title.textContent = msg.title |
|||
artist.textContent = msg.artist |
|||
time.textContent = msecToTime(new Date(msg.progress)) |
|||
duration.textContent = msecToTime(new Date(msg.duration)) |
|||
if (lastLoadedMediaUri != msg.uri) { |
|||
artwork.src = API_URL + "/artwork?randomizer=" + Date.now() |
|||
lastLoadedMediaUri = msg.uri |
|||
} |
|||
|
|||
if (msg.playing) { |
|||
play.style.display = "none"; |
|||
pause.style.display = "inline-block"; |
|||
} else { |
|||
play.style.display = "inline-block"; |
|||
pause.style.display = "none"; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
<template> |
|||
<div v-if="this.logs.length !== 0"> |
|||
<LogList :logs="logs" /> |
|||
</div> |
|||
<div v-else> |
|||
<EmptyView /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import axios from 'axios' |
|||
import { API_URL } from '../config.js' |
|||
import LogList from '../components/LogList.vue' |
|||
import EmptyView from '../components/EmptyView.vue' |
|||
|
|||
export default { |
|||
components: { |
|||
LogList, |
|||
EmptyView, |
|||
}, |
|||
data() { |
|||
return { |
|||
logs: [], |
|||
} |
|||
}, |
|||
methods: { |
|||
fetchLogs() { |
|||
axios.get(API_URL + "list-logfiles").then((response) => { |
|||
this.logs = response.data |
|||
}); |
|||
} |
|||
}, |
|||
created: function () { |
|||
this.fetchLogs(); |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style></style> |
|||
@ -0,0 +1,12 @@ |
|||
import Vue from 'vue' |
|||
import Router from 'vue-router' |
|||
import PageDownloads from './pages/PageDownloads.vue' |
|||
|
|||
Vue.use(Router) |
|||
|
|||
export default new Router({ |
|||
history: Router.createWebHashHistory(), |
|||
routes: [ |
|||
{ path: '/', component: PageDownloads, name: 'Logs' }, |
|||
] |
|||
}) |
|||
@ -0,0 +1,4 @@ |
|||
const { defineConfig } = require('@vue/cli-service') |
|||
module.exports = defineConfig({ |
|||
transpileDependencies: true |
|||
}) |
|||
@ -1,73 +0,0 @@ |
|||
var path = require("path"); |
|||
const CopyPlugin = require("copy-webpack-plugin"); |
|||
|
|||
module.exports = [{ |
|||
mode: "production", |
|||
entry: ['./scss/app.scss', './js/app.js'], |
|||
output: { |
|||
// This is necessary for webpack to compile
|
|||
// But we never use style-bundle.js
|
|||
filename: 'style-bundle.js', |
|||
path: path.join(__dirname, "../../application/webserver/assets/web/public"), |
|||
assetModuleFilename: 'images/[name][ext]' |
|||
}, |
|||
plugins: [ |
|||
new CopyPlugin({ |
|||
patterns: [ |
|||
{ from: "asset/static", to: "" }, |
|||
{ from: "asset/templates", to: "" }, |
|||
], |
|||
}), |
|||
], |
|||
module: { |
|||
rules: [ |
|||
{ |
|||
test: /\.scss$/, |
|||
use: [ |
|||
{ |
|||
loader: 'file-loader', |
|||
options: { |
|||
name: 'bundle.css', |
|||
}, |
|||
}, |
|||
{ |
|||
loader: "extract-loader", |
|||
options: { |
|||
publicPath: path.join(__dirname, "public"), |
|||
} |
|||
}, |
|||
{ |
|||
loader: 'css-loader', |
|||
options: { |
|||
url: false |
|||
} |
|||
}, |
|||
{ |
|||
loader: 'sass-loader', |
|||
options: { |
|||
// Prefer Dart Sass
|
|||
implementation: require('sass'), |
|||
|
|||
// See https://github.com/webpack-contrib/sass-loader/issues/804
|
|||
webpackImporter: false, |
|||
sassOptions: { |
|||
includePaths: ['./node_modules'] |
|||
}, |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
test: /\.html$/i, |
|||
type: 'asset/resource', |
|||
generator: { |
|||
filename: '[name][ext]' |
|||
} |
|||
}, |
|||
{ |
|||
test: /\.(png|svg|jpg|jpeg|gif|ico)$/i, |
|||
type: 'asset/resource', |
|||
}, |
|||
] |
|||
}, |
|||
}]; |
|||