Try to preserve time
This commit is contained in:
parent
08180c0412
commit
728413affd
4 changed files with 57 additions and 1 deletions
|
|
@ -112,6 +112,7 @@ class ConfigOptions(StrictDictValidator):
|
||||||
"ffprobe_path",
|
"ffprobe_path",
|
||||||
"file_name_max_bytes",
|
"file_name_max_bytes",
|
||||||
"experimental",
|
"experimental",
|
||||||
|
"preserve_mtime",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name: str, value: Any):
|
def __init__(self, name: str, value: Any):
|
||||||
|
|
@ -146,6 +147,9 @@ class ConfigOptions(StrictDictValidator):
|
||||||
self._file_name_max_bytes = self._validate_key(
|
self._file_name_max_bytes = self._validate_key(
|
||||||
key="file_name_max_bytes", validator=IntValidator, default=MAX_FILE_NAME_BYTES
|
key="file_name_max_bytes", validator=IntValidator, default=MAX_FILE_NAME_BYTES
|
||||||
)
|
)
|
||||||
|
self._preserve_mtime = self._validate_key(
|
||||||
|
key="preserve_mtime", validator=BoolValidator, default=False
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def working_directory(self) -> str:
|
def working_directory(self) -> str:
|
||||||
|
|
@ -240,6 +244,15 @@ class ConfigOptions(StrictDictValidator):
|
||||||
"""
|
"""
|
||||||
return self._ffprobe_path.value
|
return self._ffprobe_path.value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def preserve_mtime(self) -> bool:
|
||||||
|
"""
|
||||||
|
Preserve the video's original upload time as the file modification time.
|
||||||
|
When True, sets the file's mtime to match the video's upload_date from
|
||||||
|
yt-dlp metadata. (default ``False``)
|
||||||
|
"""
|
||||||
|
return self._preserve_mtime.value
|
||||||
|
|
||||||
|
|
||||||
class ConfigValidator(StrictDictValidator):
|
class ConfigValidator(StrictDictValidator):
|
||||||
_optional_keys = {"configuration", "presets"}
|
_optional_keys = {"configuration", "presets"}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ def _initialize_download_archive(
|
||||||
overrides: Overrides,
|
overrides: Overrides,
|
||||||
working_directory: str,
|
working_directory: str,
|
||||||
output_directory: str,
|
output_directory: str,
|
||||||
|
config_options: ConfigOptions,
|
||||||
) -> EnhancedDownloadArchive:
|
) -> EnhancedDownloadArchive:
|
||||||
migrated_file_name: Optional[str] = None
|
migrated_file_name: Optional[str] = None
|
||||||
if migrated_file_name_option := output_options.migrated_download_archive_name:
|
if migrated_file_name_option := output_options.migrated_download_archive_name:
|
||||||
|
|
@ -32,6 +33,7 @@ def _initialize_download_archive(
|
||||||
working_directory=working_directory,
|
working_directory=working_directory,
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
migrated_file_name=migrated_file_name,
|
migrated_file_name=migrated_file_name,
|
||||||
|
preserve_mtime=config_options.preserve_mtime,
|
||||||
).reinitialize(dry_run=True)
|
).reinitialize(dry_run=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -80,6 +82,7 @@ class BaseSubscription(ABC):
|
||||||
overrides=self.overrides,
|
overrides=self.overrides,
|
||||||
working_directory=self.working_directory,
|
working_directory=self.working_directory,
|
||||||
output_directory=self.output_directory,
|
output_directory=self.output_directory,
|
||||||
|
config_options=self._config_options,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
@ -392,7 +394,7 @@ class FileHandler:
|
||||||
# Perform the copy by first writing to a temp file, then moving it.
|
# Perform the copy by first writing to a temp file, then moving it.
|
||||||
# This tries to prevent corrupted writes if the processed dies mid-write,
|
# This tries to prevent corrupted writes if the processed dies mid-write,
|
||||||
atomic_dst = f"{dst_file_path}-ytdl-sub-incomplete"
|
atomic_dst = f"{dst_file_path}-ytdl-sub-incomplete"
|
||||||
shutil.copyfile(src=src_file_path, dst=atomic_dst)
|
shutil.copy2(src=src_file_path, dst=atomic_dst)
|
||||||
shutil.move(src=atomic_dst, dst=dst_file_path)
|
shutil.move(src=atomic_dst, dst=dst_file_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -430,6 +432,25 @@ class FileHandler:
|
||||||
if os.path.isfile(file_path):
|
if os.path.isfile(file_path):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_mtime(cls, file_path: Union[str, Path], mtime: float):
|
||||||
|
"""
|
||||||
|
Set the modification time of a file
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
file_path
|
||||||
|
Path to the file to modify
|
||||||
|
mtime
|
||||||
|
Modification time as a Unix timestamp
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Set both access time and modification time
|
||||||
|
os.utime(file_path, (mtime, mtime))
|
||||||
|
except OSError:
|
||||||
|
# If file operation fails, silently continue
|
||||||
|
pass
|
||||||
|
|
||||||
def move_file_to_output_directory(
|
def move_file_to_output_directory(
|
||||||
self,
|
self,
|
||||||
file_name: str,
|
file_name: str,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import os.path
|
import os.path
|
||||||
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -397,6 +398,7 @@ class EnhancedDownloadArchive:
|
||||||
output_directory: str,
|
output_directory: str,
|
||||||
dry_run: bool = False,
|
dry_run: bool = False,
|
||||||
migrated_file_name: Optional[str] = None,
|
migrated_file_name: Optional[str] = None,
|
||||||
|
preserve_mtime: bool = False,
|
||||||
):
|
):
|
||||||
self._file_name = file_name
|
self._file_name = file_name
|
||||||
self._file_handler = FileHandler(
|
self._file_handler = FileHandler(
|
||||||
|
|
@ -404,6 +406,7 @@ class EnhancedDownloadArchive:
|
||||||
)
|
)
|
||||||
self._download_mapping = DownloadMappings() # gets reinitialized
|
self._download_mapping = DownloadMappings() # gets reinitialized
|
||||||
self._migrated_file_name = migrated_file_name
|
self._migrated_file_name = migrated_file_name
|
||||||
|
self._preserve_mtime = preserve_mtime
|
||||||
|
|
||||||
self.num_entries_added: int = 0
|
self.num_entries_added: int = 0
|
||||||
self.num_entries_modified: int = 0
|
self.num_entries_modified: int = 0
|
||||||
|
|
@ -674,6 +677,22 @@ class EnhancedDownloadArchive:
|
||||||
copy_file=copy_file,
|
copy_file=copy_file,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Set mtime if preserve_mtime is enabled and we have an entry with upload_date
|
||||||
|
if self._preserve_mtime and entry and not self._file_handler.dry_run:
|
||||||
|
upload_date = entry.get(v.upload_date, str)
|
||||||
|
if upload_date:
|
||||||
|
try:
|
||||||
|
# Convert YYYYMMDD to timestamp
|
||||||
|
upload_datetime = datetime.strptime(upload_date, "%Y%m%d")
|
||||||
|
upload_timestamp = time.mktime(upload_datetime.timetuple())
|
||||||
|
|
||||||
|
# Set mtime on the output file
|
||||||
|
output_file_path = Path(self._file_handler.output_directory) / output_file_name
|
||||||
|
FileHandler.set_mtime(output_file_path, upload_timestamp)
|
||||||
|
except (ValueError, OSError):
|
||||||
|
# If date parsing or file operation fails, silently continue
|
||||||
|
pass
|
||||||
|
|
||||||
# Determine if it's the entry file by seeing if the file_name to move matches the entry
|
# Determine if it's the entry file by seeing if the file_name to move matches the entry
|
||||||
# download file name
|
# download file name
|
||||||
is_entry_file = entry and entry.get_download_file_name() == file_name
|
is_entry_file = entry and entry.get_download_file_name() == file_name
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue