ytdl-sub/src/ytdl_sub/utils/thumbnail.py
2023-03-13 13:30:06 -07:00

89 lines
2.6 KiB
Python

import os
import tempfile
from typing import Optional
from urllib.request import urlopen
from ytdl_sub.entries.entry import Entry
from ytdl_sub.utils.ffmpeg import FFMPEG
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.retry import retry
class ThumbnailTypes:
LATEST_ENTRY = "latest_entry"
def convert_download_thumbnail(entry: Entry, error_if_not_found: bool = True) -> None:
"""
Converts an entry's downloaded thumbnail into jpg format
Parameters
----------
entry
Entry with the thumbnail
error_if_not_found
If the thumbnail is not found, error if True.
Raises
------
ValueError
Entry thumbnail file not found
"""
download_thumbnail_path = entry.get_ytdlp_download_thumbnail_path()
download_thumbnail_path_as_jpg = entry.get_download_thumbnail_path()
# If it was already converted, do not convert again
if os.path.isfile(download_thumbnail_path_as_jpg):
return
if not download_thumbnail_path:
if error_if_not_found:
raise ValueError("Thumbnail not found")
return
if not download_thumbnail_path == download_thumbnail_path_as_jpg:
FFMPEG.run(["-bitexact", "-i", download_thumbnail_path, download_thumbnail_path_as_jpg])
FileHandler.delete(download_thumbnail_path)
@retry(times=3, exceptions=(Exception,))
def download_and_convert_url_thumbnail(
thumbnail_url: Optional[str], output_thumbnail_path: str
) -> Optional[bool]:
"""
Downloads and converts a thumbnail from a url into a jpg
Parameters
----------
thumbnail_url
URL of the thumbnail
output_thumbnail_path
Thumbnail file destination after its converted to jpg
Returns
-------
True to indicate it converted the thumbnail from url. None if the retry failed.
"""
if not thumbnail_url:
return None
# timeout after 8 seconds
with urlopen(thumbnail_url, timeout=1.0) as file:
with tempfile.NamedTemporaryFile(delete=False) as thumbnail:
thumbnail.write(file.read())
try:
os.makedirs(os.path.dirname(output_thumbnail_path), exist_ok=True)
tmp_output_path = FFMPEG.tmp_file_path(
relative_file_path=thumbnail.name, extension="jpg"
)
FFMPEG.run(["-bitexact", "-i", thumbnail.name, tmp_output_path])
# Have FileHandler handle the move to a potential cross-device
FileHandler.move(tmp_output_path, output_thumbnail_path)
finally:
FileHandler.delete(tmp_output_path)
FileHandler.delete(thumbnail.name)
return True