I have been working on a script that will check through every subdirectory in a directory and match files using regex and then use different commands based on what kind of a file it is.
So what i have finished is the use of different commands based on regex matching. Right now it checks for either a .zip file, .rar file or .r00 file and uses different commands for each match. However i need help iterating through every directory and first check if there is a .mkv file in there, then it should just pass that directory and jump to the next, but if there is a match it should run the command and then when it's finished continue to the next directory.
import os
import re
rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/folder"
for root, dirs, files in os.walk(path):
for file in files:
res = re.match(rx, file)
if res:
if res.group(1):
print("Unzipping ",file, "...")
os.system("unzip " + root + "/" + file + " -d " + root)
elif res.group(2):
os.system("unrar e " + root + "/" + file + " " + root)
if res.group(3):
print("Unraring ",file, "...")
os.system("unrar e " + root + "/" + file + " " + root)
EDIT:
Here is the code i have now:
import os
import re
from subprocess import check_call
from os.path import join
rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/Torrents/completed/test"
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
found_r = False
for file in files:
pth = join(root, file)
try:
if file.endswith(".zip"):
print("Unzipping ",file, "...")
check_call(["unzip", pth, "-d", root])
found_zip = True
elif not found_r and file.endswith((".rar",".r00")):
check_call(["unrar","e","-o-", pth, root,])
found_r = True
break
except ValueError:
print ("Oops! That did not work")
This script works mostly fine but sometimes i seem to run into issues when there are Subs in the folder, here is an error i message i get when i run the script:
$ python unrarscript.py
UNRAR 5.30 beta 2 freeware Copyright (c) 1993-2015 Alexander Roshal
Extracting from /mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs/the.conjuring.2013.1080p.bluray.x264-alliance.subs.rar
No files to extract
Traceback (most recent call last):
File "unrarscript.py", line 19, in <module>
check_call(["unrar","e","-o-", pth, root])
File "/usr/lib/python2.7/subprocess.py", line 541, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['unrar', 'e', '-o-', '/mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs/the.conjuring.2013.1080p.bluray.x264-alliance.subs.rar', '/mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs']' returned non-zero exit status 10
I cannot really understand what is wrong about the code, so what im hoping is that some of you are willing to help me.
Just use any to see if any files end in .mkv before going any further, you can also simplify to an if/else as you do the same thing for the last two matches. Also using subprocess.check_call would be a better approach:
import os
import re
from subprocess import check_call
from os.path import join
rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/folder"
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
for file in files:
res = re.match(rx, file)
if res:
# use os.path.join
pth = join(root, file)
# it can only be res.group(1) or one of the other two so we only need if/else.
if res.group(1):
print("Unzipping ",file, "...")
check_call(["unzip" , pth, "-d", root])
else:
check_call(["unrar","e", pth, root])
You could also forget the rex and just use an if/elif and str.endswith:
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
for file in files:
pth = join(root, file)
if file.endswith("zip"):
print("Unzipping ",file, "...")
check_call(["unzip" , pth, "-d", root])
elif file.endswith((".rar",".r00")):
check_call(["unrar","e", pth, root])
if you really care about not repeating steps and speed, you can filter as you iterate you can collect by extension by slicing as you do the check for the .mkv and use for/else logic:
good = {"rar", "zip", "r00"}
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
tmp = {"rar": [], "zip": []}
for file in files:
ext = file[-4:]
if ext == ".mkv":
break
elif ext in good:
tmp[ext].append(join(root, file))
else:
for p in tmp.get(".zip", []):
print("Unzipping ", p, "...")
check_call(["unzip", p, "-d", root])
for p in tmp.get(".rar", []):
check_call(["unrar", "e", p, root])
That will short circuit on any match for a .mkv or else only iterate over any matches for .rar or .r00 but unless you really care about efficiency I would use the second logic.
To avoid overwriting you can unrar/unzip each to a new subdirectory using a counter to help create a new dir name:
from itertools import count
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
counter = count()
for file in files:
pth = join(root, file)
if file.endswith("zip"):
p = join(root, "sub_{}".format(next(counter)))
os.mkdir(p)
print("Unzipping ",file, "...")
check_call(["unzip" , pth, "-d", p])
elif file.endswith((".rar",".r00")):
p = join(root, "sub_{}".format(next(counter)))
os.mkdir(p)
check_call(["unrar","e", pth, p])
Each will be unpacked into a new directory under root i.e root_path/sub_1 etc..
You probably would have been better adding an example to your question but if the real problem is you only want one of .rar or .r00 then you can set a flag when you find any match for the .rar or .r00 and only unpack if the flag is not set:
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
found_r = False
for file in files:
pth = join(root, file)
if file.endswith("zip"):
print("Unzipping ",file, "...")
check_call(["unzip", pth, "-d", root])
found_zip = True
elif not found_r and file.endswith((".rar",".r00"))
check_call(["unrar","e", pth, root])
found_r = True
If there is also only one zip you can set two flags and leave the loop where both are set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With