Repository: yt-dlp/yt-dlp

Issue:
[TikTok] Image gallery format listed as having a vcodec when it's only audio
### 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 reporting a bug unrelated to a specific site
- [X] I've verified that I'm running yt-dlp version **2023.03.04** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [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)

### Provide a description that is worded well enough to be understood

TikTok has added support for image galleries which are a slideshow of images + audio. yt-dlp reports the image galleries as having a vcodec but the media is only the audio. So when using a specific format selector (like `b[vcodec=?h265],b[vcodec=h264]` it will download the audio track instead of ignoring it.

Some `-J` outputs of gallery tiktok formats

This has a `.mp3` extension & `music` in the subdomain: https://www.tiktok.com/@user/video/7139980461132074283
```json
  "formats": [
    {
      "url": "https://sf16-ies-music-va.tiktokcdn.com/obj/ies-music-ttp-dup-us/7072971688513932078.mp3",
      "filesize": null,
      "ext": "mp4",
      "acodec": "aac",
      "source_preference": -1,
      "format_id": "play_addr",
      "format_note": "Direct video",
      "vcodec": "h264",
      "width": 0,
      "height": 0,
      "protocol": "https",
      "resolution": null,
      "dynamic_range": "SDR",
      "aspect_ratio": null,
      "http_headers": {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-us,en;q=0.5",
        "Sec-Fetch-Mode": "navigate"
      },
      "video_ext": "mp4",
      "audio_ext": "none",
      "format": "play_addr - unknown (Direct video)"
    }
  ],
```

I have also seen some galleries that don't have `.mp3` in the formats (but it does have `music` in the subdomain) output but are just the audio track with no video
Example with no `mp3`: https://www.tiktok.com/@syannee7/video/7200105375729765675
```json
  "formats": [
    {
      "url": "https://sf16-ies-music-va.tiktokcdn.com/obj/tos-useast2a-ve-2774/59e6660e96ce44b5bf5e7bb918ed2046",
      "filesize": null,
      "ext": "mp4",
      "acodec": "aac",
      "source_preference": -1,
      "format_id": "play_addr",
      "format_note": "Direct video",
      "vcodec": "h264",
      "width": 0,
      "height": 0,
      "protocol": "https",
      "resolution": null,
      "dynamic_range": "SDR",
      "aspect_ratio": null,
      "http_headers": {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-us,en;q=0.5",
        "Sec-Fetch-Mode": "navigate"
      },
      "video_ext": "mp4",
      "audio_ext": "none",
      "format": "play_addr - unknown (Direct video)"
    }
  ],
```

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [X] 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: ['--external-downloader', 'aria2c', '--external-downloader-args', '-j 10 -x 10 -s 10', '-vU', 'https://www.tiktok.com/@user/video/7139980461132074283']
[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@2023.03.04 [392389b7d] (zip)
[debug] Python 3.8.10 (CPython x86_64 64bit) - Linux-5.4.0-81-generic-x86_64-with-glibc2.29 (OpenSSL 1.1.1f  31 Mar 2020, glibc 2.31)
[debug] exe versions: ffmpeg 4.2.7, ffprobe 4.2.7, phantomjs 2.1.1
[debug] Optional libraries: certifi-2022.05.18.1, mutagen-1.46.0, pycrypto-3.10.1, secretstorage-2.3.1, sqlite3-2.6.0
[debug] Proxy map: {}
WARNING: External Downloader arguments given without specifying name. The arguments will be given to aria2c
[debug] Loaded 1786 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Available version: stable@2023.03.04, Current version: stable@2023.03.04
Current Build Hash: 91cad9f121c1f6f0a81b747415c46ecba0ff331ed38cc6433040b4ac7b6e15ca
yt-dlp is up to date (stable@2023.03.04)
[TikTok] Extracting URL: https://www.tiktok.com/@user/video/7139980461132074283
[TikTok] 7139980461132074283: Downloading video feed
[debug] Extractor gave empty title. Creating a generic title
[debug] Sort order given by extractor: quality, codec, size, br
[debug] Formats sorted by: hasvid, ie_pref, quality, vcodec, acodec, filesize, fs_approx, tbr, vbr, abr, lang, res, fps, hdr:12(7), channels, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] 7139980461132074283: Downloading 1 format(s): play_addr
[debug] Invoking aria2c downloader on "https://sf16-ies-music-va.tiktokcdn.com/obj/ies-music-ttp-dup-us/7072971688513932078.mp3"
[download] Destination: TikTok video #7139980461132074283 [7139980461132074283].mp4
[debug] aria2c command line: aria2c -c --console-log-level=warn --summary-interval=0 --download-result=hide --http-accept-gzip=true --file-allocation=none -x16 -j16 -s16 --min-split-size 1M --header 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.115 Safari/537.36' --header 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' --header 'Accept-Language: en-us,en;q=0.5' --header 'Sec-Fetch-Mode: navigate' --check-certificate=true --remote-time=true --show-console-readout=true -j 10 -x 10 -s 10 --out './TikTok video #7139980461132074283 [7139980461132074283].mp4.part' --auto-file-renaming=false -- https://sf16-ies-music-va.tiktokcdn.com/obj/ies-music-ttp-dup-us/7072971688513932078.mp3
[download] 100% of  164.53KiB in 00:00:00 at 2.42MiB/s
```



Discussion:

Resolving patch:
diff --git a/yt_dlp/extractor/tiktok.py b/yt_dlp/extractor/tiktok.py
--- a/yt_dlp/extractor/tiktok.py
+++ b/yt_dlp/extractor/tiktok.py
@@ -13,6 +13,7 @@
     LazyList,
     UnsupportedError,
     UserNotLive,
+    determine_ext,
     format_field,
     get_element_by_id,
     get_first,
@@ -204,6 +205,16 @@ def parse_url_key(url_key):
 
         known_resolutions = {}
 
+        def mp3_meta(url):
+            return {
+                'format_note': 'Music track',
+                'ext': 'mp3',
+                'acodec': 'mp3',
+                'vcodec': 'none',
+                'width': None,
+                'height': None,
+            } if determine_ext(url) == 'mp3' else {}
+
         def extract_addr(addr, add_meta={}):
             parsed_meta, res = parse_url_key(addr.get('url_key', ''))
             if res:
@@ -219,7 +230,8 @@ def extract_addr(addr, add_meta={}):
                 'source_preference': -2 if 'aweme/v1' in url else -1,  # Downloads from API might get blocked
                 **add_meta, **parsed_meta,
                 'format_note': join_nonempty(
-                    add_meta.get('format_note'), '(API)' if 'aweme/v1' in url else None, delim=' ')
+                    add_meta.get('format_note'), '(API)' if 'aweme/v1' in url else None, delim=' '),
+                **mp3_meta(url),
             } for url in addr.get('url_list') or []]
 
         # Hack: Add direct video links first to prioritize them when removing duplicate formats
@@ -553,6 +565,28 @@ class TikTokIE(TikTokBaseIE):
             'comment_count': int,
         },
         'skip': 'This video is unavailable',
+    }, {
+        # slideshow audio-only mp3 format
+        'url': 'https://www.tiktok.com/@_le_cannibale_/video/7139980461132074283',
+        'info_dict': {
+            'id': '7139980461132074283',
+            'ext': 'mp3',
+            'title': 'TikTok video #7139980461132074283',
+            'description': '',
+            'creator': 'Antaura',
+            'uploader': '_le_cannibale_',
+            'uploader_id': '6604511138619654149',
+            'uploader_url': 'https://www.tiktok.com/@MS4wLjABAAAAoShJqaw_5gvy48y3azFeFcT4jeyKWbB0VVYasOCt2tTLwjNFIaDcHAM4D-QGXFOP',
+            'artist': 'nathan !',
+            'track': 'grahamscott canon',
+            'upload_date': '20220905',
+            'timestamp': 1662406249,
+            'view_count': int,
+            'like_count': int,
+            'repost_count': int,
+            'comment_count': int,
+            'thumbnail': r're:^https://.+\.webp',
+        },
     }, {
         # Auto-captions available
         'url': 'https://www.tiktok.com/@hankgreen1/video/7047596209028074758',


Test patch: