#!/usr/bin/python3 ''' Checks available MAME 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 and filter MAME torrents * Get all torrents from PleasureDome RSS * Get all torrents currently active in Transmission * Intersect the three lists to get updatable torrents * And for each updatable torrent: - remove the old torrent from Transmission, - rename the local directory, - add the new torrent Work in progress… * TODO: implement some error handling Requirements: * Transmission for Bitorrent * A PleasureDome account * A proper config.json file (see config.template.json) * Python3 with the libraries below - feedparser - transmission-clutch * 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 feedparser import json import logging import os import re import requests import time from clutch.core import Client from collections import defaultdict from pprint import pformat def open_config_file(): """Reads configuration from config.json file""" logging.info('Opening config file: config.json') with open('config.json') as config_file: config = json.load(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: match = re_mame_version.match(directory) if match: torrents[match.group(2)]['local-version'] = int(match.group(1)) torrents[match.group(2)]['local-name'] = directory logging.debug('Found the local torrent versions: %s', pformat(torrents)) def fetch_remote_terrents(): """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: match = re_mame_version.match(post.title) if match: torrents[match.group(2)]['remote-version'] = int(match.group(1)) torrents[match.group(2)]['remote-link'] = post.link torrents[match.group(2)]['remote-name'] = post.title 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', 'transmission-id'} if not ( keys_to_check.issubset(data.keys()) and data['local-version'] < data['remote-version'] and data['remote-link'].startswith( 'http://www.pleasuredome.org.uk/download.php' ) ): del torrents[torrent] logging.info( 'The following torrents can be updated: %s', pformat(torrents) ) def prompt_for_update(): """Ask for user confirmation before updating""" if len(torrents) > 0: for torrent, data in torrents.items(): print('Torrent {}: {} -> {}'.format( torrent, data['local-version'], data['remote-version'] )) 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/login2.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(): match = re_mame_version.match(torrent['name']) if match: torrents[match.group(2)]['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(): old_name = os.path.join( config['mame-directory'], torrent['local-name'] ) new_name = os.path.join( config['mame-directory'], torrent['remote-name'] ) client.torrent.remove(torrent['transmission-id']) os.rename(old_name, new_name) client.torrent.add( filename=torrent['remote-link'], download_dir=config['mame-directory'], cookies=cookies, paused=False ) if __name__ == '__main__': logging.basicConfig( level=logging.INFO, format=' %(asctime)s - %(levelname)s - %(message)s' ) 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) re_mame_version = re.compile(r'MAME 0.(\d+) (.*)') config = open_config_file() torrents = defaultdict(dict) client = connect_to_transmission() cookies = get_cookies_from_pleasuredome() fetch_local_torrents() fetch_remote_terrents() fetch_transmission_torrents() filter_updatable_torrents() prompt_for_update() update_torrents()