Skip to content

Instantly share code, notes, and snippets.

@shidarin
Last active March 5, 2016 15:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save shidarin/0beed0d5d40c42bb7b2a to your computer and use it in GitHub Desktop.
Save shidarin/0beed0d5d40c42bb7b2a to your computer and use it in GitHub Desktop.
Used for downloading emulation movie 'snaps' from emumovies.com
#!/usr/bin/python
"""Tool for downloading matching movie files for a rom collection."""
from __future__ import absolute_import, division, print_function
from argparse import ArgumentParser
import ConfigParser
import ftplib
import os
import os.path
CWD = os.getcwd()
DEFAULT_CONFIG_FILE = '~/.config/ftp_match_dl.conf'
DEFAULT_DESTINATION_DIR = './videos/'
DEFAULT_FILE_EXT = 'mp4'
SAMPLE_CONFIG = (
"[FTP]\n"
"server=ftp.server.com\n"
"username=ftpusername@ftpusers.com\n"
"password=yourpassword"
)
# Classes
class Config(object):
"""Class containing the ftp server, username and password"""
def __init__(self, config_file, write_sample_config=True):
self.config_file = config_file
self.check_config(write_sample_config)
self.config = None
self.server = None
self.username = None
self.password = None
self.get_settings()
def check_config(self, write_sample_config):
"""Checks if a config file exists."""
if not os.path.isfile(self.config_file):
if os.path.exists(self.config_file):
raise ValueError(
"Configuration path '{config}' exists, but is a "
"directory. Cannot create a sample configuration file."
)
elif write_sample_config:
with open(self.config_file, 'w') as f:
f.write(SAMPLE_CONFIG)
print(
"No configuration file was found, so a sample "
"configuration written to: {path}".format(
path=self.config_file
)
)
raise ValueError(
"No configuration file found at: {path}".format(
path=self.config_file
)
)
def get_settings(self):
"""Reads the settings from the configuration file."""
self.config = ConfigParser.ConfigParser()
with open(self.config_file, 'r') as f:
self.config.readfp(f)
self.server = self.config.get('FTP', 'server')
self.username = self.config.get('FTP', 'username')
self.password = self.config.get('FTP', 'password')
# Public Functions
def parse_args():
"""Uses argparse to parse command line arguments"""
parser = ArgumentParser()
parser.add_argument(
"ftp_path",
help="the path on the ftp server to navigate to before searching"
)
parser.add_argument(
"-c",
"--config",
default=DEFAULT_CONFIG_FILE,
help="specify an alternate configuration file to read from. Defaults "
"to '{config}'".format(config=DEFAULT_CONFIG_FILE)
)
parser.add_argument(
"-s",
"--source",
default=CWD,
help="source directory to match potential downloads against. "
"Defaults to current directory, which is: "
"'{cwd}'".format(cwd=CWD)
)
parser.add_argument(
"-d",
"--destination",
default=DEFAULT_DESTINATION_DIR,
help="specify an output filepath to place the downloaded movies into. "
"Defaults to '{output}'".format(output=DEFAULT_DESTINATION_DIR)
)
parser.add_argument(
"-e",
"--ext",
default=DEFAULT_FILE_EXT,
help="specify an file extension to retrieve. "
"Defaults to '{ext}'".format(ext=DEFAULT_FILE_EXT)
)
parser.add_argument(
"-f",
"--force",
action='store_true',
help="if provided, do not ask for confirmation of files to be "
"downloaded. Defaults to False."
)
parser.add_argument(
"-o",
"--overwrite",
action='store_true',
help="if provided, overwrite existing files in the destination "
"directory. Defaults to False."
)
return parser.parse_args()
# Main
def main():
args = parse_args()
config = Config(
os.path.abspath(os.path.abspath(os.path.expanduser(args.config))),
write_sample_config=args.config == DEFAULT_CONFIG_FILE
)
ftp = ftplib.FTP(config.server)
ftp.login(config.username, config.password)
ftp.cwd(args.ftp_path)
abs_source = os.path.abspath(os.path.expanduser(args.source))
abs_dest = os.path.abspath(os.path.expanduser(args.destination))
if not os.path.exists(abs_dest):
if os.path.isfile(abs_dest):
raise ValueError(
"Given destination directory '{dir}' is a file, cannot "
"proceed.".format(dir=abs_dest)
)
os.mkdir(abs_dest)
match_list = [
os.path.splitext(f)[0] for f in os.listdir(abs_source)
if os.path.isfile(os.path.join(abs_source, f))
]
dest_list = [
os.path.splitext(f)[0] for f in os.listdir(abs_dest)
if os.path.isfile(os.path.join(abs_dest, f))
]
dl_list = {
os.path.splitext(f)[0]: f for f in ftp.nlst(
'*.{ext}'.format(ext=args.ext)
)
}
potentials = [f for f in dl_list if f in match_list]
potentials.sort()
if not args.overwrite:
potentials = [f for f in potentials if f not in dest_list]
print("Ready to download the following files:")
for f in potentials:
print("\t{file}".format(file=f))
if not args.force:
answer = raw_input(
"Type 'y' to download these files, anything else to cancel: "
)
if answer.lower().strip() not in ['y', 'yes']:
return
print()
for ftp_file in potentials:
print("Downloading: {file}".format(file=ftp_file))
with open(os.path.join(abs_dest, dl_list[ftp_file]), 'wb') as f:
ftp.retrbinary(
'RETR {file}'.format(file=dl_list[ftp_file]),
f.write
)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment