Commit Graph
41 Commits
Author SHA1 Message Date
zarzet ea172ba17b refactor(go): split package validation and VM lifecycle out of extension_manager.go 2026-07-26 23:05:30 +07:00
zarzet 42c266eafc fix(extensions): enforce minAppVersion and requiredRuntimeFeatures on load
Both manifest gates were parsed but only checked by the Store UI, so
manual .sflx installs and directory loads of incompatible extensions
failed cryptically at runtime despite SIGNED_SESSION_GUIDE promising a
clear refusal. validateExtensionLoad now rejects them on every install
path, and ensureRuntimeReady re-checks so a gated package cannot be
enabled anyway. Unknown runtime features and too-new feature contract
versions fail with explicit messages; an empty app version (tests)
skips the version gate.
2026-07-26 19:14:29 +07:00
zarzet 1705fb2a81 feat(extensions): verify decentralized package integrity 2026-07-26 01:14:35 +07:00
zarzet bab954c6d9 fix(extensions): harden package and runtime lifecycle 2026-07-15 21:31:16 +07:00
zarzet 3cdeeb2f5f fix(extensions): remove extension data dir on uninstall 2026-07-14 09:10:00 +07:00
zarzet 08007f493c perf(extensions): reuse isolated goja download runtimes via per-extension pool 2026-07-14 09:09:39 +07:00
zarzet 8abb99ac91 chore(backend): modernize interface{} to any, silence lint noise
gofmt -r rewrite of all 506 interface{} occurrences to the any alias
(identical semantics), drop unused spec constants into comments, rename
unused parameters to _, convert three if-else chains to tagged
switches, and use slices.ContainsFunc for the private-IP check. No
behavior change; the whole package is now gofmt-clean.
2026-07-10 10:18:00 +07:00
zarzet c1c0494912 perf: optimize queue/library pagination, counts, scan, and extension runtime
- Queue/Library: switch from growing-limit refetch to offset-based append pagination per filter/search/sort, with page cache reassembly and protected-page eviction to avoid top-of-list gaps

- Queue/Library: watch only the active filter page instead of all/singles/albums simultaneously; filter mode follows PageView swipe and tab tap

- library_database: combine three union-based count queries into a single round-trip

- library_scan: parallel scan of non-CUE audio files with a bounded 2-4 worker pool, preserving order, progress, and cancellation; CUE handling stays sequential

- extension_manager: cache compiled goja.Program per extension and RunProgram per isolated download instead of re-reading and re-parsing index.js
2026-06-26 22:39:22 +07:00
zarzet 9c054b9e3a feat: handle extension verification and retry-after on download
Classify verification-required and rate-limit errors from extensions, propagate Retry-After seconds through the download fallback, report session-grant success/failure, and add a completeGrant action fallback in the runtime.
2026-06-26 07:12:12 +07:00
zarzet ee35f52baf feat: extension runtime and provider improvements 2026-06-26 04:14:51 +07:00
zarzet 49869792cf chore: trim redundant comments 2026-06-13 15:37:00 +07:00
zarzet 6b5345a6e5 fix(downloads/extensions): iOS background task, serialize extension mutations, safer batch convert sheet
- iOS: begin/end UIBackgroundTask while a download queue is active so in-flight downloads survive backgrounding for the limited window iOS allows

- extensions: serialize install/upgrade/remove in the Go manager (mutationMu) and in the Dart store provider to stop concurrent goja VM teardown/reload from hard-crashing the app

- main: add runZonedGuarded + FlutterError/PlatformDispatcher onError so uncaught Dart errors are logged, not fatal

- batch convert sheet: precompute localized title/label before showModalBottomSheet to avoid Localizations lookup via a deactivated context
2026-06-13 02:42:23 +07:00
zarzet 012dcdc2dd fix: native FLAC handling and extension API optimizations
Native FLAC handling:
- Properly detect and publish native FLAC payloads inside MP4 containers
- Rename to .flac extension and embed metadata instead of skipping
- Fix all code paths: SAF, non-SAF, and native worker finalizer

Extension API optimizations:
- Enable response compression for API/search calls (faster metadata loads)
- Keep downloads uncompressed for accurate progress/streaming
- Add separate extensionAPITransport with compression enabled

Platform bridge caching:
- Cache handleURLWithExtension results (5 min TTL)
- Cache customSearchWithExtension results (2 min TTL)
- Prevent duplicate in-flight requests for same URL/query

