Three related resilience gaps in SourcedTrack.fetchFromTrack and URL
resolution:
- A cached SpotubeAudioSourceMatchObject whose stream resolution now
fails (source removed/changed) was never retried; it now deletes the
stale sourceMatchTable row, fetches fresh siblings, caches the new
match, and retries once.
- fetchSiblings returning empty was treated as a hard TrackNotFoundError;
it now attempts audioSource.auth.authenticate() once and retries
before giving up, via a shared _fetchSiblingsWithRetry helper.
- `url` getter and getUrlOfQuality threw/returned null when the user has
no configured quality presets, or no stream matches the selected
container; both now fall back to sources.firstOrNull?.url instead of
crashing.
Fixes#3091
* feat: add youtube engine abstraction and yt-dlp integration
* chore: add yt-dlp as optional dependency
* feat: implement custom path support for youtube engines
* chore: check for custom path in setting engine select dropdown
* chore: update yt_dlp_dart
* chore: setting video url instead of video id in fetchSiblings
* feat: implement NewPipe engine
* chore: update local path to git url for flutter_new_pipe_extractor package
* chore: fix android build isn't working
* chore: fix routes not working when initially signing in
* refactor: drop fallback support to different sources
* feat: add invidious audio source with automatic track switch even on server playback endpoint
* fix: switching to different source on playback endpoint error not working
* chore: update invidious version
* feat: invidious instances customizability
* feat: implement new SourcedTrack for youtube and piped
* refactor: replace old spotube track with sourced track
* feat: add jiosaavn as audio source
* fix: download not working other than jiosaavn
* Merge branch 'dev' into feat-jiosaavn