Author Topic: Adds support for reading files from .zip, .rar, .7zip archives  (Read 7349 times)

35kappaON

  • Newbie
  • *
  • Posts: 1
hi guys

I have been using with great pleasure for a few months now musibee

I wanted to know if there was a way to open the rar, zip and 7zip files?

I'll explain myself better:

I'm talking about the integrated option for both foobar and xmplay.
basically if I have an archive containing music files I would like to open it with musicbee directly by clicking with the right button (so that all the files in the archive are added all style playlists on musicbee)

thanks

whocares0101

  • Newbie
  • *
  • Posts: 8
I would also like to request support to read from ZIP files, only reading no writing so the files don't change.
This way I can organize my files better and put one album into a single zip file.
I only need zip file support, rar/7z especially with solid option wouldn't be any good for this.
Memory usage is not a concern even with flac files, extracting a full track or even the full album to memory should not be an issue with the amount of memory PCs have nowadays.




angang

  • Newbie
  • *
  • Posts: 3
+1 I agree with whocares0101. Foobar support it and usage of full album is quick and  easy. Jyst like cbz for jpg, it is not about compression but to have just one file well organized and quickly transferable.

BoringName

  • Full Member
  • ***
  • Posts: 201
+1 I agree with whocares0101. Foobar support it and usage of full album is quick and  easy. Jyst like cbz for jpg, it is not about compression but to have just one file well organized and quickly transferable.

Unless you are dealing in WAV, music files are already compressed. Not sure why anyone would want to deal with the overhead of handling zips.

The "well organized and quickly transferable" aspect can be achieved by using folders.

fiso64

  • Jr. Member
  • **
  • Posts: 33
I wanted zip file support as well, so here's a workaround I use. Maybe somebody will find it useful.
Create a python script anywhere you like with the following contents:
Code
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.
Last Edit: December 07, 2023, 05:29:47 PM by fiso64