Dependency cleanup:
- Remove unused sqflite_common_ffi and sqlite3 packages
2026-05-15 00:54:58 +07:00
zarzet bb06ab7e12 chore: remove dead code, fix error casing, and add lint rules
- Remove unused Go functions: buildRawAPEItem, loadCredentials,
  scanAudioFile, scanAudioFileWithKnownModTimeAndDisplayName,
  readM4AIndexValue, musixmatchSearchResponse/LyricsResponse structs
- Remove unused Go fields: downloadDir, utlsTransport.mu/h2Transports
- Lowercase Go error messages per convention (golint/ST1005)
- Simplify LyricsLine conversion and artistsMatch return
- Add Dart analysis rules: always_declare_return_types,
  avoid_types_as_parameter_names, strict_top_level_inference,
  type_annotate_public_apis
- Suppress SA1019 lint for required blowfish import
2026-05-06 00:04:49 +07:00
zarzet 1b4a6cd042 feat: show extension service health 2026-05-03 20:20:28 +07:00
zarzet 3f56b88fa5 refactor: rename skipBuiltInFallback to stopProviderFallback, unify service/search provider grid layout, and retire useExtensionProviders toggle
- Add stopProviderFallback manifest field with backward compat for skipBuiltInFallback

- Expose stop_provider_fallback in extension JSON API

- Unify service and search provider chips into 4-per-row grid layout

- Enable Ask Before Download for extensions with quality options

- Force useExtensionProviders always-on (built-in providers retired)

- Update localization: Built-in -> Legacy, remove obsolete description text

- Clear hardcoded donor names list
2026-05-01 04:43:06 +07:00
zarzet bdd3f4aef5 feat: retire built-in download providers, add isolated extension runtimes, Google Sans Flex font, and monochrome icon support
- Remove all built-in download provider code paths (DownloadTrack, DownloadWithFallback, tryBuiltInProvider, isBuiltInDownloadProvider, normalizeQualityForBuiltIn)
- Simplify DownloadByStrategy to route exclusively through extension providers
- Add newIsolatedExtensionRuntime() for concurrent per-download Goja VMs
- Extract reusable initializeExtensionRuntimeWithSettings() and runCleanupOnVM()
- Add TestExtensionDownloadUsesIsolatedRuntimeForConcurrentCalls
- Add Google Sans Flex font family to app themes
- Add Android adaptive icon monochrome support
- Regenerate iOS and Android app icons
2026-05-01 02:44:32 +07:00
zarzet 378742e37a refactor: remove author field from extension manifest and UI 2026-04-13 23:35:03 +07:00
zarzet 4c4553913f fix: harden gomobile extension bindings and m4a cover retention 2026-04-13 23:32:17 +07:00
zarzet 53a4773480 feat: add skipLyrics manifest field for extensions to opt out of lyrics fetching 2026-04-13 23:32:16 +07:00
zarzet 0e265193b8 fix: improve extension runtime safety, HTTP response URL, SongLink parsing, and recommended service for extensions
- Add 'url' field (final URL after redirects) to all extension HTTP responses and fix fetch polyfill to return final URL instead of original request URL
- Fix RunWithTimeout race condition: increase force-timeout from 1s to 60s to prevent concurrent VM access crashes, add nil guards
- Use lockReadyVM() for thread-safe VM access in GetPlaylistWithExtensionJSON and InvokeAction
- Handle mixed JSON types (string, null, array) in SongLink resolve API SongUrls field
- Fix recommended download service not showing for extension-based searches in download picker
2026-04-13 23:32:15 +07:00
Alex 3fc371b8c4 Extension OAuth + store: flatten action JSON, open auth URLs, spotiflac:// callback
Third-party extensions (e.g. Spotify PKCE addons) need three things the current app does not fully provide:

Extension button results – The Go runtime returned { success, result: { message, open_auth_url, … } } while Flutter read message / open_auth_url only on the outer map, so OAuth buttons appeared to do nothing. InvokeAction now merges the extension’s return object onto the top-level JSON (arrays/non-objects still use result).

Flutter – extension_detail_page: unwrap nested result for compatibility, merge setting_updates into saved extension settings (for copyable OAuth URLs), and launchUrl when open_auth_url is set.

Mobile OAuth return – spotiflac://callback?code=…&state=<extension_id> was not handled on Android (manifest + MainActivity) or iOS (AppDelegate open URL + cold-start launchOptions). This wires SetExtensionAuthCodeByID + invokeExtensionAction(..., "completeSpotifyLogin") so PKCE extensions can finish login after the browser redirect.

