From 5c8d20c9bfbb2cdad134e127368643422a3c215b Mon Sep 17 00:00:00 2001 From: kavinthangavel Date: Tue, 23 Sep 2025 20:38:35 +0530 Subject: [PATCH 1/5] added progress and speed columns --- requirements.txt | 1 + thinkific_downloader/__init__.py | 2 +- thinkific_downloader/download_manager.py | 434 ++++++++++ thinkific_downloader/downloader.py | 944 ++++++++++++++++------ thinkific_downloader/progress_manager.py | 228 ++++++ thinkific_downloader/wistia_downloader.py | 24 +- 6 files changed, 1370 insertions(+), 263 deletions(-) create mode 100644 thinkific_downloader/download_manager.py create mode 100644 thinkific_downloader/progress_manager.py diff --git a/requirements.txt b/requirements.txt index cc647e0..cef341a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ tqdm>=4.65.0 +requests>=2.28.0 rich>=13.0.0 \ No newline at end of file diff --git a/thinkific_downloader/__init__.py b/thinkific_downloader/__init__.py index 7254b04..ee6f1b4 100644 --- a/thinkific_downloader/__init__.py +++ b/thinkific_downloader/__init__.py @@ -11,7 +11,7 @@ Features: - Modern Python package architecture -- Rich terminal UI with progress tracking +- progress tracking - Smart retry logic and error recovery - Resume support for interrupted downloads - Docker containerization with FFmpeg diff --git a/thinkific_downloader/download_manager.py b/thinkific_downloader/download_manager.py new file mode 100644 index 0000000..10de6e0 --- /dev/null +++ b/thinkific_downloader/download_manager.py @@ -0,0 +1,434 @@ +import os +import time +import hashlib +import threading +from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path +from typing import Optional, Dict, Any, Callable, List +from urllib.parse import urlparse +import requests +from requests.adapters import HTTPAdapter +from urllib3.util.retry import Retry +from rich.progress import Progress, TaskID, TextColumn, BarColumn, TimeRemainingColumn, TransferSpeedColumn, DownloadColumn +from rich.text import Text +from rich.progress import ProgressColumn + +class CustomSpeedColumn(ProgressColumn): + """Speed column that shows 'Queued' instead of '?'""" + def render(self, task): + if task.speed is None: + return Text("Queued", style="dim") + return Text(f"{task.speed:.1f} MB/s" if task.speed > 1 else f"{task.speed*1000:.0f} KB/s") + +class CustomTimeColumn(ProgressColumn): + """Time remaining column that shows 'Queued' instead of '-:--:--'""" + def render(self, task): + if task.time_remaining is None: + return Text("Queued", style="dim") + remaining = int(task.time_remaining) + hours = remaining // 3600 + minutes = (remaining % 3600) // 60 + seconds = remaining % 60 + return Text(f"{hours:02d}:{minutes:02d}:{seconds:02d}") +from rich.console import Console +from .config import Settings +from .file_utils import filter_filename + + +class RateLimiter: + """Token bucket rate limiter for controlling download speed.""" + + def __init__(self, rate_limit_mb_s: Optional[float] = None): + self.rate_limit_bytes_s = rate_limit_mb_s * 1024 * 1024 if rate_limit_mb_s else None + self.tokens = 0.0 + self.last_update = time.time() + self.lock = threading.Lock() + + def acquire(self, size: int) -> float: + """Acquire tokens for the given size. Returns sleep time if rate limited.""" + if not self.rate_limit_bytes_s: + return 0.0 + + with self.lock: + now = time.time() + time_passed = now - self.last_update + self.tokens += time_passed * self.rate_limit_bytes_s + self.tokens = min(self.tokens, self.rate_limit_bytes_s) # Cap at burst rate + self.last_update = now + + if self.tokens >= size: + self.tokens -= size + return 0.0 + else: + # Calculate wait time + wait_time = (size - self.tokens) / self.rate_limit_bytes_s + self.tokens = 0.0 + self.last_update = now + wait_time + return wait_time + + +class DownloadSession: + """Manages HTTP sessions with connection pooling and retry logic.""" + + def __init__(self, settings: Settings): + self.settings = settings + self.session = self._create_session() + + def _create_session(self) -> requests.Session: + """Create a requests session with proper configuration.""" + session = requests.Session() + + # Configure retry strategy + retry_strategy = Retry( + total=self.settings.retry_attempts, + backoff_factor=1, + status_forcelist=[429, 500, 502, 503, 504], + ) + + # Create adapter with connection pooling + adapter = HTTPAdapter( + max_retries=retry_strategy, + pool_connections=10, + pool_maxsize=20 + ) + + session.mount("http://", adapter) + session.mount("https://", adapter) + + # Set default headers + session.headers.update({ + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': 'application/json,text/javascript,*/*;q=0.9', + 'Accept-Encoding': 'gzip, deflate, br', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'cross-site', + 'x-requested-with': 'XMLHttpRequest', + 'x-thinkific-client-date': self.settings.client_date, + 'cookie': self.settings.cookie_data, + }) + + return session + + def get(self, url: str, **kwargs) -> requests.Response: + """Make a GET request with the session.""" + return self.session.get(url, timeout=60, **kwargs) + + def close(self): + """Close the session.""" + self.session.close() + + +class FileValidator: + """Handles file validation and integrity checks.""" + + @staticmethod + def calculate_checksum(file_path: Path, algorithm: str = 'md5') -> str: + """Calculate file checksum.""" + hash_func = hashlib.new(algorithm) + with open(file_path, 'rb') as f: + for chunk in iter(lambda: f.read(8192), b""): + hash_func.update(chunk) + return hash_func.hexdigest() + + @staticmethod + def validate_file_size(file_path: Path, expected_size: Optional[int] = None) -> bool: + """Validate file size if expected size is provided.""" + if expected_size is None: + return True + return file_path.stat().st_size == expected_size + + @staticmethod + def is_file_complete(file_path: Path, expected_size: Optional[int] = None) -> bool: + """Check if file appears to be complete.""" + if not file_path.exists(): + return False + if expected_size is None: + return True + return file_path.stat().st_size == expected_size + + +class DownloadTask: + """Represents a single download task.""" + + def __init__(self, url: str, dest_path: Path, expected_size: Optional[int] = None, + checksum: Optional[str] = None, resume: bool = True): + self.url = url + self.dest_path = dest_path + self.expected_size = expected_size + self.checksum = checksum + self.resume = resume + self.downloaded_size = 0 + self.status = 'pending' + self.error: Optional[str] = None + + def is_complete(self) -> bool: + """Check if download is complete.""" + if not self.dest_path.exists(): + return False + if self.expected_size: + return self.dest_path.stat().st_size == self.expected_size + return True + + +class DownloadManager: + """Manages parallel downloads with rate limiting, retries, and validation.""" + + def __init__(self, settings: Settings): + self.settings = settings + self.session = DownloadSession(settings) + self.rate_limiter = RateLimiter(settings.rate_limit_mb_s) + self.executor = ThreadPoolExecutor(max_workers=settings.concurrent_downloads) + self.validator = FileValidator() + self.active_downloads: Dict[str, DownloadTask] = {} + self.lock = threading.Lock() + + def download_file(self, url: str, dest_path: Path, expected_size: Optional[int] = None, + checksum: Optional[str] = None, show_progress: bool = True) -> bool: + """Download a single file with all features enabled.""" + task = DownloadTask(url, dest_path, expected_size, checksum, self.settings.resume_partial) + + # Check if file already exists and is valid + if task.is_complete() and self._validate_download(task): + if self.settings.debug: + print(f"File already exists and valid: {dest_path}") + return True + + # Start download + return self._download_single_file(task, show_progress) + + def download_files_parallel(self, tasks: List[DownloadTask], + progress_callback: Optional[Callable] = None) -> List[bool]: + """Download multiple files in parallel with Rich progress display.""" + + console = Console() + + # Create rich progress display + progress = Progress( + TextColumn("[bold blue]{task.fields[filename]}", justify="right"), + BarColumn(bar_width=40), + "[progress.percentage]{task.percentage:>3.1f}%", + "โ€ข", + DownloadColumn(), + "โ€ข", + CustomSpeedColumn(), + "โ€ข", + CustomTimeColumn(), + console=console, + ) + + with progress: + futures = [] + results = [] + task_progress_map = {} + + for task in tasks: + # Check if already complete + if task.is_complete() and self._validate_download(task): + results.append(True) + continue + + # Get expected size + if task.expected_size is None: + task.expected_size = self._get_content_length(task.url) + + # Add progress task + progress_task_id = progress.add_task( + "download", + filename=task.dest_path.name, + total=task.expected_size or 100 + ) + task_progress_map[id(task)] = progress_task_id + + # Submit download job + future = self.executor.submit(self._download_with_rich_progress, task, progress, progress_task_id) + futures.append((future, task, progress_task_id)) + + # Wait for completion + for future, task, progress_task_id in futures: + try: + result = future.result() + results.append(result) + if progress_callback: + progress_callback(task, result) + except Exception as e: + console.print(f"[red]Download failed for {task.dest_path}: {e}[/red]") + results.append(False) + + return results + + def _download_with_rich_progress(self, task: DownloadTask, progress, progress_task_id: int) -> bool: + """Download a single file with Rich progress bar updates.""" + try: + # Check for resume + resume_pos = 0 + if task.resume and task.dest_path.exists(): + resume_pos = task.dest_path.stat().st_size + if task.expected_size and resume_pos >= task.expected_size: + return self._validate_download(task) + + # Prepare headers for resume + headers = {} + if task.resume and resume_pos > 0: + headers['Range'] = f'bytes={resume_pos}-' + + response = self.session.session.get(task.url, headers=headers, stream=True) + response.raise_for_status() + + # Update progress bar with actual content length + content_length = response.headers.get('Content-Length') + if content_length: + total_size = int(content_length) + resume_pos + if task.expected_size != total_size: + task.expected_size = total_size + progress.update(progress_task_id, total=total_size) + + mode = 'ab' if resume_pos > 0 else 'wb' + downloaded = resume_pos + + with open(task.dest_path, mode) as f: + for chunk in response.iter_content(chunk_size=8192): + if chunk: + # Rate limiting + sleep_time = self.rate_limiter.acquire(len(chunk)) + if sleep_time > 0: + time.sleep(sleep_time) + + f.write(chunk) + downloaded += len(chunk) + + # Update Rich progress bar + progress.update(progress_task_id, advance=len(chunk)) + + # Download completed successfully + task.status = 'completed' + return self._validate_download(task) + + except Exception as e: + task.status = 'failed' + task.error = str(e) + + # Clean up partial file if not resuming + if not task.resume and task.dest_path.exists(): + task.dest_path.unlink() + + return False + + def _download_single_file(self, task: DownloadTask, show_progress: bool = True) -> bool: + """Download a single file with resume support.""" + try: + # Get file size first + if task.expected_size is None: + task.expected_size = self._get_content_length(task.url) + + # Check for resume + resume_pos = 0 + if task.resume and task.dest_path.exists(): + resume_pos = task.dest_path.stat().st_size + if task.expected_size and resume_pos >= task.expected_size: + return self._validate_download(task) + + # Prepare headers for resume + headers = {} + if task.resume and resume_pos > 0: + headers['Range'] = f'bytes={resume_pos}-' + + # Make request + response = self.session.get(task.url, headers=headers, stream=True) + response.raise_for_status() + + # Handle redirect + if response.status_code == 302: + redirect_url = response.headers.get('Location') + if redirect_url: + response = self.session.get(redirect_url, headers=headers, stream=True) + response.raise_for_status() + + # Get actual content length + content_length = response.headers.get('Content-Length') + if content_length: + total_size = int(content_length) + resume_pos + if task.expected_size is None: + task.expected_size = total_size + + mode = 'ab' if resume_pos > 0 else 'wb' + downloaded = resume_pos + + # Progress bar + if show_progress and task.expected_size: + console = Console() + console.print(f"[blue]Downloading {task.dest_path.name}...[/blue]") + + with open(task.dest_path, mode) as f: + start_time = time.time() + for chunk in response.iter_content(chunk_size=8192): + if chunk: + # Rate limiting + sleep_time = self.rate_limiter.acquire(len(chunk)) + if sleep_time > 0: + time.sleep(sleep_time) + + f.write(chunk) + downloaded += len(chunk) + + # Only show speed updates if not in parallel mode (to avoid spam) + if downloaded % (1024 * 1024) == 0 and show_progress: # Update every 1MB + elapsed = time.time() - start_time + if elapsed > 0: + speed = downloaded / elapsed + # Only print speed updates when show_progress is True (not in parallel mode) + pass # Remove speed updates in parallel mode + + # Download completed successfully + + # Validate download + task.status = 'completed' + return self._validate_download(task) + + except Exception as e: + task.status = 'failed' + task.error = str(e) + print(f"Download failed for {task.dest_path}: {e}") + + # Clean up partial file if not resuming + if not task.resume and task.dest_path.exists(): + task.dest_path.unlink() + + return False + + def _get_content_length(self, url: str) -> Optional[int]: + """Get content length from HEAD request.""" + try: + response = self.session.session.head(url, timeout=30) + response.raise_for_status() + content_length = response.headers.get('Content-Length') + return int(content_length) if content_length else None + except: + return None + + def _validate_download(self, task: DownloadTask) -> bool: + """Validate downloaded file.""" + if not self.settings.validate_downloads: + return True + + try: + # Check file size + if not self.validator.validate_file_size(task.dest_path, task.expected_size): + print(f"Size validation failed for {task.dest_path}") + return False + + # Check checksum if provided + if task.checksum: + actual_checksum = self.validator.calculate_checksum(task.dest_path) + if actual_checksum != task.checksum: + print(f"Checksum validation failed for {task.dest_path}") + return False + + return True + except Exception as e: + print(f"Validation error for {task.dest_path}: {e}") + return False + + def close(self): + """Clean up resources.""" + self.session.close() + self.executor.shutdown(wait=True) \ No newline at end of file diff --git a/thinkific_downloader/downloader.py b/thinkific_downloader/downloader.py index 0ab5711..d74dbda 100644 --- a/thinkific_downloader/downloader.py +++ b/thinkific_downloader/downloader.py @@ -11,6 +11,8 @@ from .config import Settings, load_env from .file_utils import filter_filename, unicode_decode +from .download_manager import DownloadManager, DownloadTask +from .progress_manager import print_banner, print_download_start_banner, print_completion_summary, ContentProcessor from tqdm import tqdm # Globals to mirror PHP behavior @@ -18,14 +20,19 @@ COURSE_CONTENTS: List[Dict[str, Any]] = [] SETTINGS: Optional[Settings] = None BASE_HOST: Optional[str] = None +DOWNLOAD_MANAGER: Optional[DownloadManager] = None +DOWNLOAD_TASKS: List[Dict[str, Any]] = [] # Collect all download tasks for parallel execution +CONTENT_PROCESSOR: Optional[ContentProcessor] = None USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36' def init_settings(): - global SETTINGS + global SETTINGS, DOWNLOAD_MANAGER, CONTENT_PROCESSOR if SETTINGS is None: SETTINGS = Settings.from_env() + DOWNLOAD_MANAGER = DownloadManager(SETTINGS) + CONTENT_PROCESSOR = ContentProcessor() def http_get(url: str, headers: Optional[Dict[str, str]] = None, timeout: int = 60) -> str: @@ -85,77 +92,70 @@ def download_file_redirect(url: str, file_name: Optional[str] = None): download_file_chunked(final_url, fname) -def download_file_chunked(src_url: str, dst_name: str, chunk_mb: int = 1): - if Path(dst_name).exists(): +def add_download_task(url: str, dest_path: Path, content_type: str = "file"): + """Add a download task to the global download queue.""" + global DOWNLOAD_TASKS + if DOWNLOAD_TASKS is None: + DOWNLOAD_TASKS = [] + + # Skip if file already exists + if dest_path.exists(): return - init_settings() - if SETTINGS is None: - raise RuntimeError("Settings not initialized") - request_headers = { - 'Accept-Encoding': 'identity', # streaming - 'Sec-Fetch-Mode': 'cors', - 'Sec-Fetch-Site': 'cross-site', - 'x-requested-with': 'XMLHttpRequest', - 'x-thinkific-client-date': SETTINGS.client_date, - 'cookie': SETTINGS.cookie_data, - 'User-Agent': USER_AGENT, - } - req = urllib.request.Request(src_url, headers=request_headers) - try: - with urllib.request.urlopen(req) as resp: - # Get file size for progress bar - content_length = resp.headers.get('Content-Length') - total_size = int(content_length) if content_length else None - - chunk_bytes = chunk_mb * 1024 * 1024 - - # Create progress bar - with tqdm( - total=total_size, - unit='B', - unit_scale=True, - unit_divisor=1024, - desc=f"Downloading {Path(dst_name).name}", - bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, {rate_fmt}]' - ) as pbar: - - with open(dst_name, 'wb') as out: - start_time = time.time() - downloaded = 0 - - while True: - chunk = resp.read(chunk_bytes) - if not chunk: - break - out.write(chunk) - downloaded += len(chunk) - - # Update progress bar - pbar.update(len(chunk)) - - # Calculate and display speed every few chunks - if downloaded % (chunk_bytes * 5) == 0: # Update speed every 5MB - elapsed = time.time() - start_time - if elapsed > 0: - speed = downloaded / elapsed - pbar.set_postfix({'speed': f'{speed/1024/1024:.2f} MB/s'}) - - # Final speed calculation - elapsed = time.time() - start_time - if elapsed > 0: - speed = downloaded / elapsed - print(f"Download completed: {downloaded/1024/1024:.2f} MB in {elapsed:.2f}s (avg: {speed/1024/1024:.2f} MB/s)") + DOWNLOAD_TASKS.append({ + 'url': url, + 'dest_path': dest_path, + 'content_type': content_type + }) + + +def execute_parallel_downloads() -> int: + """Execute all queued downloads in parallel and return success count.""" + global DOWNLOAD_TASKS, DOWNLOAD_MANAGER - except Exception as e: - print(f"Download failed for {dst_name}: {e}") - # Clean up partial file - if Path(dst_name).exists(): - Path(dst_name).unlink() + if not DOWNLOAD_TASKS or not DOWNLOAD_MANAGER: + return 0 + + from .download_manager import DownloadTask + + # Convert to DownloadTask objects + tasks = [] + for task_data in DOWNLOAD_TASKS: + task = DownloadTask( + url=task_data['url'], + dest_path=task_data['dest_path'] + ) + tasks.append(task) + + # Execute downloads in parallel + results = DOWNLOAD_MANAGER.download_files_parallel(tasks) + + # Count successful downloads + success_count = sum(1 for result in results if result) + return success_count + + +def download_file_chunked(src_url: str, dst_name: str, chunk_mb: int = 1): + """Queue file for parallel download instead of downloading immediately.""" + global DOWNLOAD_TASKS + dst_path = Path(dst_name) + + # Skip if file already exists + if dst_path.exists(): + return + + # Add to download queue instead of downloading immediately + add_download_task(src_url, dst_path, "file") + def init_course(data: Dict[str, Any]): - global COURSE_CONTENTS, ROOT_PROJECT_DIR, BASE_HOST + """Initialize course structure and collect ALL download tasks first.""" + global COURSE_CONTENTS, ROOT_PROJECT_DIR, BASE_HOST, DOWNLOAD_TASKS + + # Initialize download tasks list + DOWNLOAD_TASKS = [] + course_name = filter_filename(data['course']['name']) prev_dir = Path.cwd() ROOT_PROJECT_DIR = prev_dir @@ -163,22 +163,463 @@ def init_course(data: Dict[str, Any]): course_dir.mkdir(exist_ok=True) os.chdir(course_dir) COURSE_CONTENTS = data['contents'] + + # Check for resume capability + cache_file = Path('.thinkific_progress.json') + analyzed_chapters = set() + saved_tasks = [] + + if cache_file.exists(): + try: + import json + with open(cache_file, 'r', encoding='utf-8') as f: + cache_data = json.load(f) + analyzed_chapters = set(cache_data.get('analyzed_chapters', [])) + saved_tasks = cache_data.get('download_tasks', []) + print(f"๐Ÿ“‹ Found previous progress: {len(analyzed_chapters)} chapters analyzed, {len(saved_tasks)} tasks cached") + except: + analyzed_chapters = set() + saved_tasks = [] + # Derive base host from landing_page_url if available landing = data['course'].get('landing_page_url') if landing: BASE_HOST = urlparse(landing).hostname - create_chap_folders(data) + + # Phase 1: Create all folders and collect ALL download links + print("\n๐Ÿ” Phase 1: Analyzing course content and collecting download links...") + + # Restore saved download tasks + if saved_tasks: + print(f"๐Ÿ“ฅ Restoring {len(saved_tasks)} previously collected download tasks...") + for task_data in saved_tasks: + add_download_task(task_data['url'], Path(task_data['dest_path']), task_data.get('content_type', 'video')) + + collect_all_download_tasks(data, analyzed_chapters, cache_file) + + # Phase 2: Execute ALL downloads together + if DOWNLOAD_TASKS: + from .progress_manager import print_download_start_banner + + print(f"\n๐Ÿš€ Phase 2: Starting parallel download of {len(DOWNLOAD_TASKS)} files...") + + # Initialize download manager + init_settings() + parallel_workers = SETTINGS.concurrent_downloads if SETTINGS else 3 + print_download_start_banner(len(DOWNLOAD_TASKS), parallel_workers) + + if DOWNLOAD_MANAGER: + import time + start_time = time.time() + success_count = execute_parallel_downloads() + total_time = time.time() - start_time + + if success_count is not None: + from .progress_manager import print_completion_summary + print_completion_summary(success_count, len(DOWNLOAD_TASKS), total_time) + else: + print(f"[INFO] Download process completed in {total_time:.2f}s") + else: + print("[ERROR] Download manager not initialized") + else: + print("[INFO] No files found for download") + os.chdir(prev_dir) -def create_chap_folders(data: Dict[str, Any]): +def collect_all_download_tasks(data: Dict[str, Any], analyzed_chapters = None, cache_file = None): + """Collect ALL download tasks for the entire course without downloading anything.""" + global DOWNLOAD_TASKS + + if analyzed_chapters is None: + analyzed_chapters = set() + + import json + for i, chapter in enumerate(data.get('chapters', []), start=1): + chapter_id = f"chapter_{i}" + + # Skip if already analyzed (for resume) + if chapter_id in analyzed_chapters: + print(f"โญ๏ธ Skipping Chapter {i}: {chapter['name']} (already analyzed)") + continue + chap_folder_name = f"{i}. {filter_filename(chapter['name'])}" - Path(chap_folder_name).mkdir(exist_ok=True) - prev_dir = Path.cwd() - os.chdir(chap_folder_name) - chapterwise_download(chapter['content_ids']) - os.chdir(prev_dir) + chapter_path = Path(chap_folder_name) + chapter_path.mkdir(exist_ok=True) + + print(f"๐Ÿ“ Analyzing Chapter {i}: {chapter['name']}") + + # Collect download tasks for this chapter + collect_chapter_tasks(chapter['content_ids'], chapter_path) + + # Mark as analyzed and save progress + analyzed_chapters.add(chapter_id) + if cache_file: + try: + # Save current download tasks for resume + task_data = [] + for task in DOWNLOAD_TASKS: + task_data.append({ + 'url': task.url, + 'dest_path': str(task.dest_path), + 'content_type': getattr(task, 'content_type', 'video') + }) + + with open(cache_file, 'w', encoding='utf-8') as f: + json.dump({ + 'analyzed_chapters': list(analyzed_chapters), + 'download_tasks': task_data + }, f, indent=2) + except Exception as e: + print(f" โš ๏ธ Could not save progress: {e}") + pass # Continue even if cache save fails + + +def collect_chapter_tasks(content_ids: Iterable[Any], chapter_path: Path): + """Collect download tasks for a specific chapter.""" + from .wistia_downloader import video_downloader_wistia, video_downloader_videoproxy + global COURSE_CONTENTS, SETTINGS, DOWNLOAD_TASKS + + index = 1 + for content_id in content_ids: + match = next((c for c in COURSE_CONTENTS if c['id'] == content_id), None) + if not match: + print(f" โš ๏ธ No content found for id {content_id}") + index += 1 + continue + + ctype = match.get('contentable_type') or match.get('default_lesson_type_label') + print(f" ๐Ÿ” Found {ctype}: {match.get('name')}") + + # HTML Item (Notes) - Collect download tasks + if ctype == 'HtmlItem': + fname = filter_filename(f"{match['slug']}.html") + dc = chapter_path / filter_filename(f"{index}. {match['name']} Text") + dc.mkdir(exist_ok=True) + + if not (dc / fname).exists(): + j = api_get(f"/api/course_player/v2/html_items/{match['contentable']}") + if j: + html_text = j.get('html_item', {}).get('html_text', '') + decoded = unicode_decode(html_text) + + # Collect MP3 audio files + mp3_matches = MP3_PATTERN.findall(decoded) + if mp3_matches: + for audio_url in set(mp3_matches): + audio_name = filter_filename(Path(urlparse(audio_url).path).name) + add_download_task(audio_url, dc / audio_name, "audio") + + # Save HTML content to file + fname = fname.replace(" ", "-") + (dc / fname).write_text(decoded, encoding='utf-8', errors='replace') + + # Collect video download tasks + videoproxy_matches = VIDEOPROXY_PATTERN.findall(decoded) + if videoproxy_matches: + for video_url in set(videoproxy_matches): + collect_video_task_videoproxy(video_url, filter_filename(match['name']), dc) + + wistia_matches = WISTIA_PATTERN.findall(decoded) + if wistia_matches: + for wistia_id in set(wistia_matches): + collect_video_task_wistia(wistia_id, filter_filename(match['name']), dc) + + index += 1 + continue + + # Multimedia (iframe) - Collect download tasks + if match.get('default_lesson_type_label') == 'Multimedia': + dc = chapter_path / filter_filename(f"{index}. {match['name']} Multimedia") + dc.mkdir(exist_ok=True) + + j = api_get(f"/api/course_player/v2/iframes/{match['contentable']}") + file_contents = '' + if j: + src_url = unicode_decode(j.get('iframe', {}).get('source_url') or '') + if re.search(r"(\.md|\.html|/)$", src_url): + try: + file_contents = http_get(src_url) + except Exception: + file_contents = src_url + else: + file_contents = src_url + + # Collect attached files + if j.get('download_files'): + for download_file in j['download_files']: + download_file_name = filter_filename(download_file.get('label') or 'file') + download_file_url = download_file.get('download_url') + if download_file_url: + add_download_task(download_file_url, dc / download_file_name, "file") + + # Save HTML file + fname = f"{match['name']}.html" + fname = re.sub(r"[^A-Za-z0-9\_\-\. \?]", '', fname) + fname = filter_filename(fname) + (dc / fname).write_text(file_contents, encoding='utf-8', errors='replace') + + index += 1 + continue + + # Lesson (videos + html + attachments) - Collect download tasks + if ctype == 'Lesson': + dc = chapter_path / filter_filename(f"{index}. {match['name']} Lesson") + dc.mkdir(exist_ok=True) + vname = filter_filename(match['name']) + + j = api_get(f"/api/course_player/v2/lessons/{match['contentable']}") + if j: + # Collect video download tasks + videos = j.get('videos') or [] + if videos: + for video in videos: + storage = video.get('storage_location') + identifier = video.get('identifier') + if storage == 'wistia' and identifier: + collect_video_task_wistia(identifier, vname, dc) + elif storage == 'videoproxy' and identifier: + collect_video_task_videoproxy(f"https://platform.thinkific.com/videoproxy/v1/play/{identifier}", vname, dc) + else: + direct = video.get('url') + if direct: + add_download_task(direct, dc / f"{vname}.mp4", "video") + + # Save lesson HTML content + lesson_info = j.get('lesson', {}) + html_text = lesson_info.get('html_text') if isinstance(lesson_info, dict) else None + if html_text and html_text.strip(): + html_filename = f"{vname}.html" + (dc / html_filename).write_text(html_text, encoding='utf-8', errors='replace') + + # Collect attached files + for dlf in j.get('download_files', []) or []: + download_file_name = filter_filename(dlf.get('label') or 'file') + download_file_url = dlf.get('download_url') + if download_file_url: + add_download_task(download_file_url, dc / download_file_name, "file") + + index += 1 + continue + + # PDF - Collect download tasks + if ctype == 'Pdf': + dc = chapter_path / filter_filename(f"{index}. {match['name']}") + dc.mkdir(exist_ok=True) + + j = api_get(f"/api/course_player/v2/pdfs/{match['contentable']}") + if j: + pdf = j.get('pdf', {}) + pdf_url = pdf.get('url') + if pdf_url: + fname = filter_filename(Path(urlparse(pdf_url).path).name) + add_download_task(pdf_url, dc / fname, "pdf") + + index += 1 + continue + + # Download (shared files) - Collect download tasks + if ctype == 'Download': + dc = chapter_path / filter_filename(f"{index}. {match['name']}") + dc.mkdir(exist_ok=True) + + j = api_get(f"/api/course_player/v2/downloads/{match['contentable']}") + if j: + for dlf in j.get('download_files', []) or []: + label = filter_filename(dlf.get('label') or 'file') + url = dlf.get('download_url') + if url: + add_download_task(url, dc / label, "file") + + index += 1 + continue + + # Audio - Collect download tasks + if ctype == 'Audio': + dc = chapter_path / filter_filename(f"{index}. {match['name']}") + dc.mkdir(exist_ok=True) + + j = api_get(f"/api/course_player/v2/audio/{match['contentable']}") + if j: + audio = j.get('audio', {}) + audio_url = audio.get('url') + if audio_url: + fname = filter_filename(Path(urlparse(audio_url).path).name) + add_download_task(audio_url, dc / fname, "audio") + + index += 1 + continue + + # Presentation - Collect download tasks + if ctype == 'Presentation': + dc = chapter_path / filter_filename(f"{index}. {match['name']}") + dc.mkdir(exist_ok=True) + + j = api_get(f"/api/course_player/v2/presentations/{match['contentable']}") + if j: + pres = j.get('presentation', {}) + pdf_url = pres.get('source_file_url') + pdf_name = filter_filename(pres.get('source_file_name') or 'slides.pdf') + if pdf_url: + add_download_task(pdf_url, dc / pdf_name, "presentation") + + # Handle presentation merging - collect slide assets + merge_flag = SETTINGS.ffmpeg_presentation_merge if SETTINGS else False + if merge_flag: + from shutil import which + if which('ffmpeg'): + items = j.get('presentation_items') or [] + for it in items: + pos = it.get('position') + img_url = it.get('image_file_url') + aud_url = it.get('audio_file_url') + if img_url: + img_url = 'https:' + img_url if img_url.startswith('//') else img_url + img_name = filter_filename(f"{pos}{it.get('image_file_name','slide.png')}") + add_download_task(img_url, dc / img_name, "image") + if aud_url: + aud_url = 'https:' + aud_url if aud_url.startswith('//') else aud_url + aud_name = filter_filename(f"{pos}{it.get('audio_file_name','audio.m4a')}") + add_download_task(aud_url, dc / aud_name, "audio") + + index += 1 + continue + + # Quiz - Handle separately (complex logic) + if ctype == 'Quiz': + dc = chapter_path / filter_filename(f"{index}. {match['name']} Quiz") + dc.mkdir(exist_ok=True) + + fname = filter_filename(f"{match['name']} Answers.html") + qname = filter_filename(f"{match['name']} Questions.html") + + result = api_get(f"/api/course_player/v2/quizzes/{match['contentable']}") + if result: + file_contents_with_answers = "

