Skip to content

Conversation

@mstudio005
Copy link

Summary

This PR adds a new IMAGE download type to Seal, allowing users to download video thumbnails and playlist covers at various quality levels.

Features Added

1. New Download Type: IMAGE

  • Added IMAGE to DownloadType enum
  • Integrated into download dialog workflow
  • Accessible via download type selector

2. ImageSelectionPage UI

  • Material 3 design with checkboxes for thumbnail/playlist cover selection
  • Quality selector with radio buttons:
    • Low (default.jpg)
    • Medium (mqdefault.jpg)
    • High (hqdefault.jpg)
    • HD (sddefault.jpg)
    • Original (maxresdefault.jpg - default)
  • Confirmation dialog before download
  • Toast notifications for user feedback

3. Smart Quality Selection

  • Implemented pickBestImageUrl() with HTTP HEAD request probing
  • Automatic quality fallback: ORIGINAL → HD → HIGH → MEDIUM → LOW
  • Pre-validates URLs before enqueuing downloads
  • Only downloads images that actually exist (no 404 errors)

4. Robust Download Implementation

  • Retry logic: 2 attempts with 1-second delay
  • Timeout configuration: 5s for HEAD probes, 30s for downloads
  • Proper Content-Type validation (image/*)
  • File extension extracted from Content-Type header
  • Clean filename generation: <videoId>_<quality>.<ext>

5. File Management

  • Saves to /Pictures/Seal/ directory
  • MediaScanner integration for gallery apps
  • Proper stream management and resource cleanup

Technical Details

Modified Files

  • PreferenceUtil.kt - Added IMAGE enum value
  • DownloadDialogViewModel.kt - Added ImageQuality enum and state management
  • ImageSelectionPage.kt - New UI component (327 lines)
  • DownloaderV2.kt - Image download orchestration
  • DownloadUtil.kt - pickBestImageUrl() and downloadImageFromUrl()
  • FileUtil.kt - getPicturesSealFile() helper
  • Task.kt - ImageDownload TypeInfo
  • DownloadDialogV2.kt - Image type routing and error handling
  • strings.xml - Image-related strings

Bug Fixes

  • Fixed ErrorPage crash when handling FetchImages errors
  • Fixed duplicated filename suffixes (e.g., "maxresmaxresdefault.jpg")
  • Fixed file extension mismatches

Testing

Tested with real YouTube thumbnails:

  • ✅ Old videos with limited quality availability (automatic fallback works)
  • ✅ Modern videos with all quality levels (uses requested quality)
  • ✅ HEAD request validation (200 status + image/* Content-Type)
  • ✅ Gallery integration (MediaScanner refresh)
  • ✅ Clean filenames with correct extensions

Checklist

  • Code follows project style guidelines
  • Added/updated relevant documentation
  • Tested on Android 15 (API 35)
  • No breaking changes
  • All existing tests pass
  • Added appropriate error handling

- Add IMAGE type to DownloadType enum
- Implement ImageSelectionPage with quality selector (Low, Medium, High, HD, Original)
- Add ImageQuality enum with YouTube thumbnail quality mappings
- Implement pickBestImageUrl() with HEAD request probing for quality fallback
- Add automatic quality fallback: ORIGINAL → HD → HIGH → MEDIUM → LOW
- Fix filename generation (clean format: videoId_quality.ext)
- Extract file extension from Content-Type header
- Add retry logic (2 attempts) for transient network failures
- Add timeout configuration (5s for HEAD, 30s for download)
- Add MediaScannerConnection for gallery integration
- Add Task.TypeInfo.ImageDownload for image download tasks
- Update DownloaderV2 with downloadImages() and downloadImage()
- Add downloadImageFromUrl() with proper error handling
- Add getPicturesSealFile() helper to save to /Pictures/Seal/
- Add image-related string resources
- Fix ErrorPage crash by handling FetchImages action

Closes: Image download feature request
@mstudio005 mstudio005 mentioned this pull request Nov 14, 2025
6 tasks
@mstudio005
Copy link
Author

Just an update:

This feature request was originally raised in issue #2300, and this PR fully implements the requested image download support (thumbnail + playlist cover + quality selection).

Implementation has been tested on Android 15, and all existing functionality (audio/video/playlist) works as before without regressions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant