Browse Source

WebServer: convert to vuejs 3

transifex
Duncan McNamara 3 years ago
committed by Nicolas Pomepuy
parent
commit
9624af26d6
  1. 2
      application/vlc-android/src/org/videolan/vlc/gui/MainActivity.kt
  2. 23
      application/vlc-android/src/org/videolan/vlc/util/FileUtils.kt
  3. 15
      application/webserver/build.gradle
  4. 69
      application/webserver/src/main/java/org/videolan/vlc/webserver/NetworkSharingServer.kt
  5. 24
      buildsystem/network-sharing-server/.gitignore
  6. 24
      buildsystem/network-sharing-server/README.md
  7. 28
      buildsystem/network-sharing-server/asset/templates/log_template-mat.html.temp
  8. 5
      buildsystem/network-sharing-server/babel.config.js
  9. 158
      buildsystem/network-sharing-server/html/index.html
  10. 91
      buildsystem/network-sharing-server/js/app.js
  11. 19
      buildsystem/network-sharing-server/jsconfig.json
  12. 31137
      buildsystem/network-sharing-server/package-lock.json
  13. 83
      buildsystem/network-sharing-server/package.json
  14. BIN
      buildsystem/network-sharing-server/public/favicon.ico
  15. 25
      buildsystem/network-sharing-server/public/index.html
  16. 0
      buildsystem/network-sharing-server/public/site.webmanifest
  17. 25
      buildsystem/network-sharing-server/src/App.vue
  18. 0
      buildsystem/network-sharing-server/src/assets/resources/android-chrome-192x192.png
  19. 0
      buildsystem/network-sharing-server/src/assets/resources/android-chrome-512x512.png
  20. 0
      buildsystem/network-sharing-server/src/assets/resources/apple-touch-icon.png
  21. 0
      buildsystem/network-sharing-server/src/assets/resources/favicon-16x16.png
  22. 0
      buildsystem/network-sharing-server/src/assets/resources/favicon-32x32.png
  23. 0
      buildsystem/network-sharing-server/src/assets/resources/favicon.ico
  24. 0
      buildsystem/network-sharing-server/src/assets/resources/icon.png
  25. 103
      buildsystem/network-sharing-server/src/assets/scss/app.scss
  26. 2
      buildsystem/network-sharing-server/src/assets/scss/my-theme.scss
  27. 28
      buildsystem/network-sharing-server/src/components/AppFooter.vue
  28. 30
      buildsystem/network-sharing-server/src/components/AppHeader.vue
  29. 11
      buildsystem/network-sharing-server/src/components/EmptyView.vue
  30. 30
      buildsystem/network-sharing-server/src/components/LogItem.vue
  31. 48
      buildsystem/network-sharing-server/src/components/LogList.vue
  32. 42
      buildsystem/network-sharing-server/src/components/MiniPlayer.vue
  33. 16
      buildsystem/network-sharing-server/src/components/PlayerButton.vue
  34. 8
      buildsystem/network-sharing-server/src/config.js
  35. 83
      buildsystem/network-sharing-server/src/main.js
  36. 39
      buildsystem/network-sharing-server/src/pages/PageDownloads.vue
  37. 12
      buildsystem/network-sharing-server/src/routes.js
  38. 4
      buildsystem/network-sharing-server/vue.config.js
  39. 73
      buildsystem/network-sharing-server/webpack.config.js

2
application/vlc-android/src/org/videolan/vlc/gui/MainActivity.kt

@ -26,6 +26,7 @@ import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
@ -103,6 +104,7 @@ class MainActivity : ContentActivity(),
// VLCBilling.getInstance(application).retrieveSkus()
WidgetMigration.launchIfNeeded(this)
NotificationPermissionManager.launchIfNeeded(this)
Log.d(TAG, "onCreate: skbench: ")
startWebserver()
}

23
application/vlc-android/src/org/videolan/vlc/util/FileUtils.kt