Answers of this Quiz are marked in RED

" + file_contents_with_questions = "" + + for qs in result.get("questions", []): + choice = 'A' + position = qs.get("position", 0) + 1 + prompt = unicode_decode(qs.get("prompt", "")) + explanation = unicode_decode(qs.get("text_explanation", "")) + + file_contents_with_answers += f"{position}) {prompt} Explanation: {explanation}

" + + # Collect embedded video tasks + wistia_matches = WISTIA_PATTERN.findall(prompt) + if wistia_matches: + for wistia_match in set(wistia_matches): + collect_video_task_wistia(wistia_match, f"QA Video {position}", dc) + + file_contents_with_questions += f"{position}) {prompt}

" + + for ch in result.get("choices", []): + if ch.get("question_id") == qs.get("id"): + try: + import base64 + ans = base64.b64decode(ch.get("credited", "")).decode('utf-8', 'ignore') + ans = re.sub(r'\d', '', ans) + except Exception: + ans = "" + + choice_text = unicode_decode(ch.get("text", "")) + if ans == "true": + file_contents_with_questions += f"{choice}) {choice_text}
" + file_contents_with_answers += f"{choice}) {choice_text}
" + else: + file_contents_with_questions += f"{choice}) {choice_text}
" + file_contents_with_answers += f"{choice}) {choice_text}
" + + choice = chr(ord(choice) + 1) + + file_contents_with_questions += "
" + file_contents_with_answers += "
" + + (dc / qname).write_text(file_contents_with_questions, encoding='utf-8', errors='replace') + (dc / fname).write_text(file_contents_with_answers, encoding='utf-8', errors='replace') + + index += 1 + continue + + # Assignment/Survey placeholders + if ctype in ['Assignment', 'Survey']: + print(f" โš ๏ธ {ctype} content type not yet implemented: {match['name']}") + index += 1 + continue + + index += 1 + + +def collect_video_task_wistia(wistia_id: str, file_name: str, dest_dir: Path): + """Collect Wistia video download task.""" + try: + from urllib.request import urlopen + from urllib.error import URLError, HTTPError + import json + import time + + # Get video info from Wistia API with retry logic + api_url = f"https://fast.wistia.com/embed/medias/{wistia_id}.json" + + data = None + for attempt in range(3): # 3 retry attempts + try: + with urlopen(api_url, timeout=15) as response: + data = json.loads(response.read().decode()) + break # Success, exit retry loop + + except (URLError, HTTPError, TimeoutError) as e: + if attempt < 2: # Not last attempt + print(f" โš ๏ธ Network timeout, retrying... (attempt {attempt + 1}/3)") + time.sleep(2) # Wait 2 seconds before retry + continue + else: + print(f" โŒ Failed to get video info after 3 attempts: {file_name}") + return + + if not data: + return + + assets = data.get('media', {}).get('assets', []) + if not assets: + return + + # Find best quality video + video_assets = [a for a in assets if a.get('type') == 'original'] + if not video_assets: + video_assets = [a for a in assets if a.get('type') in ['mp4_720', 'mp4_540', 'mp4_360']] + + if video_assets: + selected = video_assets[0] + video_url = selected.get('url') + if video_url: + ext = '.mp4' # Default extension + resolved_name = filter_filename(file_name) + ext + print(f" ๐Ÿ“น Found video: {resolved_name}") + add_download_task(video_url, dest_dir / resolved_name, "video") + except Exception as e: + print(f" โŒ Failed to collect Wistia video {wistia_id}: {e}") + + +def collect_video_task_videoproxy(video_url: str, file_name: str, dest_dir: Path): + """Collect videoproxy download task.""" + try: + from .wistia_downloader import VIDEO_PROXY_JSONP_ID_PATTERN + + video_html_frame = http_get(video_url) + match = VIDEO_PROXY_JSONP_ID_PATTERN.search(video_html_frame) + if match: + wistia_id = match.group(1) + collect_video_task_wistia(wistia_id, file_name, dest_dir) + except Exception as e: + print(f" โŒ Failed to collect videoproxy video: {e}") + + +def create_chap_folders(data: Dict[str, Any]): + """Legacy function - now handled by collect_all_download_tasks.""" + pass # Patterns reused @@ -195,10 +636,12 @@ def api_get(endpoint: str) -> Optional[Dict[str, Any]]: print('Base host unknown; cannot call API:', endpoint) return None url = f"https://{BASE_HOST}{endpoint}" - print(f"[API] Fetching: {url}") + if SETTINGS and SETTINGS.debug: + print(f"[API] Fetching: {url}") try: raw = http_get(url) - print(f"[API] Response (first 200 chars): {raw[:200]}") + if SETTINGS and SETTINGS.debug: + print(f"[API] Response (first 200 chars): {raw[:200]}") return json.loads(raw) except Exception as e: print(f"API GET failed {endpoint}: {e}") @@ -206,8 +649,17 @@ def api_get(endpoint: str) -> Optional[Dict[str, Any]]: def chapterwise_download(content_ids: Iterable[Any]): + """Process all content and queue downloads, then execute in parallel batches.""" from .wistia_downloader import video_downloader_wistia, video_downloader_videoproxy # local import - global COURSE_CONTENTS, SETTINGS, ROOT_PROJECT_DIR + from .progress_manager import print_completion_summary + + global COURSE_CONTENTS, SETTINGS, ROOT_PROJECT_DIR, DOWNLOAD_TASKS + + # Initialize and clear any existing download tasks + init_settings() + DOWNLOAD_TASKS = [] + + # Phase 1: Process all content and queue downloads (no actual downloading) index = 1 for content_id in content_ids: match = next((c for c in COURSE_CONTENTS if c['id'] == content_id), None) @@ -216,103 +668,101 @@ def chapterwise_download(content_ids: Iterable[Any]): index += 1 continue ctype = match.get('contentable_type') or match.get('default_lesson_type_label') - print(f"[INFO] Processing content id {content_id} type {ctype} name {match.get('name')}") + print(f"[QUEUE] Processing content id {content_id} type {ctype} name {match.get('name')}") - # HTML Item (Notes) + # HTML Item (Notes) - Queue downloads if ctype == 'HtmlItem': fname = filter_filename(f"{match['slug']}.html") - if Path(fname).exists(): - print("File already exists, skipping") - index += 1 - continue dc = filter_filename(f"{index}. {match['name']} Text") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) - print(f"Downloading {match['name']}") - j = api_get(f"/api/course_player/v2/html_items/{match['contentable']}") - if j: - html_text = j.get('html_item', {}).get('html_text', '') - decoded = unicode_decode(html_text) - - # Extract videoproxy links - videoproxy_matches = VIDEOPROXY_PATTERN.findall(decoded) - if videoproxy_matches: - print("Found Videoproxy in HTML Item") - for video_url in set(videoproxy_matches): - video_downloader_videoproxy(video_url, filter_filename(match['name']), SETTINGS.video_download_quality if SETTINGS else '720p') - - # Extract MP3 audio files - mp3_matches = MP3_PATTERN.findall(decoded) - if mp3_matches: - print("Found Audios in HTML Item") - for audio_url in set(mp3_matches): - audio_name = filter_filename(Path(urlparse(audio_url).path).name) - download_file_chunked(audio_url, audio_name) - - # Extract Wistia videos - wistia_matches = WISTIA_PATTERN.findall(decoded) - if wistia_matches: - print("Found Wistia Videos in HTML Item") - for wistia_id in set(wistia_matches): - video_downloader_wistia(wistia_id, filter_filename(match['name']), SETTINGS.video_download_quality if SETTINGS else '720p') - - # Save HTML content to file - fname = fname.replace(" ", "-") # PHP replaces spaces with dashes - Path(fname).write_text(decoded, encoding='utf-8', errors='replace') + + if not Path(fname).exists(): + j = api_get(f"/api/course_player/v2/html_items/{match['contentable']}") + if j: + html_text = j.get('html_item', {}).get('html_text', '') + decoded = unicode_decode(html_text) + + # Queue MP3 audio files with absolute paths + mp3_matches = MP3_PATTERN.findall(decoded) + if mp3_matches: + current_dir = Path.cwd() + for audio_url in set(mp3_matches): + audio_name = filter_filename(Path(urlparse(audio_url).path).name) + add_download_task(audio_url, current_dir / audio_name, "audio") + + # Save HTML content to file + fname = fname.replace(" ", "-") + Path(fname).write_text(decoded, encoding='utf-8', errors='replace') + + # Handle video downloads - queue them instead of downloading immediately + videoproxy_matches = VIDEOPROXY_PATTERN.findall(decoded) + if videoproxy_matches: + for video_url in set(videoproxy_matches): + # Extract video info and queue for download + from .wistia_downloader import video_downloader_videoproxy + video_downloader_videoproxy(video_url, filter_filename(match['name']), SETTINGS.video_download_quality if SETTINGS else '720p') + + wistia_matches = WISTIA_PATTERN.findall(decoded) + if wistia_matches: + for wistia_id in set(wistia_matches): + # Extract video info and queue for download + from .wistia_downloader import video_downloader_wistia + video_downloader_wistia(wistia_id, filter_filename(match['name']), SETTINGS.video_download_quality if SETTINGS else '720p') + os.chdir(prev) index += 1 continue - # Multimedia (iframe) + # Multimedia (iframe) - Queue downloads if match.get('default_lesson_type_label') == 'Multimedia': dc = filter_filename(f"{index}. {match['name']} Multimedia") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) - print(f"Downloading {match['name']}") + j = api_get(f"/api/course_player/v2/iframes/{match['contentable']}") file_contents = '' if j: src_url = unicode_decode(j.get('iframe', {}).get('source_url') or '') - # PHP logic: if URL contains .md, .html, or ends with /, try to fetch content if re.search(r"(\.md|\.html|/)$", src_url): try: file_contents = http_get(src_url) except Exception: - print("Not a valid documents, continuing") file_contents = src_url else: file_contents = src_url - # Download attached files + # Queue attached files with absolute paths if j.get('download_files'): + current_dir = Path.cwd() for download_file in j['download_files']: download_file_name = filter_filename(download_file.get('label') or 'file') download_file_url = download_file.get('download_url') if download_file_url: - download_file_chunked(download_file_url, download_file_name) + add_download_task(download_file_url, current_dir / download_file_name, "file") - # Save to HTML file (PHP logic) + # Save HTML file fname = f"{match['name']}.html" - fname = re.sub(r"[^A-Za-z0-9\_\-\. \?]", '', fname) # PHP filename sanitization + fname = re.sub(r"[^A-Za-z0-9\_\-\. \?]", '', fname) fname = filter_filename(fname) Path(fname).write_text(file_contents, encoding='utf-8', errors='replace') + os.chdir(prev) index += 1 continue - # Lesson (videos + html + attachments) + # Lesson (videos + html + attachments) - Queue downloads if ctype == 'Lesson': dc = filter_filename(f"{index}. {match['name']} Lesson") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) vname = filter_filename(match['name']) - print(f"Downloading Video : {vname}") + j = api_get(f"/api/course_player/v2/lessons/{match['contentable']}") if j: + # Handle videos - queue them for parallel download videos = j.get('videos') or [] - if not videos: - print('No Lesson Videos found for', vname) - else: + if videos: for video in videos: storage = video.get('storage_location') identifier = video.get('identifier') @@ -321,166 +771,123 @@ def chapterwise_download(content_ids: Iterable[Any]): elif storage == 'videoproxy' and identifier: video_downloader_videoproxy(f"https://platform.thinkific.com/videoproxy/v1/play/{identifier}", vname, SETTINGS.video_download_quality if SETTINGS else '720p') else: - print(f"Unknown video storage location. Trying Native Method for {vname}") direct = video.get('url') if direct: - download_file_redirect(direct, vname) + current_dir = Path.cwd() + add_download_task(direct, current_dir / f"{vname}.mp4", "video") - # Save lesson HTML content if exists (PHP logic) + # Save lesson HTML content lesson_info = j.get('lesson', {}) html_text = lesson_info.get('html_text') if isinstance(lesson_info, dict) else None - if html_text and html_text.strip(): # PHP checks if not empty - print(f"Saving HTML Text for {vname}") + if html_text and html_text.strip(): html_filename = f"{vname}.html" Path(html_filename).write_text(html_text, encoding='utf-8', errors='replace') - # Download attached files + # Queue attached files with absolute paths for dlf in j.get('download_files', []) or []: download_file_name = filter_filename(dlf.get('label') or 'file') download_file_url = dlf.get('download_url') if download_file_url: - download_file_chunked(download_file_url, download_file_name) + current_dir = Path.cwd() + add_download_task(download_file_url, current_dir / download_file_name, "file") + os.chdir(prev); index += 1; continue - # Pdf + # PDF - Queue downloads if ctype == 'Pdf': dc = filter_filename(f"{index}. {match['name']}") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) - print(f"Downloading {match['name']} (PDF)") + j = api_get(f"/api/course_player/v2/pdfs/{match['contentable']}") if j: pdf = j.get('pdf', {}) pdf_url = pdf.get('url') if pdf_url: + current_dir = Path.cwd() fname = filter_filename(Path(urlparse(pdf_url).path).name) - download_file_chunked(pdf_url, fname) + add_download_task(pdf_url, current_dir / fname, "pdf") + os.chdir(prev); index += 1; continue - # Download (shared files) + # Download (shared files) - Queue downloads if ctype == 'Download': dc = filter_filename(f"{index}. {match['name']}") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) - print(f"Downloading {match['name']} (Files)") + j = api_get(f"/api/course_player/v2/downloads/{match['contentable']}") if j: + current_dir = Path.cwd() for dlf in j.get('download_files', []) or []: label = filter_filename(dlf.get('label') or 'file') url = dlf.get('download_url') if url: - download_file_chunked(url, label) + add_download_task(url, current_dir / label, "file") + os.chdir(prev); index += 1; continue - # Audio + # Audio - Queue downloads if ctype == 'Audio': dc = filter_filename(f"{index}. {match['name']}") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) - print(f"Downloading {match['name']} (Audio)") + j = api_get(f"/api/course_player/v2/audio/{match['contentable']}") if j: audio = j.get('audio', {}) audio_url = audio.get('url') if audio_url: + current_dir = Path.cwd() fname = filter_filename(Path(urlparse(audio_url).path).name) - download_file_chunked(audio_url, fname) + add_download_task(audio_url, current_dir / fname, "audio") + os.chdir(prev); index += 1; continue - # Presentation + # Presentation - Queue downloads if ctype == 'Presentation': dc = filter_filename(f"{index}. {match['name']}") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) - print(f"Downloading {match['name']} (Presentation)") + j = api_get(f"/api/course_player/v2/presentations/{match['contentable']}") if j: pres = j.get('presentation', {}) pdf_url = pres.get('source_file_url') pdf_name = filter_filename(pres.get('source_file_name') or 'slides.pdf') if pdf_url: - download_file_chunked(pdf_url, pdf_name) - # Optional merging if ffmpeg available and flag is set + current_dir = Path.cwd() + add_download_task(pdf_url, current_dir / pdf_name, "presentation") + + # Handle presentation merging separately (complex ffmpeg logic not parallelized) merge_flag = SETTINGS.ffmpeg_presentation_merge if SETTINGS else False if merge_flag: - # Detect ffmpeg availability from shutil import which - if which('ffmpeg') is None: - print('ffmpeg not found in PATH; skipping merge. Install ffmpeg or disable flag.') - else: + if which('ffmpeg'): items = j.get('presentation_items') or [] - # Download images & audio (with position prefix) first - print('Downloading slide images/audio for merge') + current_dir = Path.cwd() + # Queue slide images and audio files for it in items: pos = it.get('position') img_url = it.get('image_file_url') aud_url = it.get('audio_file_url') if img_url: - download_file_chunked('https:' + img_url if img_url.startswith('//') else img_url, - filter_filename(f"{pos}{it.get('image_file_name','slide.png')}") ) - if aud_url: - download_file_chunked('https:' + aud_url if aud_url.startswith('//') else aud_url, - filter_filename(f"{pos}{it.get('audio_file_name','audio.m4a')}") ) - # Build per-slide videos - print('Merging slides to per-slide videos') - list_entries = [] - for it in items: - pos = it.get('position') - img_name = filter_filename(f"{pos}{it.get('image_file_name','slide.png')}") - aud_name = filter_filename(f"{pos}{it.get('audio_file_name','audio.m4a')}") if it.get('audio_file_url') else None - slide_video = filter_filename(f"{pos}-slide.mp4") - if Path(slide_video).exists(): - list_entries.append(slide_video) - continue - # Build ffmpeg command - if aud_name and Path(aud_name).exists(): - cmd = f'ffmpeg -r 1 -loop 1 -y -i "{img_name}" -i "{aud_name}" -c:a copy -r 1 -vcodec libx264 -shortest "{slide_video}" -hide_banner -loglevel error' - else: - cmd = f'ffmpeg -r 1 -loop 1 -t 5 -y -i "{img_name}" -f lavfi -i anullsrc -c:a aac -r 1 -vcodec libx264 -shortest "{slide_video}" -hide_banner -loglevel error' - print(cmd) - os.system(cmd) - if Path(slide_video).exists(): - list_entries.append(slide_video) - if list_entries: - # Write list.txt - with open('list.txt','w', encoding='utf-8') as lf: - for f in list_entries: - lf.write(f"file '{f}'\n") - merged_name = filter_filename(f"{match['contentable']}-{match['name']}-merged.mp4") - if not Path(merged_name).exists(): - concat_cmd = f'ffmpeg -n -f concat -safe 0 -i list.txt -c copy "{merged_name}" -hide_banner' - print(concat_cmd) - os.system(concat_cmd) - # Clean intermediates - for f in list_entries: - try: - Path(f).unlink() - except Exception: - pass - try: - Path('list.txt').unlink() - except Exception: - pass - # Remove slide assets (images/audio) - for it in items: - pos = it.get('position') + img_url = 'https:' + img_url if img_url.startswith('//') else img_url img_name = filter_filename(f"{pos}{it.get('image_file_name','slide.png')}") - if Path(img_name).exists(): - try: Path(img_name).unlink() - except Exception: pass - if it.get('audio_file_url'): - aud_name = filter_filename(f"{pos}{it.get('audio_file_name','audio.m4a')}") - if Path(aud_name).exists(): - try: Path(aud_name).unlink() - except Exception: pass + add_download_task(img_url, current_dir / img_name, "image") + if aud_url: + aud_url = 'https:' + aud_url if aud_url.startswith('//') else aud_url + aud_name = filter_filename(f"{pos}{it.get('audio_file_name','audio.m4a')}") + add_download_task(aud_url, current_dir / aud_name, "audio") + os.chdir(prev); index += 1; continue - # Quiz + # Quiz - Handle separately (complex logic) if ctype == 'Quiz': - print(f"Downloading {match['name']}") dc = filter_filename(f"{index}. {match['name']} Quiz") Path(dc).mkdir(exist_ok=True) prev = Path.cwd(); os.chdir(dc) + fname = filter_filename(f"{match['name']} Answers.html") qname = filter_filename(f"{match['name']} Questions.html") @@ -489,16 +896,15 @@ def chapterwise_download(content_ids: Iterable[Any]): file_contents_with_answers = "

Answers of this Quiz are marked in RED

" file_contents_with_questions = "" - # Process questions (PHP logic) for qs in result.get("questions", []): choice = 'A' - position = qs.get("position", 0) + 1 # PHP increments position by 1 + position = qs.get("position", 0) + 1 prompt = unicode_decode(qs.get("prompt", "")) explanation = unicode_decode(qs.get("text_explanation", "")) file_contents_with_answers += f"{position}) {prompt} Explanation: {explanation}

" - # Extract embedded Wistia videos from prompt (PHP logic) + # Handle embedded videos - queue them for parallel download wistia_matches = WISTIA_PATTERN.findall(prompt) if wistia_matches: for wistia_match in set(wistia_matches): @@ -506,13 +912,12 @@ def chapterwise_download(content_ids: Iterable[Any]): file_contents_with_questions += f"{position}) {prompt}

" - # Process choices for this question for ch in result.get("choices", []): if ch.get("question_id") == qs.get("id"): try: import base64 ans = base64.b64decode(ch.get("credited", "")).decode('utf-8', 'ignore') - ans = re.sub(r'\d', '', ans) # Remove digits + ans = re.sub(r'\d', '', ans) except Exception: ans = "" @@ -524,12 +929,11 @@ def chapterwise_download(content_ids: Iterable[Any]): file_contents_with_questions += f"{choice}) {choice_text}
" file_contents_with_answers += f"{choice}) {choice_text}
" - choice = chr(ord(choice) + 1) # Increment choice letter + choice = chr(ord(choice) + 1) file_contents_with_questions += "
" file_contents_with_answers += "
" - # Write both files (PHP logic) Path(qname).write_text(file_contents_with_questions, encoding='utf-8', errors='replace') Path(fname).write_text(file_contents_with_answers, encoding='utf-8', errors='replace') @@ -537,19 +941,36 @@ def chapterwise_download(content_ids: Iterable[Any]): index += 1 continue - # Assignment (placeholder - currently planned) - if ctype == 'Assignment': - print(f"Assignment content type not yet implemented: {match['name']}") - index += 1 - continue - - # Survey (placeholder - currently planned) - if ctype == 'Survey': - print(f"Survey content type not yet implemented: {match['name']}") + # Assignment/Survey placeholders + if ctype in ['Assignment', 'Survey']: + print(f"{ctype} content type not yet implemented: {match['name']}") index += 1 continue index += 1 + + # Phase 2: Execute all queued downloads in parallel + if DOWNLOAD_TASKS: + from .progress_manager import print_download_start_banner + + print(f"\n[PARALLEL] Starting parallel download of {len(DOWNLOAD_TASKS)} files...") + parallel_workers = SETTINGS.concurrent_downloads if SETTINGS else 3 + print_download_start_banner(len(DOWNLOAD_TASKS), parallel_workers) + + if DOWNLOAD_MANAGER: + import time + start_time = time.time() + success_count = execute_parallel_downloads() + total_time = time.time() - start_time + + if success_count is not None: + print_completion_summary(success_count, len(DOWNLOAD_TASKS), total_time) + else: + print(f"[INFO] Download process completed in {total_time:.2f}s") + else: + print("[ERROR] Download manager not initialized") + else: + print("[INFO] No files queued for download") def handler(course_url: str): @@ -566,7 +987,8 @@ def handler(course_url: str): def main(argv: List[str]): - print("THINKIFIC DOWNLOADER\nPython Port (Core)\nAuthor: Ported by Assistant\n") + print_banner() + # Ensure .env is loaded before checking COURSE_URL/COURSE_LINK try: load_env() @@ -577,38 +999,44 @@ def main(argv: List[str]): course_url_env_alt = os.getenv('COURSE_LINK') effective_course_url_env = course_url_env_primary or course_url_env_alt - if ('--json' in argv and len(argv) > 2) or os.getenv('COURSE_DATA_FILE'): - if '--json' in argv: - json_path = Path(argv[argv.index('--json') + 1]) - if not json_path.exists(): - print(f"File not found: {json_path}") - return - print('Using Custom Metadata File for course data.') - data = json.loads(json_path.read_text(encoding='utf-8')) - else: - course_data_file = os.getenv('COURSE_DATA_FILE') - if not course_data_file: - print('COURSE_DATA_FILE env var not set.') - return - json_path = Path(course_data_file) - if not json_path.exists(): - print(f"File not found: {json_path}") - return - print('Loading Custom Metadata File from env for course data.') - data = json.loads(json_path.read_text(encoding='utf-8')) - init_course(data) - elif len(argv) > 1: - course_url = argv[1] - handler(course_url) - else: - if effective_course_url_env: - print(f"Using course url from env: { 'COURSE_URL' if course_url_env_primary else 'COURSE_LINK' }") - handler(effective_course_url_env) + try: + if ('--json' in argv and len(argv) > 2) or os.getenv('COURSE_DATA_FILE'): + if '--json' in argv: + json_path = Path(argv[argv.index('--json') + 1]) + if not json_path.exists(): + print(f"File not found: {json_path}") + return + print('Using Custom Metadata File for course data.') + data = json.loads(json_path.read_text(encoding='utf-8')) + else: + course_data_file = os.getenv('COURSE_DATA_FILE') + if not course_data_file: + print('COURSE_DATA_FILE env var not set.') + return + json_path = Path(course_data_file) + if not json_path.exists(): + print(f"File not found: {json_path}") + return + print('Loading Custom Metadata File from env for course data.') + data = json.loads(json_path.read_text(encoding='utf-8')) + init_course(data) + elif len(argv) > 1: + course_url = argv[1] + handler(course_url) else: - print('No course URL resolved.') - print('Usage for using course url: python thinkidownloader3.py ') - print('Or set COURSE_URL=... (fallback: COURSE_LINK=...) in .env') - print('Usage for selective download: python thinkidownloader3.py --json ') + if effective_course_url_env: + print(f"Using course url from env: { 'COURSE_URL' if course_url_env_primary else 'COURSE_LINK' }") + handler(effective_course_url_env) + else: + print('No course URL resolved.') + print('Usage for using course url: python thinkidownloader3.py ') + print('Or set COURSE_URL=... (fallback: COURSE_LINK=...) in .env') + print('Usage for selective download: python thinkidownloader3.py --json ') + finally: + # Clean up download manager + global DOWNLOAD_MANAGER + if DOWNLOAD_MANAGER: + DOWNLOAD_MANAGER.close() if __name__ == '__main__': diff --git a/thinkific_downloader/progress_manager.py b/thinkific_downloader/progress_manager.py new file mode 100644 index 0000000..973edcf --- /dev/null +++ b/thinkific_downloader/progress_manager.py @@ -0,0 +1,228 @@ +import sys +from typing import List, Dict, Any, Optional +from pathlib import Path +from rich.console import Console +from rich.progress import Progress, TaskID, TextColumn, BarColumn, TimeRemainingColumn, TransferSpeedColumn, DownloadColumn +from rich.panel import Panel +from rich.text import Text +from rich.layout import Layout +from rich.live import Live + +console = Console() + +class ProgressDisplay: + """Manages rich progress display for downloads.""" + + def __init__(self): + self.progress = Progress( + TextColumn("[bold blue]{task.fields[filename]}", justify="right"), + BarColumn(bar_width=40), + "[progress.percentage]{task.percentage:>3.1f}%", + "โ€ข", + DownloadColumn(), + "โ€ข", + TransferSpeedColumn(), + "โ€ข", + TimeRemainingColumn(), + console=console, + transient=True + ) + self.tasks: Dict[str, TaskID] = {} + + def add_task(self, filename: str, total_size: Optional[int] = None) -> TaskID: + """Add a download task to the progress display.""" + task_id = self.progress.add_task( + "download", + filename=filename, + total=total_size + ) + self.tasks[filename] = task_id + return task_id + + def update_task(self, filename: str, advance: int = 0, **kwargs): + """Update progress for a specific task.""" + if filename in self.tasks: + self.progress.update(self.tasks[filename], advance=advance, **kwargs) + + def complete_task(self, filename: str): + """Mark a task as completed.""" + if filename in self.tasks: + self.progress.update(self.tasks[filename], completed=True) + + def start(self): + """Start the progress display.""" + self.progress.start() + + def stop(self): + """Stop the progress display.""" + self.progress.stop() + + +class ContentProcessor: + """Handles content processing with cleaner output.""" + + def __init__(self): + self.processed_items = [] + self.download_queue = [] + + def process_content_item(self, item: Dict[str, Any], index: int) -> Dict[str, Any]: + """Process a content item and collect download tasks.""" + content_type = item.get('contentable_type') or item.get('default_lesson_type_label', 'Unknown') + name = item.get('name', 'Untitled') + + # Create a clean summary + summary = { + 'index': index, + 'name': name, + 'type': content_type, + 'files': [], + 'status': 'pending' + } + + # Log the processing + console.print(f"[cyan]๐Ÿ“‹ Processing:[/cyan] {content_type} - {name}", style="dim") + + # Collect files to download based on content type + files_to_download = self._get_files_for_content_type(item, content_type) + summary['files'] = files_to_download + + # Add to download queue + self.download_queue.extend(files_to_download) + + self.processed_items.append(summary) + return summary + + def _get_files_for_content_type(self, item: Dict[str, Any], content_type: str) -> List[Dict[str, Any]]: + """Get list of files to download for a specific content type.""" + files = [] + + if content_type == 'Lesson': + # Video files + files.append({ + 'type': 'video', + 'url': f"wistia:{item.get('contentable')}", # Placeholder + 'filename': f"{item.get('name', 'video')}.mp4", + 'size_estimate': '100-500MB' + }) + + elif content_type == 'Pdf': + files.append({ + 'type': 'pdf', + 'url': f"pdf:{item.get('contentable')}", # Placeholder + 'filename': f"{item.get('name', 'document')}.pdf", + 'size_estimate': '1-10MB' + }) + + elif content_type == 'HtmlItem': + files.append({ + 'type': 'html', + 'url': f"html:{item.get('contentable')}", # Placeholder + 'filename': f"{item.get('name', 'content')}.html", + 'size_estimate': '<1MB' + }) + + elif content_type == 'Audio': + files.append({ + 'type': 'audio', + 'url': f"audio:{item.get('contentable')}", # Placeholder + 'filename': f"{item.get('name', 'audio')}.mp3", + 'size_estimate': '5-50MB' + }) + + return files + + def print_summary(self): + """Print a summary of all processed content.""" + if not self.processed_items: + console.print("[yellow]No content items processed[/yellow]") + return + + # Create summary panel + summary_text = Text() + summary_text.append("๐Ÿ“Š Content Summary\n", style="bold cyan") + + type_counts = {} + total_files = 0 + + for item in self.processed_items: + content_type = item['type'] + type_counts[content_type] = type_counts.get(content_type, 0) + 1 + total_files += len(item['files']) + + summary_text.append(f"Total Items: {len(self.processed_items)}\n", style="white") + summary_text.append(f"Total Files: {total_files}\n", style="white") + summary_text.append("\nContent Types:\n", style="bold white") + + for content_type, count in type_counts.items(): + emoji = self._get_type_emoji(content_type) + summary_text.append(f" {emoji} {content_type}: {count}\n", style="green") + + panel = Panel(summary_text, title="Processing Summary", border_style="blue") + console.print(panel) + + def _get_type_emoji(self, content_type: str) -> str: + """Get emoji for content type.""" + emoji_map = { + 'Lesson': '๐ŸŽฅ', + 'Pdf': '๐Ÿ“„', + 'HtmlItem': '๐Ÿ“', + 'Audio': '๐ŸŽต', + 'Quiz': '๐Ÿ“', + 'Download': '๐Ÿ“', + 'Presentation': '๐ŸŽจ', + 'Multimedia': '๐Ÿ–ผ๏ธ' + } + return emoji_map.get(content_type, '๐Ÿ“‹') + + +def print_banner(): + """Print a clean banner.""" + banner_text = Text() + banner_text.append("๐Ÿš€ THINKIFIC DOWNLOADER\n", style="bold cyan") + banner_text.append("Enhanced with Parallel Downloads & Rich UI\n", style="green") + + panel = Panel( + banner_text, + title="Starting Download", + border_style="cyan", + padding=(1, 2) + ) + console.print(panel) + + +def print_download_start_banner(total_files: int, parallel_workers: int): + """Print banner before starting downloads.""" + info_text = Text() + info_text.append(f"๐Ÿ“ Files to download: {total_files}\n", style="white") + info_text.append(f"๐Ÿ”„ Parallel workers: {parallel_workers}\n", style="white") + info_text.append(f"โšก Enhanced features: Rate limiting, Resume, Validation\n", style="green") + + panel = Panel( + info_text, + title="Download Configuration", + border_style="green", + padding=(1, 2) + ) + console.print(panel) + + +def print_completion_summary(successful: int, failed: int, total_time: float): + """Print completion summary.""" + status_text = Text() + + if failed == 0: + status_text.append("๐ŸŽ‰ All downloads completed successfully!\n", style="bold green") + else: + status_text.append(f"โš ๏ธ Downloads completed with {failed} failures\n", style="bold yellow") + + status_text.append(f"โœ… Successful: {successful}\n", style="green") + status_text.append(f"โŒ Failed: {failed}\n", style="red" if failed > 0 else "dim") + status_text.append(f"โฑ๏ธ Total time: {total_time:.1f}s\n", style="blue") + + panel = Panel( + status_text, + title="Download Complete", + border_style="green" if failed == 0 else "yellow", + padding=(1, 2) + ) + console.print(panel) \ No newline at end of file diff --git a/thinkific_downloader/wistia_downloader.py b/thinkific_downloader/wistia_downloader.py index a087956..5ec6423 100644 --- a/thinkific_downloader/wistia_downloader.py +++ b/thinkific_downloader/wistia_downloader.py @@ -6,6 +6,7 @@ from pathlib import Path import os from .file_utils import filter_filename +from .download_manager import DownloadManager # Local imports inside functions to avoid circular dependency during module import # Handles video proxy and wistia direct downloads @@ -32,7 +33,11 @@ def video_downloader_wistia(wistia_id: str, file_name: Optional[str] = None, qua automatically decompressed by urllib. Falls back to selecting first asset if desired quality not present. """ - from .downloader import download_file_chunked # delayed import (avoid circular) + from .downloader import DOWNLOAD_MANAGER # delayed import + + if not DOWNLOAD_MANAGER: + from .downloader import init_settings + init_settings() json_url = WISTIA_JSON_URL.format(id=wistia_id) @@ -132,7 +137,10 @@ def infer_ext(asset: dict) -> str: if all_formats_flag: print(f"Downloading all available Wistia assets for {resolved_base}") - from .downloader import download_file_chunked # local import inside to avoid circular earlier + from .downloader import DOWNLOAD_MANAGER # local import inside to avoid circular earlier + if not DOWNLOAD_MANAGER: + from .downloader import init_settings + init_settings() seen: List[str] = [] for asset in assets: a_url = asset.get('url') @@ -151,7 +159,10 @@ def infer_ext(asset: dict) -> str: if not out_name.endswith(ext): out_name += ext print(f"Asset: {display} -> {a_url}") - download_file_chunked(a_url, filter_filename(out_name)) + if DOWNLOAD_MANAGER: + DOWNLOAD_MANAGER.download_file(a_url, Path(filter_filename(out_name))) + else: + print("Download manager not initialized") return # Single quality path @@ -177,4 +188,9 @@ def infer_ext(asset: dict) -> str: ext = '.mp4' # Default fallback resolved_name = resolved_base + (ext if not resolved_base.endswith(ext) else '') print(f"URL : {video_url}\nFile Name : {resolved_name}") - download_file_chunked(video_url, resolved_name) + + # Queue video for parallel download with absolute path to current directory + from .downloader import add_download_task + current_dir = Path.cwd() # Capture current working directory + full_path = current_dir / resolved_name # Create absolute path + add_download_task(video_url, full_path, "video") From 19eda744a0388b62d79b3c8b0932f91fb73641ae Mon Sep 17 00:00:00 2001 From: kavinthangavel Date: Wed, 24 Sep 2025 13:41:31 +0530 Subject: [PATCH 2/5] okay added multi dwln --- .gitignore | 3 +- DEVELOPMENT.md | 30 +++-- README.md | 36 ++++- SETUP.md | 30 +++++ thinkific_downloader/download_manager.py | 164 +++++++++++++++++++---- thinkific_downloader/downloader.py | 127 +++++++++++++++--- 6 files changed, 335 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 385d88f..e125f38 100644 --- a/.gitignore +++ b/.gitignore @@ -93,4 +93,5 @@ ffmpeg.log # Docker runtime artifacts (keep config files in git) .docker/ docker-volumes/ -*.pid \ No newline at end of file +*.pid +thinkific-launch-accelerator-course-october-2025/.download_status.json.bak diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 78e7212..a0cdb5b 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -62,13 +62,15 @@ graph TB - Retry logic with exponential backoff - Resource management -#### **4. File Validator** (`file_validator.py`) -- **Purpose**: Smart file validation and skip logic + +#### **4. Resume Tracker** (`resume_tracker.py`) +- **Purpose**: Atomic, cross-platform resume and status tracking - **Features**: - - File integrity checking (size, checksums) - - Resume detection and validation - - Download metadata persistence - - Smart skip decisions + - Download status tracking and backup (Windows, Mac, Linux) + - File integrity checking (size, checksums) + - Resume detection and validation + - Download metadata persistence + - Smart skip decisions #### **5. Content Processors** - **Wistia Downloader** (`wistia_downloader.py`): Video processing @@ -179,7 +181,7 @@ graph TD 3. **Course Processing**: API calls โ†’ Content parsing โ†’ Task creation 4. **Download Orchestration**: Task queue โ†’ `download_manager.py` โ†’ Parallel workers 5. **Progress Tracking**: Thread-safe updates โ†’ `progress_manager.py` โ†’ Rich UI -6. **Validation**: File checks โ†’ `file_validator.py` โ†’ Skip decisions +6. **Validation**: File checks โ†’ `resume_tracker.py` โ†’ Skip decisions --- @@ -286,7 +288,7 @@ tests/ โ”œโ”€โ”€ unit/ โ”‚ โ”œโ”€โ”€ test_progress_manager.py โ”‚ โ”œโ”€โ”€ test_download_manager.py -โ”‚ โ”œโ”€โ”€ test_file_validator.py +โ”‚ โ”œโ”€โ”€ test_resume_tracker.py โ”‚ โ””โ”€โ”€ test_enhanced_downloader.py โ”œโ”€โ”€ integration/ โ”‚ โ”œโ”€โ”€ test_full_download.py @@ -339,6 +341,18 @@ class TestProgressManager: # Assert assert file_id in progress_manager.downloads assert download.filename == filename + + def test_resume_tracker_atomic_save(self): + from thinkific_downloader.resume_tracker import ResumeTracker + import tempfile + with tempfile.TemporaryDirectory() as tmpdir: + status_file = Path(tmpdir) / ".download_status.json" + tracker = ResumeTracker(str(status_file)) + tracker.status_data["test"] = {"status": "completed"} + tracker._save_status() + assert status_file.exists() + backup_file = status_file.with_suffix('.json.bak') + assert backup_file.exists() @patch('thinkific_downloader.progress_manager.time.time') def test_calculate_download_speed(self, mock_time, progress_manager): diff --git a/README.md b/README.md index 80785bf..13434a6 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,21 @@ A modern, feature-rich Python utility to download courses from Thinkific platfor - **๐Ÿง  Smart File Validation** - Automatic integrity checking and corruption detection - **โ–ถ๏ธ Resume Downloads** - Intelligent partial download recovery and continuation - **โญ๏ธ Skip Existing Files** - Automatic detection and skipping of completed downloads +- **๐Ÿ’พ Atomic Resume/Backup System** - Cross-platform safe status tracking and backup (Windows, Mac, Linux) ### ๐ŸŽฏ **Progress Monitoring** +#### Example Progress UI ``` -๐Ÿ’พ introduction.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100% 156.2MB โ€ข 12.3MB/s โ€ข Complete +๏ฟฝ Resume Status Summary + โœ… 5 files already completed + ๐Ÿ“ฅ 2 files partially downloaded (will resume) + โŒ 1 files previously failed (will retry) + +๐Ÿ“ Files to download: 31 +๐Ÿ”„ Parallel workers: 3 +โšก Enhanced features: Rate limiting, Resume, Validation + +๐ŸŽฅ welcome-video.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100% 156.2MB โ€ข 12.3MB/s โ€ข Complete ๐Ÿ”„ lesson-02.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 45% 89.1MB/198.4MB โ€ข 8.7MB/s โ€ข 0:00:12 โณ lesson-03.pdf โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 0% Queued ``` @@ -69,6 +80,7 @@ A modern, feature-rich Python utility to download courses from Thinkific platfor - **Rich Terminal Interface** - Beautiful progress bars and status updates - **Smart File Organization** - Logical folder structure with clean naming - **Resume Support** - Skip existing files, continue interrupted downloads +- **Atomic Resume/Backup** - Status file is always safely backed up and updated, works on Windows, Mac, Linux - **Multiple Quality Options** - Choose video quality (720p, 1080p, etc.) - **Comprehensive Logging** - Debug mode for troubleshooting @@ -77,6 +89,7 @@ A modern, feature-rich Python utility to download courses from Thinkific platfor - **Session Management** - Proper authentication handling - **Error Recovery** - Graceful handling of network issues - **Validation** - File integrity checks and cleanup +- **Atomic Status File** - Download status is always saved safely, with backup, for reliable resume ## ๐ŸŽฏ **Quick Start** @@ -99,6 +112,12 @@ python thinkidownloader3.py ``` +> **Resume/Backup System:** +> - Download status is tracked in `.download_status.json` (atomic, cross-platform) +> - A backup `.download_status.json.bak` is created automatically before each update +> - If interrupted, simply rerun the downloader to resume from where you left off +> - Works seamlessly on Windows, Mac, and Linux + > ๐Ÿ“– **Need detailed setup instructions?** Check out our comprehensive [**SETUP.md**](SETUP.md) guide for step-by-step installation, troubleshooting, and configuration options. > ๐Ÿ‘จโ€๐Ÿ’ป **Developer?** Visit [**DEVELOPMENT.md**](DEVELOPMENT.md) for architecture overview, API reference, and contribution guidelines. @@ -182,7 +201,22 @@ docker-compose up | **Quizzes** | `.json` | Structure export | Question/answer format | ## โ“ **FAQ** +### **Resume/Backup System** + +**Q: How does resume work?** +- The downloader automatically tracks download status in `.download_status.json`. +- Before updating, a backup `.download_status.json.bak` is created (atomic, safe). +- If interrupted, just rerun the downloader. It will resume partial downloads, skip completed files, and retry failed ones. +- No manual intervention needed. + +**Q: Is it safe on Windows, Mac, Linux?** +- Yes! The resume/backup system uses atomic file operations and works on all major platforms. + +**Q: Where is the status file stored?** +- In the current working directory (where you run the downloader). +**Q: Can I delete the status file?** +- Yes, but you will lose resume progress. The backup file is for safety only. ### **๐Ÿ” Authentication & Setup** **Q: How do I get the required authentication data?** diff --git a/SETUP.md b/SETUP.md index 244afd3..ab65d9b 100644 --- a/SETUP.md +++ b/SETUP.md @@ -204,6 +204,10 @@ VALIDATE_DOWNLOADS=true # Resume Partial Downloads (true/false) RESUME_PARTIAL=true +# Atomic Resume/Backup System (always enabled) +# Download status is tracked in .download_status.json (atomic, cross-platform) +# A backup .download_status.json.bak is created automatically before each update + # Debug Mode (true/false) DEBUG=false @@ -280,6 +284,15 @@ docker run -it --rm \ ๐Ÿ“š Course: Your Course Name | Progress: 0.0% (0/25 files) | Speed: 0.0 MB/s | ETA: Unknown +๐Ÿ“Š Resume Status Summary + โœ… 5 files already completed + ๐Ÿ“ฅ 2 files partially downloaded (will resume) + โŒ 1 files previously failed (will retry) + +๐Ÿ“ Files to download: 31 +๐Ÿ”„ Parallel workers: 3 +โšก Enhanced features: Rate limiting, Resume, Validation + ๐ŸŽฅ introduction.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100% 156.2MB โ€ข 12.3MB/s โ€ข Complete ๐Ÿ”„ lesson-02.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 45% 89.1MB/198.4MB โ€ข 8.7MB/s โ€ข 0:00:12 โณ lesson-03.pdf โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 0% Queued @@ -535,6 +548,23 @@ After setup, verify everything works: ```bash # Should show course info without downloading python -c "from thinkific_downloader.config import Settings; s=Settings.from_env(); print(f'โœ… Auth OK for {s.client_date[:20]}...')" + +## Resume/Backup System + +**How does resume work?** +- The downloader automatically tracks download status in `.download_status.json`. +- Before updating, a backup `.download_status.json.bak` is created (atomic, safe). +- If interrupted, just rerun the downloader. It will resume partial downloads, skip completed files, and retry failed ones. +- No manual intervention needed. + +**Is it safe on Windows, Mac, Linux?** +- Yes! The resume/backup system uses atomic file operations and works on all major platforms. + +**Where is the status file stored?** +- In the current working directory (where you run the downloader). + +**Can I delete the status file?** +- Yes, but you will lose resume progress. The backup file is for safety only. ``` ### **2. Test Network Connection** diff --git a/thinkific_downloader/download_manager.py b/thinkific_downloader/download_manager.py index 10de6e0..3ea0b9c 100644 --- a/thinkific_downloader/download_manager.py +++ b/thinkific_downloader/download_manager.py @@ -13,23 +13,54 @@ from rich.text import Text from rich.progress import ProgressColumn -class CustomSpeedColumn(ProgressColumn): - """Speed column that shows 'Queued' instead of '?'""" +class QueuedSpeedColumn(ProgressColumn): + """Speed column that shows 'Queued' instead of unrealistic speeds""" def render(self, task): - if task.speed is None: + # Try to get Rich's calculated speed + try: + # Rich Progress stores speed in task.speed as bytes per second + speed = task.speed + except: + speed = None + + if speed is None or speed <= 0: return Text("Queued", style="dim") - return Text(f"{task.speed:.1f} MB/s" if task.speed > 1 else f"{task.speed*1000:.0f} KB/s") - -class CustomTimeColumn(ProgressColumn): - """Time remaining column that shows 'Queued' instead of '-:--:--'""" + + # Convert bytes/sec to readable format + if speed >= 1024 * 1024: # >= 1 MB/s + speed_display = speed / (1024 * 1024) + return Text(f"{speed_display:.1f} MB/s", style="green") + elif speed >= 1024: # >= 1 KB/s + speed_display = speed / 1024 + return Text(f"{speed_display:.1f} KB/s", style="green") + else: + return Text(f"{speed:.0f} B/s", style="green") + +class QueuedTimeColumn(ProgressColumn): + """Time remaining column that shows 'Queued' for pending downloads""" def render(self, task): - if task.time_remaining is None: + try: + # Get Rich's calculated time remaining + time_remaining = task.time_remaining + except: + time_remaining = None + + if time_remaining is None or time_remaining <= 0: return Text("Queued", style="dim") - remaining = int(task.time_remaining) + + # Handle very long estimates (likely unrealistic) + if time_remaining > 86400: # More than 24 hours + return Text("Long time", style="yellow") + + remaining = int(time_remaining) hours = remaining // 3600 minutes = (remaining % 3600) // 60 seconds = remaining % 60 - return Text(f"{hours:02d}:{minutes:02d}:{seconds:02d}") + + if hours > 0: + return Text(f"{hours:02d}:{minutes:02d}:{seconds:02d}", style="cyan") + else: + return Text(f"{minutes:02d}:{seconds:02d}", style="cyan") from rich.console import Console from .config import Settings from .file_utils import filter_filename @@ -202,7 +233,7 @@ def download_files_parallel(self, tasks: List[DownloadTask], console = Console() - # Create rich progress display + # Create rich progress display progress = Progress( TextColumn("[bold blue]{task.fields[filename]}", justify="right"), BarColumn(bar_width=40), @@ -210,9 +241,9 @@ def download_files_parallel(self, tasks: List[DownloadTask], "โ€ข", DownloadColumn(), "โ€ข", - CustomSpeedColumn(), - "โ€ข", - CustomTimeColumn(), + TransferSpeedColumn(), + "โ€ข", + TimeRemainingColumn(), console=console, ) @@ -406,26 +437,103 @@ def _get_content_length(self, url: str) -> Optional[int]: return None def _validate_download(self, task: DownloadTask) -> bool: - """Validate downloaded file.""" - if not self.settings.validate_downloads: + """Validate downloaded file with comprehensive checks.""" + if not task.dest_path.exists(): + print(f"โŒ File missing: {task.dest_path.name}") + return False + + try: + file_size = task.dest_path.stat().st_size + + # Check if file is empty or too small + if file_size == 0: + print(f"โŒ Empty file detected: {task.dest_path.name}") + task.dest_path.unlink() # Remove empty file + return False + + # For video/audio files, check if they're complete and valid + if task.dest_path.suffix.lower() in ['.mp4', '.mp3', '.wav', '.m4a']: + if not self._validate_media_file(task.dest_path, file_size): + return False + + # Check expected size if available + if task.expected_size and task.expected_size > 0: + size_ratio = file_size / task.expected_size + + # File should be at least 90% of expected size + if size_ratio < 0.9: + print(f"โŒ Incomplete download: {task.dest_path.name} ({file_size:,} bytes, expected {task.expected_size:,})") + return False + + # File shouldn't be more than 110% of expected size (accounting for small variations) + if size_ratio > 1.1: + print(f"โš ๏ธ File larger than expected: {task.dest_path.name} ({file_size:,} bytes, expected {task.expected_size:,})") + # Don't fail for this case, might be normal + + # Additional validation for specific file types + if not self._validate_file_integrity(task.dest_path): + return False + + print(f"โœ… Validated: {task.dest_path.name} ({file_size:,} bytes)") return True - + + except Exception as e: + print(f"โŒ Validation error for {task.dest_path.name}: {e}") + return False + + def _validate_media_file(self, file_path: Path, file_size: int) -> bool: + """Validate media files (MP4, MP3, etc.) for corruption.""" try: - # Check file size - if not self.validator.validate_file_size(task.dest_path, task.expected_size): - print(f"Size validation failed for {task.dest_path}") + # Check for minimum file size (media files should be at least a few KB) + if file_size < 1024: # Less than 1KB is suspicious for media + print(f"โŒ Media file too small: {file_path.name} ({file_size} bytes)") + file_path.unlink() # Remove corrupted file return False - - # Check checksum if provided - if task.checksum: - actual_checksum = self.validator.calculate_checksum(task.dest_path) - if actual_checksum != task.checksum: - print(f"Checksum validation failed for {task.dest_path}") + + # Read first and last few bytes to check file structure + with open(file_path, 'rb') as f: + # Check beginning of file for media headers + header = f.read(16) + + # MP4 files should start with specific signatures + if file_path.suffix.lower() == '.mp4': + # Check for common MP4 signatures + if not (b'ftyp' in header or b'mdat' in header[:8]): + print(f"โŒ Invalid MP4 header: {file_path.name}") + file_path.unlink() + return False + + # Check if we can read the end of file (indicates complete download) + try: + f.seek(-min(1024, file_size), 2) # Go to last 1KB or file size + f.read(1024) + except: + print(f"โŒ Cannot read end of file: {file_path.name}") + file_path.unlink() return False - + return True + + except Exception as e: + print(f"โŒ Media validation failed for {file_path.name}: {e}") + if file_path.exists(): + file_path.unlink() # Remove corrupted file + return False + + def _validate_file_integrity(self, file_path: Path) -> bool: + """Basic file integrity checks.""" + try: + # Try to read the file completely + with open(file_path, 'rb') as f: + chunk_size = 8192 + while chunk := f.read(chunk_size): + pass # Just reading to ensure file is accessible + return True + except Exception as e: - print(f"Validation error for {task.dest_path}: {e}") + print(f"โŒ File integrity check failed for {file_path.name}: {e}") + if file_path.exists(): + file_path.unlink() # Remove corrupted file return False def close(self): diff --git a/thinkific_downloader/downloader.py b/thinkific_downloader/downloader.py index d74dbda..cd3f17c 100644 --- a/thinkific_downloader/downloader.py +++ b/thinkific_downloader/downloader.py @@ -36,6 +36,11 @@ def init_settings(): def http_get(url: str, headers: Optional[Dict[str, str]] = None, timeout: int = 60) -> str: + import time + import urllib.request + import urllib.error + import gzip + init_settings() if SETTINGS is None: raise RuntimeError("Settings not initialized") @@ -50,13 +55,28 @@ def http_get(url: str, headers: Optional[Dict[str, str]] = None, timeout: int = } if headers: request_headers.update(headers) - req = urllib.request.Request(url, headers=request_headers) - with urllib.request.urlopen(req, timeout=timeout) as resp: - data = resp.read() - encoding = resp.headers.get('Content-Encoding', '') - if 'gzip' in encoding: - data = gzip.decompress(data) - return data.decode('utf-8', errors='replace') + + # Retry logic for network reliability + for attempt in range(3): + try: + req = urllib.request.Request(url, headers=request_headers) + with urllib.request.urlopen(req, timeout=15) as resp: + data = resp.read() + encoding = resp.headers.get('Content-Encoding', '') + if 'gzip' in encoding: + data = gzip.decompress(data) + return data.decode('utf-8', errors='replace') + + except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError) as e: + if attempt < 2: # Not last attempt + print(f" โš ๏ธ Network timeout, retrying... (attempt {attempt + 1}/3)") + time.sleep(2) + continue + else: + raise e + + # Should never reach here, but just in case + raise RuntimeError("All retry attempts failed") def download_file_redirect(url: str, file_name: Optional[str] = None): @@ -98,15 +118,88 @@ def add_download_task(url: str, dest_path: Path, content_type: str = "file"): if DOWNLOAD_TASKS is None: DOWNLOAD_TASKS = [] - # Skip if file already exists + # Check if file exists and validate it + should_download = True if dest_path.exists(): - return + file_size = dest_path.stat().st_size + + # Always re-download empty or suspiciously small files + if file_size == 0: + print(f"๐Ÿ”„ Re-downloading empty file: {dest_path.name}") + dest_path.unlink() + should_download = True + elif content_type in ['video', 'audio'] and file_size < 1024: + print(f"๐Ÿ”„ Re-downloading corrupt media file: {dest_path.name}") + dest_path.unlink() + should_download = True + elif _validate_existing_file(dest_path, content_type): + print(f"โœ… File already complete: {dest_path.name}") + should_download = False + else: + print(f"๐Ÿ”„ Re-downloading invalid file: {dest_path.name}") + dest_path.unlink() + should_download = True - DOWNLOAD_TASKS.append({ - 'url': url, - 'dest_path': dest_path, - 'content_type': content_type - }) + if should_download: + DOWNLOAD_TASKS.append({ + 'url': url, + 'dest_path': dest_path, + 'content_type': content_type + }) + + +def _validate_existing_file(file_path: Path, content_type: str) -> bool: + """Validate an existing file to determine if re-download is needed.""" + try: + file_size = file_path.stat().st_size + + # Empty files are always invalid + if file_size == 0: + return False + + # Media files need special validation + if content_type in ['video', 'audio'] and file_path.suffix.lower() in ['.mp4', '.mp3', '.wav', '.m4a']: + return _validate_media_file_basic(file_path, file_size) + + # For other files, just check if they're readable + try: + with open(file_path, 'rb') as f: + f.read(1024) # Try to read first 1KB + return True + except: + return False + + except Exception: + return False + + +def _validate_media_file_basic(file_path: Path, file_size: int) -> bool: + """Basic validation for media files.""" + try: + # Too small files are invalid + if file_size < 1024: + return False + + # Check file headers + with open(file_path, 'rb') as f: + header = f.read(16) + + # MP4 validation + if file_path.suffix.lower() == '.mp4': + if not (b'ftyp' in header or b'mdat' in header[:8]): + return False + + # Check if we can read the end (complete file) + try: + f.seek(-min(512, file_size), 2) + f.read(512) + except: + return False + + return True + + except Exception: + return False def execute_parallel_downloads() -> int: @@ -261,9 +354,9 @@ def collect_all_download_tasks(data: Dict[str, Any], analyzed_chapters = None, c task_data = [] for task in DOWNLOAD_TASKS: task_data.append({ - 'url': task.url, - 'dest_path': str(task.dest_path), - 'content_type': getattr(task, 'content_type', 'video') + 'url': task['url'], + 'dest_path': str(task['dest_path']), + 'content_type': task.get('content_type', 'video') }) with open(cache_file, 'w', encoding='utf-8') as f: From 83da4a07d1cbff44b6469606f55f39b169c8d524 Mon Sep 17 00:00:00 2001 From: kavinthangavel Date: Wed, 24 Sep 2025 13:49:50 +0530 Subject: [PATCH 3/5] added image --- README.md | 16 ++-------------- images/image.png | Bin 0 -> 336147 bytes 2 files changed, 2 insertions(+), 14 deletions(-) create mode 100644 images/image.png diff --git a/README.md b/README.md index 13434a6..69c1568 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,8 @@ A modern, feature-rich Python utility to download courses from Thinkific platfor ### ๐ŸŽฏ **Progress Monitoring** #### Example Progress UI -``` -๏ฟฝ Resume Status Summary - โœ… 5 files already completed - ๐Ÿ“ฅ 2 files partially downloaded (will resume) - โŒ 1 files previously failed (will retry) - -๐Ÿ“ Files to download: 31 -๐Ÿ”„ Parallel workers: 3 -โšก Enhanced features: Rate limiting, Resume, Validation - -๐ŸŽฅ welcome-video.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100% 156.2MB โ€ข 12.3MB/s โ€ข Complete -๐Ÿ”„ lesson-02.mp4 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 45% 89.1MB/198.4MB โ€ข 8.7MB/s โ€ข 0:00:12 -โณ lesson-03.pdf โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 0% Queued -``` + +![Progress UI](images/image.png) ### ๐Ÿ”’ **Reliability & Safety** - **๐Ÿ”„ Exponential Retry Logic** - Smart retry with jitter for failed downloads diff --git a/images/image.png b/images/image.png new file mode 100644 index 0000000000000000000000000000000000000000..37cb897448f53b206a883502cd5feddc4cdb3f1a GIT binary patch literal 336147 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 kFj`yWqes9VJs6o=p0tNE$1pV>+&X$vs}62q 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 Lt2%{Rf8P5q$g#+b literal 0 HcmV?d00001 From f4cc7c2b49cff7950a80f5ab8209590ab86d3606 Mon Sep 17 00:00:00 2001 From: kavinthangavel Date: Wed, 24 Sep 2025 14:22:46 +0530 Subject: [PATCH 4/5] okay fyn --- .env.example | 79 +++-- .github/workflows/ci.yml | 335 +++++++++++++++++++ .github/workflows/dependencies.yml | 81 +++++ .github/workflows/release.yml | 497 +++++++++++++++++++++++++++++ .gitignore | 1 - README.md | 108 +++++-- SETUP.md | 74 ++++- setup.py | 7 + thinkific_downloader/config.py | 22 +- thinkific_downloader/downloader.py | 8 +- 10 files changed, 1144 insertions(+), 68 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/dependencies.yml create mode 100644 .github/workflows/release.yml diff --git a/.env.example b/.env.example index 17c0873..06d3c77 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,13 @@ # Thinkific-Downloader Environment Configuration # Copy this file to .env and fill in your actual values +# =============================================== +# REQUIRED AUTHENTICATION +# =============================================== + # For downloading all content, use the course link. COURSE_LINK="https://your-thinkific-site.com/api/course_player/v2/courses/your-course-name" -# For selective content downloads, use the JSON file created from Thinki Parser. -# Copy the file to the Thinkifi Downloader root folder. -# Specify the file name below. Ex. COURSE_DATA_FILE="modified-course.json" -COURSE_DATA_FILE="" - # Client date header - Get this from browser Developer Tools Network tab CLIENT_DATE="2025-09-23T07:42:31.512Z" @@ -16,31 +15,69 @@ CLIENT_DATE="2025-09-23T07:42:31.512Z" # IMPORTANT: Keep this secret and never share it! COOKIE_DATA="_thinkific_session=YOUR_SESSION_COOKIE_HERE" +# =============================================== +# BASIC SETTINGS +# =============================================== + # Quality Available: "Original File", "1080p", "720p", "540p", "360p", "224p" # Recommended: "720p" for good quality and reasonable file size VIDEO_DOWNLOAD_QUALITY="720p" -# Set to true to download all available video formats/qualities -# Warning: This will significantly increase download size and time -# ALL_VIDEO_FORMATS=false +# Set download directory (defaults to ./downloads) +# All course content will be downloaded to this directory +OUTPUT_DIR="./downloads" + +# =============================================== +# ENHANCED FEATURES +# =============================================== + +# Number of concurrent downloads (default: 3, recommended: 1-5) +# Higher numbers may trigger rate limiting +CONCURRENT_DOWNLOADS=3 + +# Delay between downloads in seconds (default: 1.0) +# Increase if you encounter rate limiting issues +DOWNLOAD_DELAY=1.0 + +# Number of retry attempts for failed downloads (default: 3) +RETRY_ATTEMPTS=3 + +# Rate limiting in MB/s (default: unlimited) +# Set a value to limit download speed (e.g., RATE_LIMIT_MB_S=5.0) +# RATE_LIMIT_MB_S= + +# File validation after download (default: true) +# Validates file integrity and size +VALIDATE_DOWNLOADS=true + +# Resume partial downloads (default: true) +# Automatically resume interrupted downloads +RESUME_PARTIAL=true + +# Debug mode (default: false) +# Enable detailed logging for troubleshooting +DEBUG=false + +# =============================================== +# ADVANCED SETTINGS +# =============================================== # Set to true to enable ffmpeg presentation merging (requires ffmpeg installed) # This combines multi-part presentations into single video files -# FFMPEG_PRESENTATION_MERGE=false - -# Optional: Set download directory (defaults to ./downloads) -# OUTPUT_DIR="./downloads" +FFMPEG_PRESENTATION_MERGE=false -# Optional: Number of concurrent downloads (default: 2) -# Higher numbers may trigger rate limiting -# CONCURRENT_DOWNLOADS=2 +# =============================================== +# OPTIONAL FEATURES (LEGACY SUPPORT) +# =============================================== -# Optional: Delay between downloads in seconds (default: 1) -# Increase if you encounter rate limiting issues -# DOWNLOAD_DELAY=1 +# For selective content downloads, use the JSON file created from Thinki Parser. +# Copy the file to the Thinkifi Downloader root folder. +# Specify the file name below. Ex. COURSE_DATA_FILE="modified-course.json" +# COURSE_DATA_FILE="" -# Optional: Number of retry attempts for failed downloads (default: 3) -# RETRY_ATTEMPTS=3 +# Set to true to download all available video formats/qualities +# Warning: This will significantly increase download size and time +# ALL_VIDEO_FORMATS=false -# Optional: Log level (DEBUG, INFO, WARNING, ERROR) +# Log level (DEBUG, INFO, WARNING, ERROR) # LOG_LEVEL="INFO" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8d7c0ac --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,335 @@ +name: ๐Ÿงช CI/CD Pipeline + +on: + push: + branches: [ main, multi-dwl ] + pull_request: + branches: [ main ] + +env: + PYTHON_VERSION: '3.11' + +jobs: + # ============================================================================ + # Job 1: Code Quality & Testing + # ============================================================================ + test: + name: ๐Ÿงช Test & Quality Check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + exclude: + # Reduce matrix size - test all Python versions only on Ubuntu + - os: windows-latest + python-version: '3.8' + - os: windows-latest + python-version: '3.9' + - os: windows-latest + python-version: '3.10' + - os: macos-latest + python-version: '3.8' + - os: macos-latest + python-version: '3.9' + - os: macos-latest + python-version: '3.10' + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๐Ÿ Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: ๐Ÿ“ฆ Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest pytest-cov flake8 black isort + + - name: ๐ŸŽจ Code formatting check + run: | + black --check --diff . + isort --check-only --diff . + + - name: ๐Ÿ” Lint check + run: | + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + - name: ๐Ÿงช Run basic import tests + run: | + python -c "import thinkific_downloader; print('โœ… Package imports successfully')" + python -c "from thinkific_downloader.config import Settings; print('โœ… Config module works')" + python -c "from thinkific_downloader.downloader import main; print('โœ… Main module works')" + + - name: ๐Ÿ”ง Test .env handling + run: | + # Test that config handles missing .env gracefully + python -c " + import os + from thinkific_downloader.config import load_env + from pathlib import Path + + # Test with non-existent .env file + non_existent = Path('non_existent.env') + try: + load_env(non_existent) + print('โœ… Handles missing .env file gracefully') + except Exception as e: + print(f'โŒ Error handling missing .env: {e}') + exit(1) + " + + - name: ๐Ÿ“Š Test environment variable parsing + run: | + python -c " + import os + from thinkific_downloader.config import Settings + + # Set test environment variables + os.environ['CLIENT_DATE'] = 'test-date' + os.environ['COOKIE_DATA'] = 'test-cookie' + os.environ['OUTPUT_DIR'] = './test-downloads' + os.environ['CONCURRENT_DOWNLOADS'] = '5' + os.environ['DEBUG'] = 'true' + + try: + settings = Settings.from_env() + assert settings.output_dir == './test-downloads' + assert settings.concurrent_downloads == 5 + assert settings.debug == True + print('โœ… Environment variable parsing works correctly') + except SystemExit: + # Expected when required vars are set + print('โœ… Environment validation works') + except Exception as e: + print(f'โŒ Error in environment parsing: {e}') + exit(1) + " + + # ============================================================================ + # Job 2: Docker Build Test + # ============================================================================ + docker-test: + name: ๐Ÿณ Docker Build Test + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๐Ÿณ Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: ๐Ÿ”จ Build Docker image (test) + uses: docker/build-push-action@v5 + with: + context: . + push: false + tags: thinkific-downloader:test + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: ๐Ÿงช Test Docker image + run: | + # Test that the image starts without errors (with minimal config) + echo "Testing Docker image startup..." + docker run --rm thinkific-downloader:test python -c " + try: + import thinkific_downloader + print('โœ… Docker image: Package imports successfully') + except Exception as e: + print(f'โŒ Docker image: Import failed: {e}') + exit(1) + " + + # ============================================================================ + # Job 3: Project Structure Validation + # ============================================================================ + structure-test: + name: ๐Ÿ“ฆ Project Structure Test + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๏ฟฝ Validate project structure + run: | + echo "๐Ÿ“ Checking project structure..." + + # Check essential files exist + files_to_check=( + "thinkific_downloader/__init__.py" + "thinkific_downloader/config.py" + "thinkific_downloader/downloader.py" + "thinkific_downloader/download_manager.py" + "README.md" + "SETUP.md" + "requirements.txt" + ".env.example" + "Dockerfile" + "docker-compose.yml" + ) + + for file in "${files_to_check[@]}"; do + if [ -f "$file" ]; then + echo "โœ… $file exists" + else + echo "โŒ $file is missing" + exit 1 + fi + done + + echo "โœ… All essential files present" + + - name: ๐Ÿ”ง Test environment configuration + run: | + echo "๐Ÿงช Testing .env.example structure..." + + # Check for required sections + required_vars=( + "COURSE_LINK" + "COOKIE_DATA" + "CLIENT_DATE" + "OUTPUT_DIR" + "CONCURRENT_DOWNLOADS" + ) + + for var in "${required_vars[@]}"; do + if grep -q "$var" .env.example; then + echo "โœ… .env.example contains $var" + else + echo "โŒ .env.example missing $var" + exit 1 + fi + done + + echo "โœ… .env.example structure is valid" + + # ============================================================================ + # Job 4: Security & Vulnerability Check + # ============================================================================ + security: + name: ๐Ÿ”’ Security Check + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๐Ÿ Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: ๐Ÿ”’ Install security tools + run: | + python -m pip install --upgrade pip + pip install safety bandit + + - name: ๐Ÿงช Check dependencies for vulnerabilities + run: | + safety check -r requirements.txt + + - name: ๐Ÿ” Run static security analysis + run: | + bandit -r thinkific_downloader/ -f json -o bandit-report.json + bandit -r thinkific_downloader/ + + # ============================================================================ + # Job 5: Documentation Check + # ============================================================================ + docs-check: + name: ๐Ÿ“š Documentation Check + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๐Ÿ“– Check README structure + run: | + echo "๐Ÿ“‹ Checking documentation completeness..." + + # Check that essential sections exist in README + required_sections=( + "Quick Start" + "Docker" + "Configuration" + "Features" + ) + + for section in "${required_sections[@]}"; do + if grep -qi "$section" README.md; then + echo "โœ… README contains '$section' section" + else + echo "โš ๏ธ README missing '$section' section" + fi + done + + # Check .env.example is properly structured + if [ -f ".env.example" ]; then + echo "โœ… .env.example file exists" + + # Check for required sections + if grep -q "COURSE_LINK" .env.example && grep -q "COOKIE_DATA" .env.example; then + echo "โœ… .env.example contains required authentication variables" + else + echo "โŒ .env.example missing required authentication variables" + exit 1 + fi + + if grep -q "OUTPUT_DIR" .env.example; then + echo "โœ… .env.example contains OUTPUT_DIR configuration" + else + echo "โŒ .env.example missing OUTPUT_DIR configuration" + exit 1 + fi + else + echo "โŒ .env.example file is missing" + exit 1 + fi + + echo "โœ… Documentation check passed" + + # ============================================================================ + # Job 6: Summary + # ============================================================================ + summary: + name: ๐Ÿ“Š CI Summary + runs-on: ubuntu-latest + needs: [test, docker-test, structure-test, security, docs-check] + if: always() + + steps: + - name: ๐ŸŽ‰ Success Summary + if: needs.test.result == 'success' && needs.docker-test.result == 'success' && needs.structure-test.result == 'success' && needs.security.result == 'success' && needs.docs-check.result == 'success' + run: | + echo "๐ŸŽ‰ All CI checks passed successfully!" + echo "" + echo "โœ… Code quality and testing" + echo "โœ… Docker build verification" + echo "โœ… Project structure validation" + echo "โœ… Security vulnerability checks" + echo "โœ… Documentation completeness" + echo "" + echo "๐Ÿš€ Ready for merge/release!" + + - name: โŒ Failure Summary + if: needs.test.result == 'failure' || needs.docker-test.result == 'failure' || needs.structure-test.result == 'failure' || needs.security.result == 'failure' || needs.docs-check.result == 'failure' + run: | + echo "โŒ Some CI checks failed:" + echo "" + echo "๐Ÿงช Tests: ${{ needs.test.result }}" + echo "๐Ÿณ Docker: ${{ needs.docker-test.result }}" + echo "๐Ÿ“ฆ Structure: ${{ needs.structure-test.result }}" + echo "๐Ÿ”’ Security: ${{ needs.security.result }}" + echo "๐Ÿ“š Docs: ${{ needs.docs-check.result }}" + echo "" + echo "๐Ÿ”ง Please review and fix failing checks before merging." + exit 1 \ No newline at end of file diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml new file mode 100644 index 0000000..ec980bd --- /dev/null +++ b/.github/workflows/dependencies.yml @@ -0,0 +1,81 @@ +name: ๐Ÿ”„ Dependency Updates + +on: + schedule: + # Run every Monday at 9 AM UTC + - cron: '0 9 * * 1' + workflow_dispatch: + +jobs: + update-dependencies: + name: ๐Ÿ“ฆ Update Dependencies + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: ๐Ÿ Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: ๐Ÿ“ฆ Install tools + run: | + python -m pip install --upgrade pip + pip install safety + + - name: ๐Ÿ”„ Check for dependency updates + run: | + # Backup current requirements + cp requirements.txt requirements.txt.backup + + echo "๐Ÿ“‹ Current dependencies:" + cat requirements.txt + + echo "" + echo "๐Ÿ” Checking for available updates..." + pip list --outdated || echo "All packages up to date" + + - name: ๐Ÿงช Test current dependencies + run: | + pip install -r requirements.txt + python -c "import thinkific_downloader; print('โœ… Current dependencies work')" + + - name: ๐Ÿ”’ Security check + run: | + safety check -r requirements.txt + + - name: ๐Ÿ“ Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: '๐Ÿ”„ Update dependencies' + title: '๏ฟฝ Dependency Security Check' + body: | + ## ๏ฟฝ Automated Dependency Security Check + + This PR was automatically created to report on dependency security status. + + ### ๐Ÿงช Status + - Checked Python dependencies for security vulnerabilities + - Verified package imports work correctly + - Listed any available updates + + ### ๐Ÿ” Review Actions + - [ ] Review any security warnings in the job logs + - [ ] Consider updating dependencies if vulnerabilities found + - [ ] Test functionality with any recommended updates + + ### ๐Ÿค– Automation Info + - Created by GitHub Actions + - Triggered by: ${{ github.event_name }} + - Python version tested: 3.11 + + --- + + **Note**: This is an informational check. Manual review and testing recommended before updating dependencies. + branch: automated-dependency-update + delete-branch: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3c02a5f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,497 @@ +name: ๐Ÿš€ Release & Package + +on: + push: + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + version: + description: 'Version to release (e.g., v1.2.3)' + required: true + type: string + +env: + PYTHON_VERSION: '3.11' + DOCKER_IMAGE: kvnxo/thinkific-downloader + +jobs: + # ============================================================================ + # Job 1: Create GitHub Release + # ============================================================================ + create-release: + name: ๐Ÿ“ฆ Create GitHub Release + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + tag_name: ${{ steps.get_version.outputs.tag_name }} + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ๐Ÿท๏ธ Get version + id: get_version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "tag_name=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT + else + echo "tag_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + fi + + - name: ๐Ÿ“ Generate changelog + id: changelog + run: | + # Generate changelog from git commits since last tag + LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + if [ -z "$LAST_TAG" ]; then + COMMITS=$(git log --pretty=format:"- %s (%h)" --reverse) + else + COMMITS=$(git log $LAST_TAG..HEAD --pretty=format:"- %s (%h)" --reverse) + fi + + # Create changelog + cat << EOF > CHANGELOG.md + ## ๐ŸŽ‰ What's New in ${{ steps.get_version.outputs.tag_name }} + + ### ๐Ÿš€ Features & Improvements + $COMMITS + + ### ๐Ÿ“ฆ Installation Options + + #### ๐Ÿณ Docker (Recommended) + \`\`\`bash + # Clone the project + git clone https://github.com/itskavin/Thinkific-Downloader.git + cd Thinkific-Downloader + + # Setup and run + cp .env.example .env + # Edit .env with your course details + docker-compose up + \`\`\` + + #### ๐Ÿ Python Direct + \`\`\`bash + # Download and extract the source code + # Or clone: git clone https://github.com/itskavin/Thinkific-Downloader.git + cd Thinkific-Downloader + + # Install and run + pip install -r requirements.txt + python thinkificdownloader.py + \`\`\` + + ### ๐ŸŽฏ Key Features + - โœ… **Downloads to ./downloads by default** - All course content organized in project directory + - โœ… **Enhanced Docker workflow** - Requires project directory for proper functionality + - โœ… **Parallel processing** - Download multiple files simultaneously + - โœ… **Smart resume** - Continue interrupted downloads automatically + - โœ… **File validation** - Integrity checks and corruption detection + - โœ… **Rich progress UI** - Beautiful terminal interface with real-time updates + + ### ๐Ÿ“‹ Requirements + - Python 3.8+ (for direct installation) + - Docker (for containerized usage) + - FFmpeg (optional, for presentation merging) + + --- + + **โš ๏ธ Important**: Always clone or download the project first, then run Docker/Python from the project directory. The app needs access to the project folder for downloads, configuration, and proper functionality. + EOF + + # Set multiline output + echo "changelog<> $GITHUB_OUTPUT + cat CHANGELOG.md >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: ๐ŸŽ‰ Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.get_version.outputs.tag_name }} + release_name: ๐Ÿš€ Thinkific Downloader ${{ steps.get_version.outputs.tag_name }} + body: ${{ steps.changelog.outputs.changelog }} + draft: false + prerelease: false + + # ============================================================================ + # Job 2: Build Docker Images + # ============================================================================ + build-docker: + name: ๐Ÿณ Build & Push Docker Images + runs-on: ubuntu-latest + needs: create-release + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๐Ÿณ Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: ๐Ÿ”‘ Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: ๐Ÿท๏ธ Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_IMAGE }} + tags: | + type=ref,event=tag + type=raw,value=latest + type=raw,value=${{ needs.create-release.outputs.tag_name }} + + - name: ๐Ÿš€ Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + + # ============================================================================ + # Job 3: Create Platform-Specific Packages (Source Code) + # ============================================================================ + build-packages: + name: ๐Ÿ“ฆ Build Source Code Packages + runs-on: ${{ matrix.os }} + needs: create-release + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + include: + - os: ubuntu-latest + platform: linux + ext: tar.gz + - os: windows-latest + platform: windows + ext: zip + - os: macos-latest + platform: macos + ext: tar.gz + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + + - name: ๏ฟฝ Create portable source package + shell: bash + run: | + # Create package directory + mkdir -p package/thinkific-downloader + + # Copy all necessary files + cp -r thinkific_downloader package/thinkific-downloader/ + cp thinkificdownloader.py package/thinkific-downloader/ + cp requirements.txt package/thinkific-downloader/ + cp .env.example package/thinkific-downloader/ + cp README.md package/thinkific-downloader/ + cp SETUP.md package/thinkific-downloader/ + cp LICENSE package/thinkific-downloader/ + + # Copy Docker files if they exist + [ -f docker-compose.yml ] && cp docker-compose.yml package/thinkific-downloader/ + [ -f Dockerfile ] && cp Dockerfile package/thinkific-downloader/ + + # Create setup scripts for each platform + if [ "${{ matrix.platform }}" = "windows" ]; then + # Windows batch file + cat > package/thinkific-downloader/setup-and-run.bat << 'EOF' + @echo off + title Thinkific Downloader Setup + echo. + echo ๐Ÿš€ Thinkific Downloader - Setup and Run + echo ======================================== + echo. + + REM Check if .env exists + if not exist ".env" ( + echo ๐Ÿ“ Creating .env file from template... + copy .env.example .env + echo. + echo โš ๏ธ IMPORTANT: Please edit the .env file with your course details! + echo - Add your COURSE_LINK + echo - Add your COOKIE_DATA + echo - Add your CLIENT_DATE + echo. + echo ๐Ÿ“– See SETUP.md for detailed instructions on getting these values. + echo. + pause + echo. + ) + + REM Check for Python + python --version >nul 2>&1 + if %errorlevel% neq 0 ( + echo โŒ Python is not installed or not in PATH + echo Please install Python 3.8+ from https://python.org + pause + exit /b 1 + ) + + echo ๐Ÿ“ฆ Installing dependencies... + pip install -r requirements.txt + if %errorlevel% neq 0 ( + echo โŒ Failed to install dependencies + pause + exit /b 1 + ) + + echo. + echo ๐ŸŽฏ Starting Thinkific Downloader... + echo Downloads will be saved to: ./downloads/ + echo. + python thinkificdownloader.py + + echo. + echo ๐ŸŽ‰ Download completed! + pause + EOF + + # Docker script for Windows + cat > package/thinkific-downloader/run-docker.bat << 'EOF' + @echo off + title Thinkific Downloader - Docker + echo. + echo ๐Ÿณ Thinkific Downloader - Docker Mode + echo ==================================== + echo. + + REM Check if .env exists + if not exist ".env" ( + echo ๐Ÿ“ Creating .env file from template... + copy .env.example .env + echo. + echo โš ๏ธ IMPORTANT: Please edit the .env file with your course details! + echo See SETUP.md for detailed instructions. + echo. + pause + exit /b 1 + ) + + echo ๐Ÿ”„ Pulling latest Docker image... + docker pull kvnxo/thinkific-downloader:latest + + echo ๏ฟฝ Starting download with Docker... + echo Downloads will be saved to: ./downloads/ + echo. + docker run -it --rm -v "%cd%\downloads:/app/downloads" --env-file .env kvnxo/thinkific-downloader:latest + + echo. + echo ๐ŸŽ‰ Download completed! + pause + EOF + + else + # Unix shell script + cat > package/thinkific-downloader/setup-and-run.sh << 'EOF' + #!/bin/bash + set -e + + echo "๐Ÿš€ Thinkific Downloader - Setup and Run" + echo "========================================" + echo + + # Check if .env exists + if [ ! -f ".env" ]; then + echo "๐Ÿ“ Creating .env file from template..." + cp .env.example .env + echo + echo "โš ๏ธ IMPORTANT: Please edit the .env file with your course details!" + echo " - Add your COURSE_LINK" + echo " - Add your COOKIE_DATA" + echo " - Add your CLIENT_DATE" + echo + echo "๐Ÿ“– See SETUP.md for detailed instructions on getting these values." + echo + echo "Edit the .env file now and run this script again." + exit 1 + fi + + # Check for Python + if ! command -v python3 &> /dev/null && ! command -v python &> /dev/null; then + echo "โŒ Python is not installed" + echo " Please install Python 3.8+ from your package manager or https://python.org" + exit 1 + fi + + # Use python3 if available, otherwise python + PYTHON_CMD="python3" + if ! command -v python3 &> /dev/null; then + PYTHON_CMD="python" + fi + + echo "๐Ÿ“ฆ Installing dependencies..." + $PYTHON_CMD -m pip install -r requirements.txt + + echo + echo "๐ŸŽฏ Starting Thinkific Downloader..." + echo " Downloads will be saved to: ./downloads/" + echo + $PYTHON_CMD thinkificdownloader.py + + echo + echo "๐ŸŽ‰ Download completed!" + EOF + chmod +x package/thinkific-downloader/setup-and-run.sh + + # Docker script for Unix + cat > package/thinkific-downloader/run-docker.sh << 'EOF' + #!/bin/bash + set -e + + echo "๐Ÿณ Thinkific Downloader - Docker Mode" + echo "====================================" + echo + + # Check if .env exists + if [ ! -f ".env" ]; then + echo "๐Ÿ“ Creating .env file from template..." + cp .env.example .env + echo + echo "โš ๏ธ IMPORTANT: Please edit the .env file with your course details!" + echo " See SETUP.md for detailed instructions." + echo + echo "Edit the .env file now and run this script again." + exit 1 + fi + + # Check for Docker + if ! command -v docker &> /dev/null; then + echo "โŒ Docker is not installed" + echo " Please install Docker from https://docker.com" + exit 1 + fi + + echo "๐Ÿ”„ Pulling latest Docker image..." + docker pull kvnxo/thinkific-downloader:latest + + echo "๏ฟฝ Starting download with Docker..." + echo " Downloads will be saved to: ./downloads/" + echo + docker run -it --rm -v "$(pwd)/downloads:/app/downloads" --env-file .env kvnxo/thinkific-downloader:latest + + echo + echo "๐ŸŽ‰ Download completed!" + EOF + chmod +x package/thinkific-downloader/run-docker.sh + fi + + # Create README for package + cat > package/thinkific-downloader/QUICK-START.md << 'EOF' + # ๐Ÿ“ฅ Thinkific Downloader - Quick Start Guide + + ## ๐Ÿš€ Quick Start Options + + ### Option 1: Docker (Recommended) + **Requirements**: Docker installed + + 1. **Setup**: Edit `.env` file with your course details + 2. **Run**: + - **Windows**: Double-click `run-docker.bat` + - **Mac/Linux**: Run `./run-docker.sh` + + ### Option 2: Python Direct + **Requirements**: Python 3.8+ installed + + 1. **Setup**: Edit `.env` file with your course details + 2. **Run**: + - **Windows**: Double-click `setup-and-run.bat` + - **Mac/Linux**: Run `./setup-and-run.sh` + + ## ๏ฟฝ Configuration Required + + **Before running**, edit the `.env` file with: + - `COURSE_LINK`: Your Thinkific course URL + - `COOKIE_DATA`: Browser session cookies + - `CLIENT_DATE`: Client date header + + See `SETUP.md` for detailed instructions on getting these values. + + ## ๐Ÿ“ Downloads Location + + All course content will be downloaded to `./downloads/` folder in this directory. + + ## ๐Ÿ†˜ Need Help? + + - See `README.md` for complete features and documentation + - See `SETUP.md` for detailed setup instructions + - Visit: https://github.com/itskavin/Thinkific-Downloader + + ## ๐ŸŽฏ Key Features + + - โœ… Downloads to `./downloads/` by default + - โœ… Docker support for easy setup + - โœ… Parallel downloads for speed + - โœ… Smart resume for interrupted downloads + - โœ… File validation and integrity checks + EOF + + - name: ๐Ÿ“ Create archive + shell: bash + run: | + cd package + if [ "${{ matrix.platform }}" = "windows" ]; then + # Use PowerShell on Windows for better ZIP creation + powershell -command "Compress-Archive -Path 'thinkific-downloader' -DestinationPath '../thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.zip'" + else + tar -czf ../thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.tar.gz thinkific-downloader + fi + + - name: ๐Ÿ“ค Upload package + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: ./thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.${{ matrix.ext }} + asset_name: thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.${{ matrix.ext }} + asset_content_type: ${{ matrix.platform == 'windows' && 'application/zip' || 'application/gzip' }} + + # ============================================================================ + # Job 4: Update Documentation + # ============================================================================ + update-docs: + name: ๐Ÿ“š Update Documentation + runs-on: ubuntu-latest + needs: [create-release, build-docker] + if: always() && needs.create-release.result == 'success' + + steps: + - name: ๐Ÿ—๏ธ Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: ๐Ÿ“ Update Docker Hub description + run: | + echo "Docker image updated to ${{ needs.create-release.outputs.tag_name }}" + echo "This step would update Docker Hub description in a real scenario" + + - name: ๐ŸŽ‰ Summary + run: | + echo "๐Ÿš€ Release ${{ needs.create-release.outputs.tag_name }} completed successfully!" + echo "" + echo "๐Ÿ“ฆ Artifacts created:" + echo " - GitHub Release with source code" + echo " - Docker images (linux/amd64, linux/arm64)" + echo " - Platform-specific source packages (Windows, macOS, Linux)" + echo "" + echo "๐Ÿ”— Access your release at:" + echo " https://github.com/itskavin/Thinkific-Downloader/releases/tag/${{ needs.create-release.outputs.tag_name }}" + echo "" + echo "๐Ÿณ Docker images available:" + echo " docker pull kvnxo/thinkific-downloader:latest" + echo " docker pull kvnxo/thinkific-downloader:${{ needs.create-release.outputs.tag_name }}" \ No newline at end of file diff --git a/.gitignore b/.gitignore index e125f38..e3dadea 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ __pycache__/ build/ develop-eggs/ dist/ -downloads/ eggs/ .eggs/ lib/ diff --git a/README.md b/README.md index 69c1568..9e266cf 100644 --- a/README.md +++ b/README.md @@ -81,25 +81,63 @@ A modern, feature-rich Python utility to download courses from Thinkific platfor ## ๐ŸŽฏ **Quick Start** +**โš ๏ธ Important**: Always clone or download the project first! The application needs access to the project directory for downloads, configuration files (.env), and proper functionality. + ### **๐Ÿณ Docker (Recommended)** +**Step 1: Get the Project** ```bash +# Clone or download the project +git clone https://github.com/itskavin/Thinkific-Downloader.git +cd Thinkific-Downloader + +# Or download and extract ZIP, then navigate to project directory +``` + +**Step 2: Setup Environment** +```bash +# Create your .env file (see configuration section below) +cp .env.example .env +# Edit .env with your course details +``` + +**Step 3: Run with Docker** +```bash +# Pull latest image and run from project directory docker pull kvnxo/thinkific-downloader -docker run -it --rm -v $(pwd)/downloads:/app/downloads kvnxo/thinkific-downloader +docker run -it --rm -v $(pwd)/downloads:/app/downloads --env-file .env kvnxo/thinkific-downloader + +# Or use docker-compose (recommended) +docker-compose up ``` ### **๐Ÿ Python Direct** ```bash +# Step 1: Clone the project git clone https://github.com/itskavin/Thinkific-Downloader.git cd Thinkific-Downloader -pip install -r requirements.txt -# Update environment variables in .env or export them directly -python thinkidownloader3.py +# Step 2: Install dependencies +pip install -r requirements.txt +# Step 3: Configure and run +# Update environment variables in .env file +python thinkificdownloader.py ``` +### **๐Ÿ“ฆ Source Code Packages** + +Download source code packages from [GitHub Releases](https://github.com/itskavin/Thinkific-Downloader/releases): + +- **Windows**: `thinkific-downloader-vX.X.X-windows.zip` +- **macOS**: `thinkific-downloader-vX.X.X-macos.tar.gz` +- **Linux**: `thinkific-downloader-vX.X.X-linux.tar.gz` + +Each package includes setup scripts: +- **Windows**: `setup-and-run.bat` (Python) or `run-docker.bat` (Docker) +- **macOS/Linux**: `setup-and-run.sh` (Python) or `run-docker.sh` (Docker) + > **Resume/Backup System:** > - Download status is tracked in `.download_status.json` (atomic, cross-platform) > - A backup `.download_status.json.bak` is created automatically before each update @@ -115,27 +153,36 @@ python thinkidownloader3.py Configure advanced features via environment variables or `.env` file: ```bash -# Required +# =============================================== +# REQUIRED AUTHENTICATION +# =============================================== COURSE_LINK="" # Thinkific course URL COOKIE_DATA="" # Browser cookies for authentication CLIENT_DATE="" # Client date header -# Optional - Performance -VIDEO_DOWNLOAD_QUALITY="Original File" # Video quality (Original File,720p, 1080p, etc.) -CONCURRENT_DOWNLOADS=3 # Number of parallel downloads (1-10 recommended) +# =============================================== +# BASIC SETTINGS +# =============================================== +VIDEO_DOWNLOAD_QUALITY="720p" # Video quality (Original File, 720p, 1080p, etc.) +OUTPUT_DIR="./downloads" # Download directory (defaults to ./downloads) + +# =============================================== +# ENHANCED FEATURES +# =============================================== +CONCURRENT_DOWNLOADS=3 # Number of parallel downloads (1-5 recommended) RETRY_ATTEMPTS=3 # Number of retry attempts for failed downloads -RATE_LIMIT_MB_S=0 # Rate limit in MB/s (0 = unlimited) DOWNLOAD_DELAY=1.0 # Delay between downloads (seconds) +RATE_LIMIT_MB_S= # Rate limit in MB/s (empty = unlimited) -# Optional - Features +# Feature toggles VALIDATE_DOWNLOADS=true # Enable file integrity validation RESUME_PARTIAL=true # Enable resume for partial downloads DEBUG=false # Enable debug logging -# Optional - System -OUTPUT_DIR=./downloads # Download directory +# =============================================== +# ADVANCED SETTINGS +# =============================================== FFMPEG_PRESENTATION_MERGE=false # Enable FFmpeg presentation merging -LOG_LEVEL=INFO # Logging level (DEBUG, INFO, WARNING) ``` ``` @@ -158,24 +205,29 @@ docker-compose up ## ๐Ÿ“ **Output Structure** +**Default Location**: All courses are downloaded to `./downloads/` directory in your project folder. + ``` -๐Ÿ“ Course Name/ -โ”œโ”€โ”€ ๐Ÿ“ 01. Introduction/ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 01. Welcome Video/ -โ”‚ โ”‚ โ”œโ”€โ”€ ๐ŸŽฅ welcome-video.mp4 -โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ video-info.json -โ”‚ โ””โ”€โ”€ ๐Ÿ“ 02. Course Overview/ -โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ course-overview.html -โ”‚ โ””โ”€โ”€ ๐Ÿ“Š quiz-structure.json -โ”œโ”€โ”€ ๐Ÿ“ 02. Getting Started/ -โ”‚ โ””โ”€โ”€ ๐Ÿ“ 01. Setup Instructions/ -โ”‚ โ”œโ”€โ”€ ๐ŸŽฅ setup-instructions.mp4 -โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ setup-guide.pdf -โ”‚ โ””โ”€โ”€ ๐ŸŽจ presentation-slides.mp4 -โ”œโ”€โ”€ ๐Ÿ“„ course-metadata.json -โ””โ”€โ”€ ๐Ÿ“Š download-summary.json +๐Ÿ“ downloads/ +โ””โ”€โ”€ ๐Ÿ“ Course Name/ + โ”œโ”€โ”€ ๐Ÿ“ 01. Introduction/ + โ”‚ โ”œโ”€โ”€ ๐Ÿ“ 01. Welcome Video/ + โ”‚ โ”‚ โ”œโ”€โ”€ ๐ŸŽฅ welcome-video.mp4 + โ”‚ โ”‚ โ””โ”€โ”€ ๐Ÿ“„ video-info.json + โ”‚ โ””โ”€โ”€ ๐Ÿ“ 02. Course Overview/ + โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ course-overview.html + โ”‚ โ””โ”€โ”€ ๐Ÿ“Š quiz-structure.json + โ”œโ”€โ”€ ๐Ÿ“ 02. Getting Started/ + โ”‚ โ””โ”€โ”€ ๐Ÿ“ 01. Setup Instructions/ + โ”‚ โ”œโ”€โ”€ ๐ŸŽฅ setup-instructions.mp4 + โ”‚ โ”œโ”€โ”€ ๐Ÿ“„ setup-guide.pdf + โ”‚ โ””โ”€โ”€ ๐ŸŽจ presentation-slides.mp4 + โ”œโ”€โ”€ ๐Ÿ“„ course-metadata.json + โ””โ”€โ”€ ๐Ÿ“Š download-summary.json ``` +**Customization**: Set `OUTPUT_DIR=./my-custom-path` in your `.env` file to change the download location. + ### **Supported Content Types** diff --git a/SETUP.md b/SETUP.md index ab65d9b..5f075e5 100644 --- a/SETUP.md +++ b/SETUP.md @@ -36,30 +36,75 @@ This comprehensive guide walks you through installing and configuring Thinkific- ## ๐Ÿš€ Installation Methods -### **Method 1: Docker (Recommended - Easiest)** +### **๐Ÿ“ฆ Option 1: Source Code Packages (Easiest)** + +Download ready-to-use source packages from [GitHub Releases](https://github.com/itskavin/Thinkific-Downloader/releases): + +1. **Download** the package for your operating system: + - **Windows**: `thinkific-downloader-vX.X.X-windows.zip` + - **macOS**: `thinkific-downloader-vX.X.X-macos.tar.gz` + - **Linux**: `thinkific-downloader-vX.X.X-linux.tar.gz` + +2. **Extract** the downloaded package to your desired location + +3. **Setup** your configuration: + - Edit the `.env` file with your course details (see Authentication Setup below) + +4. **Run** the application: + - **Docker Mode** (Recommended): + - **Windows**: Double-click `run-docker.bat` + - **macOS/Linux**: Run `./run-docker.sh` + - **Python Mode**: + - **Windows**: Double-click `setup-and-run.bat` + - **macOS/Linux**: Run `./setup-and-run.sh` + +--- + +### **๐Ÿณ Option 2: Docker (Recommended for Advanced Users)** Docker provides the most consistent and hassle-free experience with all dependencies pre-installed. -#### **1.1 Install Docker** +#### **2.1 Install Docker** - **Windows/Mac**: Download [Docker Desktop](https://www.docker.com/products/docker-desktop/) - **Linux**: Follow [Docker installation guide](https://docs.docker.com/engine/install/) -#### **1.2 Pull and Run** +#### **2.2 Get the Project** +**Important**: You must clone or download the project first, as Docker needs access to the project directory for downloads, configuration files, and proper functionality. + +```bash +# Option A: Clone with Git +git clone https://github.com/itskavin/Thinkific-Downloader.git +cd Thinkific-Downloader + +# Option B: Download ZIP +# 1. Go to https://github.com/itskavin/Thinkific-Downloader +# 2. Click "Code" -> "Download ZIP" +# 3. Extract the ZIP file +# 4. Open terminal in the extracted folder +``` + +#### **2.3 Setup Environment** +```bash +# Create .env file from template (if available) +cp .env.example .env + +# Or create .env file manually (see Configuration section below) +``` + +#### **2.4 Run with Docker** ```bash # Pull the latest image docker pull kvnxo/thinkific-downloader:latest -# Run with basic setup +# Run from project directory (this is crucial!) docker run -it --rm \ -v $(pwd)/downloads:/app/downloads \ - -e COURSE_LINK="YOUR_COURSE_URL" \ - -e COOKIE_DATA="YOUR_COOKIES" \ - -e CLIENT_DATE="YOUR_CLIENT_DATE" \ + -v $(pwd)/.env:/app/.env \ kvnxo/thinkific-downloader:latest ``` -#### **1.3 Docker Compose (Recommended)** -Create `docker-compose.yml`: +#### **2.5 Docker Compose (Recommended)** +Create `docker-compose.yml` (or use the provided one): ```yaml version: '3.8' services: @@ -75,30 +120,31 @@ services: # Enhanced features - CONCURRENT_DOWNLOADS=3 - RETRY_ATTEMPTS=3 + - OUTPUT_DIR=./downloads ``` Run with: `docker-compose up` --- -### **Method 2: Python Package Installation** +### **๐Ÿ Option 3: Python Installation (For Developers)** For users who prefer native Python installation with full control. -#### **2.1 Clone Repository** +#### **3.1 Clone Repository** ```bash # Clone the repository git clone https://github.com/itskavin/Thinkific-Downloader.git cd Thinkific-Downloader ``` -#### **2.2 Quick Setup (Automated)** +#### **3.2 Quick Setup (Automated)** ```bash # Run the automated installer python install.py ``` -#### **2.3 Manual Installation** +#### **3.3 Manual Installation** ```bash # Create virtual environment (recommended) python -m venv venv @@ -113,7 +159,7 @@ pip install -r requirements.txt pip install -e . ``` -#### **2.4 Verify Installation** +#### **3.4 Verify Installation** ```bash # Test the installation python -m thinkific_downloader --help diff --git a/setup.py b/setup.py index 15ca50e..6416b43 100644 --- a/setup.py +++ b/setup.py @@ -28,9 +28,16 @@ packages=find_packages(), python_requires=">=3.8", install_requires=[ + "requests>=2.31.0", + "rich>=13.0.0", "tqdm>=4.65.0", + "urllib3>=2.0.0", ], extras_require={ + "enhanced": [ + "beautifulsoup4>=4.12.0", + "lxml>=4.9.0", + ], "brotli": ["brotli>=1.0.9"], }, entry_points={ diff --git a/thinkific_downloader/config.py b/thinkific_downloader/config.py index adf3bb0..5b98829 100644 --- a/thinkific_downloader/config.py +++ b/thinkific_downloader/config.py @@ -27,6 +27,7 @@ class Settings: cookie_data: str video_download_quality: str = '720p' ffmpeg_presentation_merge: bool = False + output_dir: str = './downloads' # Default to downloads directory # Enhanced downloader settings concurrent_downloads: int = 3 retry_attempts: int = 3 @@ -40,23 +41,37 @@ class Settings: @classmethod def from_env(cls): load_env() + + # Required authentication client_date = os.getenv('CLIENT_DATE', '') cookie_data = os.getenv('COOKIE_DATA', '') + + # Basic settings with matching defaults to .env.example video_download_quality = os.getenv('VIDEO_DOWNLOAD_QUALITY', '720p') + output_dir = os.getenv('OUTPUT_DIR', './downloads') + + # Advanced settings ffmpeg_flag_raw = os.getenv('FFMPEG_PRESENTATION_MERGE', 'false').lower() ffmpeg_merge = ffmpeg_flag_raw in ('1', 'true', 'yes', 'on') - # Enhanced settings + # Enhanced downloader settings with matching defaults concurrent_downloads = int(os.getenv('CONCURRENT_DOWNLOADS', '3')) retry_attempts = int(os.getenv('RETRY_ATTEMPTS', '3')) - rate_limit_mb_s = float(os.getenv('RATE_LIMIT_MB_S', '0')) or None download_delay = float(os.getenv('DOWNLOAD_DELAY', '1.0')) + + # Rate limiting - empty string or 0 means unlimited + rate_limit_env = os.getenv('RATE_LIMIT_MB_S', '') + rate_limit_mb_s = float(rate_limit_env) if rate_limit_env and rate_limit_env != '0' else None + + # Feature toggles validate_downloads = os.getenv('VALIDATE_DOWNLOADS', 'true').lower() in ('1', 'true', 'yes', 'on') resume_partial = os.getenv('RESUME_PARTIAL', 'true').lower() in ('1', 'true', 'yes', 'on') debug = os.getenv('DEBUG', 'false').lower() in ('1', 'true', 'yes', 'on') + # Validation if not client_date or not cookie_data: raise SystemExit('Cookie data and Client Date not set. Use the ReadMe file first before using this script.') + # Basic directory permissions check cwd = Path.cwd() if not os.access(cwd, os.W_OK): @@ -64,7 +79,8 @@ def from_env(cls): return cls( client_date=client_date, cookie_data=cookie_data, - video_download_quality=video_download_quality, + video_download_quality=video_download_quality, + output_dir=output_dir, ffmpeg_presentation_merge=ffmpeg_merge, concurrent_downloads=concurrent_downloads, retry_attempts=retry_attempts, diff --git a/thinkific_downloader/downloader.py b/thinkific_downloader/downloader.py index cd3f17c..5a1175f 100644 --- a/thinkific_downloader/downloader.py +++ b/thinkific_downloader/downloader.py @@ -252,7 +252,13 @@ def init_course(data: Dict[str, Any]): course_name = filter_filename(data['course']['name']) prev_dir = Path.cwd() ROOT_PROJECT_DIR = prev_dir - course_dir = Path(course_name) + + # Use output_dir from settings, create it if it doesn't exist + output_dir = Path(SETTINGS.output_dir if SETTINGS else './downloads') + output_dir.mkdir(exist_ok=True, parents=True) + + # Create course directory inside the output directory + course_dir = output_dir / course_name course_dir.mkdir(exist_ok=True) os.chdir(course_dir) COURSE_CONTENTS = data['contents'] From af80ec0781ccfa5e26f8d78cf69a1b293243a2c1 Mon Sep 17 00:00:00 2001 From: kavinthangavel Date: Wed, 24 Sep 2025 14:33:03 +0530 Subject: [PATCH 5/5] okay last one --- .github/workflows/ci.yml | 324 +---------------- .github/workflows/dependencies.yml | 81 ----- .github/workflows/release.yml | 534 +++++------------------------ README.md | 29 +- SETUP.md | 144 ++------ 5 files changed, 137 insertions(+), 975 deletions(-) delete mode 100644 .github/workflows/dependencies.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d7c0ac..bf14598 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,335 +1,43 @@ -name: ๐Ÿงช CI/CD Pipeline +name: ๐Ÿงช CI on: push: - branches: [ main, multi-dwl ] + branches: [ main ] pull_request: branches: [ main ] -env: - PYTHON_VERSION: '3.11' - jobs: - # ============================================================================ - # Job 1: Code Quality & Testing - # ============================================================================ test: - name: ๐Ÿงช Test & Quality Check - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - exclude: - # Reduce matrix size - test all Python versions only on Ubuntu - - os: windows-latest - python-version: '3.8' - - os: windows-latest - python-version: '3.9' - - os: windows-latest - python-version: '3.10' - - os: macos-latest - python-version: '3.8' - - os: macos-latest - python-version: '3.9' - - os: macos-latest - python-version: '3.10' - - steps: - - name: ๐Ÿ—๏ธ Checkout code - uses: actions/checkout@v4 - - - name: ๐Ÿ Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: ๐Ÿ“ฆ Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-cov flake8 black isort - - - name: ๐ŸŽจ Code formatting check - run: | - black --check --diff . - isort --check-only --diff . - - - name: ๐Ÿ” Lint check - run: | - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - - name: ๐Ÿงช Run basic import tests - run: | - python -c "import thinkific_downloader; print('โœ… Package imports successfully')" - python -c "from thinkific_downloader.config import Settings; print('โœ… Config module works')" - python -c "from thinkific_downloader.downloader import main; print('โœ… Main module works')" - - - name: ๐Ÿ”ง Test .env handling - run: | - # Test that config handles missing .env gracefully - python -c " - import os - from thinkific_downloader.config import load_env - from pathlib import Path - - # Test with non-existent .env file - non_existent = Path('non_existent.env') - try: - load_env(non_existent) - print('โœ… Handles missing .env file gracefully') - except Exception as e: - print(f'โŒ Error handling missing .env: {e}') - exit(1) - " - - - name: ๐Ÿ“Š Test environment variable parsing - run: | - python -c " - import os - from thinkific_downloader.config import Settings - - # Set test environment variables - os.environ['CLIENT_DATE'] = 'test-date' - os.environ['COOKIE_DATA'] = 'test-cookie' - os.environ['OUTPUT_DIR'] = './test-downloads' - os.environ['CONCURRENT_DOWNLOADS'] = '5' - os.environ['DEBUG'] = 'true' - - try: - settings = Settings.from_env() - assert settings.output_dir == './test-downloads' - assert settings.concurrent_downloads == 5 - assert settings.debug == True - print('โœ… Environment variable parsing works correctly') - except SystemExit: - # Expected when required vars are set - print('โœ… Environment validation works') - except Exception as e: - print(f'โŒ Error in environment parsing: {e}') - exit(1) - " - - # ============================================================================ - # Job 2: Docker Build Test - # ============================================================================ - docker-test: - name: ๐Ÿณ Docker Build Test + name: ๐Ÿงช Basic Tests runs-on: ubuntu-latest steps: - - name: ๐Ÿ—๏ธ Checkout code - uses: actions/checkout@v4 - - - name: ๐Ÿณ Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: ๐Ÿ”จ Build Docker image (test) - uses: docker/build-push-action@v5 - with: - context: . - push: false - tags: thinkific-downloader:test - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: ๐Ÿงช Test Docker image - run: | - # Test that the image starts without errors (with minimal config) - echo "Testing Docker image startup..." - docker run --rm thinkific-downloader:test python -c " - try: - import thinkific_downloader - print('โœ… Docker image: Package imports successfully') - except Exception as e: - print(f'โŒ Docker image: Import failed: {e}') - exit(1) - " - - # ============================================================================ - # Job 3: Project Structure Validation - # ============================================================================ - structure-test: - name: ๐Ÿ“ฆ Project Structure Test - runs-on: ubuntu-latest - - steps: - - name: ๐Ÿ—๏ธ Checkout code - uses: actions/checkout@v4 - - - name: ๏ฟฝ Validate project structure - run: | - echo "๐Ÿ“ Checking project structure..." - - # Check essential files exist - files_to_check=( - "thinkific_downloader/__init__.py" - "thinkific_downloader/config.py" - "thinkific_downloader/downloader.py" - "thinkific_downloader/download_manager.py" - "README.md" - "SETUP.md" - "requirements.txt" - ".env.example" - "Dockerfile" - "docker-compose.yml" - ) - - for file in "${files_to_check[@]}"; do - if [ -f "$file" ]; then - echo "โœ… $file exists" - else - echo "โŒ $file is missing" - exit 1 - fi - done - - echo "โœ… All essential files present" - - - name: ๐Ÿ”ง Test environment configuration - run: | - echo "๐Ÿงช Testing .env.example structure..." - - # Check for required sections - required_vars=( - "COURSE_LINK" - "COOKIE_DATA" - "CLIENT_DATE" - "OUTPUT_DIR" - "CONCURRENT_DOWNLOADS" - ) - - for var in "${required_vars[@]}"; do - if grep -q "$var" .env.example; then - echo "โœ… .env.example contains $var" - else - echo "โŒ .env.example missing $var" - exit 1 - fi - done - - echo "โœ… .env.example structure is valid" - - # ============================================================================ - # Job 4: Security & Vulnerability Check - # ============================================================================ - security: - name: ๐Ÿ”’ Security Check - runs-on: ubuntu-latest - - steps: - - name: ๐Ÿ—๏ธ Checkout code + - name: ๐Ÿ—๏ธ Checkout uses: actions/checkout@v4 - name: ๐Ÿ Setup Python uses: actions/setup-python@v4 with: - python-version: ${{ env.PYTHON_VERSION }} - - - name: ๐Ÿ”’ Install security tools - run: | - python -m pip install --upgrade pip - pip install safety bandit + python-version: '3.11' - - name: ๐Ÿงช Check dependencies for vulnerabilities + - name: ๐Ÿ“ฆ Install dependencies run: | - safety check -r requirements.txt + pip install -r requirements.txt - - name: ๐Ÿ” Run static security analysis + - name: ๐Ÿงช Test imports run: | - bandit -r thinkific_downloader/ -f json -o bandit-report.json - bandit -r thinkific_downloader/ + python -c "import thinkific_downloader; print('โœ… Package imports work')" + python -c "from thinkific_downloader.config import Settings; print('โœ… Config works')" - # ============================================================================ - # Job 5: Documentation Check - # ============================================================================ - docs-check: - name: ๐Ÿ“š Documentation Check + docker: + name: ๐Ÿณ Docker Build runs-on: ubuntu-latest steps: - - name: ๐Ÿ—๏ธ Checkout code + - name: ๐Ÿ—๏ธ Checkout uses: actions/checkout@v4 - - name: ๐Ÿ“– Check README structure - run: | - echo "๐Ÿ“‹ Checking documentation completeness..." - - # Check that essential sections exist in README - required_sections=( - "Quick Start" - "Docker" - "Configuration" - "Features" - ) - - for section in "${required_sections[@]}"; do - if grep -qi "$section" README.md; then - echo "โœ… README contains '$section' section" - else - echo "โš ๏ธ README missing '$section' section" - fi - done - - # Check .env.example is properly structured - if [ -f ".env.example" ]; then - echo "โœ… .env.example file exists" - - # Check for required sections - if grep -q "COURSE_LINK" .env.example && grep -q "COOKIE_DATA" .env.example; then - echo "โœ… .env.example contains required authentication variables" - else - echo "โŒ .env.example missing required authentication variables" - exit 1 - fi - - if grep -q "OUTPUT_DIR" .env.example; then - echo "โœ… .env.example contains OUTPUT_DIR configuration" - else - echo "โŒ .env.example missing OUTPUT_DIR configuration" - exit 1 - fi - else - echo "โŒ .env.example file is missing" - exit 1 - fi - - echo "โœ… Documentation check passed" - - # ============================================================================ - # Job 6: Summary - # ============================================================================ - summary: - name: ๐Ÿ“Š CI Summary - runs-on: ubuntu-latest - needs: [test, docker-test, structure-test, security, docs-check] - if: always() - - steps: - - name: ๐ŸŽ‰ Success Summary - if: needs.test.result == 'success' && needs.docker-test.result == 'success' && needs.structure-test.result == 'success' && needs.security.result == 'success' && needs.docs-check.result == 'success' - run: | - echo "๐ŸŽ‰ All CI checks passed successfully!" - echo "" - echo "โœ… Code quality and testing" - echo "โœ… Docker build verification" - echo "โœ… Project structure validation" - echo "โœ… Security vulnerability checks" - echo "โœ… Documentation completeness" - echo "" - echo "๐Ÿš€ Ready for merge/release!" - - - name: โŒ Failure Summary - if: needs.test.result == 'failure' || needs.docker-test.result == 'failure' || needs.structure-test.result == 'failure' || needs.security.result == 'failure' || needs.docs-check.result == 'failure' + - name: ๐Ÿณ Build Docker image run: | - echo "โŒ Some CI checks failed:" - echo "" - echo "๐Ÿงช Tests: ${{ needs.test.result }}" - echo "๐Ÿณ Docker: ${{ needs.docker-test.result }}" - echo "๐Ÿ“ฆ Structure: ${{ needs.structure-test.result }}" - echo "๐Ÿ”’ Security: ${{ needs.security.result }}" - echo "๐Ÿ“š Docs: ${{ needs.docs-check.result }}" - echo "" - echo "๐Ÿ”ง Please review and fix failing checks before merging." - exit 1 \ No newline at end of file + docker build -t thinkific-downloader:test . + echo "โœ… Docker image builds successfully" \ No newline at end of file diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml deleted file mode 100644 index ec980bd..0000000 --- a/.github/workflows/dependencies.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: ๐Ÿ”„ Dependency Updates - -on: - schedule: - # Run every Monday at 9 AM UTC - - cron: '0 9 * * 1' - workflow_dispatch: - -jobs: - update-dependencies: - name: ๐Ÿ“ฆ Update Dependencies - runs-on: ubuntu-latest - - steps: - - name: ๐Ÿ—๏ธ Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: ๐Ÿ Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.11' - - - name: ๐Ÿ“ฆ Install tools - run: | - python -m pip install --upgrade pip - pip install safety - - - name: ๐Ÿ”„ Check for dependency updates - run: | - # Backup current requirements - cp requirements.txt requirements.txt.backup - - echo "๐Ÿ“‹ Current dependencies:" - cat requirements.txt - - echo "" - echo "๐Ÿ” Checking for available updates..." - pip list --outdated || echo "All packages up to date" - - - name: ๐Ÿงช Test current dependencies - run: | - pip install -r requirements.txt - python -c "import thinkific_downloader; print('โœ… Current dependencies work')" - - - name: ๐Ÿ”’ Security check - run: | - safety check -r requirements.txt - - - name: ๐Ÿ“ Create Pull Request - uses: peter-evans/create-pull-request@v5 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: '๐Ÿ”„ Update dependencies' - title: '๏ฟฝ Dependency Security Check' - body: | - ## ๏ฟฝ Automated Dependency Security Check - - This PR was automatically created to report on dependency security status. - - ### ๐Ÿงช Status - - Checked Python dependencies for security vulnerabilities - - Verified package imports work correctly - - Listed any available updates - - ### ๐Ÿ” Review Actions - - [ ] Review any security warnings in the job logs - - [ ] Consider updating dependencies if vulnerabilities found - - [ ] Test functionality with any recommended updates - - ### ๐Ÿค– Automation Info - - Created by GitHub Actions - - Triggered by: ${{ github.event_name }} - - Python version tested: 3.11 - - --- - - **Note**: This is an informational check. Manual review and testing recommended before updating dependencies. - branch: automated-dependency-update - delete-branch: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c02a5f..3ebe7c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,138 +1,87 @@ -name: ๐Ÿš€ Release & Package +name: ๐Ÿš€ Release on: push: tags: - 'v*.*.*' - workflow_dispatch: - inputs: - version: - description: 'Version to release (e.g., v1.2.3)' - required: true - type: string - -env: - PYTHON_VERSION: '3.11' - DOCKER_IMAGE: kvnxo/thinkific-downloader jobs: - # ============================================================================ - # Job 1: Create GitHub Release - # ============================================================================ - create-release: - name: ๐Ÿ“ฆ Create GitHub Release + release: + name: ๐Ÿ“ฆ Create Release runs-on: ubuntu-latest - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - tag_name: ${{ steps.get_version.outputs.tag_name }} steps: - - name: ๐Ÿ—๏ธ Checkout code + - name: ๐Ÿ—๏ธ Checkout uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: ๐Ÿท๏ธ Get version - id: get_version - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "tag_name=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "tag_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - fi - - - name: ๐Ÿ“ Generate changelog - id: changelog - run: | - # Generate changelog from git commits since last tag - LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") - if [ -z "$LAST_TAG" ]; then - COMMITS=$(git log --pretty=format:"- %s (%h)" --reverse) - else - COMMITS=$(git log $LAST_TAG..HEAD --pretty=format:"- %s (%h)" --reverse) - fi - - # Create changelog - cat << EOF > CHANGELOG.md - ## ๐ŸŽ‰ What's New in ${{ steps.get_version.outputs.tag_name }} - - ### ๐Ÿš€ Features & Improvements - $COMMITS - - ### ๐Ÿ“ฆ Installation Options - - #### ๐Ÿณ Docker (Recommended) - \`\`\`bash - # Clone the project - git clone https://github.com/itskavin/Thinkific-Downloader.git - cd Thinkific-Downloader - - # Setup and run - cp .env.example .env - # Edit .env with your course details - docker-compose up - \`\`\` - - #### ๐Ÿ Python Direct - \`\`\`bash - # Download and extract the source code - # Or clone: git clone https://github.com/itskavin/Thinkific-Downloader.git - cd Thinkific-Downloader - - # Install and run - pip install -r requirements.txt - python thinkificdownloader.py - \`\`\` - - ### ๐ŸŽฏ Key Features - - โœ… **Downloads to ./downloads by default** - All course content organized in project directory - - โœ… **Enhanced Docker workflow** - Requires project directory for proper functionality - - โœ… **Parallel processing** - Download multiple files simultaneously - - โœ… **Smart resume** - Continue interrupted downloads automatically - - โœ… **File validation** - Integrity checks and corruption detection - - โœ… **Rich progress UI** - Beautiful terminal interface with real-time updates - - ### ๐Ÿ“‹ Requirements - - Python 3.8+ (for direct installation) - - Docker (for containerized usage) - - FFmpeg (optional, for presentation merging) - - --- - - **โš ๏ธ Important**: Always clone or download the project first, then run Docker/Python from the project directory. The app needs access to the project folder for downloads, configuration, and proper functionality. - EOF - - # Set multiline output - echo "changelog<> $GITHUB_OUTPUT - cat CHANGELOG.md >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT + id: version + run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - name: ๐ŸŽ‰ Create Release - id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ steps.get_version.outputs.tag_name }} - release_name: ๐Ÿš€ Thinkific Downloader ${{ steps.get_version.outputs.tag_name }} - body: ${{ steps.changelog.outputs.changelog }} + tag_name: ${{ steps.version.outputs.tag }} + release_name: ๐Ÿš€ Release ${{ steps.version.outputs.tag }} + body: | + ## ๐ŸŽ‰ New Release: ${{ steps.version.outputs.tag }} + + ### ๐Ÿš€ Installation Options + + **Docker Hub:** + ```bash + docker pull kvnxo/thinkific-downloader:${{ steps.version.outputs.tag }} + # or + docker pull kvnxo/thinkific-downloader:latest + ``` + + **GitHub Packages:** + ```bash + docker pull ghcr.io/itskavin/thinkific-downloader:${{ steps.version.outputs.tag }} + # or + docker pull ghcr.io/itskavin/thinkific-downloader:latest + ``` + + **Setup and Run:** + ```bash + git clone https://github.com/itskavin/Thinkific-Downloader.git + cd Thinkific-Downloader + cp .env.example .env + # Edit .env with your details + docker-compose up + ``` + + **Python Direct:** + ```bash + git clone https://github.com/itskavin/Thinkific-Downloader.git + cd Thinkific-Downloader + pip install -r requirements.txt + python thinkificdownloader.py + ``` + + ### ๐ŸŽฏ Key Features + - Downloads to `./downloads/` by default + - Docker support for easy setup + - Parallel downloads + - Smart resume functionality draft: false prerelease: false - # ============================================================================ - # Job 2: Build Docker Images - # ============================================================================ - build-docker: - name: ๐Ÿณ Build & Push Docker Images + docker: + name: ๐Ÿณ Build Docker runs-on: ubuntu-latest - needs: create-release + needs: release + if: success() steps: - - name: ๐Ÿ—๏ธ Checkout code + - name: ๐Ÿ—๏ธ Checkout uses: actions/checkout@v4 - - name: ๐Ÿณ Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - name: ๐Ÿท๏ธ Get version + id: version + run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - name: ๐Ÿ”‘ Login to Docker Hub uses: docker/login-action@v3 @@ -140,358 +89,29 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: ๐Ÿท๏ธ Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.DOCKER_IMAGE }} - tags: | - type=ref,event=tag - type=raw,value=latest - type=raw,value=${{ needs.create-release.outputs.tag_name }} - - - name: ๐Ÿš€ Build and push Docker image - uses: docker/build-push-action@v5 + - name: ๐Ÿ”‘ Login to GitHub Container Registry + uses: docker/login-action@v3 with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64,linux/arm64 - cache-from: type=gha - cache-to: type=gha,mode=max - - # ============================================================================ - # Job 3: Create Platform-Specific Packages (Source Code) - # ============================================================================ - build-packages: - name: ๐Ÿ“ฆ Build Source Code Packages - runs-on: ${{ matrix.os }} - needs: create-release - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - include: - - os: ubuntu-latest - platform: linux - ext: tar.gz - - os: windows-latest - platform: windows - ext: zip - - os: macos-latest - platform: macos - ext: tar.gz - - steps: - - name: ๐Ÿ—๏ธ Checkout code - uses: actions/checkout@v4 - - - name: ๏ฟฝ Create portable source package - shell: bash - run: | - # Create package directory - mkdir -p package/thinkific-downloader - - # Copy all necessary files - cp -r thinkific_downloader package/thinkific-downloader/ - cp thinkificdownloader.py package/thinkific-downloader/ - cp requirements.txt package/thinkific-downloader/ - cp .env.example package/thinkific-downloader/ - cp README.md package/thinkific-downloader/ - cp SETUP.md package/thinkific-downloader/ - cp LICENSE package/thinkific-downloader/ - - # Copy Docker files if they exist - [ -f docker-compose.yml ] && cp docker-compose.yml package/thinkific-downloader/ - [ -f Dockerfile ] && cp Dockerfile package/thinkific-downloader/ - - # Create setup scripts for each platform - if [ "${{ matrix.platform }}" = "windows" ]; then - # Windows batch file - cat > package/thinkific-downloader/setup-and-run.bat << 'EOF' - @echo off - title Thinkific Downloader Setup - echo. - echo ๐Ÿš€ Thinkific Downloader - Setup and Run - echo ======================================== - echo. - - REM Check if .env exists - if not exist ".env" ( - echo ๐Ÿ“ Creating .env file from template... - copy .env.example .env - echo. - echo โš ๏ธ IMPORTANT: Please edit the .env file with your course details! - echo - Add your COURSE_LINK - echo - Add your COOKIE_DATA - echo - Add your CLIENT_DATE - echo. - echo ๐Ÿ“– See SETUP.md for detailed instructions on getting these values. - echo. - pause - echo. - ) - - REM Check for Python - python --version >nul 2>&1 - if %errorlevel% neq 0 ( - echo โŒ Python is not installed or not in PATH - echo Please install Python 3.8+ from https://python.org - pause - exit /b 1 - ) - - echo ๐Ÿ“ฆ Installing dependencies... - pip install -r requirements.txt - if %errorlevel% neq 0 ( - echo โŒ Failed to install dependencies - pause - exit /b 1 - ) - - echo. - echo ๐ŸŽฏ Starting Thinkific Downloader... - echo Downloads will be saved to: ./downloads/ - echo. - python thinkificdownloader.py - - echo. - echo ๐ŸŽ‰ Download completed! - pause - EOF - - # Docker script for Windows - cat > package/thinkific-downloader/run-docker.bat << 'EOF' - @echo off - title Thinkific Downloader - Docker - echo. - echo ๐Ÿณ Thinkific Downloader - Docker Mode - echo ==================================== - echo. - - REM Check if .env exists - if not exist ".env" ( - echo ๐Ÿ“ Creating .env file from template... - copy .env.example .env - echo. - echo โš ๏ธ IMPORTANT: Please edit the .env file with your course details! - echo See SETUP.md for detailed instructions. - echo. - pause - exit /b 1 - ) - - echo ๐Ÿ”„ Pulling latest Docker image... - docker pull kvnxo/thinkific-downloader:latest - - echo ๏ฟฝ Starting download with Docker... - echo Downloads will be saved to: ./downloads/ - echo. - docker run -it --rm -v "%cd%\downloads:/app/downloads" --env-file .env kvnxo/thinkific-downloader:latest - - echo. - echo ๐ŸŽ‰ Download completed! - pause - EOF - - else - # Unix shell script - cat > package/thinkific-downloader/setup-and-run.sh << 'EOF' - #!/bin/bash - set -e - - echo "๐Ÿš€ Thinkific Downloader - Setup and Run" - echo "========================================" - echo - - # Check if .env exists - if [ ! -f ".env" ]; then - echo "๐Ÿ“ Creating .env file from template..." - cp .env.example .env - echo - echo "โš ๏ธ IMPORTANT: Please edit the .env file with your course details!" - echo " - Add your COURSE_LINK" - echo " - Add your COOKIE_DATA" - echo " - Add your CLIENT_DATE" - echo - echo "๐Ÿ“– See SETUP.md for detailed instructions on getting these values." - echo - echo "Edit the .env file now and run this script again." - exit 1 - fi - - # Check for Python - if ! command -v python3 &> /dev/null && ! command -v python &> /dev/null; then - echo "โŒ Python is not installed" - echo " Please install Python 3.8+ from your package manager or https://python.org" - exit 1 - fi - - # Use python3 if available, otherwise python - PYTHON_CMD="python3" - if ! command -v python3 &> /dev/null; then - PYTHON_CMD="python" - fi - - echo "๐Ÿ“ฆ Installing dependencies..." - $PYTHON_CMD -m pip install -r requirements.txt - - echo - echo "๐ŸŽฏ Starting Thinkific Downloader..." - echo " Downloads will be saved to: ./downloads/" - echo - $PYTHON_CMD thinkificdownloader.py - - echo - echo "๐ŸŽ‰ Download completed!" - EOF - chmod +x package/thinkific-downloader/setup-and-run.sh - - # Docker script for Unix - cat > package/thinkific-downloader/run-docker.sh << 'EOF' - #!/bin/bash - set -e - - echo "๐Ÿณ Thinkific Downloader - Docker Mode" - echo "====================================" - echo - - # Check if .env exists - if [ ! -f ".env" ]; then - echo "๐Ÿ“ Creating .env file from template..." - cp .env.example .env - echo - echo "โš ๏ธ IMPORTANT: Please edit the .env file with your course details!" - echo " See SETUP.md for detailed instructions." - echo - echo "Edit the .env file now and run this script again." - exit 1 - fi - - # Check for Docker - if ! command -v docker &> /dev/null; then - echo "โŒ Docker is not installed" - echo " Please install Docker from https://docker.com" - exit 1 - fi - - echo "๐Ÿ”„ Pulling latest Docker image..." - docker pull kvnxo/thinkific-downloader:latest - - echo "๏ฟฝ Starting download with Docker..." - echo " Downloads will be saved to: ./downloads/" - echo - docker run -it --rm -v "$(pwd)/downloads:/app/downloads" --env-file .env kvnxo/thinkific-downloader:latest - - echo - echo "๐ŸŽ‰ Download completed!" - EOF - chmod +x package/thinkific-downloader/run-docker.sh - fi - - # Create README for package - cat > package/thinkific-downloader/QUICK-START.md << 'EOF' - # ๐Ÿ“ฅ Thinkific Downloader - Quick Start Guide - - ## ๐Ÿš€ Quick Start Options - - ### Option 1: Docker (Recommended) - **Requirements**: Docker installed - - 1. **Setup**: Edit `.env` file with your course details - 2. **Run**: - - **Windows**: Double-click `run-docker.bat` - - **Mac/Linux**: Run `./run-docker.sh` - - ### Option 2: Python Direct - **Requirements**: Python 3.8+ installed - - 1. **Setup**: Edit `.env` file with your course details - 2. **Run**: - - **Windows**: Double-click `setup-and-run.bat` - - **Mac/Linux**: Run `./setup-and-run.sh` - - ## ๏ฟฝ Configuration Required - - **Before running**, edit the `.env` file with: - - `COURSE_LINK`: Your Thinkific course URL - - `COOKIE_DATA`: Browser session cookies - - `CLIENT_DATE`: Client date header - - See `SETUP.md` for detailed instructions on getting these values. - - ## ๐Ÿ“ Downloads Location - - All course content will be downloaded to `./downloads/` folder in this directory. - - ## ๐Ÿ†˜ Need Help? - - - See `README.md` for complete features and documentation - - See `SETUP.md` for detailed setup instructions - - Visit: https://github.com/itskavin/Thinkific-Downloader - - ## ๐ŸŽฏ Key Features - - - โœ… Downloads to `./downloads/` by default - - โœ… Docker support for easy setup - - โœ… Parallel downloads for speed - - โœ… Smart resume for interrupted downloads - - โœ… File validation and integrity checks - EOF + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: ๐Ÿ“ Create archive - shell: bash + - name: ๐Ÿ”ง Build and Push to Docker Hub run: | - cd package - if [ "${{ matrix.platform }}" = "windows" ]; then - # Use PowerShell on Windows for better ZIP creation - powershell -command "Compress-Archive -Path 'thinkific-downloader' -DestinationPath '../thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.zip'" - else - tar -czf ../thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.tar.gz thinkific-downloader - fi - - - name: ๐Ÿ“ค Upload package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: ./thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.${{ matrix.ext }} - asset_name: thinkific-downloader-${{ needs.create-release.outputs.tag_name }}-${{ matrix.platform }}.${{ matrix.ext }} - asset_content_type: ${{ matrix.platform == 'windows' && 'application/zip' || 'application/gzip' }} + docker build -t kvnxo/thinkific-downloader:latest . + docker build -t kvnxo/thinkific-downloader:${{ steps.version.outputs.tag }} . + docker push kvnxo/thinkific-downloader:latest + docker push kvnxo/thinkific-downloader:${{ steps.version.outputs.tag }} - # ============================================================================ - # Job 4: Update Documentation - # ============================================================================ - update-docs: - name: ๐Ÿ“š Update Documentation - runs-on: ubuntu-latest - needs: [create-release, build-docker] - if: always() && needs.create-release.result == 'success' - - steps: - - name: ๐Ÿ—๏ธ Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: ๐Ÿ“ Update Docker Hub description + - name: ๐Ÿ“ฆ Build and Push to GitHub Packages run: | - echo "Docker image updated to ${{ needs.create-release.outputs.tag_name }}" - echo "This step would update Docker Hub description in a real scenario" + # Convert repository name to lowercase for GitHub Container Registry + REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') - - name: ๐ŸŽ‰ Summary - run: | - echo "๐Ÿš€ Release ${{ needs.create-release.outputs.tag_name }} completed successfully!" - echo "" - echo "๐Ÿ“ฆ Artifacts created:" - echo " - GitHub Release with source code" - echo " - Docker images (linux/amd64, linux/arm64)" - echo " - Platform-specific source packages (Windows, macOS, Linux)" - echo "" - echo "๐Ÿ”— Access your release at:" - echo " https://github.com/itskavin/Thinkific-Downloader/releases/tag/${{ needs.create-release.outputs.tag_name }}" - echo "" - echo "๐Ÿณ Docker images available:" - echo " docker pull kvnxo/thinkific-downloader:latest" - echo " docker pull kvnxo/thinkific-downloader:${{ needs.create-release.outputs.tag_name }}" \ No newline at end of file + # Build and tag for GitHub Container Registry + docker build -t ghcr.io/${REPO_LOWER}:latest . + docker build -t ghcr.io/${REPO_LOWER}:${{ steps.version.outputs.tag }} . + + # Push to GitHub Container Registry + docker push ghcr.io/${REPO_LOWER}:latest + docker push ghcr.io/${REPO_LOWER}:${{ steps.version.outputs.tag }} \ No newline at end of file diff --git a/README.md b/README.md index 9e266cf..7bf7bf3 100644 --- a/README.md +++ b/README.md @@ -103,11 +103,15 @@ cp .env.example .env **Step 3: Run with Docker** ```bash -# Pull latest image and run from project directory +# Option 1: Docker Hub docker pull kvnxo/thinkific-downloader docker run -it --rm -v $(pwd)/downloads:/app/downloads --env-file .env kvnxo/thinkific-downloader -# Or use docker-compose (recommended) +# Option 2: GitHub Packages +docker pull ghcr.io/itskavin/thinkific-downloader +docker run -it --rm -v $(pwd)/downloads:/app/downloads --env-file .env ghcr.io/itskavin/thinkific-downloader + +# Option 3: Docker Compose (recommended) docker-compose up ``` @@ -128,15 +132,22 @@ python thinkificdownloader.py ### **๐Ÿ“ฆ Source Code Packages** -Download source code packages from [GitHub Releases](https://github.com/itskavin/Thinkific-Downloader/releases): +Get the latest source code: -- **Windows**: `thinkific-downloader-vX.X.X-windows.zip` -- **macOS**: `thinkific-downloader-vX.X.X-macos.tar.gz` -- **Linux**: `thinkific-downloader-vX.X.X-linux.tar.gz` +```bash +# Clone the repository +git clone https://github.com/itskavin/Thinkific-Downloader.git +cd Thinkific-Downloader -Each package includes setup scripts: -- **Windows**: `setup-and-run.bat` (Python) or `run-docker.bat` (Docker) -- **macOS/Linux**: `setup-and-run.sh` (Python) or `run-docker.sh` (Docker) +# Setup and run with Docker +cp .env.example .env +# Edit .env with your course details +docker-compose up + +# Or run with Python +pip install -r requirements.txt +python thinkificdownloader.py +``` > **Resume/Backup System:** > - Download status is tracked in `.download_status.json` (atomic, cross-platform) diff --git a/SETUP.md b/SETUP.md index 5f075e5..a1318fc 100644 --- a/SETUP.md +++ b/SETUP.md @@ -36,134 +36,38 @@ This comprehensive guide walks you through installing and configuring Thinkific- ## ๐Ÿš€ Installation Methods -### **๐Ÿ“ฆ Option 1: Source Code Packages (Easiest)** +### **๐Ÿ“ฆ Option 1: Clone Repository (Recommended)** -Download ready-to-use source packages from [GitHub Releases](https://github.com/itskavin/Thinkific-Downloader/releases): +Get the latest version directly from GitHub: -1. **Download** the package for your operating system: - - **Windows**: `thinkific-downloader-vX.X.X-windows.zip` - - **macOS**: `thinkific-downloader-vX.X.X-macos.tar.gz` - - **Linux**: `thinkific-downloader-vX.X.X-linux.tar.gz` +1. **Clone the repository**: + ```bash + git clone https://github.com/itskavin/Thinkific-Downloader.git + cd Thinkific-Downloader + ``` -2. **Extract** the downloaded package to your desired location - -3. **Setup** your configuration: - - Edit the `.env` file with your course details (see Authentication Setup below) +2. **Setup configuration**: + ```bash + cp .env.example .env + # Edit .env with your course details (see Authentication Setup below) + ``` -4. **Run** the application: - - **Docker Mode** (Recommended): - - **Windows**: Double-click `run-docker.bat` - - **macOS/Linux**: Run `./run-docker.sh` - - **Python Mode**: - - **Windows**: Double-click `setup-and-run.bat` - - **macOS/Linux**: Run `./setup-and-run.sh` - ---- - -### **๐Ÿณ Option 2: Docker (Recommended for Advanced Users)** - -Docker provides the most consistent and hassle-free experience with all dependencies pre-installed. - -#### **2.1 Install Docker** -- **Windows/Mac**: Download [Docker Desktop](https://www.docker.com/products/docker-desktop/) -- **Linux**: Follow [Docker installation guide](https://docs.docker.com/engine/install/) - -#### **2.2 Get the Project** -**Important**: You must clone or download the project first, as Docker needs access to the project directory for downloads, configuration files, and proper functionality. - -```bash -# Option A: Clone with Git -git clone https://github.com/itskavin/Thinkific-Downloader.git -cd Thinkific-Downloader - -# Option B: Download ZIP -# 1. Go to https://github.com/itskavin/Thinkific-Downloader -# 2. Click "Code" -> "Download ZIP" -# 3. Extract the ZIP file -# 4. Open terminal in the extracted folder -``` - -#### **2.3 Setup Environment** -```bash -# Create .env file from template (if available) -cp .env.example .env - -# Or create .env file manually (see Configuration section below) -``` - -#### **2.4 Run with Docker** -```bash -# Pull the latest image -docker pull kvnxo/thinkific-downloader:latest - -# Run from project directory (this is crucial!) -docker run -it --rm \ - -v $(pwd)/downloads:/app/downloads \ - -v $(pwd)/.env:/app/.env \ - kvnxo/thinkific-downloader:latest -``` - -#### **2.5 Docker Compose (Recommended)** -Create `docker-compose.yml` (or use the provided one): -```yaml -version: '3.8' -services: - thinkific-downloader: - image: kvnxo/thinkific-downloader:latest - volumes: - - ./downloads:/app/downloads - - ./.env:/app/.env - environment: - - COURSE_LINK=${COURSE_LINK} - - COOKIE_DATA=${COOKIE_DATA} - - CLIENT_DATE=${CLIENT_DATE} - # Enhanced features - - CONCURRENT_DOWNLOADS=3 - - RETRY_ATTEMPTS=3 - - OUTPUT_DIR=./downloads -``` - -Run with: `docker-compose up` +3. **Run with Docker** (Recommended): + ```bash + docker-compose up + ``` + + **Or run with Python**: + ```bash + pip install -r requirements.txt + python thinkificdownloader.py + ``` --- -### **๐Ÿ Option 3: Python Installation (For Developers)** - -For users who prefer native Python installation with full control. +### **๐Ÿณ Option 2: Docker Only** -#### **3.1 Clone Repository** -```bash -# Clone the repository -git clone https://github.com/itskavin/Thinkific-Downloader.git -cd Thinkific-Downloader -``` - -#### **3.2 Quick Setup (Automated)** -```bash -# Run the automated installer -python install.py -``` - -#### **3.3 Manual Installation** -```bash -# Create virtual environment (recommended) -python -m venv venv -source venv/bin/activate # Linux/Mac -# or -venv\Scripts\activate # Windows - -# Install dependencies -pip install -r requirements.txt - -# Install in development mode -pip install -e . -``` - -#### **3.4 Verify Installation** -```bash -# Test the installation -python -m thinkific_downloader --help -``` +If you want to use Docker without cloning: ---