wrolpi/modules/videos/api.py
2022-01-31 21:30:07 -07:00

116 lines
4 KiB
Python

import asyncio
from functools import wraps
from http import HTTPStatus
from sanic import Blueprint, response
from sanic.request import Request
from sanic_ext import validate
from sanic_ext.extensions.openapi import openapi
from wrolpi.common import create_websocket_feed, get_sanic_url, \
wrol_mode_check
from wrolpi.common import logger
from wrolpi.root_api import add_blueprint, json_response
from wrolpi.schema import JSONErrorResponse
from .channel import lib as channel_lib
from .channel.api import channel_bp
from .lib import _refresh_videos, get_statistics
from .schema import StreamResponse, \
FavoriteRequest, FavoriteResponse, VideosStatisticsResponse
from .video import lib as video_lib
from .video.api import video_bp
content_bp = Blueprint('VideoContent', '/api/videos')
bp = Blueprint('Videos', '/api/videos').group(
content_bp, # view and manage video content and settings
channel_bp, # view and manage channels
video_bp, # view videos
)
add_blueprint(bp)
logger = logger.getChild(__name__)
refresh_queue, refresh_event = create_websocket_feed('refresh', '/feeds/refresh', content_bp)
@content_bp.post('/refresh')
@content_bp.post('/refresh/<link:str>')
@openapi.description('Search for videos that have previously been downloaded and stored.')
@openapi.response(HTTPStatus.OK, StreamResponse)
@openapi.response(HTTPStatus.BAD_REQUEST, JSONErrorResponse)
@wrol_mode_check
async def refresh(_, link: str = None):
refresh_logger = logger.getChild('refresh')
stream_url = get_sanic_url(scheme='ws', path='/api/videos/feeds/refresh')
# Only one refresh can run at a time
if refresh_event.is_set():
return response.json({'error': 'Refresh already running', 'stream_url': stream_url}, HTTPStatus.CONFLICT)
refresh_event.set()
async def do_refresh():
try:
refresh_logger.info('refresh started')
channel_links = [link] if link else None
await refresh_videos(channel_links)
refresh_logger.info('refresh complete')
except Exception:
raise
finally:
refresh_event.clear()
coro = do_refresh()
asyncio.ensure_future(coro)
refresh_logger.debug('do_refresh scheduled')
return response.json({'code': 'stream-started', 'stream_url': stream_url})
download_queue, download_event = create_websocket_feed('download', '/feeds/download', content_bp)
@content_bp.post('/download')
@content_bp.post('/download/<link:str>')
@openapi.description('Update channel catalogs, download any missing videos')
@openapi.response(HTTPStatus.OK, StreamResponse)
@openapi.response(HTTPStatus.BAD_REQUEST, JSONErrorResponse)
@wrol_mode_check
def download(_, link: str = None):
download_logger = logger.getChild('download')
stream_url = get_sanic_url(scheme='ws', path='/api/videos/feeds/download')
# Only one download can run at a time
if download_event.is_set():
return response.json({'error': 'download already running', 'stream_url': stream_url}, HTTPStatus.CONFLICT)
if refresh_event.is_set():
return response.json({'error': 'Refresh is running. Cannot download.'})
channel_lib.download_channel(link)
download_logger.debug('do_download scheduled')
return response.json({'code': 'stream-started', 'stream_url': stream_url})
@wraps(_refresh_videos)
async def refresh_videos(channel_links: list = None):
return _refresh_videos(channel_links=channel_links)
@content_bp.post('/favorite')
@openapi.description('Toggle the favorite flag on a video')
@validate(FavoriteRequest)
@openapi.response(HTTPStatus.OK, FavoriteResponse)
@openapi.response(HTTPStatus.BAD_REQUEST, JSONErrorResponse)
async def favorite(_: Request, body: FavoriteRequest):
_favorite = video_lib.set_video_favorite(body.video_id, body.favorite)
ret = {'video_id': body.video_id, 'favorite': _favorite}
return json_response(ret, HTTPStatus.OK)
@content_bp.get('/statistics')
@openapi.response(HTTPStatus.OK, VideosStatisticsResponse)
async def statistics(_: Request):
ret = await get_statistics()
return json_response(ret, HTTPStatus.OK)