Merge pull request #206 from arabcoders/dev
Improve history status display
This commit is contained in:
commit
9427f7b2a0
5 changed files with 81 additions and 50 deletions
14
API.md
14
API.md
|
|
@ -171,21 +171,19 @@ or an error:
|
|||
**Purpose**: **(Quick Add)** Add a single URL to the download queue via GET.
|
||||
|
||||
**Query Parameters**:
|
||||
- `?url=<video-url>`
|
||||
- `url=<video-url>`
|
||||
- `preset=<preset-name>`
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"status": "(ok|error)",
|
||||
}
|
||||
```
|
||||
or an error:
|
||||
```json
|
||||
{
|
||||
"error": "text"
|
||||
"status": true|false, # true if added to the queue. false otherwise.
|
||||
"message": "..." # the response message.
|
||||
}
|
||||
```
|
||||
|
||||
- If `url` is missing, returns `400 Bad Request`.
|
||||
- If `preset` is set and not found, returns `404 Not Found`.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -119,8 +119,15 @@ Change the the variable `url` and `preset` variables to match your YTPTube insta
|
|||
|
||||
### iOS Shortcuts
|
||||
|
||||
not yet available.
|
||||
You can download [Add To YTPTube](https://www.icloud.com/shortcuts/18b8f70666a04a06aed09424f97ce951) shortcut and use it to send links to your YTPTube instance.
|
||||
You have to edit the shortcut and replace the following:
|
||||
|
||||
- `https://ytp.example.org` with your YTPTube instance.
|
||||
- `username:password` replace this with your own username & password or leave it empty if you don't have authentication enabled.
|
||||
|
||||
This shortcut is powerful, as it's allow you to select your preset on the fly pulled directly from your instance.
|
||||
Combined with the new and powerful presets system, you could add presets for specific websites that need cookies,
|
||||
and use that preset to download directly from your iOS device.
|
||||
|
||||
## Running behind a reverse proxy
|
||||
|
||||
|
|
|
|||
|
|
@ -614,19 +614,24 @@ class HttpAPI(Common):
|
|||
|
||||
preset = request.query.get("preset")
|
||||
if preset:
|
||||
exists = Presets.get_instance().get(preset)
|
||||
exists = Presets.get_instance().get(name=preset)
|
||||
if not exists:
|
||||
return web.json_response(
|
||||
data={"error": f"Preset '{preset}' does not exist."}, status=web.HTTPBadRequest.status_code
|
||||
data={"status": False, "message": f"Preset '{preset}' does not exist."},
|
||||
status=web.HTTPBadRequest.status_code,
|
||||
)
|
||||
data["preset"] = preset
|
||||
|
||||
try:
|
||||
status = await self.add(**self.format_item(data))
|
||||
except ValueError as e:
|
||||
return web.json_response(data={"error": str(e)}, status=web.HTTPBadRequest.status_code)
|
||||
return web.json_response(data={"status": False, "message": str(e)}, status=web.HTTPBadRequest.status_code)
|
||||
|
||||
return web.json_response(data=status, status=web.HTTPOk.status_code, dumps=self.encoder.encode)
|
||||
return web.json_response(
|
||||
data={"status": status.get("status") == "ok", "message": status.get("msg", "URL added")},
|
||||
status=web.HTTPOk.status_code,
|
||||
dumps=self.encoder.encode,
|
||||
)
|
||||
|
||||
@route("POST", "api/history")
|
||||
async def history_item_add(self, request: Request) -> Response:
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ class Presets(metaclass=Singleton):
|
|||
|
||||
try:
|
||||
with open(self._file, "w") as f:
|
||||
json.dump(obj=[preset.serialize() for preset in presets], fp=f, indent=4)
|
||||
json.dump(obj=[preset.serialize() for preset in presets if preset.default is False], fp=f, indent=4)
|
||||
|
||||
LOG.info(f"Presets saved to '{self._file}'.")
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@
|
|||
</div>
|
||||
|
||||
<div class="card-header-icon">
|
||||
<a v-if="hideThumbnail && 'finished' === item.status" href="#" @click.prevent="playVideo(item)"
|
||||
v-tooltip="'Play video.'">
|
||||
<span class="icon"><i class="fa-solid fa-play" /></span>
|
||||
</a>
|
||||
<a :href="item.url" class="has-text-primary" v-tooltip="'Copy url.'" @click.prevent="copyText(item.url)">
|
||||
<span class="icon"><i class="fa-solid fa-copy" /></span>
|
||||
</a>
|
||||
|
|
@ -118,11 +122,6 @@
|
|||
</div>
|
||||
<div class="card-content">
|
||||
<div class="columns is-mobile is-multiline">
|
||||
<div class="column is-12" v-if="item.live_in">
|
||||
<span class="has-text-info">
|
||||
Live stream is scheduled to start at {{ moment(item.live_in).format() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-12" v-if="item.error">
|
||||
<span class="has-text-danger">{{ item.error }}</span>
|
||||
</div>
|
||||
|
|
@ -130,23 +129,16 @@
|
|||
<span class="has-text-danger">{{ item.msg }}</span>
|
||||
</div>
|
||||
<div class="column is-half-mobile has-text-centered is-text-overflow">
|
||||
<span v-if="!item.live_in && !item.is_live">
|
||||
<span class="icon-text">
|
||||
<span class="icon"
|
||||
:class="{ 'has-text-success': item.status === 'finished', 'has-text-danger': item.status !== 'finished' }">
|
||||
<i :class="setIcon(item)" />
|
||||
</span>
|
||||
<span v-if="item.status == 'finished' && item.is_live">Live Ended</span>
|
||||
<span v-else>{{ ucFirst(item.status) }}</span>
|
||||
</span>
|
||||
<span class="icon-text">
|
||||
<span class="icon" :class="setIconColor(item)"><i :class="setIcon(item)" /></span>
|
||||
<span>{{ setStatus(item) }}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
<span class="icon-text">
|
||||
<span class="icon has-text-info">
|
||||
<i class="fa-solid fa-calendar" />
|
||||
</span>
|
||||
<span>Live</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-half-mobile has-text-centered is-text-overflow"
|
||||
v-if="item.live_in && 'not_live' === item.status">
|
||||
<span :date-datetime="item.live_in" class="user-hint"
|
||||
v-tooltip="'Starts at: ' + moment(item.live_in).format('YYYY-M-DD H:mm Z')">
|
||||
{{ moment(item.live_in).fromNow() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-half-mobile has-text-centered is-text-overflow">
|
||||
|
|
@ -155,13 +147,6 @@
|
|||
{{ moment(item.datetime).fromNow() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-half-mobile has-text-centered is-text-overflow"
|
||||
v-if="item.live_in && item.status != 'finished'">
|
||||
<span :date-datetime="item.live_in"
|
||||
v-tooltip="'Starts at: ' + moment(item.live_in).format('YYYY-M-DD H:mm Z')">
|
||||
{{ moment(item.live_in).fromNow() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column is-half-mobile has-text-centered is-text-overflow" v-if="item.file_size">
|
||||
{{ formatBytes(item.file_size) }}
|
||||
</div>
|
||||
|
|
@ -400,25 +385,61 @@ const clearIncomplete = () => {
|
|||
}
|
||||
|
||||
const setIcon = item => {
|
||||
if (item.status === 'finished' && item.is_live) {
|
||||
return 'fa-solid fa-globe'
|
||||
if ('finished' === item.status) {
|
||||
return item.is_live ? 'fa-solid fa-globe' : 'fa-solid fa-circle-check'
|
||||
}
|
||||
|
||||
if (item.status === 'finished') {
|
||||
return 'fa-solid fa-circle-check'
|
||||
}
|
||||
|
||||
if (item.status === 'error') {
|
||||
if ('error' === item.status) {
|
||||
return 'fa-solid fa-circle-xmark'
|
||||
}
|
||||
|
||||
if (item.status === 'cancelled') {
|
||||
if ('cancelled' === item.status) {
|
||||
return 'fa-solid fa-eject'
|
||||
}
|
||||
|
||||
if ('not_live' === item.status) {
|
||||
return 'fa-solid fa-hourglass-half fa-spin'
|
||||
}
|
||||
|
||||
return 'fa-solid fa-circle'
|
||||
}
|
||||
|
||||
const setIconColor = item => {
|
||||
if (item.status === 'finished') {
|
||||
return 'has-text-success'
|
||||
}
|
||||
|
||||
if ('not_live' === item.status) {
|
||||
return 'has-text-info'
|
||||
}
|
||||
|
||||
if ('cancelled' === item.status) {
|
||||
return 'has-text-warning'
|
||||
}
|
||||
|
||||
return 'has-text-danger'
|
||||
}
|
||||
|
||||
const setStatus = item => {
|
||||
if ('finished' === item.status) {
|
||||
return item.is_live ? 'Live Ended' : 'Completed'
|
||||
}
|
||||
|
||||
if ('error' === item.status) {
|
||||
return 'Error'
|
||||
}
|
||||
|
||||
if ('cancelled' === item.status) {
|
||||
return 'User Cancelled'
|
||||
}
|
||||
|
||||
if ('not_live' === item.status) {
|
||||
return 'Live Stream'
|
||||
}
|
||||
|
||||
return item.status
|
||||
}
|
||||
|
||||
const requeueIncomplete = () => {
|
||||
if (false === confirm('Are you sure you want to re-queue all incomplete downloads?')) {
|
||||
return false
|
||||
|
|
|
|||
Loading…
Reference in a new issue