release: 1.6.0-alpha

This commit is contained in:
acgnhik 2022-02-26 15:58:54 +08:00
parent 93d93888e4
commit 5c9887a2a8
12 changed files with 66 additions and 5 deletions

View File

@ -1,5 +1,9 @@
# 更新日志
## 1.6.0-alpha
- REST API 支持获取正在录制的 flv 文件的路径和元数据
## 1.5.0
- 支持设置日志文件存放位置

View File

@ -1,4 +1,4 @@
__prog__ = 'blrec'
__version__ = '1.5.0'
__version__ = '1.6.0-alpha'
__github__ = 'https://github.com/acgnhiki/blrec'

View File

@ -7,6 +7,7 @@ import attr
import psutil
from . import __prog__, __version__
from .flv.data_analyser import MetaData
from .disk_space import SpaceMonitor, SpaceReclaimer
from .bili.helpers import ensure_room_id
from .task import (
@ -201,6 +202,9 @@ class Application:
def get_task_param(self, room_id: int) -> TaskParam:
return self._task_manager.get_task_param(room_id)
def get_task_metadata(self, room_id: int) -> Optional[MetaData]:
return self._task_manager.get_task_metadata(room_id)
def get_task_video_file_details(
self, room_id: int
) -> Iterator[VideoFileDetail]:

View File

@ -14,6 +14,7 @@ from .raw_danmaku_receiver import RawDanmakuReceiver
from .raw_danmaku_dumper import RawDanmakuDumper, RawDanmakuDumperEventListener
from .stream_recorder import StreamRecorder, StreamRecorderEventListener
from ..event.event_emitter import EventListener, EventEmitter
from ..flv.data_analyser import MetaData
from ..bili.live import Live
from ..bili.models import RoomInfo
from ..bili.danmaku_client import DanmakuClient
@ -274,6 +275,14 @@ class Recorder(
def duration_limit(self, value: int) -> None:
self._stream_recorder.duration_limit = value
@property
def recording_path(self) -> Optional[str]:
return self._stream_recorder.recording_path
@property
def metadata(self) -> Optional[MetaData]:
return self._stream_recorder.metadata
async def _do_start(self) -> None:
self._live_monitor.add_listener(self)
self._danmaku_dumper.add_listener(self)

View File

@ -38,6 +38,7 @@ from .statistics import StatisticsCalculator
from ..event.event_emitter import EventListener, EventEmitter
from ..bili.live import Live
from ..bili.typing import QualityNumber
from ..flv.data_analyser import MetaData
from ..flv.stream_processor import StreamProcessor, BaseOutputFileManager
from ..utils.mixins import AsyncCooperationMix, AsyncStoppableMixin
from ..path import escape_path
@ -186,6 +187,13 @@ class StreamRecorder(
def recording_path(self) -> Optional[str]:
return self._file_manager.curr_path
@property
def metadata(self) -> Optional[MetaData]:
if self._stream_processor is not None:
return self._stream_processor.metadata
else:
return None
def has_file(self) -> bool:
return self._file_manager.has_file()

View File

@ -14,7 +14,7 @@ from .models import (
from .common import Resolution, is_audio_tag, is_script_tag, is_video_tag
__all__ = 'DataAnalyser',
__all__ = 'DataAnalyser', 'MetaData', 'KeyFrames'
@attr.s(auto_attribs=True, slots=True, frozen=True, kw_only=True)

View File

@ -14,7 +14,7 @@ from rx.subject import Subject
from rx.core import Observable
from .models import FlvHeader, FlvTag, ScriptTag, VideoTag, AudioTag
from .data_analyser import DataAnalyser
from .data_analyser import DataAnalyser, MetaData
from .stream_cutter import StreamCutter
from .limit_checker import LimitChecker
from .parameters_checker import ParametersChecker
@ -117,6 +117,16 @@ class StreamProcessor:
for point in self._join_points:
yield point
@property
def metadata(self) -> Optional[MetaData]:
if not self._analyse_data:
return None
try:
return self._data_analyser.make_metadata()
except Exception as e:
logger.debug(f'Failed to make metadata data, due to: {repr(e)}')
return None
@property
def size_updates(self) -> Observable:
return self._size_updates

View File

@ -1,5 +1,4 @@
from __future__ import annotations
import os
import asyncio
from typing import Optional, TYPE_CHECKING, cast

View File

@ -29,6 +29,7 @@ class TaskStatus:
danmu_count: int # Number of Danmu in total
danmu_rate: float # Number of Danmu per minutes
real_quality_number: QualityNumber
recording_path: Optional[str] = None
postprocessor_status: PostprocessorStatus = PostprocessorStatus.WAITING
postprocessing_path: Optional[str] = None
postprocessing_progress: Optional[Progress] = None

View File

@ -21,6 +21,7 @@ from ..core import Recorder
from ..postprocess import Postprocessor, PostprocessorStatus, DeleteStrategy
from ..postprocess.remuxer import RemuxProgress
from ..flv.metadata_injector import InjectProgress
from ..flv.data_analyser import MetaData
from ..event.event_submitters import (
LiveEventSubmitter, RecorderEventSubmitter, PostprocessorEventSubmitter
)
@ -132,6 +133,7 @@ class RecordTask:
danmu_count=self._recorder.danmu_count,
danmu_rate=self._recorder.danmu_rate,
real_quality_number=self._recorder.real_quality_number,
recording_path=self.recording_path,
postprocessor_status=self._postprocessor.status,
postprocessing_path=self._postprocessor.postprocessing_path,
postprocessing_progress=(
@ -349,6 +351,14 @@ class RecordTask:
def duration_limit(self, value: int) -> None:
self._recorder.duration_limit = value
@property
def recording_path(self) -> Optional[str]:
return self._recorder.recording_path
@property
def metadata(self) -> Optional[MetaData]:
return self._recorder.metadata
@property
def remux_to_mp4(self) -> bool:
return self._postprocessor.remux_to_mp4

View File

@ -1,10 +1,11 @@
from __future__ import annotations
import asyncio
from typing import Dict, Iterator, TYPE_CHECKING
from typing import Dict, Iterator, Optional, TYPE_CHECKING
from .task import RecordTask
from .models import TaskData, TaskParam, VideoFileDetail, DanmakuFileDetail
from ..flv.data_analyser import MetaData
from ..exception import NotFoundError
if TYPE_CHECKING:
from ..setting import SettingsManager
@ -154,6 +155,10 @@ class RecordTaskManager:
task = self._get_task(room_id)
return self._make_task_param(task)
def get_task_metadata(self, room_id: int) -> Optional[MetaData]:
task = self._get_task(room_id)
return task.metadata
def get_task_video_file_details(
self, room_id: int
) -> Iterator[VideoFileDetail]:

View File

@ -53,6 +53,17 @@ async def get_task_param(room_id: int) -> Dict[str, Any]:
return attr.asdict(app.get_task_param(room_id))
@router.get(
'/{room_id}/metadata',
responses={**not_found_responses},
)
async def get_task_metadata(room_id: int) -> Dict[str, Any]:
metadata = app.get_task_metadata(room_id)
if not metadata:
return {}
return attr.asdict(metadata)
@router.get(
'/{room_id}/videos',
responses={**not_found_responses},