From 41da9fdadd21730329def9b91c83617c95ab7036 Mon Sep 17 00:00:00 2001 From: Joel Goguen Date: Sat, 15 Jun 2024 13:36:04 -0400 Subject: [PATCH] Add separate quality entry for iOS compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The iOS-compatible video may not be the best quality. Add a separate quality option to accommodate people who want the best available versus the best compatible with iOS's strict requirements. Testing with https://www.youtube.com/watch?v=YiRMs5ZhcH4 where the best quality video is 2160p and not iOS-compatible. With best quality, the VP9 video format is used (better quality but not iOS-compatible): ``` % ffprobe -hide_banner Who\ Can\ Find\ the\ Weirdest\ PC\ Parts\ on\ AliExpress?.mp4 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Who Can Find the Weirdest PC Parts on AliExpress?.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2mp41 encoder : Lavf60.16.100 Duration: 00:19:02.72, start: 0.000000, bitrate: 10941 kb/s Stream #0:0[0x1](und): Video: vp9 (Profile 0) (vp09 / 0x39307076), yuv420p(tv, bt709), 3840x1920, 10805 kb/s, 29.97 fps, 29.97 tbr, 16k tbn (default) Metadata: handler_name : ISO Media file produced by Google Inc. Created on: 06/15/2024. vendor_id : [0][0][0][0] Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default) Metadata: handler_name : ISO Media file produced by Google Inc. vendor_id : [0][0][0][0] ``` With "Best (iOS)" quality, the H264 video (lower quality but iOS-compatible) is used: ``` % ffprobe -hide_banner Who\ Can\ Find\ the\ Weirdest\ PC\ Parts\ on\ AliExpress?.mp4 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Who Can Find the Weirdest PC Parts on AliExpress?.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf60.16.100 Duration: 00:19:02.72, start: 0.000000, bitrate: 1846 kb/s Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x960 [SAR 1:1 DAR 2:1], 1710 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default) Metadata: handler_name : ISO Media file produced by Google Inc. vendor_id : [0][0][0][0] Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default) Metadata: handler_name : ISO Media file produced by Google Inc. vendor_id : [0][0][0][0] ``` Included a README note about the new quality option. --- README.md | 4 ++++ app/dl_formats.py | 18 ++++++++++-------- ui/src/app/formats.ts | 17 +++++------------ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 10cbe89..663de90 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,10 @@ __Firefox:__ contributed by [nanocortex](https://github.com/nanocortex). You can [rithask](https://github.com/rithask) has created an iOS shortcut to send the URL to MeTube from Safari. Initially, you'll need to enter the server address and port, but after that, it will be saved and you can just run the shortcut from the share menu in Safari. The address should include the protocol (http/https) and the port, if it's not the default 80/443. For example: `https://metube.example.com` or `http://192.168.1.1:8081`. The shortcut can be found [here](https://www.icloud.com/shortcuts/f1548df15b734418a77a709103bc1dd5). +## iOS Compatibility + +iOS has strict requirements for video files, requiring h264 or h265 video codec and aac audio codec in MP4 container. This can sometimes be a lower quality than the best quality available. To accommodate iOS requirements, when downloading a MP4 format you can choose "Best (iOS)" to get the best quality formats as compatible as possible with iOS requirements. + ## Bookmarklet [kushfest](https://github.com/kushfest) has created a Chrome bookmarklet for sending the currently open webpage to MeTube. Please note that if you're on an HTTPS page, your MeTube instance must be behind an HTTPS reverse proxy (see below) for the bookmarklet to work. diff --git a/app/dl_formats.py b/app/dl_formats.py index 2ae0968..8abd038 100644 --- a/app/dl_formats.py +++ b/app/dl_formats.py @@ -35,16 +35,18 @@ def get_format(format: str, quality: str) -> str: return "bestaudio/best" # video {res} {vfmt} + audio {afmt} {res} {vfmt} vfmt, afmt = ("[ext=mp4]", "[ext=m4a]") if format == "mp4" else ("", "") - vres = f"[height<={quality}]" if quality != "best" else "" + vres = f"[height<={quality}]" if quality not in ("best", "best_ios") else "" vcombo = vres + vfmt - # iOS has strict requirements for video files, requiring h264 or h265 - # video codec and aac audio codec in MP4 container. This format string - # attempts to get the fully compatible formats first, then the h264/h265 - # video codec with any M4A audio codec (because audio is faster to - # convert if needed), and falls back to getting the best available MP4 - # file. - return f"bestvideo[vcodec~='^((he|a)vc|h26[45])']{vres}+bestaudio[acodec=aac]/bestvideo[vcodec~='^((he|a)vc|h26[45])']{vres}+bestaudio{afmt}/bestvideo{vcombo}+bestaudio{afmt}/best{vcombo}" + if quality == "best_ios": + # iOS has strict requirements for video files, requiring h264 or h265 + # video codec and aac audio codec in MP4 container. This format string + # attempts to get the fully compatible formats first, then the h264/h265 + # video codec with any M4A audio codec (because audio is faster to + # convert if needed), and falls back to getting the best available MP4 + # file. + return f"bestvideo[vcodec~='^((he|a)vc|h26[45])']{vres}+bestaudio[acodec=aac]/bestvideo[vcodec~='^((he|a)vc|h26[45])']{vres}+bestaudio{afmt}/bestvideo{vcombo}+bestaudio{afmt}/best{vcombo}" + return f"bestvideo{vcombo}+bestaudio{afmt}/best{vcombo}" raise Exception(f"Unkown format {format}") diff --git a/ui/src/app/formats.ts b/ui/src/app/formats.ts index 315c37c..b8b1d28 100644 --- a/ui/src/app/formats.ts +++ b/ui/src/app/formats.ts @@ -27,6 +27,7 @@ export const Formats: Format[] = [ text: 'MP4', qualities: [ { id: 'best', text: 'Best' }, + { id: 'best_ios', text: 'Best (iOS)' }, { id: '1440', text: '1440p' }, { id: '1080', text: '1080p' }, { id: '720', text: '720p' }, @@ -55,29 +56,21 @@ export const Formats: Format[] = [ { id: 'opus', text: 'OPUS', - qualities: [ - { id: 'best', text: 'Best' }, - ], + qualities: [{ id: 'best', text: 'Best' }], }, { id: 'wav', text: 'WAV', - qualities: [ - { id: 'best', text: 'Best' }, - ], + qualities: [{ id: 'best', text: 'Best' }], }, { id: 'flac', text: 'FLAC', - qualities: [ - { id: 'best', text: 'Best' }, - ], + qualities: [{ id: 'best', text: 'Best' }], }, { id: 'thumbnail', text: 'Thumbnail', - qualities: [ - { id: 'best', text: 'Best' } - ], + qualities: [{ id: 'best', text: 'Best' }], }, ];