working on file browser
This commit is contained in:
parent
2623a6decf
commit
0510ba65c1
@ -1,11 +1,12 @@
|
||||
import configparser
|
||||
|
||||
import os
|
||||
from platform import uname
|
||||
from time import sleep
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import psutil
|
||||
from natsort import natsorted
|
||||
|
||||
|
||||
def sizeof_fmt(num, suffix='B'):
|
||||
@ -117,8 +118,26 @@ class SystemStats:
|
||||
}
|
||||
|
||||
|
||||
def set_root(path):
|
||||
# prevent access to root file system
|
||||
root = os.path.dirname(settings.MEDIA_FOLDER)
|
||||
return path.lstrip(root)
|
||||
|
||||
|
||||
def get_media_path(dir=None):
|
||||
if not dir:
|
||||
if not os.path.isdir(settings.MEDIA_FOLDER):
|
||||
return ''
|
||||
dir = settings.MEDIA_FOLDER
|
||||
else:
|
||||
dir = os.path.join(os.path.dirname(settings.MEDIA_FOLDER), dir)
|
||||
for root, dirs, files in os.walk(dir, topdown=True):
|
||||
return [set_root(root), natsorted(dirs), natsorted(files)]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('ALL: ', SystemStats().all())
|
||||
result = hasattr(SystemStats(), 'system')
|
||||
print(result)
|
||||
exit()
|
||||
print('CPU: ', SystemStats.cpu())
|
||||
print('RAM: ', SystemStats.ram())
|
||||
|
@ -4,7 +4,7 @@ from django.conf import settings
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
from .utils import IniParser, SystemStats
|
||||
from .utils import IniParser, SystemStats, get_media_path
|
||||
|
||||
|
||||
class Config(APIView):
|
||||
@ -35,8 +35,26 @@ class Statistics(APIView):
|
||||
"""
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'stats' in request.GET.dict() \
|
||||
and request.GET.dict()['stats'] == 'all':
|
||||
return Response(SystemStats().all())
|
||||
if 'stats' in request.GET.dict() and request.GET.dict()['stats'] \
|
||||
and hasattr(SystemStats(), request.GET.dict()['stats']):
|
||||
return Response(
|
||||
getattr(SystemStats(), request.GET.dict()['stats'])())
|
||||
else:
|
||||
return Response({"success": False})
|
||||
|
||||
|
||||
class Media(APIView):
|
||||
"""
|
||||
get folder/files tree, for building a file explorer
|
||||
for reading, endpoint is: http://127.0.0.1:8000/api/media/?path
|
||||
"""
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'path' in request.GET.dict() and request.GET.dict()['path']:
|
||||
return Response({'tree': get_media_path(
|
||||
request.GET.dict()['path']
|
||||
)})
|
||||
elif 'path' in request.GET.dict():
|
||||
return Response({'tree': get_media_path()})
|
||||
else:
|
||||
return Response({"success": False})
|
||||
|
@ -157,3 +157,5 @@ FFPLAYOUT_CONFIG = '/etc/ffplayout/ffplayout.conf'
|
||||
|
||||
# used network interface for statistics: eth0, eno1, etc.
|
||||
NET_INTERFACE = 'br0'
|
||||
|
||||
MEDIA_FOLDER = '/mnt/playout/ADtvMedia'
|
||||
|
@ -31,6 +31,7 @@ urlpatterns = [
|
||||
path('api/', include(router.urls)),
|
||||
path('api/config/', views.Config.as_view()),
|
||||
path('api/stats/', views.Statistics.as_view()),
|
||||
path('api/media/', views.Media.as_view()),
|
||||
path('api-auth/', include(
|
||||
'rest_framework.urls', namespace='rest_framework')),
|
||||
path('auth/token/', TokenObtainPairView.as_view(),
|
||||
|
@ -131,7 +131,9 @@
|
||||
<div class="actions">
|
||||
<b-button-group class="actions-grp">
|
||||
<b-button>Control</b-button>
|
||||
<b-button to="/media">Media</b-button>
|
||||
<b-button to="/media">
|
||||
Media
|
||||
</b-button>
|
||||
<b-button>Logging</b-button>
|
||||
<b-button>Configure</b-button>
|
||||
<b-button @click="logout()">
|
||||
|
@ -1,26 +1,111 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-container class="browser">
|
||||
<div v-if="folderTree.tree" class="browser">
|
||||
<div>
|
||||
<b-breadcrumb>
|
||||
<b-breadcrumb-item
|
||||
v-for="(crumb, index) in crumbs"
|
||||
:active="index === crumbs.length - 1"
|
||||
:key="crumb.key"
|
||||
@click="getPath(crumb.path)"
|
||||
>
|
||||
{{ crumb.text }}
|
||||
</b-breadcrumb-item>
|
||||
</b-breadcrumb>
|
||||
</div>
|
||||
|
||||
<b-row>
|
||||
<b-col class="folder-col">
|
||||
<div class="browser-div">
|
||||
<b-list-group>
|
||||
<b-list-group-item
|
||||
v-for="folder in folderTree.tree[1]"
|
||||
:key="folder.key"
|
||||
class="browser-item"
|
||||
>
|
||||
<b-link @click="getPath(`${folderTree.tree[0]}/${folder}`)">
|
||||
{{ folder }}
|
||||
</b-link>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col class="files-col">
|
||||
<div class="browser-div">
|
||||
<b-list-group>
|
||||
<b-list-group-item
|
||||
v-for="file in folderTree.tree[2]"
|
||||
:key="file.key"
|
||||
class="browser-item"
|
||||
>
|
||||
<b-link>
|
||||
{{ file }}
|
||||
</b-link>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Media',
|
||||
|
||||
components: {},
|
||||
|
||||
computed: {
|
||||
...mapState('media', ['crumbs', 'folderTree'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getPath()
|
||||
this.getPath('')
|
||||
},
|
||||
|
||||
methods: {
|
||||
async getPath () {
|
||||
async getPath (path) {
|
||||
await this.$store.dispatch('auth/inspectToken')
|
||||
// const response = await this.$axios.get('apt/')
|
||||
await this.$store.dispatch('media/getTree', path)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.browser {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.folder-col {
|
||||
min-width: 320px;
|
||||
max-width: 460px;
|
||||
}
|
||||
|
||||
.folder {
|
||||
padding: .3em;
|
||||
}
|
||||
|
||||
.files-col {
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
.browser-div {
|
||||
background: #30363d;
|
||||
height: 100%;
|
||||
border: 1px solid #000;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.browser-item {
|
||||
background: none;
|
||||
padding: .3em;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
51
ffplayout/frontend/store/media.js
Normal file
51
ffplayout/frontend/store/media.js
Normal file
@ -0,0 +1,51 @@
|
||||
export const state = () => ({
|
||||
currentPath: null,
|
||||
crumbs: [],
|
||||
folderTree: {}
|
||||
})
|
||||
|
||||
export const mutations = {
|
||||
UPDATE_CURRENT_PATH (state, path) {
|
||||
state.currentPath = path
|
||||
},
|
||||
UPDATE_CRUMBS (state, crumbs) {
|
||||
state.crumbs = crumbs
|
||||
},
|
||||
UPDATE_FOLDER_TREE (state, tree) {
|
||||
state.folderTree = tree
|
||||
}
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
async getTree ({ commit, dispatch, state, rootState }, path) {
|
||||
if ((path !== state.currentPath || !state.folderTree)) {
|
||||
const crumbs = []
|
||||
let root = '/'
|
||||
const response = await this.$axios.get(`api/media/?path=${path}`, { headers: { Authorization: 'Bearer ' + rootState.auth.jwtToken } })
|
||||
|
||||
if (response.data.tree) {
|
||||
const pathArr = response.data.tree[0].split('/')
|
||||
|
||||
if (response.data.tree[1].length === 0) {
|
||||
response.data.tree[1].push(pathArr[pathArr.length - 1])
|
||||
}
|
||||
|
||||
if (path) {
|
||||
for (const crumb of pathArr) {
|
||||
if (crumb) {
|
||||
root += crumb + '/'
|
||||
crumbs.push({ text: crumb, path: root })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
crumbs.push({ text: pathArr[pathArr.length - 1], path: '' })
|
||||
}
|
||||
|
||||
// console.log(crumbs)
|
||||
commit('UPDATE_CURRENT_PATH', path)
|
||||
commit('UPDATE_CRUMBS', crumbs)
|
||||
commit('UPDATE_FOLDER_TREE', response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,4 +2,5 @@ Django<=3.1
|
||||
django-cors-headers
|
||||
djangorestframework
|
||||
djangorestframework-simplejwt
|
||||
natsort
|
||||
psutil
|
||||
|
@ -3,6 +3,7 @@ Django==3.0.2
|
||||
django-cors-headers==3.2.1
|
||||
djangorestframework==3.11.0
|
||||
djangorestframework-simplejwt==4.4.0
|
||||
natsort==7.0.1
|
||||
psutil==5.6.7
|
||||
PyJWT==1.7.1
|
||||
pytz==2019.3
|
||||
|
Loading…
x
Reference in New Issue
Block a user