Skip to content

Instantly share code, notes, and snippets.

@rlaphoenix
Created June 3, 2020 19:53
Show Gist options
  • Save rlaphoenix/bc97d596130a7970e0e5d89454c6f0ec to your computer and use it in GitHub Desktop.
Save rlaphoenix/bc97d596130a7970e0e5d89454c6f0ec to your computer and use it in GitHub Desktop.
Pack rar files into neat split volumes based on max volume size and max volume count.
# std
import os
import glob
import math
import subprocess
import binascii
import argparse
# Arguments
ArgParser = argparse.ArgumentParser()
ArgParser.add_argument("-i", "--input",
type=str, required=True,
help="Input file to be packed. If a directory is provided, each file in it will be packed seperately.")
ArgParser.add_argument("-s", "--size",
type=int, default=50000000, required=False,
help="Maximum size (in bytes) of each rar volume.")
ArgParser.add_argument("-m", "--max",
type=int, default=101, required=False,
help="Maxmimum splits, will incrememnt the size and re-calculate until its less than or equal to this number.")
args = ArgParser.parse_args()
# Create Packer Class
class Packer():
def __init__(self, file_paths):
for file_path in file_paths:
# pack and split the file with rar
split_count = self.split_file(file_path)
# get an extensionless and lower-case named path
base_path = os.path.join(
os.path.dirname(file_path),
os.path.splitext(os.path.basename(file_path))[0].lower()
)
# generate an sfv using the base_path and split_count data
self.generate_sfv(
file_paths=[
base_path + (".rar" if x == 0 else f".r{str(x - 1).zfill(2)}") for x in range(split_count)
],
save_path=f"{base_path}.sfv"
)
def split_file(self, file_path):
"""split file and return split count"""
# get initial split size
split_size = args.size
# get the file size of the input as bytes
file_size = os.path.getsize(file_path)
print(f"File Size: {file_size}")
# calculate split count for the initial SPLIT_SIZE
split_count = math.ceil(file_size / split_size)
while split_count > args.max:
split_size += args.size
print(f"Incrememnted split size as the calculated split count is greater than args.max: {split_size}")
split_count = math.ceil(file_size / split_size)
print(f"Split Count: {split_count}")
# use rar to archive it and split it
subprocess.run([
"rar",
"a",
"-m0", "-ma4", "-vn", f"-v{split_size}b", "-ep1",
f"{os.path.splitext(os.path.basename(file_path))[0].lower()}.rar", file_path
], cwd=os.path.dirname(file_path))
return split_count
def generate_sfv(self, file_paths, save_path):
"""generate sfv checksum file"""
with open(save_path, "wt") as SFV:
for file_path in file_paths:
with open(file_path, "rb") as f:
buf = f.read()
buf = (binascii.crc32(buf) & 0xFFFFFFFF)
buf = "%08X" % buf
SFV.write(f"{os.path.basename(file_path)} {buf}\n")
print(f"Generated CRC32 for {os.path.basename(file_path)}: {buf}")
# Compile path list and send it to the packer
file_paths = []
if os.path.isfile(args.input):
file_paths.append(args.input)
else:
file_paths += glob.glob(os.path.join(args.input, "*"))
packer = Packer(file_paths)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment