Skip to content

Instantly share code, notes, and snippets.

@Natanel-Shitrit
Created October 13, 2023 21:16
Show Gist options
  • Select an option

  • Save Natanel-Shitrit/1b635f46c63fc8f93c27398c26d94da2 to your computer and use it in GitHub Desktop.

Select an option

Save Natanel-Shitrit/1b635f46c63fc8f93c27398c26d94da2 to your computer and use it in GitHub Desktop.
qBittorrent FastResume Migration Script
import argparse
import os
import pprint
import shutil
from typing import Dict, List, Optional
import bencodepy
BENCODE_TYPE = bytes | List['BENCODE_TYPE']
class FastResume:
info: Dict[str, str]
def __init__(self, data: Dict[bytes, BENCODE_TYPE]) -> None:
self.info = {}
for key, value in data.items():
self.info[key.decode()] = value
def __repr__(self) -> str:
return pprint.pformat(self.__dict__)
def __str__(self) -> str:
return pprint.pformat(self.__dict__)
def export(self, encoding: str = 'utf-8', path: Optional[str] = None) -> bytes:
"""
Export FastResume.
:param path str: Optional argument to export FastResume to file.
:returns str: Encoded data.
"""
encoded = bencodepy.encode(self.info, encoding)
if path is not None:
with open(path, 'wb') as f:
f.write(encoded)
return encoded
# "from" functions.
@staticmethod
def from_bytes(data: bytes) -> 'FastResume':
return FastResume(bencodepy.decode(data))
@staticmethod
def from_file(path: str) -> 'FastResume':
return FastResume(bencodepy.decode_from_file(path))
def change_save_path(fastresume: FastResume, new_save_path: str) -> None:
"""
Change the save path of a FastResume object.
Args:
fastresume: The FastResume object to change the save path of.
new_save_path: The new save path.
"""
fastresume.info['qBt-savePath'] = new_save_path
fastresume.info['save_path'] = new_save_path
def backup_file(file_path: str, backup_directory: str) -> None:
"""
Backup a file to a given directory.
Args:
file_path: The path of the file to backup.
backup_directory: The path of the directory to backup the file to.
"""
backup_file_path = os.path.join(backup_directory, os.path.basename(file_path))
shutil.copyfile(file_path, backup_file_path)
def process_files(files_path: str, new_save_path: str) -> None:
"""
Process all files in a directory, changing the save path of any `fastresume` files to a new save path and backing up the original files.
Args:
files_path: The directory path to process.
new_save_path: The new save path.
"""
backup_directory = os.path.join(files_path, 'fastresume-migrate-backup')
os.makedirs(backup_directory, exist_ok=True)
for root, directories, files in os.walk(files_path):
for filename in files:
if (file_path := os.path.join(root, filename)).endswith('.fastresume'):
print(f'Processing {file_path}.')
backup_file(file_path, backup_directory)
fastresume = FastResume.from_file(file_path)
change_save_path(fastresume, new_save_path)
fastresume.export(path=file_path)
break
def main():
parser = argparse.ArgumentParser(description='Change the save path of all qBittorrent `fastresume` files in a given directory to a new save path.')
parser.add_argument('--files-path', required=True, help='The path of the directory containing the `fastresume` files to modify.')
parser.add_argument('--new-save-path', required=True, help='The new save path to set.')
args = parser.parse_args()
process_files(args.files_path, args.new_save_path)
print('The save paths of all `fastresume` files have been changed.')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment