Skip to content

Commit 409ce19

Browse files
authored
Merge pull request #1 from itskavin/multi-dwl
Multi dwl
2 parents 2b5b125 + af80ec0 commit 409ce19

16 files changed

Lines changed: 2028 additions & 415 deletions

.env.example

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,83 @@
11
# Thinkific-Downloader Environment Configuration
22
# Copy this file to .env and fill in your actual values
33

4+
# ===============================================
5+
# REQUIRED AUTHENTICATION
6+
# ===============================================
7+
48
# For downloading all content, use the course link.
59
COURSE_LINK="https://your-thinkific-site.com/api/course_player/v2/courses/your-course-name"
610

7-
# For selective content downloads, use the JSON file created from Thinki Parser.
8-
# Copy the file to the Thinkifi Downloader root folder.
9-
# Specify the file name below. Ex. COURSE_DATA_FILE="modified-course.json"
10-
COURSE_DATA_FILE=""
11-
1211
# Client date header - Get this from browser Developer Tools Network tab
1312
CLIENT_DATE="2025-09-23T07:42:31.512Z"
1413

1514
# Browser session cookie - Get this from browser Developer Tools Application/Storage tab
1615
# IMPORTANT: Keep this secret and never share it!
1716
COOKIE_DATA="_thinkific_session=YOUR_SESSION_COOKIE_HERE"
1817

18+
# ===============================================
19+
# BASIC SETTINGS
20+
# ===============================================
21+
1922
# Quality Available: "Original File", "1080p", "720p", "540p", "360p", "224p"
2023
# Recommended: "720p" for good quality and reasonable file size
2124
VIDEO_DOWNLOAD_QUALITY="720p"
2225

23-
# Set to true to download all available video formats/qualities
24-
# Warning: This will significantly increase download size and time
25-
# ALL_VIDEO_FORMATS=false
26+
# Set download directory (defaults to ./downloads)
27+
# All course content will be downloaded to this directory
28+
OUTPUT_DIR="./downloads"
29+
30+
# ===============================================
31+
# ENHANCED FEATURES
32+
# ===============================================
33+
34+
# Number of concurrent downloads (default: 3, recommended: 1-5)
35+
# Higher numbers may trigger rate limiting
36+
CONCURRENT_DOWNLOADS=3
37+
38+
# Delay between downloads in seconds (default: 1.0)
39+
# Increase if you encounter rate limiting issues
40+
DOWNLOAD_DELAY=1.0
41+
42+
# Number of retry attempts for failed downloads (default: 3)
43+
RETRY_ATTEMPTS=3
44+
45+
# Rate limiting in MB/s (default: unlimited)
46+
# Set a value to limit download speed (e.g., RATE_LIMIT_MB_S=5.0)
47+
# RATE_LIMIT_MB_S=
48+
49+
# File validation after download (default: true)
50+
# Validates file integrity and size
51+
VALIDATE_DOWNLOADS=true
52+
53+
# Resume partial downloads (default: true)
54+
# Automatically resume interrupted downloads
55+
RESUME_PARTIAL=true
56+
57+
# Debug mode (default: false)
58+
# Enable detailed logging for troubleshooting
59+
DEBUG=false
60+
61+
# ===============================================
62+
# ADVANCED SETTINGS
63+
# ===============================================
2664

2765
# Set to true to enable ffmpeg presentation merging (requires ffmpeg installed)
2866
# This combines multi-part presentations into single video files
29-
# FFMPEG_PRESENTATION_MERGE=false
30-
31-
# Optional: Set download directory (defaults to ./downloads)
32-
# OUTPUT_DIR="./downloads"
67+
FFMPEG_PRESENTATION_MERGE=false
3368

34-
# Optional: Number of concurrent downloads (default: 2)
35-
# Higher numbers may trigger rate limiting
36-
# CONCURRENT_DOWNLOADS=2
69+
# ===============================================
70+
# OPTIONAL FEATURES (LEGACY SUPPORT)
71+
# ===============================================
3772

38-
# Optional: Delay between downloads in seconds (default: 1)
39-
# Increase if you encounter rate limiting issues
40-
# DOWNLOAD_DELAY=1
73+
# For selective content downloads, use the JSON file created from Thinki Parser.
74+
# Copy the file to the Thinkifi Downloader root folder.
75+
# Specify the file name below. Ex. COURSE_DATA_FILE="modified-course.json"
76+
# COURSE_DATA_FILE=""
4177

