dfdkflj
This commit is contained in:
160
scripts/refactor_download_careful.py
Normal file
160
scripts/refactor_download_careful.py
Normal file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Careful refactoring of download_data.py to class-based pattern.
|
||||
Handles nested functions and inner definitions correctly.
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def refactor_download_data():
|
||||
backup_file = Path('cmdlets/download_data_backup.py')
|
||||
output_file = Path('cmdlets/download_data.py')
|
||||
|
||||
print(f"Reading: {backup_file}")
|
||||
content = backup_file.read_text(encoding='utf-8')
|
||||
lines = content.split('\n')
|
||||
|
||||
output = []
|
||||
i = 0
|
||||
in_cmdlet_def = False
|
||||
skip_old_run_wrapper = False
|
||||
class_added = False
|
||||
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
|
||||
# Skip old _run wrapper function
|
||||
if line.strip().startswith('def _run(result: Any'):
|
||||
while i < len(lines):
|
||||
i += 1
|
||||
if lines[i] and not lines[i][0].isspace():
|
||||
break
|
||||
continue
|
||||
|
||||
# Skip old CMDLET definition
|
||||
if line.strip().startswith('CMDLET = Cmdlet('):
|
||||
while i < len(lines):
|
||||
i += 1
|
||||
if lines[i].strip() == ')':
|
||||
i += 1
|
||||
break
|
||||
output.append('')
|
||||
output.append('# Create and register the cmdlet')
|
||||
output.append('CMDLET = Download_Data()')
|
||||
output.append('')
|
||||
continue
|
||||
|
||||
# Insert class definition before first top-level helper
|
||||
if not class_added and line.strip().startswith('def _download_torrent_worker('):
|
||||
# Add class header with __init__ and run()
|
||||
output.extend([
|
||||
'',
|
||||
'',
|
||||
'class Download_Data(Cmdlet):',
|
||||
' """Class-based download-data cmdlet with self-registration."""',
|
||||
'',
|
||||
' def __init__(self) -> None:',
|
||||
' """Initialize download-data cmdlet."""',
|
||||
' super().__init__(',
|
||||
' name="download-data",',
|
||||
' summary="Download data from url with playlist/clip support using yt-dlp",',
|
||||
' usage="download-data <url> [options] or search-file | download-data [options]",',
|
||||
' alias=["download", "dl"],',
|
||||
' arg=[',
|
||||
' CmdletArg(name="url", type="string", required=False, description="URL to download (HTTP/HTTPS or file with URL list)", variadic=True),',
|
||||
' CmdletArg(name="-url", type="string", description="URL to download (alias for positional argument)", variadic=True),',
|
||||
' CmdletArg(name="list-formats", type="flag", description="List available formats without downloading"),',
|
||||
' CmdletArg(name="audio", type="flag", alias="a", description="Download audio only (extract from video)"),',
|
||||
' CmdletArg(name="video", type="flag", alias="v", description="Download video (default if not specified)"),',
|
||||
' CmdletArg(name="format", type="string", alias="fmt", description="Explicit yt-dlp format selector (e.g., bestvideo+bestaudio)"),',
|
||||
' CmdletArg(name="clip", type="string", description="Extract time range: MM:SS-MM:SS (e.g., 34:03-35:08) or seconds"),',
|
||||
' CmdletArg(name="section", type="string", description="Download sections (yt-dlp only): TIME_RANGE[,TIME_RANGE...] (e.g., 1:30-1:35,0:05-0:15)"),',
|
||||
' CmdletArg(name="cookies", type="string", description="Path to cookies.txt file for authentication"),',
|
||||
' CmdletArg(name="torrent", type="flag", description="Download torrent/magnet via AllDebrid (requires API key in config)"),',
|
||||
' CmdletArg(name="wait", type="float", description="Wait time (seconds) for magnet processing timeout"),',
|
||||
' CmdletArg(name="background", type="flag", alias="bg", description="Start download in background and return to prompt immediately"),',
|
||||
' CmdletArg(name="item", type="string", alias="items", description="Item selection for playlists/formats: use -item N to select format N, or -item to show table for @N selection in next command"),',
|
||||
' SharedArgs.STORAGE,',
|
||||
' ],',
|
||||
' detail=["Download media from url with advanced features.", "", "See help for full usage examples."],',
|
||||
' exec=self.run,',
|
||||
' )',
|
||||
' self.register()',
|
||||
'',
|
||||
' def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:',
|
||||
' """Main execution method."""',
|
||||
' stage_ctx = pipeline_context.get_stage_context()',
|
||||
' in_pipeline = stage_ctx is not None and getattr(stage_ctx, "total_stages", 1) > 1',
|
||||
' if in_pipeline and isinstance(config, dict):',
|
||||
' config["_quiet_background_output"] = True',
|
||||
' return self._run_impl(result, args, config, emit_results=True)',
|
||||
'',
|
||||
' # ' + '='*70,
|
||||
' # HELPER METHODS',
|
||||
' # ' + '='*70,
|
||||
'',
|
||||
])
|
||||
class_added = True
|
||||
|
||||
# Convert top-level helper functions to static methods
|
||||
if class_added and line and not line[0].isspace() and line.strip().startswith('def _'):
|
||||
output.append(' @staticmethod')
|
||||
output.append(f' {line}')
|
||||
i += 1
|
||||
# Copy function body with indentation
|
||||
while i < len(lines):
|
||||
next_line = lines[i]
|
||||
# Stop at next top-level definition
|
||||
if next_line and not next_line[0].isspace() and (next_line.strip().startswith(('def ', 'class ', 'CMDLET'))):
|
||||
break
|
||||
# Add indentation
|
||||
if next_line.strip():
|
||||
output.append(f' {next_line}')
|
||||
else:
|
||||
output.append(next_line)
|
||||
i += 1
|
||||
continue
|
||||
|
||||
output.append(line)
|
||||
i += 1
|
||||
|
||||
result_text = '\n'.join(output)
|
||||
|
||||
# NOW: Update function calls carefully
|
||||
# Only update calls in _run_impl, not in nested function definitions
|
||||
# Pattern: match _func( but NOT when it's after "def " on the same line
|
||||
helper_funcs = [
|
||||
'_download_torrent_worker', '_guess_libgen_title', '_is_libgen_entry',
|
||||
'_download_libgen_entry', '_libgen_background_worker',
|
||||
'_start_libgen_background_worker', '_run_pipeline_tail',
|
||||
'_download_http_background_worker', '_start_http_background_download',
|
||||
'_parse_torrent_file', '_download_torrent_file', '_is_torrent_file_or_url',
|
||||
'_process_torrent_input', '_show_playlist_table', '_parse_time_range',
|
||||
'_parse_section_ranges', '_parse_playlist_selection_indices',
|
||||
'_select_playlist_entries', '_sanitize_title_for_filename',
|
||||
'_find_playlist_files_from_entries', '_snapshot_playlist_paths',
|
||||
'_is_openlibrary_downloadable', '_as_dict', '_is_youtube_url',
|
||||
]
|
||||
|
||||
# Split into lines for careful replacement
|
||||
result_lines = result_text.split('\n')
|
||||
for idx, line in enumerate(result_lines):
|
||||
# Skip lines that are function definitions
|
||||
if 'def ' in line:
|
||||
continue
|
||||
# Replace helper function calls with self.
|
||||
for func in helper_funcs:
|
||||
# Pattern: _func( with word boundary before
|
||||
pattern = rf'\b({re.escape(func)})\('
|
||||
if re.search(pattern, line):
|
||||
result_lines[idx] = re.sub(pattern, r'self.\1(', line)
|
||||
|
||||
result_text = '\n'.join(result_lines)
|
||||
|
||||
output_file.write_text(result_text, encoding='utf-8')
|
||||
print(f"✓ Written: {output_file}")
|
||||
print(f"✓ Class-based refactor complete")
|
||||
|
||||
if __name__ == '__main__':
|
||||
refactor_download_data()
|
||||
Reference in New Issue
Block a user