Repository: yt-dlp
Issue: 8tracks improvements: saving after extraction and bug fix for tracklist with extra phantom entry
Labels: site-enhancement,triage

### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm requesting a site-specific feature
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [ ] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

US

### Example URLs

https://8tracks.com/jsagsjfhdh/flight

### Provide a description that is worded well enough to be understood

I've been using the 8tracks downloader and made 2 modifications to my local setup that I think would be useful. 

First is that with 8tracks there seems to be some sort of monitoring they do which results in http 403 error and yt-dlp addresses by adding wait time equal to the time it would take to listen to the song. This works great but results in the download taking a very long time. 
<img width="392" alt="image" src="https://github.com/yt-dlp/yt-dlp/assets/3032338/53657064-ee02-4868-97bf-b733d8d81a09">
I have found it helpful to be able to save the progress during the extraction phase. 
<img width="1107" alt="image" src="https://github.com/yt-dlp/yt-dlp/assets/3032338/c7d1dd7e-047c-4e93-8f93-09054ad198c1">
The idea here is if I decide I need to stop the process or there is an error that stops it I can resume at a later time by passing the path to the saved json file and telling the extractor to resume at the current index rather than having to start from scratch. I have not completed this but expect it would be pretty quick for me to do. The save json and load json would need to be added as command flags - which I have less experience in but willing to look into.

This feature may also be useful more broadly - but as the loop runs in the site specific extractor method looks like it would have to be implemented per site. Please correct me if I am wrong here. Also I see resume capability for partial downloads but not at the extraction phase - so this may be an issue specific to 8tracks

Second is a simple bug fix, when accessing the track link: https://8tracks.com/jsagsjfhdh/flight for some reason the final api_data entry has no track data as shown below. You'll also notice that 'at_end': True but 'at_last_track': False

```
{'set': {'at_beginning': False, 'at_end': True, 'at_last_track': False, 'skip_allowed': False, 'skip_message': 'Our music license allows us to do some awesome things, but it doesn’t allow more than 3 skips within a playlist per hour. Skip again to go to the next playlist or choose a new playlist to reset your listening session.', 'track': {}}, 'listening_quota': {'weekly_quota_reached': False, 'weekly_hours_quota': 168.0, 'weekly_hours_quota_used': 0.0}, 'status': '200 OK', 'errors': None, 'notices': '', 'logged_in': False, 'api_version': 3}
```

the second to last entry has 'at_end': False, 'at_last_track': True
```
{'set': {'at_beginning': False, 'at_end': False, 'at_last_track': True, 'skip_allowed': False, 'skip_message': 'Our music license allows us to do some awesome things, but it doesn’t allow more than 3 skips within a playlist per hour. Skip again to go to the next playlist or choose a new playlist to reset your listening session.', 'track': {'faved_by_current_user': False, 'buy_link': 'http://redirect.viglink.com/?key=f4be5dc2078785c5846df105343edee0&out=https%3A%2F%2Fsearch.itunes.apple.com%2FWebObjects%2FMZSearch.woa%2Fwa%2Fsearch%3Fterm%3DHarry%2520Potter%2520Fawkes%2520the%2520Phoenix', 'buy_icon': 'http://8tracks.com/assets/buy/itunes.png', 'buy_text': 'iTunes', 'track_file_stream_url': 'http://cft.8tracks.com/tf/054/280/293/KHuzYT.48k.v3.m4a', 'stream_source': 'upload_v3', 'user_id': 4473830, 'full_length': True, 'id': 19009162, 'name': 'Fawkes the Phoenix', 'performer': 'Harry Potter', 'url': 'http://8tracks.com/tracks/19009162', 'year': None, 'uid': 19009162, 'report_delay_s': 17, 'release_name': 'HP Soundtrack', 'is_soundcloud': False}}, 'listening_quota': {'weekly_quota_reached': False, 'weekly_hours_quota': 168.0, 'weekly_hours_quota_used': 0.0}, 'status': '200 OK', 'errors': None, 'notices': '', 'logged_in': False, 'api_version': 3}
```

this results in a keyerror.

2 line fix I used is adding the below at line 146 in eighttracks.py
```
            if api_data['set']['at_end'] == True and len(track_data)==0:
                continue
```

Just wanted to post this here to get some input. I am not sure what the pull request process and test process is but if these additions are helpful I'm happy to contribute them.

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['-x', 'https://8tracks.com/jsagsjfhdh/flight', '--audio-format', 'm4a', '-o', '%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s', '--no-geo-bypas', '-v']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2024.05.27 from yt-dlp/yt-dlp [12b248ce6] (pip)
[debug] Python 3.10.10 (CPython arm64 64bit) - macOS-13.1-arm64-arm-64bit (OpenSSL 1.1.1t  7 Feb 2023)
[debug] exe versions: ffmpeg 7.0.1 (setts), ffprobe 7.0.1
[debug] Optional libraries: Cryptodome-3.20.0, brotli-None, certifi-2022.12.07, mutagen-1.47.0, requests-2.31.0, sqlite3-3.41.1, urllib3-2.2.2, websockets-12.0
[debug] Proxy map: {}
[debug] Request Handlers: urllib, requests, websockets
[debug] Loaded 1820 extractors
[8tracks] Extracting URL: https://8tracks.com/jsagsjfhdh/flight
[8tracks] flight: Downloading webpage
[8tracks] flight: Downloading song information 1/13
[8tracks] flight: Downloading song information 2/13
[8tracks] flight: Downloading song information 3/13
[8tracks] flight: Downloading song information 4/13
[8tracks] flight: Downloading song information 5/13
[8tracks] flight: Downloading song information 6/13
[8tracks] flight: Downloading song information 7/13
[8tracks] flight: Downloading song information 8/13
[8tracks] flight: Downloading song information 9/13
[8tracks] flight: Downloading song information 10/13
[8tracks] flight: Downloading song information 11/13
[8tracks] flight: Downloading song information 12/13
ERROR: flight: An extractor error has occurred. (caused by KeyError('id')); please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
  File "/opt/homebrew/Caskroom/miniconda/base/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 734, in extract
    ie_result = self._real_extract(url)
  File "/opt/homebrew/Caskroom/miniconda/base/lib/python3.10/site-packages/yt_dlp/extractor/eighttracks.py", line 147, in _real_extract
    'id': compat_str(track_data['id']),
KeyError: 'id'
```