From 8923b28f60cd2b2aebb7ee4ec0c1d6ada627ef8f Mon Sep 17 00:00:00 2001
From: Kyle K <kylek389@gmail.com>
Date: Sun, 27 Sep 2020 02:54:25 -0500
Subject: xbox og ftp transfer utility helper for 2TB of game data

---
 xbox_og_ftp_helper.py | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)
 create mode 100644 xbox_og_ftp_helper.py

(limited to 'xbox_og_ftp_helper.py')

diff --git a/xbox_og_ftp_helper.py b/xbox_og_ftp_helper.py
new file mode 100644
index 0000000..d69a4e6
--- /dev/null
+++ b/xbox_og_ftp_helper.py
@@ -0,0 +1,131 @@
+import os
+import argparse
+import operator
+import pathlib
+import py7zr
+from ftplib import FTP
+
+# pip install py7zr
+
+
+def humanize_bytes(bytes, precision=1):
+    """Return a humanized string representation of a number of bytes.
+    >>> humanize_bytes(1024*12342)
+    '12.1 MB'
+    """
+
+    abbrevs = (
+        (1<<50, 'PB'),
+        (1<<40, 'TB'),
+        (1<<30, 'GB'),
+        (1<<20, 'MB'),
+        (1<<10, 'kB'),
+        (1, 'b')
+    )
+    if bytes == 1:
+        return '1b'
+    for factor, suffix in abbrevs:
+        if bytes >= factor:
+            break
+    return '%.*f%s' % (precision, bytes / factor, suffix)
+
+
+def get_dir_size(path):
+    dirSize = 0
+    for dirName, subdirList, fileList in os.walk(path):
+        try:
+            dirSize += sum(os.path.getsize(os.path.join(dirName, name)) for name in fileList)
+        except OSError:
+            pass
+    return dirSize
+
+
+def myftp_connect(addr, user, passwd, dest):
+    try:
+        ftp = FTP("192.168.1.123")
+        ftp.login("xbox", "xbox")
+        ftp.cwd(dest)
+        return ftp
+    except Exception as e:
+        print(e)
+        return None
+
+
+# pathnames should not contain trailing slash!
+# 3rd param is e.g. F:\\Games\\Ford Racing 2
+def upload_dir(ftp, localdir, ftpdir):
+    try:
+        if (ftp.pwd() == '/'):
+            ftp.cwd(os.path.dirname(ftpdir)) # runs initially to cd into e.g. F:\\Games
+        ftp.mkd(os.path.basename(ftpdir))
+        ftp.cwd(os.path.basename(ftpdir)) # .cwd() expects relative path
+    except Exception as e:
+        print(e)
+        raise
+
+    localdir = os.path.join(localdir, '') # append slash at the end if not already there
+    ftpdir = os.path.join(ftpdir, '')     # append slash at the end if not already there
+
+    for fname in os.listdir(localdir):
+        if os.path.isdir(localdir + fname):      
+            upload_dir(ftp, localdir + fname, ftpdir + fname)
+        else:
+            print('STOR ' + ftpdir + fname)
+            with open(localdir + fname, 'rb') as f:
+                try:
+                    ftp.storbinary('STOR ' + fname, f)
+                except Exception as e:
+                    print(e)
+                    pass
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--addr", help="XBOX IPv4 address", required=True)
+    parser.add_argument("--user", default="xbox", help="ftp user (default: xbox)")
+    parser.add_argument("--pass", dest='passwd', default="xbox", help="ftp password (default: xbox)")
+    parser.add_argument("--list", help="list games currently present on XBOX", action="store_true")
+    parser.add_argument("--dryrun", help="dry run without actually transferring files", action="store_true")
+    parser.add_argument("--path", dest='src', default=".", help="path to source directory (default: current directory)")
+    parser.add_argument("--dest", dest='dst', default="F:\\Games\\", help="destination path (default: F:\\Games)")
+    args = parser.parse_args()
+
+    path = pathlib.Path(args.src).resolve()
+    print("ftp credentials..: %s %s/%s\nsource...........: %s\ndestination......: %s\n" % (args.addr, args.user, args.passwd, path, args.dst))
+
+    if not args.dryrun:
+        ftp = myftp_connect(args.addr, args.user, args.passwd, args.dst)
+        if ftp is None:
+            exit(1)
+
+    if args.list and not args.dryrun:
+        print("[listing] %s" % args.dst)
+        ftp.dir()
+        ftp.quit()
+        exit(0)
+
+    for f in os.listdir(path):
+        fullpath = os.path.join(path, f)
+        if os.path.isdir(fullpath):
+            print("[transferring] %s | %9s" % (fullpath, humanize_bytes(get_dir_size(fullpath))))
+            if not args.dryrun:
+                upload_dir(ftp, fullpath, os.path.join(args.dst, f))
+        elif os.path.isfile(fullpath):
+            if pathlib.Path(fullpath).suffix == '.7z':
+                with py7zr.SevenZipFile(fullpath, mode='r') as z:
+                    print("[extracting] %s | %9s" % (fullpath, os.path.getsize(fullpath)))
+                    if not args.dryrun:
+                        try:
+                            z.extractall('_tmp')
+                        except Exception as e:
+                            pass
+                        for root, dirs, files in os.walk('_tmp'):
+                            if 'default.xbe' in files:
+                                break
+                        print("root of extracted .7z game is: %s" % (root))
+                        upload_dir(ftp, os.path.join(os.path.dirname(fullpath), root), os.path.join(args.dst, f))
+        else:
+            pass
+            #print("%s %s" % (f, 'not a directory or .7z file'))
+    ftp.quit()
+
-- 
cgit v1.2.3