[A] vuejs frontend: load , list, display, skip, play/pause, server poll file list

This commit is contained in:
Jan 2020-07-16 23:09:33 +02:00
parent ccb306f325
commit 17add0d254
8 changed files with 12138 additions and 18 deletions

View file

@ -3,3 +3,4 @@ WEBDAV_USER=user
WEBDAV_PW=pass
WEBFRAME_PATH=/path/to/imgs/
PORT=3000
POLL_TIMEOUT=60000

1
.gitignore vendored
View file

@ -4,6 +4,7 @@ dist
dist-bkp
.env
files/*
db.json
# https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs

View file

@ -8,7 +8,7 @@ const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
const adapter = new FileSync('db.json');
const db = low(adapter);
// db.defaults({ files: [], count: 0}).write();
db.defaults({ files: [], count: 0}).write();
// create webdav-client
const client = createClient(
@ -29,20 +29,25 @@ function dlFile(file, dir = process.env.WEBFRAME_PATH) {
return client.createReadStream(dir+'/'+file).pipe(fs.createWriteStream('./files/'+file));
}
client.exists(process.env.WEBFRAME_PATH).then(async data => {
if (data) {
const list = await listDir(process.env.WEBFRAME_PATH);
list.forEach(file => {
// if (!fs.existsSync('./files/'+file.basename)) {
const inDb = db.get('files').find({ basename: file.basename }).value() !== undefined ? true : false;
if (!inDb) {
dlFile(file.basename);
db.get('files').push(file).write();
db.update('count', n => n + 1).write();
}
});
}
});
function loadImages() {
client.exists(process.env.WEBFRAME_PATH).then(async data => {
if (data) {
const list = await listDir(process.env.WEBFRAME_PATH);
list.forEach(file => {
const inDb = db.get('files').find({ basename: file.basename }).value() !== undefined ? true : false;
if (!inDb) {
console.log('Downloaded new File:', file.basename);
dlFile(file.basename);
db.get('files').push(file).write();
db.update('count', n => n + 1).write();
}
});
}
});
setTimeout(() => loadImages(), process.env.POLL_TIMEOUT);
}
loadImages();
// webserver
const express = require('express');
@ -50,8 +55,8 @@ const app = express();
app.use('/files', express.static(path.join(__dirname, 'files')));
app.get('/api/files', (req, res) => {
res.json(db.get('files').value());
res.json({resource: db.get('files').value()});
});
app.use('*', express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.listen(process.env.PORT, () => console.log(`Example app listening at http://localhost:${process.env.PORT}`));

57
public/app.js Normal file
View file

@ -0,0 +1,57 @@
new Vue({
el: "#app",
data: {
files: [],
index: 0,
timeout: null,
carouselTimeout: 10000,
carouselActive: true
},
methods: {
next: function () {
clearTimeout(this.timeout);
setTimeout(() => this.carousel(), this.carouselTimeout*2);
if (this.index + 1 < this.files.length) {
this.index++;
} else {
this.index = 0;
}
},
prev: function () {
clearTimeout(this.timeout);
setTimeout(() => this.carousel(), this.carouselTimeout*2);
if (this.index - 1 >= 0) {
this.index--;
} else {
this.index = this.files.length - 1;
}
},
carousel: function (time = this.carouselTimeout) {
this.timeout = setTimeout(() => {
this.next();
this.carousel();
}, time);
},
loadData: function () {
fetch('api/files').then(response => response.json()).then(
data => {
this.files = data.resource;
this.carousel();
}
)
},
toggleCarousel: function () {
if (this.carouselActive) {
this.carouselActive = false;
clearTimeout(this.timeout);
console.log(this.timeout)
} else {
this.carouselActive = true;
this.carousel();
}
}
},
mounted() {
this.loadData();
}
})

51
public/index.css Normal file
View file

@ -0,0 +1,51 @@
#app, #app div {
display: flex;
height: 100%;
width: 100%;
}
#app img {
width: 100%;
height: auto;
z-index: 0;
align-self: center;
}
#app video {
height: 100vh;
margin: 0 auto;
display: block;
}
#app .floatBtn {
display: block;
width: 40px;
height: 30px;
border-radius: 100%;
background-color: rgba(0,0,0,.3);
color: white;
z-index: 10;
position: absolute;
top: 50vh;
text-align: center;
padding-top: 10px;
}
#app .floatBtn.left {
left: 10px;
}
#app .floatBtn.right {
right: 10px;
}
#app .floatBtn.bottom {
left: 49%;
top: 90%;
}
#app .empty {
text-align: center;
margin-top: 48vh;
}

View file

@ -1 +1,35 @@
index
<html>
<head>
<title>WebFrame</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="index.css">
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div v-if="files && files.length > 0">
<div class="floatBtn left" v-on:click="prev()">
-
</div>
<div class="floatBtn right" v-on:click="next()">
+
</div>
<div class="floatBtn bottom" v-on:click="toggleCarousel()">
<span v-if="!carouselActive">Play</span>
<span v-if="carouselActive">Pause</span>
</div>
<img v-if="files[index].mime.includes('image')" v-bind:src="'/files/'+files[index].basename" alt="">
<video v-if="files[index].mime.includes('video')" autoplay muted loop>
<source v-bind:src="'/files/'+files[index].basename" v-bind:type="files[index].mime">
</video>
</div>
<div v-else class="empty">
No images
</div>
</div>
<script src="app.js"></script>
</body>
</html>

11965
public/vue.js Normal file

File diff suppressed because it is too large Load diff

6
public/vue.min.js vendored Normal file

File diff suppressed because one or more lines are too long