42-
# Optional: Number of retry attempts for failed downloads (default: 3)
43-
# RETRY_ATTEMPTS=3
78+
# Set to true to download all available video formats/qualities
79+
# Warning: This will significantly increase download size and time
80+
# ALL_VIDEO_FORMATS=false
4481

45-
# Optional: Log level (DEBUG, INFO, WARNING, ERROR)
82+
# Log level (DEBUG, INFO, WARNING, ERROR)
4683
# LOG_LEVEL="INFO"

.github/workflows/ci.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: 🧪 CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
name: 🧪 Basic Tests
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: 🏗️ Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: 🐍 Setup Python
19+
uses: actions/setup-python@v4
20+
with:
21+
python-version: '3.11'
22+
23+
- name: 📦 Install dependencies
24+
run: |
25+
pip install -r requirements.txt
26+
27+
- name: 🧪 Test imports
28+
run: |
29+
python -c "import thinkific_downloader; print('✅ Package imports work')"
30+
python -c "from thinkific_downloader.config import Settings; print('✅ Config works')"
31+
32+
docker:
33+
name: 🐳 Docker Build
34+
runs-on: ubuntu-latest
35+
36+
steps:
37+
- name: 🏗️ Checkout
38+
uses: actions/checkout@v4
39+
40+
- name: 🐳 Build Docker image
41+
run: |
42+
docker build -t thinkific-downloader:test .
43+
echo "✅ Docker image builds successfully"

.github/workflows/release.yml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: 🚀 Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*.*.*'
7+
8+
jobs:
9+
release:
10+
name: 📦 Create Release
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: 🏗️ Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: 🏷️ Get version
18+
id: version
19+
run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
20+
21+
- name: 🎉 Create Release
22+
uses: actions/create-release@v1
23+
env:
24+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25+
with:
26+
tag_name: ${{ steps.version.outputs.tag }}
27+
release_name: 🚀 Release ${{ steps.version.outputs.tag }}
28+
body: |
29+
## 🎉 New Release: ${{ steps.version.outputs.tag }}
30+
31+
### 🚀 Installation Options
32+
33+
**Docker Hub:**
34+
```bash
35+
docker pull kvnxo/thinkific-downloader:${{ steps.version.outputs.tag }}
36+
# or
37+
docker pull kvnxo/thinkific-downloader:latest
38+
```
39+
40+
**GitHub Packages:**
41+
```bash
42+
docker pull ghcr.io/itskavin/thinkific-downloader:${{ steps.version.outputs.tag }}
43+
# or
44+
docker pull ghcr.io/itskavin/thinkific-downloader:latest
45+
```
46+
47+
**Setup and Run:**
48+
```bash
49+
git clone https://github.com/itskavin/Thinkific-Downloader.git
50+
cd Thinkific-Downloader
51+
cp .env.example .env
52+
# Edit .env with your details
53+
docker-compose up
54+
```
55+
56+
**Python Direct:**
57+
```bash
58+
git clone https://github.com/itskavin/Thinkific-Downloader.git
59+
cd Thinkific-Downloader
60+
pip install -r requirements.txt
61+
python thinkificdownloader.py
62+
```
63+
64+
### 🎯 Key Features
65+
- Downloads to `./downloads/` by default
66+
- Docker support for easy setup
67+
- Parallel downloads
68+
- Smart resume functionality
69+
draft: false
70+
prerelease: false
71+
72+
docker:
73+
name: 🐳 Build Docker
74+
runs-on: ubuntu-latest
75+
needs: release
76+
if: success()
77+
78+
steps:
79+
- name: 🏗️ Checkout
80+
uses: actions/checkout@v4
81+
82+
- name: 🏷️ Get version
83+
id: version
84+
run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
85+
86+
- name: 🔑 Login to Docker Hub
87+
uses: docker/login-action@v3
88+
with:
89+
username: ${{ secrets.DOCKER_USERNAME }}
90+
password: ${{ secrets.DOCKER_PASSWORD }}
91+
92+
- name: 🔑 Login to GitHub Container Registry
93+
uses: docker/login-action@v3
94+
with:
95+
registry: ghcr.io
96+
username: ${{ github.actor }}
97+
password: ${{ secrets.GITHUB_TOKEN }}
98+
99+
- name: 🔧 Build and Push to Docker Hub
100+
run: |
101+
docker build -t kvnxo/thinkific-downloader:latest .
102+
docker build -t kvnxo/thinkific-downloader:${{ steps.version.outputs.tag }} .
103+
docker push kvnxo/thinkific-downloader:latest
104+
docker push kvnxo/thinkific-downloader:${{ steps.version.outputs.tag }}
105+
106+
- name: 📦 Build and Push to GitHub Packages
107+
run: |
108+
# Convert repository name to lowercase for GitHub Container Registry
109+
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
110+
111+
# Build and tag for GitHub Container Registry
112+
docker build -t ghcr.io/${REPO_LOWER}:latest .
113+
docker build -t ghcr.io/${REPO_LOWER}:${{ steps.version.outputs.tag }} .
114+
115+
# Push to GitHub Container Registry
116+
docker push ghcr.io/${REPO_LOWER}:latest
117+
docker push ghcr.io/${REPO_LOWER}:${{ steps.version.outputs.tag }}

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ __pycache__/
1111
build/
1212
develop-eggs/
1313
dist/
14-
downloads/
1514
eggs/
1615
.eggs/
1716
lib/
@@ -93,4 +92,5 @@ ffmpeg.log
9392
# Docker runtime artifacts (keep config files in git)
9493
.docker/
9594
docker-volumes/
96-
*.pid
95+
*.pid
96+
thinkific-launch-accelerator-course-october-2025/.download_status.json.bak

