Added play-pause icons swap.

Signed-off-by: Pavel Kirilin <win10@list.ru>
This commit is contained in:
2024-05-02 04:38:29 +02:00
parent 4d0b1e1c86
commit 24937da840
6 changed files with 186 additions and 21 deletions

View File

@ -1,12 +1,13 @@
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from fastapi import FastAPI, HTTPException, Request, Response
import uvicorn
from fastapi import FastAPI
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from typer import Typer, Argument from typer import Argument, Typer
import uvicorn
from anime.routes import router from anime.routes import router
from starlette.middleware.base import BaseHTTPMiddleware
CURRENT_DIR = Path(__file__).parent CURRENT_DIR = Path(__file__).parent
STATIC_DIR = CURRENT_DIR / "static" STATIC_DIR = CURRENT_DIR / "static"

View File

@ -1,7 +1,8 @@
import os import os
from pathlib import Path
import shutil import shutil
import subprocess import subprocess
from pathlib import Path
from fastapi import APIRouter, HTTPException, Request from fastapi import APIRouter, HTTPException, Request
from anime.dtos import KillRequest, PlayerOffsetRequest from anime.dtos import KillRequest, PlayerOffsetRequest
@ -10,6 +11,16 @@ CWD = Path.cwd()
router = APIRouter() router = APIRouter()
def is_pid_alive(pid: int) -> bool:
if pid:
try:
os.kill(pid, 0)
except OSError:
return False
else:
return True
@router.get("/can-start-watching") @router.get("/can-start-watching")
def can_start_watching(request: Request) -> None: def can_start_watching(request: Request) -> None:
if not request.app.state.anime_dir: if not request.app.state.anime_dir:
@ -27,12 +38,7 @@ def start_watching(request: Request) -> None:
anime_dir = request.app.state.anime_dir anime_dir = request.app.state.anime_dir
if not anime_dir: if not anime_dir:
raise HTTPException(status_code=400, detail="Anime directory is not set") raise HTTPException(status_code=400, detail="Anime directory is not set")
if request.app.state.pid: if request.app.state.pid and is_pid_alive(request.app.state.pid):
try:
os.kill(request.app.state.pid, 0)
except OSError:
pass
else:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
detail="Awatch is already running", detail="Awatch is already running",
@ -75,3 +81,24 @@ async def play_pause() -> None:
) )
subprocess.run([playerctl, "play-pause"], check=False) subprocess.run([playerctl, "play-pause"], check=False)
@router.get("/player/playing")
def player_state(request: Request):
playerctl = shutil.which("playerctl")
if playerctl is None:
raise HTTPException(
status_code=500,
detail="playerctl command is not available",
)
status_cmd = subprocess.Popen([playerctl, "status"], stdout=subprocess.PIPE)
status_cmd.wait()
current_state = status_cmd.stdout.read().decode("utf-8").strip().lower()
if (
request.app.state.pid
and is_pid_alive(request.app.state.pid)
and current_state == "playing"
):
return {"playing": True}
return {"playing": False}

View File

@ -1,7 +1,9 @@
<script setup> <script setup>
import { ActionBar, ActionBarButton } from 'vant'; import { ActionBar, ActionBarButton } from 'vant';
import { postRequest } from '@/utils' import { postRequest } from '@/utils'
import { ref } from 'vue'
const is_playing = ref(false);
async function offsetRequest(offset, forward) { async function offsetRequest(offset, forward) {
await postRequest(`/api/player/offset`, { await postRequest(`/api/player/offset`, {
@ -12,16 +14,28 @@ async function offsetRequest(offset, forward) {
async function playPauseRequest() { async function playPauseRequest() {
await postRequest(`/api/player/play-pause`) await postRequest(`/api/player/play-pause`)
update_state()
} }
function update_state() {
fetch('/api/player/playing').then((response) => {
if (response.ok) {
response.json().then((resp_json) => {
is_playing.value = resp_json.playing
})
}
})
}
update_state()
</script> </script>
<template> <template>
<ActionBar> <ActionBar>
<ActionBarButton icon="arrow-double-left" @click="offsetRequest(90, false)"></ActionBarButton> <ActionBarButton icon="arrow-double-left" @click="offsetRequest(85, false)"></ActionBarButton>
<ActionBarButton icon="arrow-left" @click="offsetRequest(10, false)"></ActionBarButton> <ActionBarButton icon="arrow-left" @click="offsetRequest(10, false)"></ActionBarButton>
<ActionBarButton icon="play" @click="playPauseRequest()"></ActionBarButton> <ActionBarButton :icon="is_playing ? 'pause' : 'play'" @click="playPauseRequest()"></ActionBarButton>
<ActionBarButton icon="arrow" @click="offsetRequest(10, true)"></ActionBarButton> <ActionBarButton icon="arrow" @click="offsetRequest(10, true)"></ActionBarButton>
<ActionBarButton icon="arrow-double-right" @click="offsetRequest(90, true)"></ActionBarButton> <ActionBarButton icon="arrow-double-right" @click="offsetRequest(85, true)"></ActionBarButton>
</ActionBar> </ActionBar>
</template> </template>

View File

@ -17,14 +17,14 @@ async function kill(...names) {
async function startWatching() { async function startWatching() {
await postRequest("/api/start-watching") await postRequest("/api/start-watching")
} }
</script> </script>
<template> <template>
<Space fill direction="vertical" :size="20"> <Space fill direction="vertical" :size="20">
<Button type="warning" round size="large" @click="kill('mpv')">Убить MPV</Button> <Button type="warning" round size="large" @click="kill('mpv')">Убить MPV</Button>
<Button type="danger" round size="large" @click="kill('awatch', 'mpv')">Убить awatch</Button> <Button type="danger" round size="large" @click="kill('awatch', 'mpv')">Убить awatch</Button>
<Button type="primary" round size="large" :disabled="!can_watch" @click="startWatching">Начать потребление анимы</Button> <Button type="primary" round size="large" :disabled="!can_watch" @click="startWatching">Начать потребление
анимы</Button>
</Space> </Space>
<PlayerComponent /> <PlayerComponent />
</template> </template>

121
poetry.lock generated
View File

@ -31,6 +31,50 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (>=0.23)"] trio = ["trio (>=0.23)"]
[[package]]
name = "black"
version = "24.4.2"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
files = [
{file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
{file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
{file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
{file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
{file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
{file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
{file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
{file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
{file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
{file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
{file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
{file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
{file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
{file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
{file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
{file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
{file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
{file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
{file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
{file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
{file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
{file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
]
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0"
platformdirs = ">=2"
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]] [[package]]
name = "click" name = "click"
version = "8.1.7" version = "8.1.7"
@ -180,6 +224,55 @@ files = [
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
] ]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "24.0"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
]
[[package]]
name = "pathspec"
version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
python-versions = ">=3.8"
files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
[[package]]
name = "platformdirs"
version = "4.2.1"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.8"
files = [
{file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"},
{file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"},
]
[package.extras]
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
type = ["mypy (>=1.8)"]
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "2.7.1" version = "2.7.1"
@ -397,6 +490,32 @@ pygments = ">=2.13.0,<3.0.0"
[package.extras] [package.extras]
jupyter = ["ipywidgets (>=7.5.1,<9)"] jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "ruff"
version = "0.4.2"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.4.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d14dc8953f8af7e003a485ef560bbefa5f8cc1ad994eebb5b12136049bbccc5"},
{file = "ruff-0.4.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:24016ed18db3dc9786af103ff49c03bdf408ea253f3cb9e3638f39ac9cf2d483"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2e06459042ac841ed510196c350ba35a9b24a643e23db60d79b2db92af0c2b"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3afabaf7ba8e9c485a14ad8f4122feff6b2b93cc53cd4dad2fd24ae35112d5c5"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:799eb468ea6bc54b95527143a4ceaf970d5aa3613050c6cff54c85fda3fde480"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ec4ba9436a51527fb6931a8839af4c36a5481f8c19e8f5e42c2f7ad3a49f5069"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a2243f8f434e487c2a010c7252150b1fdf019035130f41b77626f5655c9ca22"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8772130a063f3eebdf7095da00c0b9898bd1774c43b336272c3e98667d4fb8fa"},
{file = "ruff-0.4.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ab165ef5d72392b4ebb85a8b0fbd321f69832a632e07a74794c0e598e7a8376"},
{file = "ruff-0.4.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1f32cadf44c2020e75e0c56c3408ed1d32c024766bd41aedef92aa3ca28eef68"},
{file = "ruff-0.4.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:22e306bf15e09af45ca812bc42fa59b628646fa7c26072555f278994890bc7ac"},
{file = "ruff-0.4.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:82986bb77ad83a1719c90b9528a9dd663c9206f7c0ab69282af8223566a0c34e"},
{file = "ruff-0.4.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:652e4ba553e421a6dc2a6d4868bc3b3881311702633eb3672f9f244ded8908cd"},
{file = "ruff-0.4.2-py3-none-win32.whl", hash = "sha256:7891ee376770ac094da3ad40c116258a381b86c7352552788377c6eb16d784fe"},
{file = "ruff-0.4.2-py3-none-win_amd64.whl", hash = "sha256:5ec481661fb2fd88a5d6cf1f83403d388ec90f9daaa36e40e2c003de66751798"},
{file = "ruff-0.4.2-py3-none-win_arm64.whl", hash = "sha256:cbd1e87c71bca14792948c4ccb51ee61c3296e164019d2d484f3eaa2d360dfaf"},
{file = "ruff-0.4.2.tar.gz", hash = "sha256:33bcc160aee2520664bc0859cfeaebc84bb7323becff3f303b8f1f2d81cb4edc"},
]
[[package]] [[package]]
name = "shellingham" name = "shellingham"
version = "1.5.4" version = "1.5.4"
@ -704,4 +823,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "393201687c83f5df988de3af661b5887843efb8e03128761f5ba5174b7331d69" content-hash = "f9e9fd7090b241c75ccfdafcf03212d386197cfc54664a7055ec40446a970232"

View File

@ -19,6 +19,10 @@ anime = "anime.__main__:main"
generate-setup-file = false generate-setup-file = false
script = "build.py" script = "build.py"
[tool.poetry.group.dev.dependencies]
black = "^24.4.2"
ruff = "^0.4.2"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"