[FEATURE] Add summary to console output (#515)
This commit is contained in:
parent
fddf3d3088
commit
91e9fe7602
6 changed files with 148 additions and 2 deletions
|
|
@ -28,6 +28,7 @@ packages=find:
|
||||||
install_requires =
|
install_requires =
|
||||||
yt-dlp==2023.3.4
|
yt-dlp==2023.3.4
|
||||||
argparse==1.4.0
|
argparse==1.4.0
|
||||||
|
colorama==0.4.6,
|
||||||
mergedeep==1.3.4
|
mergedeep==1.3.4
|
||||||
mediafile==0.10.1
|
mediafile==0.10.1
|
||||||
PyYAML==6.0
|
PyYAML==6.0
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import gc
|
import gc
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
@ -7,6 +8,7 @@ from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
|
from colorama import Fore
|
||||||
from yt_dlp.utils import sanitize_filename
|
from yt_dlp.utils import sanitize_filename
|
||||||
|
|
||||||
from ytdl_sub.cli.download_args_parser import DownloadArgsParser
|
from ytdl_sub.cli.download_args_parser import DownloadArgsParser
|
||||||
|
|
@ -209,6 +211,79 @@ def _output_transaction_log(
|
||||||
transaction_log_file.write(transaction_log_file_contents)
|
transaction_log_file.write(transaction_log_file_contents)
|
||||||
|
|
||||||
|
|
||||||
|
def _green(value: str) -> str:
|
||||||
|
return Fore.GREEN + value + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
|
def _red(value: str) -> str:
|
||||||
|
return Fore.RED + value + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
|
def _str_int(value: int) -> str:
|
||||||
|
if value > 0:
|
||||||
|
return f"+{value}"
|
||||||
|
if value < 0:
|
||||||
|
return f"-{value}"
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def _color_int(value: int) -> str:
|
||||||
|
str_int = _str_int(value)
|
||||||
|
if value > 0:
|
||||||
|
return _green(str_int)
|
||||||
|
if value < 0:
|
||||||
|
return _red(str_int)
|
||||||
|
return str_int
|
||||||
|
|
||||||
|
|
||||||
|
def _output_summary(transaction_logs: List[Tuple[Subscription, FileHandlerTransactionLog]]):
|
||||||
|
summary: List[str] = []
|
||||||
|
|
||||||
|
# Initialize widths to 0
|
||||||
|
width_sub_name: int = 0
|
||||||
|
width_num_entries_added: int = 0
|
||||||
|
width_num_entries_modified: int = 0
|
||||||
|
width_num_entries_removed: int = 0
|
||||||
|
width_num_entries: int = 0
|
||||||
|
|
||||||
|
# Calculate min width needed
|
||||||
|
for subscription, _ in transaction_logs:
|
||||||
|
width_sub_name = max(width_sub_name, len(subscription.name))
|
||||||
|
width_num_entries_added = max(
|
||||||
|
width_num_entries_added, len(_str_int(subscription.num_entries_added))
|
||||||
|
)
|
||||||
|
width_num_entries_modified = max(
|
||||||
|
width_num_entries_modified, len(_str_int(subscription.num_entries_modified))
|
||||||
|
)
|
||||||
|
width_num_entries_removed = max(
|
||||||
|
width_num_entries_removed, len(_str_int(subscription.num_entries_removed * -1))
|
||||||
|
)
|
||||||
|
width_num_entries = max(width_num_entries, len(str(subscription.num_entries)))
|
||||||
|
|
||||||
|
# Add spacing for aesthetics
|
||||||
|
width_sub_name += 4
|
||||||
|
width_num_entries += 4
|
||||||
|
|
||||||
|
# Build the summary
|
||||||
|
for subscription, _ in transaction_logs:
|
||||||
|
num_entries_added = _color_int(subscription.num_entries_added)
|
||||||
|
num_entries_modified = _color_int(subscription.num_entries_modified)
|
||||||
|
num_entries_removed = _color_int(subscription.num_entries_removed * -1)
|
||||||
|
num_entries = str(subscription.num_entries)
|
||||||
|
status = _green("success")
|
||||||
|
|
||||||
|
summary.append(
|
||||||
|
f"{subscription.name:<{width_sub_name}} "
|
||||||
|
f"{num_entries_added:>{width_num_entries_added}} "
|
||||||
|
f"{num_entries_modified:>{width_num_entries_modified}} "
|
||||||
|
f"{num_entries_removed:>{width_num_entries_removed}} "
|
||||||
|
f"{num_entries:>{width_num_entries}} "
|
||||||
|
f"{status}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return "\n".join(summary)
|
||||||
|
|
||||||
|
|
||||||
def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||||
"""
|
"""
|
||||||
Entrypoint for ytdl-sub, without the error handling
|
Entrypoint for ytdl-sub, without the error handling
|
||||||
|
|
@ -253,4 +328,7 @@ def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||||
transaction_log_file_path=args.transaction_log,
|
transaction_log_file_path=args.transaction_log,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Hack to always show download summary, even if logs are set to quiet
|
||||||
|
logger.log(logging.WARNING, "Download Summary:\n%s", _output_summary(transaction_logs))
|
||||||
|
|
||||||
return transaction_logs
|
return transaction_logs
|
||||||
|
|
|
||||||
|
|
@ -458,7 +458,7 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
|
||||||
upload_date_idx = self._enhanced_download_archive.mapping.get_num_entries_with_upload_date(
|
upload_date_idx = self._enhanced_download_archive.mapping.get_num_entries_with_upload_date(
|
||||||
upload_date_standardized=entry.upload_date_standardized
|
upload_date_standardized=entry.upload_date_standardized
|
||||||
)
|
)
|
||||||
download_idx = self._enhanced_download_archive.mapping.get_num_entries()
|
download_idx = self._enhanced_download_archive.num_entries
|
||||||
|
|
||||||
entry.add_kwargs(
|
entry.add_kwargs(
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,42 @@ class BaseSubscription(ABC):
|
||||||
and self.downloader_class.supports_download_archive
|
and self.downloader_class.supports_download_archive
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def num_entries_added(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Number of entries added
|
||||||
|
"""
|
||||||
|
return self._enhanced_download_archive.num_entries_added
|
||||||
|
|
||||||
|
@property
|
||||||
|
def num_entries_modified(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Number of entries modified
|
||||||
|
"""
|
||||||
|
return self._enhanced_download_archive.num_entries_modified
|
||||||
|
|
||||||
|
@property
|
||||||
|
def num_entries_removed(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Number of entries removed
|
||||||
|
"""
|
||||||
|
return self._enhanced_download_archive.num_entries_removed
|
||||||
|
|
||||||
|
@property
|
||||||
|
def num_entries(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
The number of entries
|
||||||
|
"""
|
||||||
|
return self._enhanced_download_archive.num_entries
|
||||||
|
|
||||||
def as_yaml(self) -> str:
|
def as_yaml(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
|
|
|
||||||
|
|
@ -416,7 +416,13 @@ class FileHandler:
|
||||||
Optional. Metadata to record to the transaction log for this file
|
Optional. Metadata to record to the transaction log for this file
|
||||||
copy_file
|
copy_file
|
||||||
Optional. If True, copy the file. Move otherwise
|
Optional. If True, copy the file. Move otherwise
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if modified. False otherwise.
|
||||||
"""
|
"""
|
||||||
|
is_modified = False
|
||||||
source_file_path = Path(self.working_directory) / file_name
|
source_file_path = Path(self.working_directory) / file_name
|
||||||
output_file_path = Path(self.output_directory) / output_file_name
|
output_file_path = Path(self.output_directory) / output_file_name
|
||||||
|
|
||||||
|
|
@ -429,6 +435,7 @@ class FileHandler:
|
||||||
self.file_handler_transaction_log.log_modified_file(
|
self.file_handler_transaction_log.log_modified_file(
|
||||||
file_name=output_file_name, file_metadata=file_metadata
|
file_name=output_file_name, file_metadata=file_metadata
|
||||||
)
|
)
|
||||||
|
is_modified = True
|
||||||
# output file does not already exist, creates a new file
|
# output file does not already exist, creates a new file
|
||||||
else:
|
else:
|
||||||
self.file_handler_transaction_log.log_created_file(
|
self.file_handler_transaction_log.log_created_file(
|
||||||
|
|
@ -445,6 +452,8 @@ class FileHandler:
|
||||||
elif self.dry_run and not copy_file:
|
elif self.dry_run and not copy_file:
|
||||||
FileHandler.delete(source_file_path)
|
FileHandler.delete(source_file_path)
|
||||||
|
|
||||||
|
return is_modified
|
||||||
|
|
||||||
def delete_file_from_output_directory(self, file_name: str):
|
def delete_file_from_output_directory(self, file_name: str):
|
||||||
"""
|
"""
|
||||||
Deletes a file from the output directory. All file deletions should use this function
|
Deletes a file from the output directory. All file deletions should use this function
|
||||||
|
|
|
||||||
|
|
@ -363,6 +363,19 @@ class EnhancedDownloadArchive:
|
||||||
|
|
||||||
self._logger = Logger.get(name=subscription_name)
|
self._logger = Logger.get(name=subscription_name)
|
||||||
|
|
||||||
|
self.num_entries_added: int = 0
|
||||||
|
self.num_entries_modified: int = 0
|
||||||
|
self.num_entries_removed: int = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def num_entries(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Total number of entries in the mapping
|
||||||
|
"""
|
||||||
|
return self.mapping.get_num_entries()
|
||||||
|
|
||||||
def reinitialize(self, dry_run: bool) -> "EnhancedDownloadArchive":
|
def reinitialize(self, dry_run: bool) -> "EnhancedDownloadArchive":
|
||||||
"""
|
"""
|
||||||
Re-initialize the enhanced download archive for successive downloads w/the same
|
Re-initialize the enhanced download archive for successive downloads w/the same
|
||||||
|
|
@ -544,6 +557,7 @@ class EnhancedDownloadArchive:
|
||||||
self._file_handler.delete_file_from_output_directory(file_name=file_name)
|
self._file_handler.delete_file_from_output_directory(file_name=file_name)
|
||||||
|
|
||||||
self.mapping.remove_entry(entry_id=uid)
|
self.mapping.remove_entry(entry_id=uid)
|
||||||
|
self.num_entries_removed += 1
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
@ -600,13 +614,21 @@ class EnhancedDownloadArchive:
|
||||||
elif entry:
|
elif entry:
|
||||||
self.mapping.add_entry(entry=entry, entry_file_path=output_file_name)
|
self.mapping.add_entry(entry=entry, entry_file_path=output_file_name)
|
||||||
|
|
||||||
self._file_handler.move_file_to_output_directory(
|
is_modified = self._file_handler.move_file_to_output_directory(
|
||||||
file_name=file_name,
|
file_name=file_name,
|
||||||
file_metadata=file_metadata,
|
file_metadata=file_metadata,
|
||||||
output_file_name=output_file_name,
|
output_file_name=output_file_name,
|
||||||
copy_file=copy_file,
|
copy_file=copy_file,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Determine if it's the entry file by seeing if the file_name to move matches the entry
|
||||||
|
# download file name
|
||||||
|
is_entry_file = entry and entry.get_download_file_name() == file_name
|
||||||
|
if is_entry_file and is_modified:
|
||||||
|
self.num_entries_modified += 1
|
||||||
|
elif is_entry_file:
|
||||||
|
self.num_entries_added += 1
|
||||||
|
|
||||||
def get_file_handler_transaction_log(self) -> FileHandlerTransactionLog:
|
def get_file_handler_transaction_log(self) -> FileHandlerTransactionLog:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue