Skip to content

Instantly share code, notes, and snippets.

@tos-kamiya
Created May 17, 2025 20:10
Show Gist options
  • Save tos-kamiya/2031496d0bedf179227df11f8e6d2c17 to your computer and use it in GitHub Desktop.
Save tos-kamiya/2031496d0bedf179227df11f8e6d2c17 to your computer and use it in GitHub Desktop.
A lightweight clone of unar for Windows: utilizes BusyBox to handle various archive formats, with optional support for 7-Zip and WinRAR if installed.
#!/usr/bin/env python3
import sys
import os
import subprocess
import zipfile
import shutil
import argparse
import time
def is_tool_available(tool_name):
"""Check if a tool is available in the system PATH."""
from shutil import which
return which(tool_name) is not None
def extract_with_7zip(file_path, dest_dir):
try:
subprocess.run(['7z', 'x', file_path, f'-o{dest_dir}', '-y'], check=True)
print(f"Extracted archive with 7-Zip: {file_path}")
return True
except (subprocess.CalledProcessError, FileNotFoundError):
return False
def extract_with_winrar(file_path, dest_dir):
try:
subprocess.run(['unrar', 'x', '-y', file_path, dest_dir], check=True)
print(f"Extracted archive with WinRAR: {file_path}")
return True
except (subprocess.CalledProcessError, FileNotFoundError):
return False
def extract_zip_with_python(file_path, dest_dir, force_dir, copy_time):
try:
with zipfile.ZipFile(file_path, 'r') as zip_ref:
names = zip_ref.namelist()
top_level = set(name.split('/')[0] for name in names if '/' in name)
if force_dir or len(top_level) != 1:
base_name = os.path.splitext(os.path.basename(file_path))[0]
dest_dir = os.path.join(dest_dir, base_name)
os.makedirs(dest_dir, exist_ok=True)
zip_ref.extractall(dest_dir)
print(f"Extracted ZIP archive: {file_path}")
if copy_time:
mod_time = os.path.getmtime(file_path)
os.utime(dest_dir, (mod_time, mod_time))
except zipfile.BadZipFile:
print(f"Invalid ZIP file: {file_path}")
except Exception as e:
print(f"Error extracting ZIP file: {e}")
def extract_with_busybox(file_path, dest_dir):
try:
ext = file_path.lower()
if ext.endswith(('.tar.gz', '.tgz')):
cmd = ['busybox', 'tar', 'xvzf', file_path]
elif ext.endswith(('.tar.bz2', '.tbz2')):
cmd = ['busybox', 'tar', 'xvjf', file_path]
elif ext.endswith('.tar'):
cmd = ['busybox', 'tar', 'xvf', file_path]
elif ext.endswith('.gz'):
cmd = ['busybox', 'gunzip', '-k', file_path]
elif ext.endswith('.bz2'):
cmd = ['busybox', 'bunzip2', '-k', file_path]
else:
print(f"Unsupported file format: {file_path}")
return False
subprocess.run(cmd, check=True, cwd=dest_dir)
print(f"Extracted archive with BusyBox: {file_path}")
return True
except (subprocess.CalledProcessError, FileNotFoundError) as e:
print(f"Error extracting archive with BusyBox: {e}")
return False
def main():
parser = argparse.ArgumentParser(description='bb_unar: Archive extraction tool')
parser.add_argument('archive', help='Archive file to extract')
parser.add_argument('-o', '--output-directory', default='.', help='Directory to extract files to (default: current directory). Use "-" for stdout (not implemented).')
parser.add_argument('-d', '--force-directory', action='store_true', help='Always create a containing directory for the extracted contents')
parser.add_argument('-t', '--copy-time', action='store_true', help='Copy the archive file\'s modification time to the containing directory')
args = parser.parse_args()
file_path = args.archive
dest_dir = args.output_directory
force_dir = args.force_directory
copy_time = args.copy_time
if not os.path.isfile(file_path):
print(f"File not found: {file_path}")
sys.exit(1)
if dest_dir == '-':
print("Output to stdout is not implemented.")
sys.exit(1)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir, exist_ok=True)
file_lower = file_path.lower()
if file_lower.endswith('.zip'):
if is_tool_available('7z'):
if not extract_with_7zip(file_path, dest_dir):
print("7-Zip extraction failed.")
sys.exit(1)
else:
extract_zip_with_python(file_path, dest_dir, force_dir, copy_time)
elif file_lower.endswith(('.7z', '.rar')):
if is_tool_available('7z'):
if not extract_with_7zip(file_path, dest_dir):
print("7-Zip extraction failed.")
sys.exit(1)
elif is_tool_available('unrar'):
if not extract_with_winrar(file_path, dest_dir):
print("WinRAR extraction failed.")
sys.exit(1)
else:
print("Neither 7-Zip nor WinRAR is available. Please install one of them.")
sys.exit(1)
else:
if not extract_with_busybox(file_path, dest_dir):
sys.exit(1)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment