Author Topic: Adds support for reading files from .zip, .rar, .7zip archives  (Read 7437 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: 209
+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: 34
I wanted zip file support as well, so here's a workaround I use. Maybe somebody will find it useful.
I made a python script that will decompress zips (and rars, if rarfile is installed) and then queue the result in musicbee. For easy access I have also added a context menu entry that can be used when right clicking zips to unzip & queue it.

Create a python script anywhere you like with the following contents:
Code
import argparse
import os
import subprocess
import sys
from zipfile 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)

def extract_archive(archive_file, out_dir, skip_single_parent=True):
    if archive_file.lower().endswith('.rar'):
        from rarfile import RarFile
        ArchiveFile = RarFile
        skip_single_parent = False
    else: ArchiveFile = ZipFile      

    with ArchiveFile(archive_file, "r") as archive_file:
        names = [n for n in archive_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 skip_single_parent and len(root_dirs) == 1 and len(subdirs) == len(names):
            root_dir = list(root_dirs)[0] + '/'
            for archive_info in archive_file.infolist():
                if archive_info.is_dir() or archive_info.filename.startswith('__MACOSX'):
                    continue
                archive_info.filename = archive_info.filename.replace(root_dir, '', 1)
                archive_file.extract(archive_info, out_dir)
        else:
            for archive_info in archive_file.infolist():
                if not archive_info.filename.startswith('__MACOSX'):
                    archive_file.extract(archive_info, out_dir)

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('/')
archive_name = os.path.splitext(os.path.basename(archive_file))[0]
temp_dir = os.path.join(extract_parent_dir, archive_name)

os.makedirs(temp_dir, exist_ok=True)
extract_archive(archive_file, temp_dir, skip_single_parent=True)

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

if args.auto:
    need_track_num = lambda file: file.lower().endswith(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))
                key = f.tags.get('DISCNUMBER',['999'])[0] + '-' + f.tags.get('TRACKNUMBER',['999'])[0] + '-' + file
                files.append((os.path.join(root, file), key))
            except:
                if file.lower().endswith(music_exts):
                    files.append((os.path.join(root, file), f'999-999-{file}'))

    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.relpath(f[0], temp_dir) + '\n')
        
        musicbee_args = [musicbee_exe, args.option, temp_m3u]
        subprocess.Popen(musicbee_args)
    finally:
        sleep(10) # waiting before delete in case musicbee hasn't started yet
        try: os.remove(temp_m3u)
        except: pass
else:
    musicbee_args = [musicbee_exe, args.option, temp_dir]
    subprocess.Popen(musicbee_args)

Configure the `musicbee_exe` and `extract_parent_dir` variables at the start. Then, create a shortcut in "C:\Users\username\AppData\Roaming\Microsoft\Windows\SendTo". Name it something like "MusicBee Queue Archive".  In the file 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 command window. Also, sometimes zipped songs don't start with the track number (e.g zips from bandcamp), leading to incorrect order of queued files. Add ` -a` add the end of the target path in the properties if that's an issue. This option will sort the tracks by their track number before queueing them, but requires the pytaglib module.

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: April 04, 2024, 11:05:22 AM by fiso64