I wanted zip file support as well, so here's a workaround I use. Maybe somebody will find it useful.
import argparse
import os
import subprocess
import sys
import zipfile
from time import sleep
musicbee_exe = r'C:\Programs\MusicBee\MusicBee.exe'
extract_parent_dir = os.path.join(os.path.expanduser("~"), 'Temp')
def show_error_dialog(exc_type, exc_value, exc_traceback):
import tkinter as tk
from tkinter import messagebox
import traceback
filename = exc_traceback.tb_frame.f_code.co_filename
error_msg = f"{exc_type.__name__}: {exc_value}\n\n"
error_msg += "\n".join(traceback.format_tb(exc_traceback))
root = tk.Tk()
root.withdraw()
messagebox.showerror(filename, error_msg)
if sys.executable.endswith('pythonw.exe'):
sys.excepthook = show_error_dialog
parser = argparse.ArgumentParser()
parser.add_argument("zip_file", help="Path to the zip file")
parser.add_argument("-t", "--track-number", help="Queue files in order of the track number in their tags (requires pytaglib)", action="store_true")
parser.add_argument("-a", "--auto", help="Enable --track-number automatically if filenames don't start with track number", action="store_true")
parser.add_argument("-i", "--ignore-m3u", help="Do not use any m3u files within the archive", action="store_true")
parser.add_argument("-o", "--option", default='QueueLast', help="MusicBee option, see https://musicbee.fandom.com/wiki/Command_Line_Parameters.", action="store_true")
args = parser.parse_args()
archive_file = os.path.abspath(args.zip_file)
args.option = '/' + args.option.lstrip('/')
if not zipfile.is_zipfile(archive_file):
raise ValueError(f'\"{archive_file}\" is not a zip archive')
archive_name = os.path.splitext(os.path.basename(archive_file))[0]
temp_dir = os.path.join(extract_parent_dir, archive_name)
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)
with zipfile.ZipFile(archive_file, "r") as zip_file:
names = [n for n in zip_file.namelist() if not n.startswith('__MACOSX')]
subdirs = [os.path.dirname(n) for n in names if '/' in n]
root_dirs = {n.split('/')[0] for n in names if '/' in n}
if len(root_dirs) == 1 and len(subdirs) == len(names):
root_dir = list(root_dirs)[0] + '/'
for zip_info in zip_file.infolist():
if zip_info.is_dir() or zip_info.filename.startswith('__MACOSX'):
continue
zip_info.filename = zip_info.filename.replace(root_dir, '', 1)
zip_file.extract(zip_info, temp_dir)
else:
for zip_info in zip_file.infolist():
if not zip_info.filename.startswith('__MACOSX'):
zip_file.extract(zip_info, temp_dir)
temp_m3u_name = '_archive_temp_playlist.m3u8'
m3u_file = None
if not args.ignore_m3u:
is_m3u = lambda file: (file.endswith(".m3u") or file.endswith(".m3u8")) and file != temp_m3u_name
m3u_file = next((os.path.join(r, f) for r, d, fnames in os.walk(temp_dir) for f in fnames if is_m3u(f)), None)
if m3u_file:
musicbee_args = [musicbee_exe, args.option, m3u_file]
subprocess.Popen(musicbee_args)
sys.exit()
music_exts_tags = [".mp3", ".flac", ".ogg", ".aac", ".wma", ".m4a", ".alac", ".ape", ".opus", ".mpc"]
music_exts_notags = [".wav", ".wave", ".mod", ".mid"]
music_exts = music_exts_tags + music_exts_notags
has_ext = lambda file, exts: os.path.splitext(file)[1].lower() in exts
if args.auto:
need_track_num = lambda file: has_ext(file, music_exts_tags) and not file.lstrip()[0].isdigit()
args.track_number = any(need_track_num(f) for r, d, fnames in os.walk(temp_dir) for f in fnames)
if args.track_number:
import taglib
files = []
for root, dirs, fnames in os.walk(temp_dir):
for file in fnames:
try:
f = taglib.File(os.path.join(root, file))
num = int(f.tags['TRACKNUMBER'][0].split('/')[0])
files.append((os.path.join(root, file), num))
except:
if has_ext(file, music_exts):
files.append((os.path.join(root, file), 9999999))
files.sort(key=lambda f: f[1])
# Need to create m3u as queueing files one-by-one causes MB to automatically sort by name
temp_m3u = os.path.join(temp_dir, temp_m3u_name)
try:
with open(temp_m3u, 'w', encoding="utf-8") as playlist_file:
for f in files:
playlist_file.write(os.path.basename(f[0]) + '\n')
musicbee_args = [musicbee_exe, args.option, temp_m3u]
subprocess.Popen(musicbee_args)
finally:
sleep(10)
try: os.remove(temp_m3u)
except: pass
else:
musicbee_args = [musicbee_exe, args.option, temp_dir]
subprocess.Popen(musicbee_args)
Then, create a shortcut in "C:\Users\username\AppData\Roaming\Microsoft\Windows\SendTo". Name it "MusicBee Queue Archive". In the properties, set the target to "python.exe {full path to script}". This is assuming your python.exe is added to PATH. You can also use pythonw.exe instead to hide the window.
It should now be available in file explorer as a context menu entry under "Send To". Using it on an archive will extract it to "C:\Users\username\temp\{name}" and queue last the contents in MusicBee.