DEVELOPMENT.md

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ graph TB
6262
- Retry logic with exponential backoff
6363
- Resource management
6464

65-
#### **4. File Validator** (`file_validator.py`)
66-
- **Purpose**: Smart file validation and skip logic
65+
66+
#### **4. Resume Tracker** (`resume_tracker.py`)
67+
- **Purpose**: Atomic, cross-platform resume and status tracking
6768
- **Features**:
68-
- File integrity checking (size, checksums)
69-
- Resume detection and validation
70-
- Download metadata persistence
71-
- Smart skip decisions
69+
- Download status tracking and backup (Windows, Mac, Linux)
70+
- File integrity checking (size, checksums)
71+
- Resume detection and validation
72+
- Download metadata persistence
73+
- Smart skip decisions
7274

7375
#### **5. Content Processors**
7476
- **Wistia Downloader** (`wistia_downloader.py`): Video processing
@@ -179,7 +181,7 @@ graph TD
179181
3. **Course Processing**: API calls → Content parsing → Task creation
180182
4. **Download Orchestration**: Task queue → `download_manager.py` → Parallel workers
181183
5. **Progress Tracking**: Thread-safe updates → `progress_manager.py` → Rich UI
182-
6. **Validation**: File checks → `file_validator.py` → Skip decisions
184+
6. **Validation**: File checks → `resume_tracker.py` → Skip decisions
183185

184186
---
185187

@@ -286,7 +288,7 @@ tests/
286288
├── unit/
287289
│ ├── test_progress_manager.py
288290
│ ├── test_download_manager.py
289-
│ ├── test_file_validator.py
291+
│ ├── test_resume_tracker.py
290292
│ └── test_enhanced_downloader.py
291293
├── integration/
292294
│ ├── test_full_download.py
@@ -339,6 +341,18 @@ class TestProgressManager:
339341
# Assert
340342
assert file_id in progress_manager.downloads
341343
assert download.filename == filename
344+
345+
def test_resume_tracker_atomic_save(self):
346+
from thinkific_downloader.resume_tracker import ResumeTracker
347+
import tempfile
348+
with tempfile.TemporaryDirectory() as tmpdir:
349+
status_file = Path(tmpdir) / ".download_status.json"
350+
tracker = ResumeTracker(str(status_file))
351+
tracker.status_data["test"] = {"status": "completed"}
352+
tracker._save_status()
353+
assert status_file.exists()
354+
backup_file = status_file.with_suffix('.json.bak')
355+
assert backup_file.exists()
342356

343357
@patch('thinkific_downloader.progress_manager.time.time')
344358
def test_calculate_download_speed(self, mock_time, progress_manager):

0 commit comments

Comments
 (0)