|
- #!/usr/bin/python3
- '''
- Checks available Torrents on PleasureDome
- and updates the local versions if more recent
- versions are detected
-
- Basically what it does is:
- * Get all torrents in a directory torrents
- * Get all torrents from PleasureDome RSS
- * Get all torrents currently active in Transmission
- * Intersect the first two lists to get updatable torrents
- * And for each updatable torrent:
- - remove the old torrent from Transmission (if needed),
- - rename the local directory,
- - add the new torrent
-
- Supported Torrents:
- * MAME
- * HBMAME
- * No-Intro
-
- Work in progress…
- * TODO: implement some error handling
-
- Requirements:
- * Transmission for Bitorrent
- * A PleasureDome account
- * A proper PDMameUpdate.json file (see PDMameUpdate.template.json)
- * Python3 with the libraries below
- - feedparser
- - transmission-clutch
- - tabulate
- * Linux (untested on other OS, but it might work)
-
- Notes
- * This script logs in PleasureDome to get the proper cookies.
- It seems you can also set your cookies in Transmission using
- a cookies.txt file in the .config/transmission directory
- See: https://forum.transmissionbt.com/viewtopic.php?t=7468
-
- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !!! Provided with no warranty whatsoever. !!!
- !!! Make sure you understand what the script !!!
- !!! does and adapt it to your context !!!
- !!! Use with caution. !!!
- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- '''
- import argparse
- import feedparser
- import json
- import logging
- import os
- import re
- import requests
- import time
- import pathlib
- from clutch.core import Client
- from tabulate import tabulate
- from collections import defaultdict
- from pprint import pformat
- from urllib.parse import quote
-
-
- def open_config_file():
- """Reads configuration from PDMameUpdate.json file"""
-
- locations = (
- os.environ.get("PDMAMEUPDATE_CONF"),
- "/etc",
- os.path.expanduser("~"),
- os.curdir
- )
- for loc in locations:
- if loc is not None:
- logging.info("Searching for config file in '%s'", loc)
- config_path = loc + '/PDMameUpdate.json'
- if pathlib.Path(config_path).is_file():
- config_file_loc = config_path
- break
-
- if 'config_file_loc' not in locals():
- logging.error("Config file not found")
- raise FileNotFoundError("Config file not found")
-
- logging.info('Opening config file: '+config_file_loc)
- config_file = None
- with open(config_file_loc, 'r') as config_file:
- config = json.load(config_file)
- parameters = [
- "mame-directory",
- "pleasuredome-password",
- "pleasuredome-user",
- "torrent-directory",
- "transmission-password",
- "transmission-port",
- "transmission-user"
- ]
- for key in parameters:
- if key not in config:
- logging.error('Missing key in config file: %s', key)
- raise ValueError('Invalid config file.')
- return config
-
-
- def fetch_local_torrents():
- """Fetches local torrents versions"""
-
- logging.info('Fetching current MAME versions')
- directories = os.listdir(config['mame-directory'])
- for directory in directories:
- for regexp in regexps:
- match = regexp.search(directory)
- if match:
- version = match.group(0)
- name = regexp.sub('#', directory)
- torrents[name]['local-version'] = version
- torrents[name]['local-name'] = directory
- logging.debug('Found the local torrent versions: %s', pformat(torrents))
-
-
- def fetch_remote_torrents():
- """Fetches PleasureDome torrents versions"""
-
- logging.info('Opening PleasureDome RSS feed')
- d = feedparser.parse('http://www.pleasuredome.org.uk/rss.xml')
- for post in d.entries:
- for regexp in regexps:
- match = regexp.search(post.title)
- if match:
- matched_version = match.group(0)
- matched_torrent = torrents[regexp.sub('#', post.title)]
- if matched_version > matched_torrent.get('remote-version', ''):
- matched_torrent['remote-version'] = matched_version
- matched_torrent['remote-link'] = post.link
- matched_torrent['remote-name'] = post.title
- else:
- logging.info("Skipping '{}' version '{}'".format(
- match.group(0),
- matched_version
- ))
- logging.debug('Found the remote torrent versions: %s', pformat(torrents))
-
-
- def filter_updatable_torrents():
- """Checks if newer versions are available and prompt for update"""
-
- for torrent, data in list(torrents.items()):
- keys_to_check = {'local-version', 'remote-version'}
- if (
- keys_to_check.issubset(data.keys())
- and
- data['local-version'] < data['remote-version']
- ):
- check_and_rewrite_download_url(data)
- else:
- del torrents[torrent]
-
- logging.debug(
- 'The following torrents can be updated: %s',
- [t for t in torrents.keys()]
- )
-
-
- def check_and_rewrite_download_url(torrent_data):
- url_match = re.compile(
- r"https?://www.pleasuredome.org.uk/details.php\?id=(.*)"
- )
- match = url_match.match(torrent_data['remote-link'])
- if match:
- url = ("http://www.pleasuredome.org.uk/download.php"
- "?id={}&f={}.torrent&secure=no").format(
- match.group(1),
- quote('+'.join(torrent_data['remote-name'].split(' ')), safe='+')
- )
- logging.info('Changed url {} to {}'.format(
- torrent_data['remote-link'],
- url
- ))
- torrent_data['remote-link'] = url
-
-
- def prompt_for_update():
- """Ask for user confirmation before updating"""
-
- output_header = ["Torrent", "From", "To", "Transmission ID"]
- output = []
- if len(torrents) > 0:
- for torrent, data in torrents.items():
- output.append([
- torrent,
- data['local-version'],
- data['remote-version'],
- data.get('transmission-id', 'N/A')
- ])
- print(tabulate(output, headers=output_header, tablefmt="simple"))
- print('Should I update the torrents listed above? (y/N)')
- answer = input()
- if answer.lower() != 'y':
- logging.info('Quitting: user cancelled update')
- print('Quitting…')
- exit(0)
- else:
- logging.info('Quitting: no update candidate')
- print('No update found…')
- exit(0)
- logging.info('User chose to update torrents')
-
-
- def get_cookies_from_pleasuredome():
- """Connects to PleasureDome to retrieve Cookies"""
-
- logging.info('Logging in PleasureDome')
- data = {
- 'uid': config['pleasuredome-user'],
- 'pwd': config['pleasuredome-password']
- }
- r = requests.post('http://www.pleasuredome.org.uk/login3.php', data=data)
- if r.status_code == 200:
- logging.info('Connected to PleasureDome')
- logging.info('Logging out')
- requests.get('http://www.pleasuredome.org.uk/logout.php')
- else:
- logging.error(
- 'Connection to PleasureDome failed with status %s',
- r.status_code
- )
- exit(1)
- return {k: r.cookies[k] for k in ('uid', 'pass')}
-
-
- def connect_to_transmission():
- """Connects to Transmission and return a Client object"""
-
- logging.info('Connecting to Transmission Remote Control')
- return Client(
- username=config['transmission-user'],
- password=config['transmission-password'],
- port=config['transmission-port']
- )
-
-
- def fetch_transmission_torrents():
- """Gets the torrents id from Transmission"""
-
- logging.info('Listing Transmission torrents')
- for torrent in client.list().values():
- for regexp in regexps:
- match = regexp.search(torrent['name'])
- if match:
- name = regexp.sub('#', torrent['name'])
- torrents[name]['transmission-id'] = torrent['id']
- logging.debug('Found the Transmission torrent ids: %s', pformat(torrents))
-
-
- def update_torrents():
- """
- Updates torrents:
- * remove it from Transmission,
- * rename the local directory,
- * and add the new torrent
- """
-
- logging.info('Updating torrents')
- for torrent in torrents.values():
- logging.info('Updating torrent : %s', torrent['remote-name'])
- old_name = os.path.join(
- config['mame-directory'],
- torrent['local-name']
- )
- new_name = os.path.join(
- config['mame-directory'],
- torrent['remote-name']
- )
- new_torrent = os.path.join(
- config['torrent-directory'],
- torrent['remote-name']+'.torrent'
- )
- if 'transmission-id' in torrent:
- logging.debug('Removing from transmission : %s',torrent['transmission-id'])
- client.torrent.remove(torrent['transmission-id'])
- logging.debug('Renaming %s to %s',old_name, new_name)
- os.rename(old_name, new_name)
- logging.debug('Adding to transmission : %s', torrent['remote-link'])
- client.torrent.add(
- filename=torrent['remote-link'],
- download_dir=config['mame-directory'],
- cookies=cookies,
- paused=False
- )
- if args.keep:
- logging.debug('Downloading torrent : %s', new_torrent)
- t = requests.get(torrent['remote-link'], verify=False, cookies=cookies)
- open(new_torrent, 'wb').write(t.content)
-
-
- if __name__ == '__main__':
- logging.basicConfig(
- level=logging.WARNING,
- format=' %(asctime)s - %(levelname)s - %(message)s'
- )
- parser = argparse.ArgumentParser(
- description='Update PleasureDome MAME Torrents'
- )
- parser.add_argument(
- '-l', '--log',
- action='store_true',
- help='Display more log messages'
- )
- parser.add_argument(
- '-d', '--debug',
- action='store_true',
- help='Display debugging messages'
- )
- parser.add_argument(
- '-k', '--keep',
- action='store_true',
- help='Keep torrent files localy'
- )
- parser.add_argument(
- '-c', '--countdown',
- action='store_true',
- help='Start with a 5 second countdown'
- )
- args = parser.parse_args()
- if args.log:
- logging.getLogger().setLevel(logging.INFO)
- if args.debug:
- logging.getLogger().setLevel(logging.DEBUG)
- if args.countdown:
- print('PDMameUpdate is about to start')
- # Useful if you run this script when your machine boots
- for i in range(5, 0, -1):
- print('{}\r'.format(i), end=''),
- time.sleep(1)
-
- regexps = [
- re.compile(r'(?<=MAME )[\d.]+'),
- re.compile(r'(?<=HBMAME )[\d.]+'),
- re.compile(r'(?<=No-Intro \()[\d-]+')
- ]
- config = open_config_file()
- torrents = defaultdict(dict)
-
- client = connect_to_transmission()
- cookies = get_cookies_from_pleasuredome()
-
- fetch_local_torrents()
- fetch_remote_torrents()
- fetch_transmission_torrents()
- filter_updatable_torrents()
- prompt_for_update()
- update_torrents()
|