working on file browser
This commit is contained in:
parent
2623a6decf
commit
0510ba65c1
@ -1,11 +1,12 @@
|
|||||||
import configparser
|
import configparser
|
||||||
|
import os
|
||||||
from platform import uname
|
from platform import uname
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
from natsort import natsorted
|
||||||
|
|
||||||
|
|
||||||
def sizeof_fmt(num, suffix='B'):
|
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__':
|
if __name__ == '__main__':
|
||||||
print('ALL: ', SystemStats().all())
|
result = hasattr(SystemStats(), 'system')
|
||||||
|
print(result)
|
||||||
exit()
|
exit()
|
||||||
print('CPU: ', SystemStats.cpu())
|
print('CPU: ', SystemStats.cpu())
|
||||||
print('RAM: ', SystemStats.ram())
|
print('RAM: ', SystemStats.ram())
|
||||||
|
@ -4,7 +4,7 @@ from django.conf import settings
|
|||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from .utils import IniParser, SystemStats
|
from .utils import IniParser, SystemStats, get_media_path
|
||||||
|
|
||||||
|
|
||||||
class Config(APIView):
|
class Config(APIView):
|
||||||
@ -35,8 +35,26 @@ class Statistics(APIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
if 'stats' in request.GET.dict() \
|
if 'stats' in request.GET.dict() and request.GET.dict()['stats'] \
|
||||||
and request.GET.dict()['stats'] == 'all':
|
and hasattr(SystemStats(), request.GET.dict()['stats']):
|
||||||
return Response(SystemStats().all())
|
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:
|
else:
|
||||||
return Response({"success": False})
|
return Response({"success": False})
|
||||||
|
@ -157,3 +157,5 @@ FFPLAYOUT_CONFIG = '/etc/ffplayout/ffplayout.conf'
|
|||||||
|
|
||||||
# used network interface for statistics: eth0, eno1, etc.
|
# used network interface for statistics: eth0, eno1, etc.
|
||||||
NET_INTERFACE = 'br0'
|
NET_INTERFACE = 'br0'
|
||||||
|
|
||||||
|
MEDIA_FOLDER = '/mnt/playout/ADtvMedia'
|
||||||
|
@ -31,6 +31,7 @@ urlpatterns = [
|
|||||||
path('api/', include(router.urls)),
|
path('api/', include(router.urls)),
|
||||||
path('api/config/', views.Config.as_view()),
|
path('api/config/', views.Config.as_view()),
|
||||||
path('api/stats/', views.Statistics.as_view()),
|
path('api/stats/', views.Statistics.as_view()),
|
||||||
|
path('api/media/', views.Media.as_view()),
|
||||||
path('api-auth/', include(
|
path('api-auth/', include(
|
||||||
'rest_framework.urls', namespace='rest_framework')),
|
'rest_framework.urls', namespace='rest_framework')),
|
||||||
path('auth/token/', TokenObtainPairView.as_view(),
|
path('auth/token/', TokenObtainPairView.as_view(),
|
||||||
|
@ -131,7 +131,9 @@
|
|||||||
<div class="actions">
|
<div class="actions">
|
||||||
<b-button-group class="actions-grp">
|
<b-button-group class="actions-grp">
|
||||||
<b-button>Control</b-button>
|
<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>Logging</b-button>
|
||||||
<b-button>Configure</b-button>
|
<b-button>Configure</b-button>
|
||||||
<b-button @click="logout()">
|
<b-button @click="logout()">
|
||||||
|
@ -1,26 +1,111 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'Media',
|
||||||
|
|
||||||
components: {},
|
components: {},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapState('media', ['crumbs', 'folderTree'])
|
||||||
|
},
|
||||||
|
|
||||||
created () {
|
created () {
|
||||||
this.getPath()
|
this.getPath('')
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async getPath () {
|
async getPath (path) {
|
||||||
await this.$store.dispatch('auth/inspectToken')
|
await this.$store.dispatch('auth/inspectToken')
|
||||||
// const response = await this.$axios.get('apt/')
|
await this.$store.dispatch('media/getTree', path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<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>
|
</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
|
django-cors-headers
|
||||||
djangorestframework
|
djangorestframework
|
||||||
djangorestframework-simplejwt
|
djangorestframework-simplejwt
|
||||||
|
natsort
|
||||||
psutil
|
psutil
|
||||||
|
@ -3,6 +3,7 @@ Django==3.0.2
|
|||||||
django-cors-headers==3.2.1
|
django-cors-headers==3.2.1
|
||||||
djangorestframework==3.11.0
|
djangorestframework==3.11.0
|
||||||
djangorestframework-simplejwt==4.4.0
|
djangorestframework-simplejwt==4.4.0
|
||||||
|
natsort==7.0.1
|
||||||
psutil==5.6.7
|
psutil==5.6.7
|
||||||
PyJWT==1.7.1
|
PyJWT==1.7.1
|
||||||
pytz==2019.3
|
pytz==2019.3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user