Merge pull request 'chore: clean repo for public release' (#16) from improve/v1 into main
Reviewed-on: https://git.example.com/jarianc/youtube-cli/pulls/16
This commit is contained in:
commit
c58943f6b8
29
.github/workflows/test.yml
vendored
Normal file
29
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --all-extras --locked
|
||||
|
||||
- name: Lint
|
||||
run: uv run ruff check .
|
||||
|
||||
- name: Run tests
|
||||
run: uv run python -m pytest tests/ -v
|
||||
@ -1,187 +0,0 @@
|
||||
# Comprehensive Logging Implementation - Final Summary
|
||||
|
||||
## Project: YouTube CLI
|
||||
## Date: February 25, 2026
|
||||
|
||||
## Summary of Changes
|
||||
|
||||
### 1. Logs Directory Structure
|
||||
```
|
||||
/Users/user/Projects/youtube-cli/logs/
|
||||
├── app.log # Main application log file (auto-created)
|
||||
└── .gitignore (logs/ already present)
|
||||
```
|
||||
|
||||
### 2. Logging Configuration
|
||||
|
||||
**Global Settings:**
|
||||
- **Log Directory**: `~/.config/youtube_cli/logs/`
|
||||
- **Log File**: `app.log`
|
||||
- **Max Size**: 10MB
|
||||
- **Backup Count**: 5 rotations
|
||||
- **File Level**: DEBUG
|
||||
- **Console Level**: INFO
|
||||
|
||||
**Log Format:**
|
||||
```
|
||||
YYYY-MM-DD HH:MM:SS | module.name | LEVEL | message
|
||||
```
|
||||
|
||||
### 3. Files Modified
|
||||
|
||||
| File | Logger Added | Console Print Replaced |
|
||||
|------|-------------|----------------------|
|
||||
| `youtube_cli/main.py` | ✅ | 30+ statements |
|
||||
| `youtube_tui/app.py` | ✅ | N/A (no console.print) |
|
||||
| `youtube_tui/services/download_manager.py` | ✅ | 3 statements |
|
||||
| `youtube_tui/services/youtube.py` | ✅ | 4 statements |
|
||||
| `youtube_tui/services/queue.py` | ✅ | 2 statements |
|
||||
| `app.py` (REST API) | ✅ | N/A (no console.print) |
|
||||
|
||||
### 4. Logging Implementation Pattern
|
||||
|
||||
**Standard Import Block:**
|
||||
```python
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
|
||||
# Configure logging
|
||||
LOG_DIR = Path.home() / ".config" / "youtube_cli" / "logs"
|
||||
LOG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
LOG_FILE = LOG_DIR / "app.log"
|
||||
|
||||
file_handler = RotatingFileHandler(LOG_FILE, maxBytes=10 * 1024 * 1024, backupCount=5)
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler.setFormatter(logging.Formatter(
|
||||
"%(asctime)s | %(name)s | %(levelname)s | %(message)s",
|
||||
"%Y-%m-%d %H:%M:%S"
|
||||
))
|
||||
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.INFO)
|
||||
console_handler.setFormatter(logging.Formatter("%(message)s"))
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
handlers=[file_handler, console_handler],
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
```
|
||||
|
||||
**Usage Pattern:**
|
||||
```python
|
||||
logger.debug("Detailed debugging info")
|
||||
logger.info("Normal operations")
|
||||
logger.warning("Non-critical issues")
|
||||
logger.error("Errors with full context")
|
||||
logger.exception("Exceptions with traceback")
|
||||
```
|
||||
|
||||
### 5. Logging Coverage
|
||||
|
||||
#### youtube_cli/main.py
|
||||
- **Search Operations**: Query logging, pagination, result display
|
||||
- **Download Operations**: URL validation, directory setup, format selection, completion status
|
||||
- **Archive Operations**: Loading, saving, adding videos
|
||||
- **Configuration**: Loading, validation, defaults
|
||||
- **Network Share**: Copy operations, path validation
|
||||
- **Error Handling**: Full error context with file paths and parameters
|
||||
|
||||
#### youtube_tui/services/download_manager.py
|
||||
- **Download Management**: Queue processing, cancellation, errors
|
||||
- **Progress Tracking**: Download status updates
|
||||
- **Error Recovery**: Exception handling with context
|
||||
|
||||
#### youtube_tui/services/youtube.py
|
||||
- **Service Errors**: Search failures, download errors, archive issues
|
||||
- **Async Operations**: Thread execution tracking
|
||||
|
||||
#### youtube_tui/services/queue.py
|
||||
- **Queue Operations**: Loading, saving, status updates
|
||||
- **Item Management**: Add/remove operations
|
||||
|
||||
#### app.py (REST API)
|
||||
- **API Operations**: Request handling, error responses
|
||||
- **Module Initialization**: Flask app setup
|
||||
|
||||
### 6. Benefits
|
||||
|
||||
1. **Production Monitoring**: Full visibility into application behavior
|
||||
2. **Troubleshooting**: Detailed logs with timestamps and module context
|
||||
3. **Disk Space Management**: Automatic log rotation prevents unbounded growth
|
||||
4. **Development Efficiency**: Console output for quick debugging, file logs for detailed analysis
|
||||
5. **Consistency**: Unified logging approach across all modules
|
||||
|
||||
### 7. Testing Results
|
||||
|
||||
**Verification Commands:**
|
||||
```bash
|
||||
# Test logging
|
||||
python3 -c "from youtube_cli.main import logger; logger.info('Test message')"
|
||||
|
||||
# View logs
|
||||
tail -f ~/.config/youtube_cli/logs/app.log
|
||||
|
||||
# Search logs
|
||||
grep "ERROR" ~/.config/youtube_cli/logs/app.log
|
||||
grep "WARNING" ~/.config/youtube_cli/logs/app.log
|
||||
```
|
||||
|
||||
**Test Output:**
|
||||
```
|
||||
2026-02-25 20:14:40 | youtube_cli.main | INFO | Test info message
|
||||
2026-02-25 20:14:40 | youtube_cli.main | WARNING | Test warning message
|
||||
2026-02-25 20:14:40 | youtube_cli.main | ERROR | Test error message
|
||||
```
|
||||
|
||||
### 8. Git Ignore
|
||||
|
||||
The `logs/` directory is already in `.gitignore`:
|
||||
```
|
||||
logs/
|
||||
```
|
||||
|
||||
This ensures log files are never committed to the repository.
|
||||
|
||||
### 9. Next Steps for Users
|
||||
|
||||
1. **View logs**: `tail -f ~/.config/youtube_cli/logs/app.log`
|
||||
2. **Search errors**: `grep "ERROR" ~/.config/youtube_cli/logs/app.log`
|
||||
3. **Debug mode**: Check DEBUG level messages in the log file
|
||||
4. **Rotation management**: Logs automatically rotate at 10MB with 5 backups
|
||||
|
||||
### 10. Files Created/Modified
|
||||
|
||||
**Created:**
|
||||
- `/Users/user/Projects/youtube-cli/logs/` (directory)
|
||||
- `/Users/user/Projects/youtube-cli/LOGGING_SUMMARY.md` (documentation)
|
||||
|
||||
**Modified:**
|
||||
- `/Users/user/Projects/youtube-cli/youtube_cli/main.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/app.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/services/download_manager.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/services/youtube.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/services/queue.py`
|
||||
- `/Users/user/Projects/youtube-cli/app.py`
|
||||
|
||||
### 11. Requirements Met
|
||||
|
||||
✅ Logs directory created at `/Users/user/Projects/youtube-cli/logs/`
|
||||
✅ Logs directory added to `.gitignore`
|
||||
✅ Logging configured with rotation (10MB max, 5 backups)
|
||||
✅ Logging added to all specified files:
|
||||
- `/Users/user/Projects/youtube-cli/youtube_cli/main.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/app.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/services/download_manager.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/services/youtube.py`
|
||||
- `/Users/user/Projects/youtube-cli/youtube_tui/services/queue.py`
|
||||
- `/Users/user/Projects/youtube-cli/app.py`
|
||||
✅ Module-level loggers created
|
||||
✅ All console.print statements replaced with appropriate logger calls
|
||||
✅ Logging initialized in main entry points
|
||||
✅ Summary document provided
|
||||
|
||||
---
|
||||
|
||||
**Implementation Complete**: All requirements have been met and verified.
|
||||
@ -1,114 +0,0 @@
|
||||
# Logging Implementation Summary
|
||||
|
||||
## Overview
|
||||
Comprehensive logging has been added to all Python files in the YouTube CLI project.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Logs Directory
|
||||
- Created `/Users/user/Projects/youtube-cli/logs/` directory
|
||||
- Added `logs/` to `.gitignore` (already present)
|
||||
|
||||
### 2. Logging Configuration
|
||||
All Python files now have:
|
||||
- **Log file**: `~/.config/youtube_cli/logs/app.log`
|
||||
- **Rotation**: 10MB max, keep 5 backups
|
||||
- **Level**: DEBUG (file), INFO (console)
|
||||
- **Format**: `%(asctime)s | %(name)s | %(levelname)s | %(message)s`
|
||||
|
||||
### 3. Files Modified
|
||||
|
||||
#### `/Users/user/Projects/youtube-cli/youtube_cli/main.py`
|
||||
- Added `logging` and `RotatingFileHandler` imports
|
||||
- Added module-level logger: `logger = logging.getLogger(__name__)`
|
||||
- Replaced all `console.print()` statements with appropriate logger calls:
|
||||
- `logger.debug()` for verbose debugging info
|
||||
- `logger.info()` for normal operations
|
||||
- `logger.warning()` for warnings
|
||||
- `logger.error()` for errors
|
||||
- `logger.exception()` for exceptions (includes traceback)
|
||||
|
||||
Key logging additions:
|
||||
- Search operations
|
||||
- Download operations
|
||||
- Archive operations
|
||||
- Configuration loading
|
||||
- Network share operations
|
||||
- Error handling with full context
|
||||
|
||||
#### `/Users/user/Projects/youtube-cli/youtube_tui/app.py`
|
||||
- Added logging imports and configuration
|
||||
- Added module-level logger
|
||||
- Added logging initialization in `main()` function
|
||||
|
||||
#### `/Users/user/Projects/youtube-cli/youtube_tui/services/download_manager.py`
|
||||
- Added logging imports and configuration
|
||||
- Added module-level logger
|
||||
- Replaced `console.print()` with:
|
||||
- `logger.warning()` for cancellations
|
||||
- `logger.error()` for errors
|
||||
|
||||
#### `/Users/user/Projects/youtube-cli/youtube_tui/services/youtube.py`
|
||||
- Added logging imports and configuration
|
||||
- Added module-level logger
|
||||
- Replaced `self.console.print()` with `logger.error()` for service errors
|
||||
|
||||
#### `/Users/user/Projects/youtube-cli/youtube_tui/services/queue.py`
|
||||
- Added logging imports and configuration
|
||||
- Added module-level logger
|
||||
- Replaced `console.print()` with `logger.warning()` for queue operations
|
||||
|
||||
#### `/Users/user/Projects/youtube-cli/app.py` (REST API)
|
||||
- Added logging imports and configuration
|
||||
- Added module-level logger
|
||||
- Added logging initialization in module scope
|
||||
|
||||
### 4. Logging Levels Used
|
||||
|
||||
| Level | Usage | Example |
|
||||
|-------|-------|---------|
|
||||
| `DEBUG` | Detailed debugging info | Download directory paths |
|
||||
| `INFO` | Normal operations | Search queries, download starts, completions |
|
||||
| `WARNING` | Non-critical issues | Invalid inputs, skipped operations |
|
||||
| `ERROR` | Errors | Failed downloads, missing dependencies |
|
||||
| `CRITICAL` | Critical failures | Not used (reserved for severe issues) |
|
||||
|
||||
### 5. Benefits
|
||||
|
||||
1. **Production Monitoring**: Full visibility into application behavior
|
||||
2. **Troubleshooting**: Detailed logs with timestamps and context
|
||||
3. **Performance Tracking**: Log rotation prevents disk space issues
|
||||
4. **Debugging**: Both file and console output for development
|
||||
5. **Consistency**: Same logging approach across all modules
|
||||
|
||||
## Usage
|
||||
|
||||
### View Logs in Real-Time
|
||||
```bash
|
||||
tail -f ~/.config/youtube_cli/logs/app.log
|
||||
```
|
||||
|
||||
### Search Logs
|
||||
```bash
|
||||
grep "ERROR" ~/.config/youtube_cli/logs/app.log
|
||||
grep "WARNING" ~/.config/youtube_cli/logs/app.log
|
||||
```
|
||||
|
||||
### Log File Location
|
||||
- Logs are stored in: `~/.config/youtube_cli/logs/app.log`
|
||||
- Old logs are automatically rotated and archived
|
||||
|
||||
## Testing
|
||||
|
||||
To verify logging works:
|
||||
1. Run the CLI: `python -m youtube_cli "test query"`
|
||||
2. Run the TUI: `python youtube_tui/app.py`
|
||||
3. Run the API: `python app.py`
|
||||
4. Check logs: `cat ~/.config/youtube_cli/logs/app.log`
|
||||
|
||||
## Notes
|
||||
|
||||
- The `RotatingFileHandler` ensures log files don't grow indefinitely
|
||||
- Console output is limited to INFO level for cleaner terminal output
|
||||
- File output captures all DEBUG level messages for thorough logging
|
||||
- All exceptions are logged with full tracebacks using `logger.error()`
|
||||
@ -350,4 +350,4 @@ youtube-tui
|
||||
|
||||
### Documentation
|
||||
|
||||
See [TUI.md](TUI.md) for complete TUI documentation.
|
||||
See [TUI.md](docs/TUI.md) for complete TUI documentation.
|
||||
122
agent.md
122
agent.md
@ -1,122 +0,0 @@
|
||||
# YouTube CLI Agent
|
||||
|
||||
## Project Overview
|
||||
This is a command-line interface for browsing and downloading YouTube videos. The application allows users to search YouTube, display videos in pages of 15, and download videos using yt-dlp with progress indication.
|
||||
|
||||
## Core Features
|
||||
- **Search YouTube videos** with keyword queries
|
||||
- **Display videos** with title, author, duration, and type (short/video)
|
||||
- **Download videos** using yt-dlp with progress indication
|
||||
- **Configure download locations** through configuration files
|
||||
- **Handle short videos** (videos with /shorts/ in URL) with special "(short)" prefix
|
||||
- **Pagination support** to view more than 15 videos per search
|
||||
- **Network share integration** for copying downloaded videos
|
||||
|
||||
## Project Structure
|
||||
```
|
||||
youtube-cli/
|
||||
├── youtube_cli/ # Main package directory
|
||||
│ ├── __init__.py # Package initialization
|
||||
│ ├── __main__.py # Main entry point
|
||||
│ └── main.py # Core application logic
|
||||
├── setup.py # Python package setup
|
||||
├── requirements.txt # Python dependencies
|
||||
├── README.md # Project documentation
|
||||
├── prompt.md # Prompt template
|
||||
├── structure.md # Project structure documentation
|
||||
└── run.sh # Run script
|
||||
```
|
||||
|
||||
## Main Components
|
||||
|
||||
### youtube_cli/main.py
|
||||
The core application logic file containing:
|
||||
- `YouTubeCLI` class with all main functionality
|
||||
- Search videos using yt-dlp with pagination support
|
||||
- Display videos in formatted tables with Rich library
|
||||
- Download videos with progress indication
|
||||
- Configuration management
|
||||
- Archive tracking for downloaded videos
|
||||
- Network share copying functionality
|
||||
- Update checking for yt-dlp
|
||||
|
||||
### Key Methods in YouTubeCLI Class
|
||||
- `search_videos()`: Search YouTube videos using yt-dlp
|
||||
- `display_videos()`: Display videos in a formatted table
|
||||
- `download_video()`: Download individual videos with progress
|
||||
- `download_playlist()`: Download YouTube playlists
|
||||
- `load_config()`: Load configuration from file or use defaults
|
||||
- `load_archive()`: Load archive of already downloaded videos
|
||||
- `add_to_archive()`: Add videos to download archive
|
||||
- `copy_to_network_share()`: Copy downloaded videos to network share
|
||||
- `check_for_updates()`: Check and update yt-dlp if needed
|
||||
|
||||
## Configuration
|
||||
The application creates a default configuration file at `~/.config/youtube_cli/config.json` if one doesn't exist. Configuration includes:
|
||||
- `download_dir`: Default download directory (set to `/Volumes/MediaServer/Youtube/`)
|
||||
- `default_locations`: List of default download locations including Tech, AI, Art, Homes, Cooking, Fitness, Music, Gaming, Education, Travel, Business, Science, History, Comedy, News, Sports, Nature, Photography, Language, and Automotive categories
|
||||
- `max_videos_per_page`: Number of videos per page (default: 15)
|
||||
- `yt_dlp_args`: Custom yt-dlp arguments for video format and extraction
|
||||
- `network_share_path`: Network share path for copying videos
|
||||
- `default_network_subfolder`: Default subfolder on network share
|
||||
|
||||
## Usage Examples
|
||||
```bash
|
||||
# Search for videos
|
||||
youtube-cli "python tutorial"
|
||||
|
||||
# Download a specific video
|
||||
youtube-cli --download "https://www.youtube.com/watch?v=xyz123"
|
||||
|
||||
# View help
|
||||
youtube-cli --help
|
||||
|
||||
# Check for yt-dlp updates
|
||||
youtube-cli --check-update
|
||||
|
||||
# Update yt-dlp
|
||||
youtube-cli --update
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
- Python 3.6+
|
||||
- yt-dlp (for video downloading)
|
||||
- rich (for formatted console output)
|
||||
- requests (for API calls)
|
||||
|
||||
## Installation
|
||||
### From Source
|
||||
```bash
|
||||
git clone https://github.com/yourusername/youtube-cli.git
|
||||
cd youtube-cli
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
### Using pip
|
||||
```bash
|
||||
pip install youtube-cli
|
||||
```
|
||||
|
||||
## How It Works
|
||||
1. **Search**: Users enter a search query to find YouTube videos
|
||||
2. **Display**: Videos are shown 15 at a time with title, author, duration, and type
|
||||
3. **Navigation**: Users can go to next page (n), search for new term (s), or quit (q)
|
||||
4. **Selection**: Users can select videos by number to download
|
||||
5. **Download**: Videos are downloaded using yt-dlp with progress indication
|
||||
6. **Tracking**: Downloaded videos are tracked in an archive file
|
||||
|
||||
## Special Features
|
||||
- **Short Video Detection**: Automatically detects and marks short videos with "(short)" prefix
|
||||
- **Pagination**: View 15 videos at a time with option for more
|
||||
- **Multiple Download Locations**: Choose from default locations or specify custom paths
|
||||
- **Network Share Integration**: Copy downloaded videos to network shares after download
|
||||
- **Update Checking**: Automatically checks for and updates yt-dlp when needed
|
||||
- **Archive Tracking**: Keeps track of already downloaded videos to avoid duplicates
|
||||
|
||||
## Technical Details
|
||||
- Uses yt-dlp for all YouTube operations
|
||||
- Implements Rich library for beautiful console output
|
||||
- Supports both individual video and playlist downloads
|
||||
- Handles JavaScript challenges with remote components
|
||||
- Includes retry mechanisms for downloads
|
||||
- Cross-platform compatibility (macOS and Linux)
|
||||
14
app.log
14
app.log
@ -1,14 +0,0 @@
|
||||
Error saving archive: [Errno 13] Permission denied: '/app'
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: on
|
||||
[31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:4096
|
||||
* Running on http://192.168.122.203:4096
|
||||
[33mPress CTRL+C to quit[0m
|
||||
* Restarting with stat
|
||||
Error saving archive: [Errno 13] Permission denied: '/app'
|
||||
* Debugger is active!
|
||||
* Debugger PIN: 556-686-523
|
||||
192.168.122.1 - - [03/Feb/2026 19:10:11] "GET /search?q=roo+vs+cline HTTP/1.1" 200 -
|
||||
127.0.0.1 - - [03/Feb/2026 19:10:13] "GET /health HTTP/1.1" 200 -
|
||||
@ -4,8 +4,12 @@ Manual test script for YouTube TUI
|
||||
Tests all required functionality
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def print_section(title):
|
||||
@ -145,7 +149,7 @@ def test_unit_tests():
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
cwd="/Users/user/Projects/youtube-cli",
|
||||
cwd=str(REPO_ROOT),
|
||||
)
|
||||
|
||||
print(result.stdout)
|
||||
@ -431,12 +435,13 @@ print("OK")
|
||||
|
||||
|
||||
def main():
|
||||
os.chdir(REPO_ROOT)
|
||||
"""Run all tests"""
|
||||
print("=" * 60)
|
||||
print(" YouTube TUI Manual Test Suite")
|
||||
print("=" * 60)
|
||||
print(f"\nPython: {sys.version}")
|
||||
print("Working directory: /Users/user/Projects/youtube-cli")
|
||||
print(f"Working directory: {REPO_ROOT}")
|
||||
|
||||
results = []
|
||||
|
||||
|
||||
18
prompt.md
18
prompt.md
@ -1,18 +0,0 @@
|
||||
The goal is to make a cli app that lets you traverse videos through youtube search and listed all the videos that are display for search. It should show at max 15 videos at a time and give options for asking for more. It should denote what videos are shorts (very short videos with /short in the url) with a name starting with (short). It should allow the user to search all of youtube with a query.
|
||||
|
||||
Display the Title, Name, Author, Video length of each youtube video on the list.
|
||||
Give an option to get the next 15 videos in the list.
|
||||
Give an option to download the video and show a status bar for the download.
|
||||
Provide a configuration file that the user can set the default download location for all of this.
|
||||
Let the user select from a set of default locations for where to download videos.
|
||||
|
||||
When downloading the video, it should leverage yt-dlp. A valid command in yt-dlp looks like
|
||||
|
||||
yt-dlp \
|
||||
--format "bestvideo[height=1080]+bestaudio/bestvideo[height<=1080]+bestaudio" \
|
||||
--download-archive "/mnt/centralstoragemedia/Youtube/Caseoh/caseoh-archive" \
|
||||
--playlist-items 1:2 "https://www.youtube.com/@caseoh_/videos" \
|
||||
-o "/mnt/centralstoragemedia/Youtube/Caseoh/%(title)s.%(ext)s" \
|
||||
--write-thumbnail --extractor-args "youtube:player-client=default,-tv_simply"
|
||||
|
||||
Coding Language should be python and it should work on Mac and Linux.
|
||||
@ -9,7 +9,7 @@ description = "A command-line interface for browsing and downloading YouTube vid
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
authors = [
|
||||
{name = "jarianc", email = "user@example.com"},
|
||||
{name = "Jarian Cottingham", email = "jarianc@proton.me"},
|
||||
]
|
||||
license = {text = "MIT"}
|
||||
classifiers = [
|
||||
@ -62,7 +62,7 @@ api = [
|
||||
"Flask==2.3.3",
|
||||
]
|
||||
tui = [
|
||||
"textual>=0.40.0",
|
||||
"textual>=0.40.0,<2.0.0",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
|
||||
4
setup.py
4
setup.py
@ -6,8 +6,8 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
||||
setup(
|
||||
name="youtube-cli",
|
||||
version="0.1.0",
|
||||
author="jarianc",
|
||||
author_email="user@example.com",
|
||||
author="Jarian Cottingham",
|
||||
author_email="jarianc@proton.me",
|
||||
description="A command-line interface for browsing and downloading YouTube videos",
|
||||
keywords="youtube, cli, download, video, yt-dlp, tui, terminal",
|
||||
long_description=long_description,
|
||||
|
||||
@ -40,15 +40,17 @@ class TestSearchScreen:
|
||||
|
||||
async def test_search_action_with_empty_input(self, app):
|
||||
"""Test search action with empty input"""
|
||||
from youtube_tui.screens.search import SearchScreen
|
||||
|
||||
screen = SearchScreen()
|
||||
# Use app.run_test() to ensure proper screen mounting
|
||||
async with app.run_test() as pilot:
|
||||
app.push_screen(screen)
|
||||
# Wait for the screen to be fully mounted
|
||||
await pilot.pause()
|
||||
|
||||
# Mock the update_status method to track calls
|
||||
update_calls = []
|
||||
screen = app.screen
|
||||
screen.update_status = lambda message: update_calls.append(message)
|
||||
|
||||
# Simulate pressing Enter with empty input
|
||||
@ -62,8 +64,11 @@ class TestSearchScreen:
|
||||
"""Test search action with valid input"""
|
||||
|
||||
search_term = "python tutorial"
|
||||
from youtube_tui.screens.search import SearchScreen
|
||||
|
||||
screen = SearchScreen()
|
||||
async with app.run_test() as pilot:
|
||||
app.push_screen(screen)
|
||||
# Wait for the screen to be fully mounted
|
||||
await pilot.pause()
|
||||
|
||||
@ -83,8 +88,11 @@ class TestSearchScreen:
|
||||
"""Test search from anywhere action"""
|
||||
|
||||
search_term = "music"
|
||||
from youtube_tui.screens.search import SearchScreen
|
||||
|
||||
screen = SearchScreen()
|
||||
async with app.run_test() as pilot:
|
||||
app.push_screen(screen)
|
||||
# Wait for the screen to be fully mounted
|
||||
await pilot.pause()
|
||||
|
||||
|
||||
@ -190,7 +190,7 @@ class TestCustomWidgets:
|
||||
from textual.widgets import Static
|
||||
|
||||
widget = Static("Test content")
|
||||
assert widget._Static__content == "Test content"
|
||||
assert widget.renderable == "Test content"
|
||||
|
||||
def test_static_widget_with_rich_markup(self):
|
||||
"""Test Static widget with Rich markup"""
|
||||
@ -198,14 +198,14 @@ class TestCustomWidgets:
|
||||
|
||||
widget = Static("[bold]Test[/bold] [red]content[/red]")
|
||||
# The content should contain the markup
|
||||
assert "[bold]" in str(widget._Static__content)
|
||||
assert "[bold]" in str(widget.renderable)
|
||||
|
||||
def test_button_widget_creation(self):
|
||||
"""Test Button widget"""
|
||||
from textual.widgets import Button
|
||||
|
||||
button = Button("Click me")
|
||||
assert button.label == "Click me"
|
||||
assert str(button.label) == "Click me"
|
||||
|
||||
def test_input_widget_creation(self):
|
||||
"""Test Input widget"""
|
||||
|
||||
17
uv.lock
generated
17
uv.lock
generated
@ -309,7 +309,7 @@ name = "exceptiongroup"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
||||
wheels = [
|
||||
@ -484,6 +484,9 @@ wheels = [
|
||||
linkify = [
|
||||
{ name = "linkify-it-py" },
|
||||
]
|
||||
plugins = [
|
||||
{ name = "mdit-py-plugins" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markupsafe"
|
||||
@ -831,19 +834,17 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "textual"
|
||||
version = "8.0.2"
|
||||
version = "1.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py", extra = ["linkify"] },
|
||||
{ name = "mdit-py-plugins" },
|
||||
{ name = "markdown-it-py", extra = ["linkify", "plugins"] },
|
||||
{ name = "platformdirs" },
|
||||
{ name = "pygments" },
|
||||
{ name = "rich" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/be/08/c6bcb1e3c4c9528ec9049f4ac685afdafc72866664270f0deb416ccbba2a/textual-8.0.2.tar.gz", hash = "sha256:7b342f3ee9a5f2f1bd42d7b598cae00ff1275da68536769510db4b7fe8cabf5d", size = 6099270, upload-time = "2026-03-03T20:23:46.858Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/b6/59b1de04bb4dca0f21ed7ba0b19309ed7f3f5de4396edf20cc2855e53085/textual-1.0.0.tar.gz", hash = "sha256:bec9fe63547c1c552569d1b75d309038b7d456c03f86dfa3706ddb099b151399", size = 1532733, upload-time = "2024-12-12T10:42:03.286Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/77/bc/0cd17f96f00b6e8bfbca64c574088c85f3c614912b3030f313752e30a099/textual-8.0.2-py3-none-any.whl", hash = "sha256:4ceadbe0e8a30eb80f9995000f4d031f711420a31b02da38f3482957b7c50ce4", size = 719174, upload-time = "2026-03-03T20:23:50.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/bb/5fb6656c625019cd653d5215237d7cd6e0b12e7eae4195c3d1c91b2136fc/textual-1.0.0-py3-none-any.whl", hash = "sha256:2d4a701781c05104925e463ae370c630567c70c2880e92ab838052e3e23c986f", size = 660456, upload-time = "2024-12-12T10:42:00.375Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -989,7 +990,7 @@ requires-dist = [
|
||||
{ name = "requests", specifier = ">=2.28.0" },
|
||||
{ name = "rich", specifier = ">=13.0.0" },
|
||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" },
|
||||
{ name = "textual", marker = "extra == 'tui'", specifier = ">=0.40.0" },
|
||||
{ name = "textual", marker = "extra == 'tui'", specifier = ">=0.40.0,<2.0.0" },
|
||||
{ name = "types-requests", marker = "extra == 'dev'", specifier = ">=2.28.0" },
|
||||
{ name = "yt-dlp" },
|
||||
]
|
||||
|
||||
@ -24,8 +24,9 @@ if os.environ.get('DOCKER'):
|
||||
errorlog = "-"
|
||||
loglevel = "info"
|
||||
else:
|
||||
accesslog = "/home/user/repos/youtube-cli/web/server/gunicorn-access.log"
|
||||
errorlog = "/home/user/repos/youtube-cli/web/server/gunicorn-error.log"
|
||||
log_dir = os.environ.get("GUNICORN_LOG_DIR", os.path.dirname(os.path.abspath(__file__)))
|
||||
accesslog = os.path.join(log_dir, "gunicorn-access.log")
|
||||
errorlog = os.path.join(log_dir, "gunicorn-error.log")
|
||||
loglevel = "debug"
|
||||
|
||||
# Process naming
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user