Last active
March 13, 2018 07:48
-
-
Save Laharah/da1b4b51d68987fca8a1c70617b02344 to your computer and use it in GitHub Desktop.
Seperate active and non-active files from a directory according to uTorrent paths
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# The contents of this file are subject to the Python Software Foundation | |
# License Version 2.3 (the License). You may not copy or use this file, in | |
# either source code or executable form, except in compliance with the License. | |
# You may obtain a copy of the License at http://www.python.org/license. | |
# | |
# Software distributed under the License is distributed on an AS IS basis, | |
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
# for the specific language governing rights and limitations under the | |
# License. | |
from pathlib import Path | |
import os | |
import sys | |
import shutil | |
def get_default_resume_path(): | |
""" | |
Checks the various common paths resume.dat may reside and returns a path to | |
it if it's found. | |
""" | |
print('Getting resume.dat path...') | |
app_datas = [] | |
user_home = os.path.expanduser('~') | |
if os.getenv('APPDATA'): | |
app_datas.append(os.getenv('APPDATA')) | |
app_datas.append(os.path.join(user_home, 'Library', 'Application Support')) | |
app_datas.append('/opt') | |
app_datas.append(user_home) | |
for app_data in app_datas: | |
resume_path = os.path.join(app_data, 'uTorrent', 'resume.dat') | |
if not os.path.exists(resume_path) or not os.path.isfile(resume_path): | |
print('no resume.dat found at {0}...'.format(app_data)) | |
else: | |
print('resume.dat found at {0}'.format(resume_path)) | |
return resume_path | |
print('no resume.dat could be found') | |
return None | |
def get_active_paths_from_resume_dat(path): | |
"""given the path to resume.dat, decode and return 'path' items""" | |
if not os.path.exists(path): | |
er = ("{0} could not be found. Please check the file exists and " | |
"that you have permission to read it.".format(path)) | |
print(er) | |
raise AssertionError(er) | |
if not os.path.isfile(path): | |
er = '{0} is a folder, "Path to resume.dat" must be a file.'.format(path) | |
print(er) | |
raise AssertionError(er) | |
try: | |
with open(path, 'rb') as f: | |
raw = f.read() | |
except (IOError, OSError) as e: | |
print('Could not open {0}. Reason{1}'.format(path, e)) | |
raise | |
data = bdecode(raw) | |
paths = set() | |
for info in data.values(): | |
try: | |
path = Path(info[b'path'].decode('utf8')) | |
except UnicodeDecodeError: | |
print("Could not decode file path: {}".format(info[b'path'])) | |
continue | |
except TypeError: | |
continue | |
if not path.exists(): | |
print("{} is listed as a uTorrent path, but it does not exist.".format(path)) | |
continue | |
else: | |
paths.add(path.absolute()) | |
return paths | |
def get_unref_items(target, ut_paths): | |
"return a set of paths from target that are not referenced by uTorrent" | |
target = Path(target) | |
if not target.exists(): | |
raise AssertionError('{} does not exsist or cannot be opened'.format(target)) | |
all_items = set(p.absolute() for p in target.iterdir()) | |
unref = all_items - ut_paths | |
return unref | |
####### | |
# bencode | |
####### | |
def decode_int(x, f): | |
f += 1 | |
newf = x.index(b'e', f) | |
n = int(x[f:newf]) | |
if x[f] == '-': | |
if x[f + 1] == '0': | |
raise ValueError | |
elif x[f] == '0' and newf != f + 1: | |
raise ValueError | |
return (n, newf + 1) | |
def decode_string(x, f): | |
colon = x.index(b':', f) | |
n = int(x[f:colon]) | |
if x[f] == b'0' and colon != f + 1: | |
raise ValueError | |
colon += 1 | |
return (x[colon:colon + n], colon + n) | |
def decode_list(x, f): | |
r, f = [], f + 1 | |
while x[f] != ord('e'): | |
v, f = decode_func[x[f]](x, f) | |
r.append(v) | |
return (r, f + 1) | |
def decode_dict(x, f): | |
r, f = {}, f + 1 | |
while x[f] != ord('e'): | |
k, f = decode_string(x, f) | |
r[k], f = decode_func[x[f]](x, f) | |
return (r, f + 1) | |
decode_func = {} | |
decode_func[ord('l')] = decode_list | |
decode_func[ord('d')] = decode_dict | |
decode_func[ord('i')] = decode_int | |
decode_func[ord('0')] = decode_string | |
decode_func[ord('1')] = decode_string | |
decode_func[ord('2')] = decode_string | |
decode_func[ord('3')] = decode_string | |
decode_func[ord('4')] = decode_string | |
decode_func[ord('5')] = decode_string | |
decode_func[ord('6')] = decode_string | |
decode_func[ord('7')] = decode_string | |
decode_func[ord('8')] = decode_string | |
decode_func[ord('9')] = decode_string | |
def bdecode(x): | |
try: | |
r, l = decode_func[x[0]](x, 0) | |
except (IndexError, KeyError, ValueError): | |
raise Exception("not a valid bencoded string") | |
return r | |
if __name__ == '__main__': | |
args = sys.argv[1:] | |
if len(args) < 1: | |
target = os.getcwd() | |
else: | |
target = args[0] | |
if len(args) == 2: | |
resume = args[1] | |
else: | |
print("no resume.dat given, locating...") | |
resume = get_default_resume_path() | |
active = get_active_paths_from_resume_dat(resume) | |
unref = get_unref_items(target, active) | |
if not unref: | |
print("No unreferenced files found. EXITING") | |
sys.exit(0) | |
print('\nFound Unreferenced Files in {}'.format(target)) | |
for f in sorted(unref): | |
print(str(f)) | |
ans = None | |
while ans not in ('y n yes no'.split()): | |
ans = input("Move unreferenced files into an 'unreferenced' folder? (Y\\N):") | |
ans = ans.lower() | |
if ans.startswith('n'): | |
print("FINISHED, 0 items moved.") | |
sys.exit(0) | |
print("Moving Files...") | |
target = Path(target).absolute() | |
ur = target / 'unreferenced' | |
if not ur.exists(): | |
ur.mkdir() | |
for f in unref: | |
try: | |
shutil.move(str(f), str(ur)) | |
except Exception as e: | |
print("error relocating {}: {}".format(f, e)) | |
print("FINISHED") | |
sys.exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Given a target directory, identify and move files/folders that aren't being seeded from uTorrent and move them to a folder called 'unreferenced'. Requires Python 3.6