Improve yt-dlp version check

This commit is contained in:
Taras Terletskyi 2022-03-13 21:54:46 +02:00
parent 72c69be8cc
commit 8dcf6408a7
5 changed files with 48 additions and 32 deletions

View file

@ -1,5 +1,3 @@
import asyncio
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
@ -14,8 +12,7 @@ router = APIRouter()
response_model_by_alias=False)
async def yt_dlp_version(db: AsyncSession = Depends(get_db)):
version_checker = VersionChecker()
latest, current = await asyncio.gather(
version_checker.get_latest_version(),
version_checker.get_current_version(db))
return YTDLPLatestVersion(current=current, latest=latest,
need_upgrade=latest.version != current.version)
ctx = await version_checker.get_version_context(db)
return YTDLPLatestVersion(current=ctx.current, latest=ctx.latest,
need_upgrade=ctx.has_new_version)

View file

@ -1,8 +1,8 @@
from yt_shared.schemas.base import RealBaseModel
from yt_shared.schemas.ytdlp import Current, Latest
from yt_shared.schemas.ytdlp import CurrentVersion, LatestVersion
class YTDLPLatestVersion(RealBaseModel):
latest: Latest
current: Current
latest: LatestVersion
current: CurrentVersion
need_upgrade: bool

View file

@ -9,7 +9,7 @@ from core.utils.utils import bold, code
from yt_shared.config import YTDLP_VERSION_CHECK_INTERVAL
from yt_shared.db import get_db
from yt_shared.emoji import INFORMATION_EMOJI
from yt_shared.schemas.ytdlp import Current, Latest
from yt_shared.schemas.ytdlp import VersionContext
from yt_shared.ytdlp.version_checker import VersionChecker
if TYPE_CHECKING:
@ -32,7 +32,7 @@ class YtdlpNewVersionNotifyTask(AbstractTask):
except Exception:
self._log.exception('Failed check new yt-dlp version')
self._log.info(
'Next check for new yt-dlp version planned at %s',
'Next yt-dlp version check planned at %s',
self._get_next_check_datetime().isoformat(' '))
await asyncio.sleep(YTDLP_VERSION_CHECK_INTERVAL)
@ -44,28 +44,25 @@ class YtdlpNewVersionNotifyTask(AbstractTask):
async def _notify_if_new_version(self) -> None:
async for db in get_db():
latest, current = await asyncio.gather(
self._version_checker.get_latest_version(),
self._version_checker.get_current_version(db))
if latest.version != current.version:
await self._notify_outdated(latest, current)
context = await self._version_checker.get_version_context(db)
if context.has_new_version:
await self._notify_outdated(context)
elif not self._startup_message_sent:
await self._notify_up_to_date(current)
await self._notify_up_to_date(context)
self._startup_message_sent = True
async def _notify_outdated(self, latest: Latest, current: Current) -> None:
async def _notify_outdated(self, ctx: VersionContext) -> None:
text = (
f'New {code("yt-dlp")} version available: {bold(latest.version)}\n'
f'Current version: {bold(current.version)}\n'
f'New {code("yt-dlp")} version available: {bold(ctx.latest.version)}\n'
f'Current version: {bold(ctx.current.version)}\n'
f'Rebuild worker with {code("docker-compose build --no-cache worker")}'
)
await self._send_to_chat(text)
async def _notify_up_to_date(self, current: Current) -> None:
async def _notify_up_to_date(self, ctx: VersionContext) -> None:
"""Send startup message that yt-dlp version is up to date."""
text = f'{INFORMATION_EMOJI} Your {code("yt-dlp")} version ' \
f'{bold(current.version)} is up to date. Have fun.'
f'{bold(ctx.current.version)} is up to date. Have fun.'
await self._send_to_chat(text)
async def _send_to_chat(self, text: str) -> None:

View file

@ -1,4 +1,5 @@
import datetime
from typing import Optional
from pydantic import Field, StrictStr, validator
@ -9,7 +10,7 @@ def _remove_microseconds(dt_obj: datetime.datetime) -> datetime.datetime:
return dt_obj.replace(microsecond=0)
class Latest(RealBaseModel):
class LatestVersion(RealBaseModel):
version: StrictStr
retrieved_at: datetime.datetime
@ -18,7 +19,7 @@ class Latest(RealBaseModel):
return _remove_microseconds(value)
class Current(RealBaseModel):
class CurrentVersion(RealBaseModel):
version: StrictStr = Field(..., alias='current_version')
updated_at: datetime.datetime
@ -28,3 +29,14 @@ class Current(RealBaseModel):
class Config(RealBaseModel.Config):
orm_mode = True
class VersionContext(RealBaseModel):
latest: LatestVersion
current: CurrentVersion
has_new_version: Optional[bool]
@validator('has_new_version', always=True)
def check_new_version(cls, value, values: dict) -> bool:
return [int(x) for x in values['latest'].version.split('.')] > \
[int(x) for x in values['current'].version.split('.')]

View file

@ -1,3 +1,4 @@
import asyncio
import datetime
import logging
@ -5,7 +6,11 @@ import aiohttp
from sqlalchemy.ext.asyncio import AsyncSession
from yt_shared.repositories.ytdlp import YtdlpRepository
from yt_shared.schemas.ytdlp import Current, Latest
from yt_shared.schemas.ytdlp import (
CurrentVersion,
LatestVersion,
VersionContext,
)
class VersionChecker:
@ -17,18 +22,23 @@ class VersionChecker:
def __init__(self) -> None:
self._log = logging.getLogger(self.__class__.__name__)
async def get_latest_version(self) -> Latest:
async def get_version_context(self, db: AsyncSession) -> VersionContext:
latest, current = await asyncio.gather(self.get_latest_version(),
self.get_current_version(db))
return VersionContext(latest=latest, current=current)
async def get_latest_version(self) -> LatestVersion:
self._log.info('Get latest yt-dlp version number')
async with aiohttp.ClientSession() as session:
async with session.get(self.LATEST_TAG_URL) as resp:
version = resp.url.parts[-1]
self._log.info('Latest yt-dlp version number: %s', version)
return Latest(version=version,
retrieved_at=datetime.datetime.utcnow())
return LatestVersion(version=version,
retrieved_at=datetime.datetime.utcnow())
async def get_current_version(self, db: AsyncSession) -> Current:
async def get_current_version(self, db: AsyncSession) -> CurrentVersion:
self._log.info('Get current yt-dlp version number')
ytdlp_ = await self.REPOSITORY_CLS().get_current_version(db)
self._log.info('Current yt-dlp version number: %s',
ytdlp_.current_version)
return Current.from_orm(ytdlp_)
return CurrentVersion.from_orm(ytdlp_)