Extension store HTTP – Add Cache-Control: no-cache on registry and extension package downloads to reduce stale CDN/proxy responses.

Testing: Install a metadata extension that uses PKCE; tap Connect; confirm browser opens, return via spotiflac://callback, and tokens complete without pasting the code manually.

extension InvokeAction JSON was nested under result while the Flutter settings UI only read the top level, so OAuth-related buttons never showed messages or opened the browser. This PR flattens that payload, merges optional setting_updates, launches open_auth_url, adds spotiflac://callback handling on Android and iOS, and sends no-cache on store HTTP fetches. Needed for extensions like SpoitiLists (Spotify Web API + PKCE).
2026-04-12 02:40:31 -06:00
zarzet 03fd734048 perf: lazy extension VM init, incremental startup maintenance, and UI optimizations
- Defer extension VM initialization until first use with lockReadyVM() pattern to eliminate TOCTOU races and reduce startup overhead
- Add validateExtensionLoad() to catch JS errors at install time without keeping VM alive
- Teardown VM on extension disable to free resources; re-init lazily on re-enable
- Replace full orphan cleanup with incremental cursor-based pagination across launches
- Batch DB writes (upsertBatch, replaceAll) with transactions for atomicity
- Parse JSON natively on Kotlin side to avoid double-serialization over MethodChannel
- Add identity-based memoization caches for unified items and path match keys in queue tab
- Use ValueListenableBuilder for targeted embedded cover refreshes instead of full setState
- Extract shared widgets (_buildAlbumGridItemCore, _buildFilterButton, _navigateWithUnfocus)
- Use libraryCollectionsProvider selector and MediaQuery.paddingOf for fewer rebuilds
- Simplify supporter chip tiers and localize remaining hardcoded strings
2026-03-25 19:55:02 +07:00
zarzet 5948e4f125 chore: remove redundant inline comments 2026-03-14 15:07:15 +07:00
zarzet 7d5cb574c6 feat: move Amazon Music to extension, fix Deezer download timeout 2026-03-08 04:15:28 +07:00
zarzet ab26d84632 chore: rebuild dev history without streaming-era commits 2026-02-27 13:48:44 +07:00
zarzet 30973a8e78 feat: lyrics provider extensions, configurable lyrics cascade, and iOS method channel parity
Add lyrics_provider as a new extension type alongside metadata_provider and
download_provider. Extensions implementing fetchLyrics() are called before
built-in providers, giving user-installed extensions highest priority.

Built-in lyrics cascade is now configurable from Download Settings:
  - Reorderable provider list (LRCLIB, Musixmatch, Netease, Apple Music, QQ Music)
  - Per-provider options: Netease translation/romanization, Apple/QQ multi-person
    word-by-word speaker tags, Musixmatch language code
  - Provider order and options synced to Go backend on app start and on change

Go backend changes:
  - New lyrics_provider manifest type with validation (extension_manifest.go)
  - ExtensionProviderWrapper.FetchLyrics() with Goja JS bridge (extension_providers.go)
  - Configurable SetLyricsProviderOrder/GetLyricsProviderOrder cascade (lyrics.go)
  - LyricsFetchOptions struct for per-provider settings (lyrics.go)
  - Extracted tryLRCLIB() helper, randomized LRCLIB User-Agent (lyrics.go)
  - Refactored msToLRCTimestamp to separate msToLRCTimestampInline (lyrics.go)
  - New provider source files: lyrics_apple.go, lyrics_musixmatch.go,
    lyrics_netease.go, lyrics_qqmusic.go
  - JSON export functions for lyrics settings (exports.go)
  - hasLyricsProvider field in extension manager JSON output

Platform channels:
  - Android (MainActivity.kt): setLyricsProviders, getLyricsProviders,
    getAvailableLyricsProviders, setLyricsFetchOptions, getLyricsFetchOptions
  - iOS (AppDelegate.swift): same 5 method channel handlers for iOS parity

Flutter side:
  - Extension model: hasLyricsProvider field + Lyrics Provider capability badge
  - Settings model: lyricsProviders, lyricsIncludeTranslationNetease,
    lyricsIncludeRomanizationNetease, lyricsMultiPersonWordByWord,
    musixmatchLanguage fields with generated serialization
  - Settings provider: setters + _syncLyricsSettingsToBackend()
  - Download settings UI: provider picker, toggle switches, language picker
  - Platform bridge: lyrics provider/options methods

