diff --git a/ffplayout/api/apps.py b/ffplayout/api/apps.py deleted file mode 100644 index d87006dd..00000000 --- a/ffplayout/api/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class ApiConfig(AppConfig): - name = 'api' diff --git a/ffplayout/api/migrations/0001_initial.py b/ffplayout/api/migrations/0001_initial.py deleted file mode 100644 index 7ba69868..00000000 --- a/ffplayout/api/migrations/0001_initial.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.0.5 on 2020-04-16 09:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='GuiSettings', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('player_url', models.CharField(max_length=255)), - ('playout_config', models.CharField(default='/etc/ffplayout/ffplayout.yml', max_length=255)), - ('net_interface', models.CharField(choices=[('lo', 'lo'), ('br0', 'br0'), ('virbr0', 'virbr0'), ('eno1', 'eno1'), ('virbr0-nic', 'virbr0-nic')], default=None, max_length=20)), - ('media_disk', models.CharField(default='/', help_text='should be a mount point, for statistics', max_length=255)), - ('extra_extensions', models.CharField(blank=True, default='', help_text='file extensions, that are only visible in GUI', max_length=255, null=True)), - ], - options={ - 'verbose_name_plural': 'guisettings', - }, - ), - ] diff --git a/ffplayout/api/migrations/0002_messengepresets.py b/ffplayout/api/migrations/0002_messengepresets.py deleted file mode 100644 index 87b38f5b..00000000 --- a/ffplayout/api/migrations/0002_messengepresets.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 3.0.5 on 2020-04-28 13:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('api', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='MessengePresets', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(help_text='the preset name', max_length=255)), - ('message', models.CharField(blank=True, default='', max_length=1024, null=True)), - ('x', models.CharField(blank=True, default='', max_length=512, null=True)), - ('y', models.CharField(blank=True, default='', max_length=512, null=True)), - ('font_size', models.IntegerField(default=24)), - ('font_spacing', models.IntegerField(default=4)), - ('font_color', models.CharField(default='#ffffff', max_length=12)), - ('font_alpha', models.FloatField(default=1.0)), - ('show_box', models.BooleanField(default=True)), - ('box_color', models.CharField(default='#000000', max_length=12)), - ('box_alpha', models.FloatField(default=0.8)), - ('border_width', models.IntegerField(default=4)), - ('overall_alpha', models.CharField(blank=True, default='', max_length=255, null=True)), - ], - ), - ] diff --git a/ffplayout/api/__init__.py b/ffplayout/api_player/__init__.py similarity index 100% rename from ffplayout/api/__init__.py rename to ffplayout/api_player/__init__.py diff --git a/ffplayout/api/admin.py b/ffplayout/api_player/admin.py similarity index 82% rename from ffplayout/api/admin.py rename to ffplayout/api_player/admin.py index 595e4e28..02e3c895 100644 --- a/ffplayout/api/admin.py +++ b/ffplayout/api_player/admin.py @@ -1,7 +1,6 @@ +from api_player.models import GuiSettings from django.contrib import admin -from api.models import GuiSettings - class GuiSettingsAdmin(admin.ModelAdmin): diff --git a/ffplayout/api_player/apps.py b/ffplayout/api_player/apps.py new file mode 100644 index 00000000..43fc82da --- /dev/null +++ b/ffplayout/api_player/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ApiPlayerConfig(AppConfig): + name = 'api_player' diff --git a/ffplayout/api/migrations/__init__.py b/ffplayout/api_player/migrations/__init__.py similarity index 100% rename from ffplayout/api/migrations/__init__.py rename to ffplayout/api_player/migrations/__init__.py diff --git a/ffplayout/api/models.py b/ffplayout/api_player/models.py similarity index 100% rename from ffplayout/api/models.py rename to ffplayout/api_player/models.py diff --git a/ffplayout/api/serializers.py b/ffplayout/api_player/serializers.py similarity index 97% rename from ffplayout/api/serializers.py rename to ffplayout/api_player/serializers.py index 6245d748..bd3b4cb1 100644 --- a/ffplayout/api/serializers.py +++ b/ffplayout/api_player/serializers.py @@ -1,9 +1,7 @@ +from api_player.models import GuiSettings, MessengePresets from django.contrib.auth.models import User - from rest_framework import serializers -from api.models import GuiSettings, MessengePresets - class UserSerializer(serializers.ModelSerializer): new_password = serializers.CharField(write_only=True, required=False) diff --git a/ffplayout/api/tests.py b/ffplayout/api_player/tests.py similarity index 100% rename from ffplayout/api/tests.py rename to ffplayout/api_player/tests.py diff --git a/ffplayout/api_player/urls.py b/ffplayout/api_player/urls.py new file mode 100644 index 00000000..6e1a0d3f --- /dev/null +++ b/ffplayout/api_player/urls.py @@ -0,0 +1,26 @@ +from django.urls import include, path, re_path +from rest_framework import routers + +from . import views + +router = routers.DefaultRouter() +router.register(r'users', views.UserViewSet) +router.register(r'guisettings', views.GuiSettingsViewSet, 'guisettings') +router.register(r'messenger', views.MessengerViewSet, 'messenger') + +app_name = 'api_player' + +urlpatterns = [ + path('player/', include(router.urls)), + path('player/config/', views.Config.as_view()), + path('player/system/', views.SystemCtl.as_view()), + path('player/playlist/', views.Playlist.as_view()), + path('player/stats/', views.Statistics.as_view()), + path('player/log/', views.LogReader.as_view()), + path('player/current/user/', views.CurrentUserView.as_view()), + path('player/media/', views.Media.as_view()), + path('player/send/', views.MessegeSender.as_view()), + re_path(r'^player/media/upload/(?P[^/]+)$', + views.FileUpload.as_view()), + path('player/media/op/', views.FileOperations.as_view()), +] diff --git a/ffplayout/api/utils.py b/ffplayout/api_player/utils.py similarity index 97% rename from ffplayout/api/utils.py rename to ffplayout/api_player/utils.py index f09412a6..61857083 100644 --- a/ffplayout/api/utils.py +++ b/ffplayout/api_player/utils.py @@ -1,17 +1,17 @@ import json import os from platform import uname -from subprocess import run, PIPE, STDOUT +from subprocess import PIPE, STDOUT, run from time import sleep import psutil + import yaml import zmq +from api_player.models import GuiSettings from django.conf import settings -from pymediainfo import MediaInfo - -from api.models import GuiSettings from natsort import natsorted +from pymediainfo import MediaInfo def read_yaml(): @@ -244,8 +244,6 @@ def get_media_path(extensions, dir=None): media_dir = media_path.split('/')[-1] media_root = os.path.dirname(media_path) if not dir: - if not os.path.isdir(media_path): - return '' dir = media_path else: if '/..' in dir: @@ -257,7 +255,8 @@ def get_media_path(extensions, dir=None): if dir.startswith(media_dir): dir = dir[len(media_dir):] - dir = os.path.join(media_root, media_dir, os.path.abspath('/' + dir).strip('/')) + dir = os.path.join( + media_root, media_dir, os.path.abspath('/' + dir).strip('/')) for root, dirs, files in os.walk(dir, topdown=True): root = root.rstrip('/') diff --git a/ffplayout/api/views.py b/ffplayout/api_player/views.py similarity index 93% rename from ffplayout/api/views.py rename to ffplayout/api_player/views.py index cb3a5bf2..920a9d0e 100644 --- a/ffplayout/api/views.py +++ b/ffplayout/api_player/views.py @@ -2,9 +2,9 @@ import os import shutil from urllib.parse import unquote -from api.models import GuiSettings, MessengePresets -from api.serializers import (GuiSettingsSerializer, MessengerSerializer, - UserSerializer) +from api_player.models import GuiSettings, MessengePresets +from api_player.serializers import (GuiSettingsSerializer, MessengerSerializer, + UserSerializer) from django.contrib.auth.models import User from django_filters import rest_framework as filters from rest_framework import viewsets @@ -13,7 +13,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from .utils import (PlayoutService, SystemStats, get_media_path, read_json, - read_yaml, write_json, write_yaml, read_log, send_message) + read_log, read_yaml, send_message, write_json, write_yaml) class CurrentUserView(APIView): @@ -71,7 +71,7 @@ class MessegeSender(APIView): class Config(APIView): """ read and write config from ffplayout engine - for reading endpoint is: http://127.0.0.1:8000/api/config/?config + for reading endpoint is: http://127.0.0.1:8000/api/player/config/?config """ parser_classes = [JSONParser] @@ -148,7 +148,8 @@ class LogReader(APIView): class Playlist(APIView): """ read and write config from ffplayout engine - for reading endpoint: http://127.0.0.1:8000/api/playlist/?date=2020-04-12 + for reading endpoint: + http://127.0.0.1:8000/api/player/playlist/?date=2020-04-12 """ def get(self, request, *args, **kwargs): @@ -176,7 +177,7 @@ class Playlist(APIView): class Statistics(APIView): """ get system statistics: cpu, ram, etc. - for reading, endpoint is: http://127.0.0.1:8000/api/stats/?stats=all + for reading, endpoint is: http://127.0.0.1:8000/api/player/stats/?stats=all """ def get(self, request, *args, **kwargs): @@ -192,7 +193,7 @@ class Statistics(APIView): 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 + for reading, endpoint is: http://127.0.0.1:8000/api/player/media/?path """ def get(self, request, *args, **kwargs): diff --git a/ffplayout/db.sqlite3 b/ffplayout/db.sqlite3 index 0d998b13..efcf4107 100644 Binary files a/ffplayout/db.sqlite3 and b/ffplayout/db.sqlite3 differ diff --git a/ffplayout/ffplayout/settings/common.py b/ffplayout/ffplayout/settings/common.py index 9f476e97..42468ab9 100644 --- a/ffplayout/ffplayout/settings/common.py +++ b/ffplayout/ffplayout/settings/common.py @@ -29,7 +29,7 @@ INSTALLED_APPS = [ 'django_filters', 'rest_framework', 'corsheaders', - 'api' + 'api_player' ] MIDDLEWARE = [ diff --git a/ffplayout/ffplayout/urls.py b/ffplayout/ffplayout/urls.py index 7c48bd0d..4f563404 100644 --- a/ffplayout/ffplayout/urls.py +++ b/ffplayout/ffplayout/urls.py @@ -14,34 +14,13 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import include, path, re_path - -from rest_framework import routers -from api import views - -from rest_framework_simplejwt.views import ( - TokenObtainPairView, - TokenRefreshView, -) - -router = routers.DefaultRouter() -router.register(r'users', views.UserViewSet) -router.register(r'guisettings', views.GuiSettingsViewSet, 'guisettings') -router.register(r'messenger', views.MessengerViewSet, 'messenger') +from django.urls import include, path +from rest_framework_simplejwt.views import (TokenObtainPairView, + TokenRefreshView) urlpatterns = [ path('admin/', admin.site.urls), - path('api/', include(router.urls)), - path('api/config/', views.Config.as_view()), - path('api/system/', views.SystemCtl.as_view()), - path('api/playlist/', views.Playlist.as_view()), - path('api/stats/', views.Statistics.as_view()), - path('api/log/', views.LogReader.as_view()), - path('api/current/user/', views.CurrentUserView.as_view()), - path('api/media/', views.Media.as_view()), - path('api/send/', views.MessegeSender.as_view()), - re_path(r'^api/media/upload/(?P[^/]+)$', views.FileUpload.as_view()), - path('api/media/op/', views.FileOperations.as_view()), + path('api/', include('api_player.urls', namespace='api_player')), path('api-auth/', include( 'rest_framework.urls', namespace='rest_framework')), path('auth/token/', TokenObtainPairView.as_view(), diff --git a/ffplayout/frontend/pages/index.vue b/ffplayout/frontend/pages/index.vue index d68bb1e9..86de2ff4 100644 --- a/ffplayout/frontend/pages/index.vue +++ b/ffplayout/frontend/pages/index.vue @@ -210,13 +210,13 @@ export default { }, async sysStats () { - const response = await this.$axios.get('api/stats/?stats=all') + const response = await this.$axios.get('api/player/stats/?stats=all') this.stat = response.data if (process.browser) { this.interval = setInterval(async () => { await this.$store.dispatch('auth/inspectToken') - const response = await this.$axios.get('api/stats/?stats=all') + const response = await this.$axios.get('api/player/stats/?stats=all') this.stat = response.data }, 2000) } diff --git a/ffplayout/frontend/pages/logging.vue b/ffplayout/frontend/pages/logging.vue index 4a56ed50..fe734a49 100644 --- a/ffplayout/frontend/pages/logging.vue +++ b/ffplayout/frontend/pages/logging.vue @@ -75,7 +75,7 @@ export default { methods: { async getLog (type) { await this.$store.dispatch('auth/inspectToken') - const response = await this.$axios.get(`api/log/?type=${type}`) + const response = await this.$axios.get(`api/player/log/?type=${type}`) if (response.data.log) { this.currentLog = response.data.log @@ -83,7 +83,7 @@ export default { }, async getSystemLog () { await this.$store.dispatch('auth/inspectToken') - const response = await this.$axios.post('api/system/', { run: 'log' }) + const response = await this.$axios.post('api/player/system/', { run: 'log' }) if (response.data.data) { this.currentLog = response.data.data diff --git a/ffplayout/frontend/pages/media.vue b/ffplayout/frontend/pages/media.vue index 65d4bd95..ca7b651e 100644 --- a/ffplayout/frontend/pages/media.vue +++ b/ffplayout/frontend/pages/media.vue @@ -36,7 +36,7 @@ - + @@ -70,7 +70,7 @@ {{ file.file }} - + @@ -78,7 +78,7 @@ {{ file.duration | toMin }} - + @@ -276,7 +276,7 @@ export default { await this.$store.dispatch('auth/inspectToken') await this.$axios.post( - 'api/media/op/', + 'api/player/media/op/', { folder: this.folderName, path: this.crumbs.map(e => e.text).join('/') } ) @@ -322,7 +322,7 @@ export default { } await this.$axios.put( - `api/media/upload/${encodeURIComponent(file.name)}?path=${encodeURIComponent(this.crumbs.map(e => e.text).join('/'))}`, + `api/player/media/upload/${encodeURIComponent(file.name)}?path=${encodeURIComponent(this.crumbs.map(e => e.text).join('/'))}`, file, config ) @@ -403,7 +403,7 @@ export default { pathName = this.deleteSource } - await this.$axios.delete(`api/media/op/?file=${encodeURIComponent(file)}&path=${encodeURIComponent(pathName)}`) + await this.$axios.delete(`api/player/media/op/?file=${encodeURIComponent(file)}&path=${encodeURIComponent(pathName)}`) .catch(err => console.log(err)) this.$root.$emit('bv::hide::modal', 'delete-modal') diff --git a/ffplayout/frontend/pages/message.vue b/ffplayout/frontend/pages/message.vue index 09b7466b..fa49ec03 100644 --- a/ffplayout/frontend/pages/message.vue +++ b/ffplayout/frontend/pages/message.vue @@ -281,7 +281,7 @@ export default { if (preset) { req = `?name=${preset}` } - const response = await this.$axios.get(`api/messenger/${req}`) + const response = await this.$axios.get(`api/player/messenger/${req}`) if (response.data && !preset) { for (const item of response.data) { @@ -333,7 +333,7 @@ export default { overall_alpha: this.form.overallAlpha } - const response = await this.$axios.post('api/messenger/', preset) + const response = await this.$axios.post('api/player/messenger/', preset) if (response.status === 201) { this.success = true @@ -365,7 +365,7 @@ export default { overall_alpha: this.form.overallAlpha } - const response = await this.$axios.put(`api/messenger/${this.form.id}/`, preset) + const response = await this.$axios.put(`api/player/messenger/${this.form.id}/`, preset) if (response.status === 200) { this.success = true @@ -385,7 +385,7 @@ export default { async deletePreset () { await this.$store.dispatch('auth/inspectToken') if (this.selected) { - await this.$axios.delete(`api/messenger/${this.form.id}/`) + await this.$axios.delete(`api/player/messenger/${this.form.id}/`) } this.$bvModal.hide('delete-modal') @@ -411,7 +411,7 @@ export default { boxborderw: this.form.border } - const response = await this.$axios.post('api/send/', { data: obj }) + const response = await this.$axios.post('api/player/send/', { data: obj }) if (response.data && response.data.status.Success && response.data.status.Success === '0 Success') { this.success = true diff --git a/ffplayout/frontend/pages/player.vue b/ffplayout/frontend/pages/player.vue index e29a51bb..66006f7b 100644 --- a/ffplayout/frontend/pages/player.vue +++ b/ffplayout/frontend/pages/player.vue @@ -372,7 +372,7 @@ export default { async getStatus () { await this.$store.dispatch('auth/inspectToken') - const status = await this.$axios.post('api/system/', { run: 'status' }) + const status = await this.$axios.post('api/player/system/', { run: 'status' }) if (status.data.data && status.data.data === 'active') { this.isPlaying = 'is-playing' @@ -382,7 +382,7 @@ export default { }, async playoutControl (state) { await this.$store.dispatch('auth/inspectToken') - await this.$axios.post('api/system/', { run: state }) + await this.$axios.post('api/player/system/', { run: state }) setTimeout(() => { this.getStatus() }, 1000) }, @@ -447,7 +447,7 @@ export default { const saveList = this.playlist.map(({ begin, ...item }) => item) await this.$axios.post( - 'api/playlist/', + 'api/player/playlist/', { data: { channel: this.$store.state.playlist.playlistChannel, date: this.listDate, program: saveList } } ) } diff --git a/ffplayout/frontend/plugins/axios.js b/ffplayout/frontend/plugins/axios.js index 6cc779ba..f8f1b113 100644 --- a/ffplayout/frontend/plugins/axios.js +++ b/ffplayout/frontend/plugins/axios.js @@ -6,7 +6,7 @@ export default function ({ $axios, store, redirect }) { } // disable progress on auth and stats - if (config.url.includes('stats') || config.url.includes('auth')) { + if (config.url.includes('stats') || config.url.includes('auth') || config.url.includes('system')) { config.progress = false } }) diff --git a/ffplayout/frontend/store/config.js b/ffplayout/frontend/store/config.js index 9a605c40..ef25fe27 100644 --- a/ffplayout/frontend/store/config.js +++ b/ffplayout/frontend/store/config.js @@ -26,8 +26,8 @@ export const mutations = { export const actions = { async getGuiConfig ({ commit, state }) { - const options = await this.$axios.options('api/guisettings/') - const response = await this.$axios.get('api/guisettings/') + const options = await this.$axios.options('api/player/guisettings/') + const response = await this.$axios.get('api/player/guisettings/') if (options.data) { const choices = options.data.actions.POST.net_interface.choices.map(function (obj) { @@ -46,12 +46,12 @@ export const actions = { async setGuiConfig ({ commit, state }, obj) { const stringObj = JSON.parse(JSON.stringify(obj)) stringObj.extra_extensions = obj.extra_extensions.join(' ') - const update = await this.$axios.put('api/guisettings/1/', stringObj) + const update = await this.$axios.put('api/player/guisettings/1/', stringObj) return update }, async getPlayoutConfig ({ commit, state }) { - const response = await this.$axios.get('api/config/?configPlayout') + const response = await this.$axios.get('api/player/config/?configPlayout') if (response.data) { commit('UPDATE_PLAYLOUT_CONFIG', response.data) @@ -59,13 +59,13 @@ export const actions = { }, async setPlayoutConfig ({ commit, state }, obj) { - const update = await this.$axios.post('api/config/?configPlayout', { data: obj }) + const update = await this.$axios.post('api/player/config/?configPlayout', { data: obj }) return update }, async getUserConfig ({ commit, state }) { - const user = await this.$axios.get('api/current/user/') - const response = await this.$axios.get(`api/users/?username=${user.data.username}`) + const user = await this.$axios.get('api/player/current/user/') + const response = await this.$axios.get(`api/player/users/?username=${user.data.username}`) if (user.data) { commit('SET_CURRENT_USER', user.data.username) @@ -76,7 +76,7 @@ export const actions = { }, async setUserConfig ({ commit, state }, obj) { - const update = await this.$axios.put(`api/users/${obj.id}/`, obj) + const update = await this.$axios.put(`api/player/users/${obj.id}/`, obj) return update } } diff --git a/ffplayout/frontend/store/media.js b/ffplayout/frontend/store/media.js index db6489d0..f63109c8 100644 --- a/ffplayout/frontend/store/media.js +++ b/ffplayout/frontend/store/media.js @@ -20,7 +20,7 @@ export const actions = { async getTree ({ commit, dispatch, state }, { extensions, path }) { const crumbs = [] let root = '/' - const response = await this.$axios.get(`api/media/?extensions=${extensions}&path=${path}`) + const response = await this.$axios.get(`api/player/media/?extensions=${extensions}&path=${path}`) if (response.data.tree) { const pathArr = response.data.tree[0].split('/') diff --git a/ffplayout/frontend/store/playlist.js b/ffplayout/frontend/store/playlist.js index beb51249..afc23ac4 100644 --- a/ffplayout/frontend/store/playlist.js +++ b/ffplayout/frontend/store/playlist.js @@ -46,7 +46,7 @@ export const mutations = { export const actions = { async getPlaylist ({ commit, dispatch, state }, { dayStart, date }) { - const response = await this.$axios.get(`api/playlist/?date=${date}`) + const response = await this.$axios.get(`api/player/playlist/?date=${date}`) if (response.data && response.data.program) { commit('UPDATE_PLAYLIST_CHANNEL', response.data.channel)