From fc39561b3239c186ced208284f90668472fa8727 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 8 Mar 2026 09:02:57 +0000 Subject: [PATCH] add m4a aliases m4b/m4r; closes #1317 --- README.md | 2 +- copyparty/__main__.py | 2 +- copyparty/mtag.py | 3 ++- copyparty/sutil.py | 2 +- copyparty/up2k.py | 2 +- copyparty/util.py | 2 +- copyparty/web/browser.js | 8 ++++---- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 637817aa..9bd04620 100644 --- a/README.md +++ b/README.md @@ -1168,7 +1168,7 @@ open the `[🎺]` media-player-settings tab to configure it, * `[flac]` converts `flac` and `wav` files into opus (if supported by browser) or mp3 * `[aac]` converts `aac` and `m4a` files into opus (if supported by browser) or mp3 * `[oth]` converts all other known formats into opus (if supported by browser) or mp3 - * `aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|m4a|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|ogg|okt|opus|ra|s3m|tak|tta|ulaw|wav|wma|wv|xm|xpk` + * `aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|m4a|m4b|m4r|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|ogg|okt|opus|ra|s3m|tak|tta|ulaw|wav|wma|wv|xm|xpk` * "transcode to": * `[opus]` produces an `opus` whenever transcoding is necessary (the best choice on Android and PCs) * `[awo]` is `opus` in a `weba` file, good for iPhones (iOS 17.5 and newer) but Apple is still fixing some state-confusion bugs as of iOS 18.2.1 diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 0f78f99f..955c5830 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1735,7 +1735,7 @@ def add_thumbnail(ap): ap2.add_argument("--th-r-raw", metavar="T,T", type=u, default="3fr,arw,cr2,cr3,crw,dcr,dng,erf,k25,kdc,mdc,mef,mos,mrw,nef,nrw,orf,pef,raf,raw,sr2,srf,srw,x3f", help="image formats to decode using rawpy") ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,epub,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg") ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg") - ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,oga,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg") + ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,m4b,m4r,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,oga,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg") ap2.add_argument("--th-spec-cnv", metavar="T", type=u, default="it,itgz,itxz,itz,mdgz,mdxz,mdz,mo3,mod,s3m,s3gz,s3xz,s3z,xm,xmgz,xmxz,xmz,xpk", help="audio formats which provoke https://trac.ffmpeg.org/ticket/10797 (huge ram usage for s3xmodit spectrograms)") ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz, epub=jpg.epub", help="audio/image formats to decompress before passing to ffmpeg") diff --git a/copyparty/mtag.py b/copyparty/mtag.py index 7a1d7a62..ad56eec6 100644 --- a/copyparty/mtag.py +++ b/copyparty/mtag.py @@ -68,6 +68,7 @@ CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif jxl".split()) CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b") FMT_AU = set("mp3 ogg flac wav".split()) +M4A = set("aac m4a m4b m4r".split()) class MParser(object): @@ -259,7 +260,7 @@ def parse_ffprobe( md: dict[str, list[Any]] = {} # raw tags is_audio = fmt.get("format_name") in FMT_AU - if fmt.get("filename", "").split(".")[-1].lower() in ["m4a", "aac"]: + if fmt.get("filename", "").split(".")[-1].lower() in M4A: is_audio = True # if audio file, ensure audio stream appears first diff --git a/copyparty/sutil.py b/copyparty/sutil.py index 454fc968..6cc57f6f 100644 --- a/copyparty/sutil.py +++ b/copyparty/sutil.py @@ -18,7 +18,7 @@ if True: # pylint: disable=using-constant-test from .util import NamedLogger -TAR_NO_OPUS = set("aac|m4a|mp3|oga|ogg|opus|wma".split("|")) +TAR_NO_OPUS = set("aac|m4a|m4b|m4r|mp3|oga|ogg|opus|wma".split("|")) class StreamArc(object): diff --git a/copyparty/up2k.py b/copyparty/up2k.py index 4681c223..3fa7f092 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -102,7 +102,7 @@ ICV_EXTS = set(zsg.split(",")) zsg = "3gp,asf,av1,avc,avi,flv,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,vob,webm,wmv" VCV_EXTS = set(zsg.split(",")) -zsg = "aif,aiff,alac,ape,flac,m4a,mp3,oga,ogg,opus,tak,tta,wav,wma,wv,cbz,epub" +zsg = "aif,aiff,alac,ape,flac,m4a,m4b,m4r,mp3,oga,ogg,opus,tak,tta,wav,wma,wv,cbz,epub" ACV_EXTS = set(zsg.split(",")) zsg = "nohash noidx xdev xvol" diff --git a/copyparty/util.py b/copyparty/util.py index 13113199..5a627171 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -501,7 +501,7 @@ image heics=heic-sequence heifs=heif-sequence hdr=vnd.radiance svg=svg+xml image arw=x-sony-arw cr2=x-canon-cr2 crw=x-canon-crw dcr=x-kodak-dcr dng=x-adobe-dng erf=x-epson-erf image k25=x-kodak-k25 kdc=x-kodak-kdc mrw=x-minolta-mrw nef=x-nikon-nef orf=x-olympus-orf image pef=x-pentax-pef raf=x-fuji-raf raw=x-panasonic-raw sr2=x-sony-sr2 srf=x-sony-srf x3f=x-sigma-x3f -audio caf=x-caf mp3=mpeg m4a=mp4 mid=midi mpc=musepack aif=aiff au=basic qcp=qcelp +audio caf=x-caf mp3=mpeg m4a=mp4 m4b=mp4 m4r=mp4 mid=midi mpc=musepack aif=aiff au=basic qcp=qcelp video mkv=x-matroska mov=quicktime avi=x-msvideo m4v=x-m4v ts=mp2t video asf=x-ms-asf flv=x-flv 3gp=3gpp 3g2=3gpp2 rmvb=vnd.rn-realmedia-vbr font ttc=collection diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index c114a7be..2552bfa8 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -1439,7 +1439,7 @@ var mpl = (function () { c = false; else if (/\.(wav|flac)$/i.exec(cs)) c = r.ac_flac; - else if (/\.(aac|m4a)$/i.exec(cs)) + else if (/\.(aac|m4[abr])$/i.exec(cs)) c = r.ac_aac; else if (/\.(oga|ogg|opus)$/i.exec(cs) && (!can_ogg || mpl.ac2 == 'mp3')) c = true; @@ -1636,9 +1636,9 @@ mpl.init_ac2(); var re_m3u = /\.(m3u8?)$/i; -var re_au_native = (can_ogg || have_acode) ? /\.(aac|flac|m4a|mp3|oga|ogg|opus|wav)$/i : /\.(aac|flac|m4a|mp3|wav)$/i, +var re_au_native = (can_ogg || have_acode) ? /\.(aac|flac|m4[abr]|mp3|oga|ogg|opus|wav)$/i : /\.(aac|flac|m4[abr]|mp3|wav)$/i, re_au_vid = /\.(3gp|asf|avi|flv|m4v|mkv|mov|mp4|mpeg|mpeg2|mpegts|mpg|mpg2|nut|ogm|ogv|rm|ts|vob|webm|wmv)$/i, - re_au_all = /\.(aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|itgz|itxz|itz|m4a|mdgz|mdxz|mdz|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|oga|ogg|okt|opus|ra|s3m|s3gz|s3xz|s3z|tak|tta|ulaw|wav|wma|wv|xm|xmgz|xmxz|xmz|xpk|3gp|asf|avi|flv|m4v|mkv|mov|mp4|mpeg|mpeg2|mpegts|mpg|mpg2|nut|ogm|ogv|rm|ts|vob|webm|wmv)$/i; + re_au_all = /\.(aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|it|itgz|itxz|itz|m4[abr]|mdgz|mdxz|mdz|mo3|mod|mp2|mp3|mpc|mptm|mt2|mulaw|oga|ogg|okt|opus|ra|s3m|s3gz|s3xz|s3z|tak|tta|ulaw|wav|wma|wv|xm|xmgz|xmxz|xmz|xpk|3gp|asf|avi|flv|m4v|mkv|mov|mp4|mpeg|mpeg2|mpegts|mpg|mpg2|nut|ogm|ogv|rm|ts|vob|webm|wmv)$/i; // extract songs + add play column @@ -3360,7 +3360,7 @@ function evau_error(e) { break; case eplaya.error.MEDIA_ERR_SRC_NOT_SUPPORTED: err = L.mm_esupp; - if (/\.(aac|m4a)(\?|$)/i.exec(eplaya.rsrc) && !mpl.ac_aac) { + if (/\.(aac|m4[abr])(\?|$)/i.exec(eplaya.rsrc) && !mpl.ac_aac) { try { ebi('ac_aac').click(); QS('a.play.act').click();