@ -135,18 +135,23 @@ object FileUtils {
if (files.isNullOrEmpty()) return false
File(toPath).mkdirs()
var res = true
for (file in files)
for (file in files) {
res = if (file.contains(".")) {
res and copyAsset(assetManager,
"$fromAssetPath/$file",
"$toPath/$file",
force)
res and copyAsset(
assetManager,
"$fromAssetPath/$file",
"$toPath/$file",
force
)
} else {
res and copyAssetFolder(assetManager,
"$fromAssetPath/$file",
"$toPath/$file",
force)
res and copyAssetFolder(
assetManager,
"$fromAssetPath/$file",
"$toPath/$file",
force
)
}
}
return res
} catch (e: Exception) {
e.printStackTrace()

15
application/webserver/build.gradle

@ -21,9 +21,20 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
task webCopy(type: Copy) {
from '../../buildsystem/network-sharing-server/dist'
into 'assets/dist'
}
sourceSets.main {
assets.srcDirs = ['assets']
}
sourceSets.main {
assets.srcDirs = ['assets']
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@ -33,13 +44,15 @@ android {
}
}
dependencies {
preBuild.dependsOn(webCopy)
dependencies {
implementation project(':application:vlc-android')
implementation "io.ktor:ktor:2.1.2"
implementation "io.ktor:ktor-server-netty:2.1.2"
implementation "io.ktor:ktor-gson:1.6.8"
implementation "io.ktor:ktor-server-websockets:2.1.2"
implementation "io.ktor:ktor-server-cors:2.1.2"
testImplementation 'junit:junit:4.13.2'

69
application/webserver/src/main/java/org/videolan/vlc/webserver/NetworkSharingServer.kt

@ -35,6 +35,7 @@ import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.http.content.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
@ -46,6 +47,8 @@ import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray
import org.json.JSONObject
import org.videolan.libvlc.MediaPlayer
import org.videolan.libvlc.interfaces.IMedia
import org.videolan.resources.AndroidDevices
@ -80,6 +83,10 @@ object NetworkSharingServer: SingletonHolder<NettyApplicationEngine, Context>({
return launchServer(applicationContext)
}
private fun getServerFiles(context: Context) : String {
return "${context.filesDir.path}/server/"
}
private fun onServiceChanged(service: PlaybackService?) {
if (service !== null) {
NetworkSharingServer.service = service
@ -90,40 +97,48 @@ object NetworkSharingServer: SingletonHolder<NettyApplicationEngine, Context>({
}
}
private val TAG = this::class.java.name
fun copyWebServer(context: Context) {
File("${context.filesDir.path}/server").mkdirs()
FileUtils.copyAssetFolder(context.assets, "web", "${context.filesDir.path}/server", true)
Log.d(TAG, "copyWebServer: skbench: ")
File(getServerFiles(context)).mkdirs()
FileUtils.copyAssetFolder(context.assets, "dist", "${context.filesDir.path}/server", true)
// FileUtils.copyAssetFolder(context.assets, "js", "${context.filesDir.path}/server", true)
// FileUtils.copyAssetFolder(context.assets, "css", "${context.filesDir.path}/server", true)
}
fun launchServer(context: Context) = embeddedServer(Netty, 8080) {
Log.d(TAG, "launchServer: skbench: ")
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
install(CORS) {
allowMethod(HttpMethod.Options)
allowMethod(HttpMethod.Post)
allowMethod(HttpMethod.Get)
allowHeader(HttpHeaders.AccessControlAllowOrigin)
allowHeader(HttpHeaders.ContentType)
anyHost()
}
routing {
static("") {
files("${context.filesDir.path}/server/public")
files(getServerFiles(context))
}
get("/") {
Log.d(TAG, "launchServer: skbench: /")
call.respondRedirect("index.html", permanent = true)
}
get("/index.html") {
val logs = getLogsFiles().sortedBy { File(it).lastModified() }.reversed()
val template = FileUtils.getStringFromFile("${context.filesDir.path}/server/public/log_template-mat.html.temp")
val logsHtml = buildString {
logs.forEach {
append(template.replace("%%FILE_NAME%%", it).replace("%%FILE_NAME_SHORT%%", format.format(File(it).lastModified())))
}
try {
val html = FileUtils.getStringFromFile("${getServerFiles(context)}index.html")
call.respondText(html, ContentType.Text.Html)
} catch (e: Exception) {
Log.d(TAG, "launchServer: $e")
call.respondText("Fuck you")
}
val html = FileUtils.getStringFromFile("${context.filesDir.path}/server/public/index.html")
call.respondText(html.networkShareReplace(context).contentReplace(context, logsHtml), ContentType.Text.Html)
}
post("/upload.json") {
var fileDescription = ""
@ -146,11 +161,8 @@ object NetworkSharingServer: SingletonHolder<NettyApplicationEngine, Context>({
}
call.respondText("$fileDescription is uploaded to 'uploads/$fileName'")
}
get("/logs.html") {
call.respondText("<a>toto</a>")
}
get("/download") {
get("/download-logfile") {
Log.d(TAG, "launchServer: skbench: /download-logfile")
call.request.queryParameters["file"]?.let { filePath ->
val file = File(filePath)
if (file.exists()) {
@ -160,6 +172,18 @@ object NetworkSharingServer: SingletonHolder<NettyApplicationEngine, Context>({
}
call.respond(HttpStatusCode.NotFound, "")
}
get("/list-logfiles"){
val logs = getLogsFiles().sortedBy { File(it).lastModified() }.reversed()
val jsonArray = JSONArray()
for (log in logs) {
val json = JSONObject()
json.put("path", log)
json.put("date", format.format(File(log).lastModified()))
jsonArray.put(json)
}
call.respondText(jsonArray.toString())
}
get("/artwork") {
try {
service?.coverArt?.let { coverArt ->
@ -228,8 +252,9 @@ object NetworkSharingServer: SingletonHolder<NettyApplicationEngine, Context>({
try {
val logEntry = Pattern.compile("\\{%(.*?)%\\}")
newString = newString.replace(logEntry.toRegex()) {
Log.d("networkShareReplace", it.value)
context.getString(context.resIdByName(it.value.trim().drop(2).dropLast(2), "string"))
val str = context.getString(context.resIdByName(it.value.trim().drop(2).dropLast(2), "string"))
Log.d("networkShareReplace: ", "skbench: ${it .value} -> $str")
str
}
} catch (e: Exception) {
Log.e("networkShareReplace", e.message, e)

24
buildsystem/network-sharing-server/.gitignore

@ -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?

24
buildsystem/network-sharing-server/README.md

@ -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/).

28
buildsystem/network-sharing-server/asset/templates/log_template-mat.html.temp

@ -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>

5
buildsystem/network-sharing-server/babel.config.js

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

158
buildsystem/network-sharing-server/html/index.html

@ -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>

91
buildsystem/network-sharing-server/js/app.js

@ -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";
}
}

19
buildsystem/network-sharing-server/jsconfig.json

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

31137
buildsystem/network-sharing-server/package-lock.json

File diff suppressed because it is too large

83
buildsystem/network-sharing-server/package.json

@ -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"
]
}

BIN
buildsystem/network-sharing-server/public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

25
buildsystem/network-sharing-server/public/index.html

@ -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
buildsystem/network-sharing-server/asset/static/site.webmanifest → buildsystem/network-sharing-server/public/site.webmanifest

25
buildsystem/network-sharing-server/src/App.vue

@ -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>

0
buildsystem/network-sharing-server/asset/resource/android-chrome-192x192.png → buildsystem/network-sharing-server/src/assets/resources/android-chrome-192x192.png

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
buildsystem/network-sharing-server/asset/resource/android-chrome-512x512.png → buildsystem/network-sharing-server/src/assets/resources/android-chrome-512x512.png

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

0
buildsystem/network-sharing-server/asset/resource/apple-touch-icon.png → buildsystem/network-sharing-server/src/assets/resources/apple-touch-icon.png

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

0
buildsystem/network-sharing-server/asset/resource/favicon-16x16.png → buildsystem/network-sharing-server/src/assets/resources/favicon-16x16.png

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 603 B

0
buildsystem/network-sharing-server/asset/resource/favicon-32x32.png → buildsystem/network-sharing-server/src/assets/resources/favicon-32x32.png

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

0
buildsystem/network-sharing-server/asset/resource/favicon.ico → buildsystem/network-sharing-server/src/assets/resources/favicon.ico

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

0
buildsystem/network-sharing-server/asset/resource/icon.png → buildsystem/network-sharing-server/src/assets/resources/icon.png

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

103
buildsystem/network-sharing-server/scss/app.scss → buildsystem/network-sharing-server/src/assets/scss/app.scss

@ -1,5 +1,4 @@
@use "@material/theme" with (
$primary: #ff610a,
@use "@material/theme" with ($primary: #ff610a,
$secondary: #ff610a,
$on-primary: #ffffff,
$on-secondary: #ffffff,
@ -17,17 +16,41 @@
@include data-table.core-styles;
@include data-table.theme-baseline;
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre,
form, fieldset, input, textarea, p, blockquote, th, td, nav, header, footer {
margin: 0;
padding: 0;
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
form,
fieldset,
input,
textarea,
p,
blockquote,
th,
td,
nav,
header,
footer {
margin: 0;
padding: 0;
}
main {
min-height: calc(100vh - var(--navbar-height));
display:flex;
flex-direction:column;
justify-content:space-between;
display: flex;
flex-direction: column;
justify-content: space-between;
}
:root {
@ -35,15 +58,15 @@ main {
}
.footer {
background-color: $mdc-theme-primary;
padding: 8px;
position: fixed;
bottom : 0;
left : 0;
right : 0;
height: var(--navbar-height);
color: #fff;
color: var(--mdc-theme-on-primary, #fff);
background-color: $mdc-theme-primary;
padding: 8px;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: var(--navbar-height);
color: #fff;
color: var(--mdc-theme-on-primary, #fff);
}
@ -51,8 +74,8 @@ main {
// Check out the MDC Web documentation for how to use MDC Typography Sass mixins:
// https://github.com/material-components/material-components-web/tree/master/packages/mdc-typography
body {
background: $mdc-theme--background;
color: $mdc-theme-on-surface;
background: $mdc-theme--background;
color: $mdc-theme-on-surface;
}
h1 {
@ -85,28 +108,30 @@ p {
}
#player {
position:absolute;
display: flex;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
bottom: 0;
width: calc(100% - 32px);
padding: 16px;
background: #444444;
color: #ffffff;
border-radius-top-left: 8px;
border-radius-top-right: 8px;
align-items:center;
position: absolute;
display: flex;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
bottom: 0;
width: calc(100% - 32px);
padding: 16px;
background: #444444;
color: #ffffff;
border-radius-top-left: 8px;
border-radius-top-right: 8px;
align-items: center;
}
.player_info, .player_right, #progress_bar {
flex: auto;
.player_info,
.player_right,
#progress_bar {
flex: auto;
}
#progress_bar {
min-width:200px;
}
#progress_bar {
min-width: 200px;
}
#player_controls_progress {
display: flex;
}
display: flex;
}

2
buildsystem/network-sharing-server/scss/my-theme.scss → buildsystem/network-sharing-server/src/assets/scss/my-theme.scss

@ -3,7 +3,7 @@
@import url('https://fonts.googleapis.com/css?family=Fira+Sans&display=swap');
$mdc-typography-family: 'Fira Sans';
$mdc-theme-primary: #ff610a;
$mdc-theme-primary: #0a91ff;
$mdc-theme-on-primary: #ffffff;
$mdc-theme-surface: #222222;
$mdc-theme--background: #222222;

28
buildsystem/network-sharing-server/src/components/AppFooter.vue

@ -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>

30
buildsystem/network-sharing-server/src/components/AppHeader.vue

@ -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>

11
buildsystem/network-sharing-server/src/components/EmptyView.vue

@ -0,0 +1,11 @@
<template>
<main class="mdc-top-app-bar--fixed-adjust">
<h1>This is empty</h1>
</main>
</template>
<script>
export default {
}
</script>

30
buildsystem/network-sharing-server/src/components/LogItem.vue

@ -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>

48
buildsystem/network-sharing-server/src/components/LogList.vue

@ -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>

42
buildsystem/network-sharing-server/src/components/MiniPlayer.vue

@ -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>

16
buildsystem/network-sharing-server/src/components/PlayerButton.vue

@ -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>

8
buildsystem/network-sharing-server/src/config.js

@ -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=`,
}

83
buildsystem/network-sharing-server/src/main.js

@ -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";
}
}

39
buildsystem/network-sharing-server/src/pages/PageDownloads.vue

@ -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>

12
buildsystem/network-sharing-server/src/routes.js

@ -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' },
]
})

4
buildsystem/network-sharing-server/vue.config.js

@ -0,0 +1,4 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})

73
buildsystem/network-sharing-server/webpack.config.js

@ -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',
},
]
},
}];
Loading…
Cancel
Save