add doc generator, tweak routes, add channel_id to presets and user, better defaults
This commit is contained in:
parent
cb65d8084f
commit
7978eb1126
@ -3,7 +3,7 @@ Description=Rust and ffmpeg based playout solution
|
|||||||
After=network.target remote-fs.target
|
After=network.target remote-fs.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart= /usr/bin/ffplayout
|
ExecStart=/usr/bin/ffplayout
|
||||||
ExecReload=/bin/kill -1 $MAINPID
|
ExecReload=/bin/kill -1 $MAINPID
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=1
|
RestartSec=1
|
||||||
|
@ -10,7 +10,7 @@ general:
|
|||||||
rpc_server:
|
rpc_server:
|
||||||
help_text: Run a JSON RPC server, for getting infos about current playing, and
|
help_text: Run a JSON RPC server, for getting infos about current playing, and
|
||||||
control for some functions.
|
control for some functions.
|
||||||
enable: false
|
enable: true
|
||||||
address: 127.0.0.1:7070
|
address: 127.0.0.1:7070
|
||||||
authorization: av2Kx8g67lF9qj5wEH3ym1bI4cCs
|
authorization: av2Kx8g67lF9qj5wEH3ym1bI4cCs
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ text:
|
|||||||
'text_from_filename' activate the extraction from text of a filename. With 'style'
|
'text_from_filename' activate the extraction from text of a filename. With 'style'
|
||||||
you can define the drawtext parameters like position, color, etc. Post Text over
|
you can define the drawtext parameters like position, color, etc. Post Text over
|
||||||
API will override this. With 'regex' you can format file names, to get a title from it.
|
API will override this. With 'regex' you can format file names, to get a title from it.
|
||||||
add_text: false
|
add_text: true
|
||||||
text_from_filename: false
|
text_from_filename: false
|
||||||
fontfile: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
fontfile: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
||||||
style: "x=(w-tw)/2:y=(h-line_h)*0.9:fontsize=24:fontcolor=#ffffff:box=1:boxcolor=#000000:boxborderw=4"
|
style: "x=(w-tw)/2:y=(h-line_h)*0.9:fontsize=24:fontcolor=#ffffff:box=1:boxcolor=#000000:boxborderw=4"
|
||||||
|
381
docs/api.md
381
docs/api.md
@ -1,186 +1,313 @@
|
|||||||
#### Possible endpoints
|
### Possible endpoints
|
||||||
|
|
||||||
Run the API thru the systemd service, or like:
|
Run the API thru the systemd service, or like:
|
||||||
|
|
||||||
```BASH
|
```BASH
|
||||||
ffpapi -l 127.0.0.1:8080
|
ffpapi -l 127.0.0.1:8000
|
||||||
```
|
```
|
||||||
|
|
||||||
For all endpoints an (Bearer) authentication is required.\
|
For all endpoints an (Bearer) authentication is required.\
|
||||||
`{id}` represent the channel id, and at default is 1.
|
`{id}` represent the channel id, and at default is 1.
|
||||||
|
|
||||||
#### Login is
|
#### User Handling
|
||||||
|
|
||||||
|
**Login**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://127.0.0.1:8000/auth/login/ -H "Content-Type: application/json" \
|
||||||
|
-d '{ "username": "<USER>", "password": "<PASS>" }'
|
||||||
|
```
|
||||||
|
**Response:**
|
||||||
|
|
||||||
- **POST** `/auth/login/`\
|
|
||||||
JSON Data: `{"username": "<USER>", "password": "<PASS>"}`\
|
|
||||||
JSON Response:
|
|
||||||
```JSON
|
```JSON
|
||||||
{
|
{
|
||||||
"message": "login correct!",
|
"id": 1,
|
||||||
"status": 200,
|
"mail": "user@example.org",
|
||||||
"data": {
|
"username": "<USER>",
|
||||||
"id": 1,
|
"token": "<TOKEN>"
|
||||||
"mail": "user@example.org",
|
|
||||||
"username": "user",
|
|
||||||
"token": "<TOKEN>"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
From here on all request **must** contain the authorization header:\
|
From here on all request **must** contain the authorization header:\
|
||||||
`"Authorization: Bearer <TOKEN>"`
|
`"Authorization: Bearer <TOKEN>"`
|
||||||
|
|
||||||
#### User
|
**Get current User**
|
||||||
|
|
||||||
- **GET** `/api/user`\
|
```BASH
|
||||||
Get current user, response is in JSON format
|
curl -X GET 'http://localhost:8000/api/user' -H 'Content-Type: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
- **PUT** `/api/user/{user id}`\
|
**Update current User**
|
||||||
JSON Data: `{"mail": "<MAIL>", "password": "<PASS>"}`
|
|
||||||
|
```BASH
|
||||||
|
curl -X PUT http://localhost:8000/api/user/1 -H 'Content-Type: application/json' \
|
||||||
|
-d '{"mail": "<MAIL>", "password": "<PASS>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Add User**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/json' \
|
||||||
|
-d '{"mail": "<MAIL>", "username": "<USER>", "password": "<PASS>", "role_id": 1, "channel_id": 1}' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ffpapi Settings
|
||||||
|
|
||||||
|
**Get Settings**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
- **POST** `/api/user/`\
|
|
||||||
JSON Data:
|
|
||||||
```JSON
|
```JSON
|
||||||
{
|
{
|
||||||
"mail": "<MAIL>",
|
"id": 1,
|
||||||
"username": "<USER>",
|
"channel_name": "Channel 1",
|
||||||
"password": "<PASS>",
|
"preview_url": "http://localhost/live/preview.m3u8",
|
||||||
"role_id": 1
|
"config_path": "/etc/ffplayout/ffplayout.yml",
|
||||||
|
"extra_extensions": "jpg,jpeg,png",
|
||||||
|
"timezone": "UTC",
|
||||||
|
"service": "ffplayout.service"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### API Settings
|
**Get all Settings**
|
||||||
|
|
||||||
- **GET** `/api/settings`\
|
```BASH
|
||||||
Response is in JSON format
|
curl -X GET http://127.0.0.1:8000/api/settings -H "Authorization: Bearer <TOKEN>"
|
||||||
|
|
||||||
- **GET** `/api/settings/{id}`\
|
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
- **PATCH** `/api/settings/{id}`\
|
|
||||||
JSON Data:
|
|
||||||
```JSON
|
|
||||||
"id": 1,
|
|
||||||
"channel_name": "Channel 1",
|
|
||||||
"preview_url": "http://localhost/live/stream.m3u8",
|
|
||||||
"config_path": "/etc/ffplayout/ffplayout.yml",
|
|
||||||
"extra_extensions": ".jpg,.jpeg,.png"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Playout Config
|
**Update Settings**
|
||||||
|
|
||||||
- **GET** `/api/playout/config/{id}`\
|
```BASH
|
||||||
Response is in JSON format
|
curl -X PATCH http://127.0.0.1:8000/api/settings/1 -H "Content-Type: application/json" \
|
||||||
|
-d '{ "id": 1, "channel_name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \
|
||||||
|
"config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png",
|
||||||
|
"role_id": 1, "channel_id": 1 }' \
|
||||||
|
-H "Authorization: Bearer <TOKEN>"
|
||||||
|
```
|
||||||
|
|
||||||
- **PUT** `/api/playout/config/{id}`\
|
#### ffplayout Config
|
||||||
JSON Data: `{ <CONFIG DATA> }`\
|
|
||||||
Response is in TEXT format
|
**Get Config**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X GET http://localhost:8000/api/playout/config/1 -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response is a JSON object from the ffplayout.yml
|
||||||
|
|
||||||
|
**Update Config**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X PUT http://localhost:8000/api/playout/config/1 -H "Content-Type: application/json" \
|
||||||
|
-d { <CONFIG DATA> } -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
#### Text Presets
|
#### Text Presets
|
||||||
|
|
||||||
- **GET** `/api/presets/`\
|
Text presets are made for sending text messages to the ffplayout engine, to overlay them as a lower third.
|
||||||
Response is in JSON format
|
|
||||||
|
**Get all Presets**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X GET http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \
|
||||||
|
-H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update Preset**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X PUT http://localhost:8000/api/presets/1 -H 'Content-Type: application/json' \
|
||||||
|
-d '{"name": "<PRESET NAME>", "text": "<TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
|
||||||
|
"line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0}' \
|
||||||
|
-H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ad new Preset**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \
|
||||||
|
-d '{"name": "<PRESET NAME>", "text": "TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
|
||||||
|
"line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0}}' \
|
||||||
|
-H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### ffplayout controlling
|
||||||
|
|
||||||
|
here we communicate with the engine for:
|
||||||
|
- jump to last or next clip
|
||||||
|
- reset playlist state
|
||||||
|
- get infos about current, next, last clip
|
||||||
|
- send text to the engine, for overlaying it (as lower third etc.)
|
||||||
|
|
||||||
|
**Send Text to ffplayout**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/control/1/text/ \
|
||||||
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>' \
|
||||||
|
-d '{"text": "Hello from ffplayout", "x": "(w-text_w)/2", "y": "(h-text_h)/2", \
|
||||||
|
"fontsize": "24", "line_spacing": "4", "fontcolor": "#ffffff", "box": "1", \
|
||||||
|
"boxcolor": "#000000", "boxborderw": "4", "alpha": "1.0"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Jump to next Clip**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/control/1/playout/next/ -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Jump to last Clip**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/control/1/playout/back/ -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Reset ffplayout State**
|
||||||
|
|
||||||
|
When before was jumped to next, or last clips, here we go back to the original clip.
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/control/1/playout/reset/ -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Get current Clip**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X GET http://localhost:8000/api/control/1/media/current/
|
||||||
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
- **PUT** `/api/playout/presets/{id}`\
|
|
||||||
JSON Data:
|
|
||||||
```JSON
|
```JSON
|
||||||
{
|
{
|
||||||
"name": "<PRESET NAME>",
|
"jsonrpc": "2.0",
|
||||||
"text": "<TEXT>",
|
"result": {
|
||||||
"x": "<X>",
|
"current_media": {
|
||||||
"y": "<Y>",
|
"category": "",
|
||||||
"fontsize": 24,
|
"duration": 154.2,
|
||||||
"line_spacing": 4,
|
"out": 154.2,
|
||||||
"fontcolor": "#ffffff",
|
"seek": 0.0,
|
||||||
"box": 1,
|
"source": "/opt/tv-media/clip.mp4"
|
||||||
"boxcolor": "#000000",
|
},
|
||||||
"boxborderw": 4,
|
"index": 39,
|
||||||
"alpha": "<alpha>"
|
"play_mode": "playlist",
|
||||||
}
|
"played_sec": 67.80771999300123,
|
||||||
|
"remaining_sec": 86.39228000699876,
|
||||||
```
|
"start_sec": 24713.631999999998,
|
||||||
Response is in TEXT format
|
"start_time": "06:51:53.631"
|
||||||
|
},
|
||||||
- **POST** `/api/playout/presets/`\
|
"id": 1
|
||||||
JSON Data: `{ <PRESET DATA> }`\
|
|
||||||
Response is in TEXT format
|
|
||||||
|
|
||||||
#### Playout Process Control
|
|
||||||
|
|
||||||
- **POST** `/api/control/{id}/text/`¸
|
|
||||||
JSON Data:
|
|
||||||
```JSON
|
|
||||||
{
|
|
||||||
"text": "Hello from ffplayout",
|
|
||||||
"x": "(w-text_w)/2",
|
|
||||||
"y": "(h-text_h)/2",
|
|
||||||
"fontsize": "24",
|
|
||||||
"line_spacing": "4",
|
|
||||||
"fontcolor": "#ffffff",
|
|
||||||
"box": "1",
|
|
||||||
"boxcolor": "#000000",
|
|
||||||
"boxborderw": "4",
|
|
||||||
"alpha": "1.0"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Response is in TEXT format
|
|
||||||
|
|
||||||
- **POST** `api/control/{id}/playout/next/`\
|
**Get next Clip**
|
||||||
Response is in TEXT format
|
|
||||||
|
|
||||||
- **POST** `api/control/{id}/playout/back/`\
|
```BASH
|
||||||
Response is in TEXT format
|
curl -X GET http://localhost:8000/api/control/1/media/next/ -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
- **POST** `api/control/{id}/playout/reset/`\
|
**Get last Clip**
|
||||||
Response is in TEXT format
|
|
||||||
|
|
||||||
- **GET** `/api/control/{id}/media/current`\
|
```BASH
|
||||||
Response is in JSON format
|
curl -X GET http://localhost:8000/api/control/1/media/last/
|
||||||
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
- **GET** `/api/control/{id}/media/next`\
|
#### ffplayout Process Control
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
- **GET** `/api/control/{id}/media/last`\
|
Control ffplayout process, like:
|
||||||
Response is in JSON format
|
- start
|
||||||
|
- stop
|
||||||
|
- restart
|
||||||
|
- status
|
||||||
|
|
||||||
- **POST** `/api/control/{id}/process/`\
|
```BASH
|
||||||
JSON Data: `{"command": "<start/stop/restart/status>"}`
|
curl -X POST http://localhost:8000/api/control/1/process/
|
||||||
Response is in TEXT format
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
-d '{"command": "start"}'
|
||||||
|
```
|
||||||
|
|
||||||
#### Playlist Operations
|
#### ffplayout Playlist Operations
|
||||||
|
|
||||||
- **GET** `/api/playlist/{id}/2022-06-20`\
|
**Get playlist**
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
- **POST** `/api/playlist/1/`\
|
```BASH
|
||||||
JSON Data: `{ <PLAYLIST DATA> }`\
|
curl -X GET http://localhost:8000/api/playlist/1?date=2022-06-20
|
||||||
Response is in TEXT format
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
- **GET** `/api/playlist/{id}/generate/2022-06-20`\
|
**Save playlist**
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
- **DELETE** `/api/playlist/{id}/2022-06-20`\
|
```BASH
|
||||||
Response is in TEXT format
|
curl -X POST http://localhost:8000/api/playlist/1/
|
||||||
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
-- data "{<JSON playlist data>}"
|
||||||
|
```
|
||||||
|
|
||||||
#### Log File
|
**Generate Playlist**
|
||||||
|
|
||||||
- **GET** `/api/file/{id}/browse/`\
|
A new playlist will be generated and response.
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X GET http://localhost:8000/api/playlist/1/generate/2022-06-20
|
||||||
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
#### File Operations
|
**Delete Playlist**
|
||||||
|
|
||||||
- **GET** `/api/log/{id}(/{date})`\
|
```BASH
|
||||||
Response is in TEXT format
|
curl -X DELETE http://localhost:8000/api/playlist/1/2022-06-20
|
||||||
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
- **POST** `/api/file/{id}/move/`\
|
### Log file
|
||||||
JSON Data: `{"source": "<SOURCE>", "target": "<TARGET>"}`\
|
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
- **DELETE** `/api/file/{id}/remove/`\
|
**Read Log Life**
|
||||||
JSON Data: `{"source": "<SOURCE>"}`\
|
|
||||||
Response is in JSON format
|
|
||||||
|
|
||||||
- **POST** `/file/{id}/upload/`\
|
```BASH
|
||||||
Multipart Form: `name=<TARGET PATH>, filename=<FILENAME>`\
|
curl -X Get http://localhost:8000/api/log/1
|
||||||
Response is in TEXT format
|
-H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Operations
|
||||||
|
|
||||||
|
**Get File/Folder List**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/file/1/browse/ -H 'Content-Type: application/json'
|
||||||
|
-d '{ "source": "/" }' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Create Folder**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/file/1/create-folder/ -H 'Content-Type: application/json'
|
||||||
|
-d '{"source": "<FOLDER PATH>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rename File**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/file/1/rename/ -H 'Content-Type: application/json'
|
||||||
|
-d '{"source": "<SOURCE>", "target": "<TARGET>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Remove File/Folder**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/file/1/remove/ -H 'Content-Type: application/json'
|
||||||
|
-d '{"source": "<SOURCE>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Upload File**
|
||||||
|
|
||||||
|
```BASH
|
||||||
|
curl -X POST http://localhost:8000/api/file/1/upload/ -H 'Authorization: <TOKEN>'
|
||||||
|
-F "file=@file.mp4"
|
||||||
|
```
|
||||||
|
@ -17,9 +17,9 @@ use utils::{
|
|||||||
routes::{
|
routes::{
|
||||||
add_dir, add_preset, add_user, del_playlist, file_browser, gen_playlist, get_all_settings,
|
add_dir, add_preset, add_user, del_playlist, file_browser, gen_playlist, get_all_settings,
|
||||||
get_log, get_playlist, get_playout_config, get_presets, get_settings, get_user,
|
get_log, get_playlist, get_playout_config, get_presets, get_settings, get_user,
|
||||||
jump_to_last, jump_to_next, login, media_current, media_last, media_next, move_rename,
|
control_playout, login, media_current, media_last, media_next, move_rename,
|
||||||
patch_settings, process_control, remove, reset_playout, save_file, save_playlist,
|
patch_settings, process_control, remove, save_file, save_playlist,
|
||||||
send_text_message, update_playout_config, update_preset, update_user,
|
send_text_message, update_playout_config, update_preset, update_user, delete_preset,
|
||||||
},
|
},
|
||||||
run_args, Role,
|
run_args, Role,
|
||||||
};
|
};
|
||||||
@ -83,14 +83,13 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.service(add_preset)
|
.service(add_preset)
|
||||||
.service(get_presets)
|
.service(get_presets)
|
||||||
.service(update_preset)
|
.service(update_preset)
|
||||||
|
.service(delete_preset)
|
||||||
.service(get_settings)
|
.service(get_settings)
|
||||||
.service(get_all_settings)
|
.service(get_all_settings)
|
||||||
.service(patch_settings)
|
.service(patch_settings)
|
||||||
.service(update_user)
|
.service(update_user)
|
||||||
.service(send_text_message)
|
.service(send_text_message)
|
||||||
.service(jump_to_next)
|
.service(control_playout)
|
||||||
.service(jump_to_last)
|
|
||||||
.service(reset_playout)
|
|
||||||
.service(media_current)
|
.service(media_current)
|
||||||
.service(media_next)
|
.service(media_next)
|
||||||
.service(media_last)
|
.service(media_last)
|
||||||
|
@ -97,7 +97,7 @@ impl SystemD {
|
|||||||
|
|
||||||
let output = Command::new("sudo").args(self.cmd).output()?;
|
let output = Command::new("sudo").args(self.cmd).output()?;
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,17 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
|||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
UNIQUE(name)
|
UNIQUE(name)
|
||||||
);
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS settings
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
channel_name TEXT NOT NULL,
|
||||||
|
preview_url TEXT NOT NULL,
|
||||||
|
config_path TEXT NOT NULL,
|
||||||
|
extra_extensions TEXT NOT NULL,
|
||||||
|
timezone TEXT NOT NULL,
|
||||||
|
service TEXT NOT NULL,
|
||||||
|
UNIQUE(channel_name)
|
||||||
|
);
|
||||||
CREATE TABLE IF NOT EXISTS presets
|
CREATE TABLE IF NOT EXISTS presets
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -51,17 +62,6 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
|||||||
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||||
UNIQUE(name)
|
UNIQUE(name)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS settings
|
|
||||||
(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
channel_name TEXT NOT NULL,
|
|
||||||
preview_url TEXT NOT NULL,
|
|
||||||
config_path TEXT NOT NULL,
|
|
||||||
extra_extensions TEXT NOT NULL,
|
|
||||||
timezone TEXT NOT NULL,
|
|
||||||
service TEXT NOT NULL,
|
|
||||||
UNIQUE(channel_name)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS user
|
CREATE TABLE IF NOT EXISTS user
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -70,7 +70,9 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
|||||||
password TEXT NOT NULL,
|
password TEXT NOT NULL,
|
||||||
salt TEXT NOT NULL,
|
salt TEXT NOT NULL,
|
||||||
role_id INTEGER NOT NULL DEFAULT 2,
|
role_id INTEGER NOT NULL DEFAULT 2,
|
||||||
|
channel_id INTEGER NOT NULL DEFAULT 1,
|
||||||
FOREIGN KEY (role_id) REFERENCES roles (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
FOREIGN KEY (role_id) REFERENCES roles (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||||
UNIQUE(mail, username)
|
UNIQUE(mail, username)
|
||||||
);";
|
);";
|
||||||
let result = sqlx::query(query).execute(&conn).await;
|
let result = sqlx::query(query).execute(&conn).await;
|
||||||
@ -294,3 +296,12 @@ pub async fn db_add_preset(preset: TextPreset) -> Result<SqliteQueryResult, sqlx
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn db_delete_preset(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||||
|
let conn = db_connection().await?;
|
||||||
|
let query = "DELETE FROM presets WHERE id = $1;";
|
||||||
|
let result: SqliteQueryResult = sqlx::query(query).bind(id).execute(&conn).await?;
|
||||||
|
conn.close().await;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
@ -159,6 +159,7 @@ pub async fn run_args(mut args: Args) -> Result<(), i32> {
|
|||||||
password: args.password.unwrap(),
|
password: args.password.unwrap(),
|
||||||
salt: None,
|
salt: None,
|
||||||
role_id: Some(1),
|
role_id: Some(1),
|
||||||
|
channel_id: Some(1),
|
||||||
token: None,
|
token: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,9 @@ pub struct User {
|
|||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub role_id: Option<i64>,
|
pub role_id: Option<i64>,
|
||||||
#[sqlx(default)]
|
#[sqlx(default)]
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub channel_id: Option<i64>,
|
||||||
|
#[sqlx(default)]
|
||||||
pub token: Option<String>,
|
pub token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +45,6 @@ pub struct TextPreset {
|
|||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub channel_id: i64,
|
pub channel_id: i64,
|
||||||
#[serde(skip_deserializing)]
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub x: String,
|
pub x: String,
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/// ### Possible endpoints
|
||||||
|
///
|
||||||
|
/// Run the API thru the systemd service, or like:
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// ffpapi -l 127.0.0.1:8000
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// For all endpoints an (Bearer) authentication is required.\
|
||||||
|
/// `{id}` represent the channel id, and at default is 1.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
@ -21,6 +32,7 @@ use crate::utils::{
|
|||||||
handles::{
|
handles::{
|
||||||
db_add_preset, db_add_user, db_get_all_settings, db_get_presets, db_get_settings,
|
db_add_preset, db_add_user, db_get_all_settings, db_get_presets, db_get_settings,
|
||||||
db_get_user, db_login, db_role, db_update_preset, db_update_settings, db_update_user,
|
db_get_user, db_login, db_role, db_update_preset, db_update_settings, db_update_user,
|
||||||
|
db_delete_preset,
|
||||||
},
|
},
|
||||||
models::{LoginUser, Settings, TextPreset, User},
|
models::{LoginUser, Settings, TextPreset, User},
|
||||||
playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist},
|
playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist},
|
||||||
@ -53,8 +65,24 @@ pub struct FileObj {
|
|||||||
path: String,
|
path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://127.0.0.1:8080/auth/login/ -H "Content-Type: application/json" \
|
/// #### User Handling
|
||||||
/// -d '{"username": "<USER>", "password": "<PASS>" }'
|
///
|
||||||
|
/// **Login**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X POST http://127.0.0.1:8000/auth/login/ -H "Content-Type: application/json" \
|
||||||
|
/// -d '{ "username": "<USER>", "password": "<PASS>" }'
|
||||||
|
/// ```
|
||||||
|
/// **Response:**
|
||||||
|
///
|
||||||
|
/// ```JSON
|
||||||
|
/// {
|
||||||
|
/// "id": 1,
|
||||||
|
/// "mail": "user@example.org",
|
||||||
|
/// "username": "<USER>",
|
||||||
|
/// "token": "<TOKEN>"
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[post("/auth/login/")]
|
#[post("/auth/login/")]
|
||||||
pub async fn login(credentials: web::Json<User>) -> impl Responder {
|
pub async fn login(credentials: web::Json<User>) -> impl Responder {
|
||||||
match db_login(&credentials.username).await {
|
match db_login(&credentials.username).await {
|
||||||
@ -107,8 +135,15 @@ pub async fn login(credentials: web::Json<User>) -> impl Responder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET 'http://localhost:8080/api/user' --header 'Content-Type: application/json' \
|
/// From here on all request **must** contain the authorization header:\
|
||||||
/// --header 'Authorization: Bearer <TOKEN>'
|
/// `"Authorization: Bearer <TOKEN>"`
|
||||||
|
|
||||||
|
/// **Get current User**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET 'http://localhost:8000/api/user' -H 'Content-Type: application/json' \
|
||||||
|
/// -H 'Authorization: Bearer <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/user")]
|
#[get("/user")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn get_user(user: web::ReqData<LoginUser>) -> Result<impl Responder, ServiceError> {
|
async fn get_user(user: web::ReqData<LoginUser>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -121,8 +156,12 @@ async fn get_user(user: web::ReqData<LoginUser>) -> Result<impl Responder, Servi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X PUT http://localhost:8080/api/user/1 --header 'Content-Type: application/json' \
|
/// **Update current User**
|
||||||
/// --data '{"mail": "<MAIL>", "password": "<PASS>"}' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X PUT http://localhost:8000/api/user/1 -H 'Content-Type: application/json' \
|
||||||
|
/// -d '{"mail": "<MAIL>", "password": "<PASS>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[put("/user/{id}")]
|
#[put("/user/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn update_user(
|
async fn update_user(
|
||||||
@ -160,9 +199,13 @@ async fn update_user(
|
|||||||
Err(ServiceError::Unauthorized)
|
Err(ServiceError::Unauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST 'http://localhost:8080/api/user/' --header 'Content-Type: application/json' \
|
/// **Add User**
|
||||||
/// -d '{"mail": "<MAIL>", "username": "<USER>", "password": "<PASS>", "role_id": 1}' \
|
///
|
||||||
/// --header 'Authorization: Bearer <TOKEN>'
|
/// ```BASH
|
||||||
|
/// curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/json' \
|
||||||
|
/// -d '{"mail": "<MAIL>", "username": "<USER>", "password": "<PASS>", "role_id": 1, "channel_id": 1}' \
|
||||||
|
/// -H 'Authorization: Bearer <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[post("/user/")]
|
#[post("/user/")]
|
||||||
#[has_any_role("Role::Admin", type = "Role")]
|
#[has_any_role("Role::Admin", type = "Role")]
|
||||||
async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError> {
|
async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -175,7 +218,27 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://127.0.0.1:8080/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
/// #### ffpapi Settings
|
||||||
|
///
|
||||||
|
/// **Get Settings**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// **Response:**
|
||||||
|
///
|
||||||
|
/// ```JSON
|
||||||
|
/// {
|
||||||
|
/// "id": 1,
|
||||||
|
/// "channel_name": "Channel 1",
|
||||||
|
/// "preview_url": "http://localhost/live/preview.m3u8",
|
||||||
|
/// "config_path": "/etc/ffplayout/ffplayout.yml",
|
||||||
|
/// "extra_extensions": "jpg,jpeg,png",
|
||||||
|
/// "timezone": "UTC",
|
||||||
|
/// "service": "ffplayout.service"
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[get("/settings/{id}")]
|
#[get("/settings/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn get_settings(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
async fn get_settings(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -186,7 +249,11 @@ async fn get_settings(id: web::Path<i64>) -> Result<impl Responder, ServiceError
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://127.0.0.1:8080/api/settings -H "Authorization: Bearer <TOKEN>"
|
/// **Get all Settings**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://127.0.0.1:8000/api/settings -H "Authorization: Bearer <TOKEN>"
|
||||||
|
/// ```
|
||||||
#[get("/settings")]
|
#[get("/settings")]
|
||||||
#[has_any_role("Role::Admin", type = "Role")]
|
#[has_any_role("Role::Admin", type = "Role")]
|
||||||
async fn get_all_settings() -> Result<impl Responder, ServiceError> {
|
async fn get_all_settings() -> Result<impl Responder, ServiceError> {
|
||||||
@ -197,10 +264,15 @@ async fn get_all_settings() -> Result<impl Responder, ServiceError> {
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X PATCH http://127.0.0.1:8080/api/settings/1 -H "Content-Type: application/json" \
|
/// **Update Settings**
|
||||||
/// --data '{"id":1,"channel_name":"Channel 1","preview_url":"http://localhost/live/stream.m3u8", \
|
///
|
||||||
/// "config_path":"/etc/ffplayout/ffplayout.yml","extra_extensions":".jpg,.jpeg,.png"}' \
|
/// ```BASH
|
||||||
|
/// curl -X PATCH http://127.0.0.1:8000/api/settings/1 -H "Content-Type: application/json" \
|
||||||
|
/// -d '{ "id": 1, "channel_name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \
|
||||||
|
/// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png",
|
||||||
|
/// "role_id": 1, "channel_id": 1 }' \
|
||||||
/// -H "Authorization: Bearer <TOKEN>"
|
/// -H "Authorization: Bearer <TOKEN>"
|
||||||
|
/// ```
|
||||||
#[patch("/settings/{id}")]
|
#[patch("/settings/{id}")]
|
||||||
#[has_any_role("Role::Admin", type = "Role")]
|
#[has_any_role("Role::Admin", type = "Role")]
|
||||||
async fn patch_settings(
|
async fn patch_settings(
|
||||||
@ -214,7 +286,15 @@ async fn patch_settings(
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://localhost:8080/api/playout/config/1 --header 'Authorization: <TOKEN>'
|
/// #### ffplayout Config
|
||||||
|
///
|
||||||
|
/// **Get Config**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://localhost:8000/api/playout/config/1 -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Response is a JSON object from the ffplayout.yml
|
||||||
#[get("/playout/config/{id}")]
|
#[get("/playout/config/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn get_playout_config(
|
async fn get_playout_config(
|
||||||
@ -230,8 +310,12 @@ async fn get_playout_config(
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X PUT http://localhost:8080/api/playout/config/1 -H "Content-Type: application/json" \
|
/// **Update Config**
|
||||||
/// --data { <CONFIG DATA> } --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X PUT http://localhost:8000/api/playout/config/1 -H "Content-Type: application/json" \
|
||||||
|
/// -d { <CONFIG DATA> } -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[put("/playout/config/{id}")]
|
#[put("/playout/config/{id}")]
|
||||||
#[has_any_role("Role::Admin", type = "Role")]
|
#[has_any_role("Role::Admin", type = "Role")]
|
||||||
async fn update_playout_config(
|
async fn update_playout_config(
|
||||||
@ -255,8 +339,16 @@ async fn update_playout_config(
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://localhost:8080/api/presets/ --header 'Content-Type: application/json' \
|
/// #### Text Presets
|
||||||
/// --data '{"mail": "<MAIL>", "password": "<PASS>"}' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// Text presets are made for sending text messages to the ffplayout engine, to overlay them as a lower third.
|
||||||
|
///
|
||||||
|
/// **Get all Presets**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \
|
||||||
|
/// -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/presets/{id}")]
|
#[get("/presets/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn get_presets(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
async fn get_presets(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -267,10 +359,14 @@ async fn get_presets(id: web::Path<i64>) -> Result<impl Responder, ServiceError>
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X PUT http://localhost:8080/api/presets/1 --header 'Content-Type: application/json' \
|
/// **Update Preset**
|
||||||
/// --data '{"name": "<PRESET NAME>", "text": "<TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
|
///
|
||||||
/// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0}' \
|
/// ```BASH
|
||||||
/// --header 'Authorization: <TOKEN>'
|
/// curl -X PUT http://localhost:8000/api/presets/1 -H 'Content-Type: application/json' \
|
||||||
|
/// -d '{ "name": "<PRESET NAME>", "text": "<TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
|
||||||
|
/// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \
|
||||||
|
/// -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[put("/presets/{id}")]
|
#[put("/presets/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn update_preset(
|
async fn update_preset(
|
||||||
@ -284,10 +380,14 @@ async fn update_preset(
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/presets/ --header 'Content-Type: application/json' \
|
/// **Add new Preset**
|
||||||
/// --data '{"name": "<PRESET NAME>", "text": "TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
|
///
|
||||||
/// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0}}' \
|
/// ```BASH
|
||||||
/// --header 'Authorization: <TOKEN>'
|
/// curl -X POST http://localhost:8000/api/presets/ -H 'Content-Type: application/json' \
|
||||||
|
/// -d '{ "name": "<PRESET NAME>", "text": "TEXT>", "x": "<X>", "y": "<Y>", "fontsize": 24, \
|
||||||
|
/// "line_spacing": 4, "fontcolor": "#ffffff", "box": 1, "boxcolor": "#000000", "boxborderw": 4, "alpha": 1.0, "channel_id": 1 }' \
|
||||||
|
/// -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[post("/presets/")]
|
#[post("/presets/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn add_preset(data: web::Json<TextPreset>) -> Result<impl Responder, ServiceError> {
|
async fn add_preset(data: web::Json<TextPreset>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -298,21 +398,39 @@ async fn add_preset(data: web::Json<TextPreset>) -> Result<impl Responder, Servi
|
|||||||
Err(ServiceError::InternalServerError)
|
Err(ServiceError::InternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------------------------------
|
/// **Delete Preset**
|
||||||
/// ffplayout process controlling
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X DELETE http://localhost:8000/api/presets/1 -H 'Content-Type: application/json' \
|
||||||
|
/// -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
|
#[delete("/presets/{id}")]
|
||||||
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
|
async fn delete_preset(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||||
|
if db_delete_preset(&id).await.is_ok() {
|
||||||
|
return Ok("Delete preset Success");
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ServiceError::InternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### ffplayout controlling
|
||||||
///
|
///
|
||||||
/// here we communicate with the engine for:
|
/// here we communicate with the engine for:
|
||||||
/// - jump to last or next clip
|
/// - jump to last or next clip
|
||||||
/// - reset playlist state
|
/// - reset playlist state
|
||||||
/// - get infos about current, next, last clip
|
/// - get infos about current, next, last clip
|
||||||
/// - send text the the engine, for overlaying it (as lower third etc.)
|
/// - send text to the engine, for overlaying it (as lower third etc.)
|
||||||
/// ----------------------------------------------------------------------------
|
///
|
||||||
|
/// **Send Text to ffplayout**
|
||||||
/// curl -X POST http://localhost:8080/api/control/1/text/ \
|
///
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>' \
|
/// ```BASH
|
||||||
/// --data '{"text": "Hello from ffplayout", "x": "(w-text_w)/2", "y": "(h-text_h)/2", \
|
/// curl -X POST http://localhost:8000/api/control/1/text/ \
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>' \
|
||||||
|
/// -d '{"text": "Hello from ffplayout", "x": "(w-text_w)/2", "y": "(h-text_h)/2", \
|
||||||
/// "fontsize": "24", "line_spacing": "4", "fontcolor": "#ffffff", "box": "1", \
|
/// "fontsize": "24", "line_spacing": "4", "fontcolor": "#ffffff", "box": "1", \
|
||||||
/// "boxcolor": "#000000", "boxborderw": "4", "alpha": "1.0"}'
|
/// "boxcolor": "#000000", "boxborderw": "4", "alpha": "1.0"}'
|
||||||
|
/// ```
|
||||||
#[post("/control/{id}/text/")]
|
#[post("/control/{id}/text/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn send_text_message(
|
pub async fn send_text_message(
|
||||||
@ -325,41 +443,55 @@ pub async fn send_text_message(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/control/1/playout/next/
|
/// **Control Playout**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
#[post("/control/{id}/playout/next/")]
|
/// - next
|
||||||
|
/// - back
|
||||||
|
/// - reset
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/control/1/playout/next/ -H 'Content-Type: application/json'
|
||||||
|
/// -d '{ "command": "reset" }' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
|
#[post("/control/{id}/playout/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn jump_to_next(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
pub async fn control_playout(id: web::Path<i64>, control: web::Json<Process>) -> Result<impl Responder, ServiceError> {
|
||||||
match control_state(*id, "next".into()).await {
|
match control_state(*id, control.command.clone()).await {
|
||||||
Ok(res) => return Ok(res.text().await.unwrap_or_else(|_| "Success".into())),
|
Ok(res) => return Ok(res.text().await.unwrap_or_else(|_| "Success".into())),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/control/1/playout/back/
|
/// **Get current Clip**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
#[post("/control/{id}/playout/back/")]
|
/// ```BASH
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
/// curl -X GET http://localhost:8000/api/control/1/media/current
|
||||||
pub async fn jump_to_last(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
match control_state(*id, "back".into()).await {
|
/// ```
|
||||||
Ok(res) => return Ok(res.text().await.unwrap_or_else(|_| "Success".into())),
|
///
|
||||||
Err(e) => Err(e),
|
/// **Response:**
|
||||||
}
|
///
|
||||||
}
|
/// ```JSON
|
||||||
|
/// {
|
||||||
/// curl -X POST http://localhost:8080/api/control/1/playout/reset/
|
/// "jsonrpc": "2.0",
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
/// "result": {
|
||||||
#[post("/control/{id}/playout/reset/")]
|
/// "current_media": {
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
/// "category": "",
|
||||||
pub async fn reset_playout(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
/// "duration": 154.2,
|
||||||
match control_state(*id, "reset".into()).await {
|
/// "out": 154.2,
|
||||||
Ok(res) => return Ok(res.text().await.unwrap_or_else(|_| "Success".into())),
|
/// "seek": 0.0,
|
||||||
Err(e) => Err(e),
|
/// "source": "/opt/tv-media/clip.mp4"
|
||||||
}
|
/// },
|
||||||
}
|
/// "index": 39,
|
||||||
|
/// "play_mode": "playlist",
|
||||||
/// curl -X GET http://localhost:8080/api/control/1/media/current/
|
/// "played_sec": 67.80771999300123,
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
/// "remaining_sec": 86.39228000699876,
|
||||||
|
/// "start_sec": 24713.631999999998,
|
||||||
|
/// "start_time": "06:51:53.631"
|
||||||
|
/// },
|
||||||
|
/// "id": 1
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[get("/control/{id}/media/current")]
|
#[get("/control/{id}/media/current")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn media_current(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
pub async fn media_current(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -369,8 +501,11 @@ pub async fn media_current(id: web::Path<i64>) -> Result<impl Responder, Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://localhost:8080/api/control/1/media/next/
|
/// **Get next Clip**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://localhost:8000/api/control/1/media/next/ -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/control/{id}/media/next")]
|
#[get("/control/{id}/media/next")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn media_next(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
pub async fn media_next(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -380,8 +515,12 @@ pub async fn media_next(id: web::Path<i64>) -> Result<impl Responder, ServiceErr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://localhost:8080/api/control/1/media/last/
|
/// **Get last Clip**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://localhost:8000/api/control/1/media/last/
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/control/{id}/media/last")]
|
#[get("/control/{id}/media/last")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn media_last(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
pub async fn media_last(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||||
@ -391,9 +530,19 @@ pub async fn media_last(id: web::Path<i64>) -> Result<impl Responder, ServiceErr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://localhost:8080/api/control/1/process/
|
/// #### ffplayout Process Control
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// Control ffplayout process, like:
|
||||||
|
/// - start
|
||||||
|
/// - stop
|
||||||
|
/// - restart
|
||||||
|
/// - status
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/control/1/process/
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
/// -d '{"command": "start"}'
|
/// -d '{"command": "start"}'
|
||||||
|
/// ```
|
||||||
#[post("/control/{id}/process/")]
|
#[post("/control/{id}/process/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn process_control(
|
pub async fn process_control(
|
||||||
@ -403,13 +552,14 @@ pub async fn process_control(
|
|||||||
control_service(*id, &proc.command).await
|
control_service(*id, &proc.command).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------------------------------
|
/// #### ffplayout Playlist Operations
|
||||||
/// ffplayout playlist operations
|
|
||||||
///
|
///
|
||||||
/// ----------------------------------------------------------------------------
|
/// **Get playlist**
|
||||||
|
///
|
||||||
/// curl -X GET http://localhost:8080/api/playlist/1?date=2022-06-20
|
/// ```BASH
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
/// curl -X GET http://localhost:8000/api/playlist/1?date=2022-06-20
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/playlist/{id}")]
|
#[get("/playlist/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn get_playlist(
|
pub async fn get_playlist(
|
||||||
@ -422,9 +572,13 @@ pub async fn get_playlist(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/playlist/1/
|
/// **Save playlist**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/playlist/1/
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
/// -- data "{<JSON playlist data>}"
|
/// -- data "{<JSON playlist data>}"
|
||||||
|
/// ```
|
||||||
#[post("/playlist/{id}/")]
|
#[post("/playlist/{id}/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn save_playlist(
|
pub async fn save_playlist(
|
||||||
@ -437,8 +591,14 @@ pub async fn save_playlist(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X GET http://localhost:8080/api/playlist/1/generate/2022-06-20
|
/// **Generate Playlist**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// A new playlist will be generated and response.
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X GET http://localhost:8000/api/playlist/1/generate/2022-06-20
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/playlist/{id}/generate/{date}")]
|
#[get("/playlist/{id}/generate/{date}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn gen_playlist(
|
pub async fn gen_playlist(
|
||||||
@ -450,8 +610,12 @@ pub async fn gen_playlist(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X DELETE http://localhost:8080/api/playlist/1/2022-06-20
|
/// **Delete Playlist**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X DELETE http://localhost:8000/api/playlist/1/2022-06-20
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[delete("/playlist/{id}/{date}")]
|
#[delete("/playlist/{id}/{date}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn del_playlist(
|
pub async fn del_playlist(
|
||||||
@ -463,11 +627,14 @@ pub async fn del_playlist(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------------------------------
|
/// ### Log file
|
||||||
/// read log file
|
|
||||||
///
|
///
|
||||||
/// ----------------------------------------------------------------------------
|
/// **Read Log Life**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X Get http://localhost:8000/api/log/1
|
||||||
|
/// -H 'Content-Type: application/json' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[get("/log/{id}")]
|
#[get("/log/{id}")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn get_log(
|
pub async fn get_log(
|
||||||
@ -477,13 +644,14 @@ pub async fn get_log(
|
|||||||
read_log_file(&id, &log.date).await
|
read_log_file(&id, &log.date).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----------------------------------------------------------------------------
|
/// ### File Operations
|
||||||
/// file operations
|
|
||||||
///
|
///
|
||||||
/// ----------------------------------------------------------------------------
|
/// **Get File/Folder List**
|
||||||
|
///
|
||||||
/// curl -X GET http://localhost:8080/api/file/1/browse/
|
/// ```BASH
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
/// curl -X POST http://localhost:8000/api/file/1/browse/ -H 'Content-Type: application/json'
|
||||||
|
/// -d '{ "source": "/" }' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[post("/file/{id}/browse/")]
|
#[post("/file/{id}/browse/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn file_browser(
|
pub async fn file_browser(
|
||||||
@ -496,9 +664,12 @@ pub async fn file_browser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/file/1/create-folder/
|
/// **Create Folder**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
/// -d '{"source": "<FOLDER PATH>"}'
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/file/1/create-folder/ -H 'Content-Type: application/json'
|
||||||
|
/// -d '{"source": "<FOLDER PATH>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[post("/file/{id}/create-folder/")]
|
#[post("/file/{id}/create-folder/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn add_dir(
|
pub async fn add_dir(
|
||||||
@ -508,9 +679,12 @@ pub async fn add_dir(
|
|||||||
create_directory(*id, &data.into_inner()).await
|
create_directory(*id, &data.into_inner()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/file/1/move/
|
/// **Rename File**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
/// -d '{"source": "<SOURCE>", "target": "<TARGET>"}'
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/file/1/rename/ -H 'Content-Type: application/json'
|
||||||
|
/// -d '{"source": "<SOURCE>", "target": "<TARGET>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[post("/file/{id}/rename/")]
|
#[post("/file/{id}/rename/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn move_rename(
|
pub async fn move_rename(
|
||||||
@ -523,9 +697,12 @@ pub async fn move_rename(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// curl -X POST http://localhost:8080/api/file/1/remove/
|
/// **Remove File/Folder**
|
||||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
///
|
||||||
/// -d '{"source": "<SOURCE>"}'
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/file/1/remove/ -H 'Content-Type: application/json'
|
||||||
|
/// -d '{"source": "<SOURCE>"}' -H 'Authorization: <TOKEN>'
|
||||||
|
/// ```
|
||||||
#[post("/file/{id}/remove/")]
|
#[post("/file/{id}/remove/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
pub async fn remove(
|
pub async fn remove(
|
||||||
@ -538,6 +715,12 @@ pub async fn remove(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// **Upload File**
|
||||||
|
///
|
||||||
|
/// ```BASH
|
||||||
|
/// curl -X POST http://localhost:8000/api/file/1/upload/ -H 'Authorization: <TOKEN>'
|
||||||
|
/// -F "file=@file.mp4"
|
||||||
|
/// ```
|
||||||
#[put("/file/{id}/upload/")]
|
#[put("/file/{id}/upload/")]
|
||||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||||
async fn save_file(
|
async fn save_file(
|
||||||
|
23
scripts/gen_doc.sh
Executable file
23
scripts/gen_doc.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
input=$1
|
||||||
|
output=$2
|
||||||
|
print_block=false
|
||||||
|
|
||||||
|
if [ ! "$input" ] || [ ! "$output" ]; then
|
||||||
|
echo "Run script like: den_doc.sh input.rs output.md"
|
||||||
|
fi
|
||||||
|
|
||||||
|
:> "$output"
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if echo $line | grep -Eq "^///"; then
|
||||||
|
echo "$line" | sed -E "s|^/// ?||g" >> "$output"
|
||||||
|
print_block=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$line" ] && [[ $print_block == true ]]; then
|
||||||
|
echo "" >> "$output"
|
||||||
|
print_block=false
|
||||||
|
fi
|
||||||
|
done < "$input"
|
Loading…
Reference in New Issue
Block a user