Docs: lyrics provider extension documentation in site/docs.html
CHANGELOG: updated with lyrics provider and search feature entries
2026-02-14 01:42:18 +07:00
zarzet 7c08321ce3 refactor: continue code cleanup 2026-02-04 10:42:51 +07:00
zarzet b9c3f2f0dd fix: remove duplicate plugin registration warning
Remove manual GeneratedPluginRegistrant.registerWith() call since
super.configureFlutterEngine() already handles this automatically.
2026-02-01 20:18:51 +07:00
zarzet 81b0eede8c v3.3.5: Same as 3.3.1 but fixes crash issues caused by FFmpeg
Changes:
- Fix FFmpeg crash issues during M4A to MP3/Opus conversion
- Add format picker (MP3/Opus) when selecting Tidal Lossy 320kbps
- Fix Deezer album blank screen when opened from home
- LRC file generation now follows lyrics mode setting
- Version bump to 3.3.5 (build 70)
2026-02-01 20:12:00 +07:00
zarzet 79180dd918 feat: add Home Feed with pull-to-refresh and gobackend.getLocalTime() API
- Add Home Feed/Explore feature with extension capabilities system
- Add pull-to-refresh on home feed (replaces refresh button)
- Add gobackend.getLocalTime() API for accurate device timezone detection
- Add YT Music Quick Picks UI with swipeable vertical format
- Fix greeting time showing wrong time due to Goja getTimezoneOffset() returning 0
- Update spotify-web and ytmusic extensions to use getLocalTime()
- Add Turkish language support
- Update CHANGELOG for v3.2.0
2026-01-21 08:30:44 +07:00
zarzet 03027813c1 chore: cleanup unused code and dead imports 2026-01-20 02:10:10 +07:00
zarzet 0119db094d feat: add extended metadata (genre, label, copyright) support
- Add genre, label, copyright fields to ExtTrackMetadata and DownloadResponse
- Add utils.randomUserAgent() for extensions to get random User-Agent strings
- Fix VM race condition panic by adding mutex locks to all provider methods
- Fix Tidal release date fallback when req.ReleaseDate is empty
- Display genre, label, copyright in track metadata screen
- Store extended metadata in download history for persistence
- Add trackGenre, trackLabel, trackCopyright localization strings
2026-01-19 21:13:40 +07:00
zarzet 595bfb2711 feat: add button setting type for extension actions
- Add SettingTypeButton for action buttons in extension settings
- Add Action field to ExtensionSetting for JS function name
- Update extension detail page UI to render button settings
- Add InvokeAction method to execute button actions
2026-01-19 02:14:52 +07:00
zarzet 8d92d22fda refactor: more code cleanup 2026-01-17 10:04:21 +07:00
zarzet b99764b1ad refactor: cleanup unused code and imports 2026-01-17 09:50:00 +07:00
zarzet 18bc079632 Merge dev into main: v3.0.0 stable release 2026-01-14 18:08:30 +07:00
zarzet 13b917d1a0 fix: preserve directory structure when extracting extension packages 2026-01-13 17:50:12 +07:00
zarzet 8daff4d0a4 feat: improve Extension Store with custom icons and various fixes
- Support custom extension icons from registry (iconUrl field)
- Support both camelCase and snake_case in registry JSON
- Fix download file extension (.spotiflac-ext)
- New extensions start disabled by default
- Preserve enabled state on extension upgrade
- Add toggle to show/hide Store tab in Settings > Options
- Reorder tabs: Home, History, Store, Settings
2026-01-13 01:01:43 +07:00
zarzet 93b4047143 fix: persist extension enabled state and clear search provider when disabled
- Save enabled state to settings store when extension is enabled/disabled
- Restore enabled state from settings store when extension is loaded
- Clear searchProvider setting when the extension is disabled
- Update search hint to check if extension is still enabled
2026-01-12 01:56:16 +07:00
zarzet 57cb575483 feat: add extension system with skipBuiltInFallback support
- Add extension manager, manifest, runtime, providers, settings
- Add extension provider and UI pages (extensions, detail, priority)
- Add download service picker widget
- Add metadata provider priority page
- Add source field to Track model for extension tracking
- Add skipBuiltInFallback manifest option to skip built-in providers
- Update download queue to use source extension first
- Add extension upgrade support without data loss
2026-01-12 00:17:52 +07:00