class TorrentMigrationJob(object):
    REAL_RUN = True

    def __init__(self, what, location_mapping, data, flac_only):
        self.flac_only = flac_only
        self.what = what
        self.location_mapping = location_mapping
        self.data = data
        self.what_torrent = self.data['what_torrent']
        self.what_torrent_info = ujson.loads(self.what_torrent['info'])
        self.full_location = os.path.join(
            wm_str(self.data['location']['path']),
            str(self.what_torrent['id']),
        )
        self.torrent_dict = bencode.bdecode(b64decode(self.what_torrent['torrent_file']))
        self.torrent_name = self.torrent_dict['info']['name']
        self.torrent_new_name = self.torrent_name
        self.torrent_dir_path = os.path.join(self.full_location.encode('utf-8'), self.torrent_name)

        self.new_torrent = None
        self.log_files = set()
        self.log_files_full_paths = []
        self.torrent_file_new_data = None
        self.torrent_new_infohash = None
        self.payload = None
        self.payload_files = None
        self.existing_new_group = None
        self.full_new_location = None

    def check_valid(self):
        print 'Verifying torrent data...'
        try:
            if not torrentcheck.verify(self.torrent_dict['info'], self.full_location):
                raise Exception('Torrent does not verify')
        except Exception as ex:
            WhatTorrentMigrationStatus.objects.create(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_FAILED_VALIDATION
            )
            raw_input('Verification threw {}. Press enter to continue.'.format(ex))
            return False
        print('Hash matching')
        torrent_file_set = {'/'.join(f['path']) for f in self.torrent_dict['info']['files']}
        for dirpath, dirnames, filenames in os.walk(self.torrent_dir_path):
            for filename in filenames:
                abs_path = os.path.join(dirpath, filename)
                file_path = os.path.relpath(abs_path, self.torrent_dir_path)
                if file_path not in torrent_file_set:
                    raise Exception(
                        'Extraneous file: {}/{}'.format(self.torrent_dir_path, file_path))
                if filename.lower().endswith('.log'):
                    print 'Candidate log file', abs_path
                    with open(abs_path, 'r') as log_f:
                        try:
                            self.log_files.add(LogFile(log_f.read()))
                        except UnrecognizedRippingLogException:
                            print 'Skipping: unrecognized'
                            pass
                        except InvalidRippingLogException:
                            raw_input('Log file unrecognized!')
                    self.log_files_full_paths.append(abs_path)
        print('No extraneous files')
        print 'Torrent verification complete'
        return True

    def mktorrent(self):
        print 'Creating torrent file...'
        torrent_temp_filename = 'temp.torrent'
        try:
            os.remove(torrent_temp_filename)
        except OSError:
            pass
        call_mktorrent(self.torrent_dir_path,
                       torrent_temp_filename,
                       settings.WHAT_ANNOUNCE,
                       self.torrent_new_name)
        with open(torrent_temp_filename, 'rb') as torrent_file:
            self.torrent_file_new_data = pthify_torrent(torrent_file.read())
            self.torrent_new_infohash = get_info_hash_from_data(self.torrent_file_new_data)
            print 'New info hash is: ', self.torrent_new_infohash
        print 'Torrent file created'

    def retrieve_new_torrent(self, info_hash):
        if self.new_torrent is None:
            self.new_torrent = safe_retrieve_new_torrent(self.what, info_hash)
            self.migration_status.pth_torrent_id = self.new_torrent['torrent']['id']
            self.migration_status.save()

    def set_new_location(self):
        mapped_location = self.location_mapping[self.data['location']['path']]
        self.new_location_obj = DownloadLocation.objects.get(path=mapped_location)
        self.full_new_location = os.path.join(
            mapped_location,
            str(self.new_torrent['torrent']['id'])
        )

    def prepare_payload(self):
        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']

        if g_info['categoryName'] != 'Music':
            raise Exception('Can only upload Music torrents for now')
        if t_info['format'] == 'MP3' and t_info['encoding'] not in ['V0 (VBR)', '320']:
            raise Exception('Please let\'s not upload this bitrate MP3')

        payload = dict()
        payload['submit'] = 'true'
        payload['auth'] = self.what.authkey
        payload['type'] = '0'  # Music
        if self.existing_new_group:
            payload['groupid'] = self.existing_new_group['group']['id']
        else:
            payload['artists[]'], payload['importance[]'] = extract_new_artists_importance(g_info)
            payload['title'] = html_parser.unescape(g_info['name'])
            payload['year'] = str(g_info['year'])
            payload['record_label'] = g_info['recordLabel'] or ''
            payload['catalogue_number'] = g_info['catalogueNumber'] or ''
            payload['releasetype'] = str(g_info['releaseType'])
            payload['tags'] = ','.join(g_info['tags'])
            payload['image'] = g_info['wikiImage'] or ''
            payload['album_desc'] = fix_duplicate_newlines(html_to_bbcode.feed(g_info['wikiBody']))
        if t_info['scene']:
            payload['scene'] = 'on'
        payload['format'] = t_info['format']
        payload['bitrate'] = t_info['encoding']
        payload['media'] = t_info['media']
        payload['release_desc'] = fix_duplicate_newlines(html_to_bbcode.feed(
            t_info['description']).replace('karamanolevs', 'karamanolev\'s'))

        if t_info['remastered']:
            payload['remaster'] = 'on'
            payload['remaster_year'] = t_info['remasterYear']
            payload['remaster_title'] = t_info['remasterTitle']
            payload['remaster_record_label'] = t_info['remasterRecordLabel']
            payload['remaster_catalogue_number'] = t_info['remasterCatalogueNumber']
        self.payload = payload

    def prepare_payload_files(self):
        payload_files = []
        payload_files.append(('file_input', ('torrent.torrent', self.torrent_file_new_data)))
        if self.what_torrent_info['torrent']['format'] == 'FLAC':
            for log_file_path in self.log_files_full_paths:
                print 'Log file {}'.format(log_file_path)
                print ''.join(list(open(log_file_path))[:4])
                print
                response = raw_input('Add to upload [y/n]: ')
                if response == 'y':
                    payload_files.append(('logfiles[]', ('logfile.log', open(log_file_path, 'rb'))))
                elif response == 'n':
                    pass
                else:
                    raise Exception('Bad response')
        self.payload_files = payload_files

    def perform_upload(self):
        if self.REAL_RUN:
            old_content_type = self.what.session.headers['Content-type']
            try:
                del self.what.session.headers['Content-type']

                response = self.what.session.post(
                    settings.WHAT_UPLOAD_URL, data=self.payload, files=self.payload_files)
                if response.url == settings.WHAT_UPLOAD_URL:
                    try:
                        errors = extract_upload_errors(response.text)
                    except Exception:
                        errors = ''
                    exception = Exception(
                        'Error uploading data to what.cd. Errors: {0}'.format('; '.join(errors)))
                    exception.response_text = response.text
                    with open('uploaded_error.html', 'w') as error_file:
                        error_file.write(response.text.encode('utf-8'))
                    raise exception
            except Exception as ex:
                time.sleep(2)
                try:
                    self.retrieve_new_torrent(self.torrent_new_infohash)
                except:
                    raise ex
            finally:
                self.retrieve_new_torrent(self.torrent_new_infohash)
                self.what.session.headers['Content-type'] = old_content_type
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_UPLOADED
            self.migration_status.save()
        else:
            print 'Ready with payload'
            print ujson.dumps(self.payload, indent=4)

    def get_total_size(self):
        return sum(f['length'] for f in self.torrent_dict['info']['files'])

    def print_info(self):
        if 'groupid' in self.payload:
            print 'Part of existing torrent group'
            print 'Artists:       ', ','.join(
                artist['name'] for artist in
                self.existing_new_group['group']['musicInfo']['artists']
            )
            print 'Album title:   ', self.existing_new_group['group']['name']
            print 'Year:          ', self.existing_new_group['group']['year']
            print 'Record label:  ', self.existing_new_group['group']['recordLabel']
            print 'Catalog number:', self.existing_new_group['group']['catalogueNumber']
            print 'Release type:  ', self.existing_new_group['group']['releaseType']
            print
        else:
            print 'Artists:       ', ','.join(
                artist['name'] for artist, importance in zip(
                    self.payload['artists[]'], self.payload['importance[]'])
                if importance == 1  # Main
            )
            print 'Album title:   ', self.payload['title']
            print 'Year:          ', self.payload['year']
            print 'Record label:  ', self.payload['record_label']
            print 'Catalog number:', self.payload['catalogue_number']
            print 'Release type:  ', self.payload['releasetype']
            print
        if 'remaster' in self.payload:
            print '  Edition information'
            print '  Year:          ', self.payload['remaster_year']
            print '  Record label:  ', self.payload['remaster_record_label']
            print '  Catalog number:', self.payload['remaster_catalogue_number']
            print
        print 'Scene:         ', 'yes' if 'scene' in self.payload else 'no'
        print 'Format:        ', self.payload['format']
        print 'Bitrate:       ', self.payload['bitrate']
        print 'Media:         ', self.payload['media']
        if 'groupid' not in self.payload:
            print 'Tags:          ', self.payload['tags']
            print 'Image:         ', self.payload['image']
            print 'Album desc:    ', self.payload['album_desc']
        print 'Release desc:  ', self.payload['release_desc']

    def find_existing_torrent_by_hash(self):
        try:
            existing_by_hash = self.what.request('torrent', hash=self.torrent_new_infohash)
            if existing_by_hash['status'] == 'success':
                self.new_torrent = existing_by_hash['response']
        except RequestException:
            pass
        return None

    def find_existing_torrent_group(self):
        if self.existing_new_group is not None:
            return

        existing_group_id = None

        group_id = self.what_torrent_info['group']['id']
        try:
            mapping = TorrentGroupMapping.objects.get(what_group_id=group_id)
            mapping_group = self.what.request('torrentgroup', id=mapping.pth_group_id)['response']
            if mapping_group['group']['id'] != mapping.pth_group_id:
                raise Exception('NOOOOO THIS CANNOT HAPPEN {} {}!'.format(
                    mapping_group['group']['id'],
                    mapping.pth_group_id,
                ))
            existing_group_id = mapping.pth_group_id
            print 'Found torrent group mapping with {}'.format(existing_group_id)
        except TorrentGroupMapping.DoesNotExist:
            pass
        except BadIdException:
            print 'Mapping has gone bad, deleting...'
            mapping.delete()

        if existing_group_id is None:
            group_year = self.what_torrent_info['group']['year']
            group_name = html_parser.unescape(self.what_torrent_info['group']['name']).lower()
            search_str = '{} {}'.format(wm_str(group_name), wm_str(str(group_year)))
            results = self.what.request('browse', searchstr=search_str)['response']['results']
            for result in results:
                if html_parser.unescape(result['groupName']).lower() == group_name and \
                                result['groupYear'] == group_year:
                    if not existing_group_id:
                        existing_group_id = result['groupId']
                        print 'Found existing group', existing_group_id
                    else:
                        print 'Multiple matching existing groups!!!!!!!!!!'
                        existing_group_id = None
                        break
        if existing_group_id is None:
            existing_group_id = raw_input(u'Enter existing group id (empty if non-existent): ')
            if existing_group_id:
                TorrentGroupMapping.objects.get_or_create(
                    what_group_id=self.what_torrent_info['group']['id'],
                    pth_group_id=existing_group_id
                )
        if existing_group_id:
            self.existing_new_group = self.existing_new_group = self.what.request(
                'torrentgroup', id=existing_group_id)['response']

    def find_matching_torrent_within_group(self):
        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']

        existing_torrent_id = None
        for torrent in self.existing_new_group['torrents']:
            if torrent['size'] == t_info['size']:
                if not existing_torrent_id:
                    existing_torrent_id = torrent['id']
                else:
                    raw_input('Warning: Multiple matching torrent sizes ({} and {})! '
                              'Taking first.'.format(
                        existing_torrent_id, torrent['id']))
        return existing_torrent_id

    def find_existing_torrent_within_group(self):
        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']

        existing_torrent_id = None
        original_catalog_number = normalize_for_matching(
            t_info['remasterCatalogueNumber'] or g_info['catalogueNumber'])
        for torrent in self.existing_new_group['torrents']:
            torrent_catalog_number = normalize_for_matching(
                torrent['remasterCatalogueNumber'] or
                self.existing_new_group['group']['catalogueNumber'])
            torrent_catalog_number = torrent_catalog_number.lower()
            matching_media_format = \
                t_info['media'] == torrent['media'] and \
                t_info['format'] == torrent['format'] and \
                t_info['encoding'] == torrent['encoding']

            # Comparing log files
            if torrent['format'] == 'FLAC' and t_info['format'] == 'FLAC' and len(self.log_files):
                try:
                    torrent_log_files = {
                        LogFile(l) for l in
                        self.what.request('torrentlog', torrentid=torrent['id'])['response']
                        }
                    if torrent_log_files == self.log_files:
                        print 'Found matching log files with {}!!!'.format(torrent['id'])
                        if not existing_torrent_id:
                            existing_torrent_id = torrent['id']
                            continue
                        else:
                            print 'Multiple existing catalog numbers ({} and {})'.format(
                                existing_torrent_id, torrent['id'])
                            existing_torrent_id = raw_input('Enter torrent id if dup: ')
                    else:
                        if len(torrent_log_files.intersection(self.log_files)):
                            raw_input('Log file sets are not exact matches, '
                                      'but found matching log files between ours and {}!!!'.format(
                                torrent['id']))
                except InvalidRippingLogException:
                    raw_input('Log file for {} invalid!'.format(torrent['id']))
                except UnrecognizedRippingLogException:
                    raw_input('Log file for {} unrecognized!'.format(torrent['id']))

            if original_catalog_number == torrent_catalog_number and matching_media_format:
                if not existing_torrent_id:
                    existing_torrent_id = torrent['id']
                    continue
                else:
                    print 'Multiple existing catalog numbers ({} and {})'.format(
                        existing_torrent_id, torrent['id'])
                    existing_torrent_id = raw_input('Enter torrent id if dup: ')

        return existing_torrent_id

    def find_dupes(self):
        response = None
        existing_torrent_id = None

        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']
        remaster = t_info['remastered']
        print 'What id:      ', self.what_torrent['id']
        print 'Title:        ', '; '.join(
            a['name'] for a in g_info['musicInfo']['artists']), '-', html_parser.unescape(
            g_info['name'])
        print 'Year:         ', g_info['year']
        print 'Media:        ', t_info['media']
        print 'Format:       ', t_info['format']
        print 'Bitrate:      ', t_info['encoding']
        print 'Remaster:     ', 'yes ({})'.format(t_info['remasterYear']) if remaster else 'no'
        print 'Label:        ', t_info['remasterRecordLabel'] if remaster else g_info['recordLabel']
        print 'Cat no:       ', t_info['remasterCatalogueNumber'] if remaster else g_info[
            'catalogueNumber']
        print 'Remaster desc:', t_info['remasterTitle']
        print 'Torrent name: ', self.torrent_name
        print 'Torrent size: ', format_bytes_pth(self.get_total_size())
        print

        self.find_existing_torrent_by_hash()
        if self.new_torrent:
            print 'Found existing torrent by hash ' + str(
                self.new_torrent['torrent']['id']) + ' reseeding!!!'
            self.migration_status = WhatTorrentMigrationStatus.objects.create(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                pth_torrent_id=self.new_torrent['torrent']['id'],
            )
            return True

        self.find_existing_torrent_group()
        if self.existing_new_group:
            matching_torrent_id = self.find_matching_torrent_within_group()
            if matching_torrent_id:
                print 'Found matching torrent id:', matching_torrent_id
                response = 'reseed'
            else:
                existing_torrent_id = self.find_existing_torrent_within_group()
                if existing_torrent_id:
                    print 'Found existing torrent id:', existing_torrent_id
                    response = 'dup'

        if not response:
            response = raw_input('Choose action [up/dup/skip/skipp/reseed/changetg]: ')
        else:
            if response != 'reseed':
                new_response = raw_input(response + '. Override: ')
                if new_response:
                    response = new_response

        if response == 'up':
            self.migration_status = WhatTorrentMigrationStatus(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_PROCESSING,
            )
            return True
        elif response == 'reseed':
            if not matching_torrent_id:
                matching_torrent_id = int(raw_input('Enter matching torrent id: '))
            existing_torrent = WhatTorrent.get_or_create(dummy_request, what_id=matching_torrent_id)
            existing_info = bencode.bdecode(existing_torrent.torrent_file_binary)
            success = False
            try:
                if not torrentcheck.verify(existing_info['info'], self.full_location):
                    raise Exception('Torrent does not verify')
                success = True
            except Exception as ex:
                print 'Existing torrent does not verify with', ex
            if success:
                self.new_torrent = self.what.request('torrent', id=matching_torrent_id)['response']
                self.migration_status = WhatTorrentMigrationStatus.objects.create(
                    what_torrent_id=self.what_torrent['id'],
                    status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                    pth_torrent_id=matching_torrent_id,
                )
                return True
        self.migration_status = WhatTorrentMigrationStatus(
            what_torrent_id=self.what_torrent['id'],
        )
        if response == 'dup':
            if not existing_torrent_id:
                existing_torrent_id = int(raw_input('Enter existing torrent id: '))
            existing_torrent = self.what.request('torrent', id=existing_torrent_id)['response']
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = existing_torrent_id
            TorrentGroupMapping.objects.get_or_create(
                what_group_id=self.what_torrent_info['group']['id'],
                pth_group_id=existing_torrent['group']['id'],
            )
        elif response == 'skip':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED
        elif response == 'skipp':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED_PERMANENTLY
        elif response == 'reseed':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = matching_torrent_id
        elif response == 'changetg':
            existing_group_id = raw_input(u'Enter existing group id (empty if non-existent): ')
            if existing_group_id:
                self.existing_new_group = self.existing_new_group = self.what.request(
                    'torrentgroup', id=existing_group_id)['response']
            return self.find_dupes()
        else:
            raise Exception('Unknown response')
        self.migration_status.save()
        return False

    def _add_to_wm(self):
        new_id = self.new_torrent['torrent']['id']
        instance = ReplicaSet.get_what_master().get_preferred_instance()
        trans_torrent = add_torrent(dummy_request, instance, self.new_location_obj, new_id)
        print 'Added to', trans_torrent.instance.name

    def add_to_wm(self):
        for i in range(3):
            try:
                self._add_to_wm()
                return
            except Exception:
                print 'Error adding to wm, trying again in 5 sec...'
                time.sleep(5)
        self._add_to_wm()

    def enhance_torrent_data(self):
        if self.what_torrent_info['torrent']['media'] == 'Blu-ray':
            self.what_torrent_info['torrent']['media'] = 'Blu-Ray'
        if not any(self.what_torrent_info['group']['tags']):
            tags = raw_input('Enter tags (comma separated): ').split(',')
            self.what_torrent_info['group']['tags'] = tags
        if len(self.what_torrent_info['group']['wikiBody']) < 10:
            wiki_body = raw_input('Enter wiki body: ')
            self.what_torrent_info['group']['wikiBody'] = wiki_body
        if 'tinypic.com' in self.what_torrent_info['group']['wikiImage'].lower():
            self.what_torrent_info['group']['wikiImage'] = ''
        if self.what_torrent_info['torrent']['remastered'] and not \
                self.what_torrent_info['torrent']['remasterYear']:
            remaster_year = raw_input('Enter remaster year: ')
            self.what_torrent_info['torrent']['remasterYear'] = remaster_year

    def generate_spectrals(self):
        print 'Generating spectrals...'
        generate_spectrals_for_dir(self.full_location)

    def save_torrent_group_mapping(self):
        TorrentGroupMapping.objects.get_or_create(
            what_group_id=self.what_torrent_info['group']['id'],
            pth_group_id=self.new_torrent['group']['id']
        )

    def process(self):
        what_torrent_id = self.what_torrent['id']

        if self.what_torrent_info['group']['categoryName'] != 'Music':
            print 'Skipping non-Music torrent', what_torrent_id
            return

        if self.flac_only and self.what_torrent_info['torrent']['format'] != 'FLAC':
            print 'Skipping non-FLAC torrent', what_torrent_id
            return

        try:
            status = WhatTorrentMigrationStatus.objects.get(what_torrent_id=what_torrent_id)
            if status.status == WhatTorrentMigrationStatus.STATUS_COMPLETE:
                print 'Skipping complete torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_DUPLICATE:
                print 'Skipping duplicate torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_SKIPPED:
                print 'Skipping skipped torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_SKIPPED_PERMANENTLY:
                print 'Skipping permanently skipped torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_FAILED_VALIDATION:
                print 'Skipping failed validation torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_RESEEDED:
                print 'Skipping reseeded torrent', what_torrent_id
                return
            else:
                raise Exception('Not sure what to do with status {} on {}'.format(
                    status.status, what_torrent_id))
        except WhatTorrentMigrationStatus.DoesNotExist:
            pass
        if not self.check_valid():
            return
        self.mktorrent()
        if not self.find_dupes():
            return
        if not self.new_torrent:
            self.enhance_torrent_data()
            self.prepare_payload()
            self.print_info()
            self.prepare_payload_files()
            self.generate_spectrals()
            raw_input('Will perform upload (CHECK THE SPECTRALS)...')
            self.perform_upload()
        self.set_new_location()
        if self.REAL_RUN:
            os.makedirs(self.full_new_location)
            shutil.move(wm_str(self.torrent_dir_path), wm_str(self.full_new_location))
            try:
                recursive_chmod(self.full_new_location, 0777)
            except OSError:
                print 'recursive_chmod failed'
        else:
            print 'os.makedirs({})'.format(self.full_new_location)
            print 'shutil.move({}, {})'.format(self.torrent_dir_path, self.full_new_location)
            print 'recursive_chmod({}, 0777)'.format(self.full_new_location)
        if self.REAL_RUN:
            self.add_to_wm()
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_COMPLETE
            self.migration_status.save()
            self.save_torrent_group_mapping()
        else:
            print 'add_to_wm()'
        print
        print
class TorrentMigrationJob(object):
    REAL_RUN = True

    def __init__(self, what, location_mapping, data, flac_only):
        self.flac_only = flac_only
        self.what = what
        self.location_mapping = location_mapping
        self.data = data
        self.what_torrent = self.data['what_torrent']
        self.what_torrent_info = ujson.loads(self.what_torrent['info'])
        self.full_location = os.path.join(
            wm_str(self.data['location']['path']),
            str(self.what_torrent['id']),
        )
        self.torrent_dict = bencode.bdecode(
            b64decode(self.what_torrent['torrent_file']))
        self.torrent_name = self.torrent_dict['info']['name']
        self.torrent_new_name = self.torrent_name
        self.torrent_dir_path = os.path.join(
            self.full_location.encode('utf-8'), self.torrent_name)

        self.new_torrent = None
        self.log_files = set()
        self.log_files_full_paths = []
        self.torrent_file_new_data = None
        self.torrent_new_infohash = None
        self.payload = None
        self.payload_files = None
        self.existing_new_group = None
        self.full_new_location = None

    def check_valid(self):
        print 'Verifying torrent data...'
        try:
            if not torrentcheck.verify(self.torrent_dict['info'],
                                       self.full_location):
                raise Exception('Torrent does not verify')
        except Exception as ex:
            WhatTorrentMigrationStatus.objects.create(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_FAILED_VALIDATION)
            raw_input(
                'Verification threw {}. Press enter to continue.'.format(ex))
            return False
        print('Hash matching')
        torrent_file_set = {
            '/'.join(f['path'])
            for f in self.torrent_dict['info']['files']
        }
        for dirpath, dirnames, filenames in os.walk(self.torrent_dir_path):
            for filename in filenames:
                abs_path = os.path.join(dirpath, filename)
                file_path = os.path.relpath(abs_path, self.torrent_dir_path)
                if file_path not in torrent_file_set:
                    raise Exception('Extraneous file: {}/{}'.format(
                        self.torrent_dir_path, file_path))
                if filename.lower().endswith('.log'):
                    print 'Candidate log file', abs_path
                    with open(abs_path, 'r') as log_f:
                        try:
                            self.log_files.add(LogFile(log_f.read()))
                        except UnrecognizedRippingLogException:
                            print 'Skipping: unrecognized'
                            pass
                        except InvalidRippingLogException:
                            raw_input('Log file unrecognized!')
                    self.log_files_full_paths.append(abs_path)
        print('No extraneous files')
        print 'Torrent verification complete'
        return True

    def mktorrent(self):
        print 'Creating torrent file...'
        torrent_temp_filename = 'temp.torrent'
        try:
            os.remove(torrent_temp_filename)
        except OSError:
            pass
        call_mktorrent(self.torrent_dir_path, torrent_temp_filename,
                       settings.WHAT_ANNOUNCE, self.torrent_new_name)
        with open(torrent_temp_filename, 'rb') as torrent_file:
            self.torrent_file_new_data = pthify_torrent(torrent_file.read())
            self.torrent_new_infohash = get_info_hash_from_data(
                self.torrent_file_new_data)
            print 'New info hash is: ', self.torrent_new_infohash
        print 'Torrent file created'

    def retrieve_new_torrent(self, info_hash):
        if self.new_torrent is None:
            self.new_torrent = safe_retrieve_new_torrent(self.what, info_hash)
            self.migration_status.pth_torrent_id = self.new_torrent['torrent'][
                'id']
            self.migration_status.save()

    def set_new_location(self):
        mapped_location = self.location_mapping[self.data['location']['path']]
        self.new_location_obj = DownloadLocation.objects.get(
            path=mapped_location)
        self.full_new_location = os.path.join(
            mapped_location, str(self.new_torrent['torrent']['id']))

    def prepare_payload(self):
        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']

        if g_info['categoryName'] != 'Music':
            raise Exception('Can only upload Music torrents for now')
        if t_info['format'] == 'MP3' and t_info['encoding'] not in [
                'V0 (VBR)', '320'
        ]:
            raise Exception('Please let\'s not upload this bitrate MP3')

        payload = dict()
        payload['submit'] = 'true'
        payload['auth'] = self.what.authkey
        payload['type'] = '0'  # Music
        if self.existing_new_group:
            payload['groupid'] = self.existing_new_group['group']['id']
        else:
            payload['artists[]'], payload[
                'importance[]'] = extract_new_artists_importance(g_info)
            payload['title'] = html_parser.unescape(g_info['name'])
            payload['year'] = str(g_info['year'])
            payload['record_label'] = g_info['recordLabel'] or ''
            payload['catalogue_number'] = g_info['catalogueNumber'] or ''
            payload['releasetype'] = str(g_info['releaseType'])
            payload['tags'] = ','.join(g_info['tags'])
            payload['image'] = g_info['wikiImage'] or ''
            payload['album_desc'] = fix_duplicate_newlines(
                html_to_bbcode.feed(g_info['wikiBody']))
        if t_info['scene']:
            payload['scene'] = 'on'
        payload['format'] = t_info['format']
        payload['bitrate'] = t_info['encoding']
        payload['media'] = t_info['media']
        payload['release_desc'] = fix_duplicate_newlines(
            html_to_bbcode.feed(t_info['description']).replace(
                'karamanolevs', 'karamanolev\'s'))

        if t_info['remastered']:
            payload['remaster'] = 'on'
            payload['remaster_year'] = t_info['remasterYear']
            payload['remaster_title'] = t_info['remasterTitle']
            payload['remaster_record_label'] = t_info['remasterRecordLabel']
            payload['remaster_catalogue_number'] = t_info[
                'remasterCatalogueNumber']
        self.payload = payload

    def prepare_payload_files(self):
        payload_files = []
        payload_files.append(
            ('file_input', ('torrent.torrent', self.torrent_file_new_data)))
        if self.what_torrent_info['torrent']['format'] == 'FLAC':
            for log_file_path in self.log_files_full_paths:
                print 'Log file {}'.format(log_file_path)
                print ''.join(list(open(log_file_path))[:4])
                print
                response = raw_input('Add to upload [y/n]: ')
                if response == 'y':
                    payload_files.append(
                        ('logfiles[]', ('logfile.log',
                                        open(log_file_path, 'rb'))))
                elif response == 'n':
                    pass
                else:
                    raise Exception('Bad response')
        self.payload_files = payload_files

    def perform_upload(self):
        if self.REAL_RUN:
            old_content_type = self.what.session.headers['Content-type']
            try:
                del self.what.session.headers['Content-type']

                response = self.what.session.post(settings.WHAT_UPLOAD_URL,
                                                  data=self.payload,
                                                  files=self.payload_files)
                if response.url == settings.WHAT_UPLOAD_URL:
                    try:
                        errors = extract_upload_errors(response.text)
                    except Exception:
                        errors = ''
                    exception = Exception(
                        'Error uploading data to what.cd. Errors: {0}'.format(
                            '; '.join(errors)))
                    exception.response_text = response.text
                    with open('uploaded_error.html', 'w') as error_file:
                        error_file.write(response.text.encode('utf-8'))
                    raise exception
            except Exception as ex:
                time.sleep(2)
                try:
                    self.retrieve_new_torrent(self.torrent_new_infohash)
                except:
                    raise ex
            finally:
                self.retrieve_new_torrent(self.torrent_new_infohash)
                self.what.session.headers['Content-type'] = old_content_type
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_UPLOADED
            self.migration_status.save()
        else:
            print 'Ready with payload'
            print ujson.dumps(self.payload, indent=4)

    def get_total_size(self):
        return sum(f['length'] for f in self.torrent_dict['info']['files'])

    def print_info(self):
        if 'groupid' in self.payload:
            print 'Part of existing torrent group'
            print 'Artists:       ', ','.join(
                artist['name'] for artist in self.existing_new_group['group']
                ['musicInfo']['artists'])
            print 'Album title:   ', self.existing_new_group['group']['name']
            print 'Year:          ', self.existing_new_group['group']['year']
            print 'Record label:  ', self.existing_new_group['group'][
                'recordLabel']
            print 'Catalog number:', self.existing_new_group['group'][
                'catalogueNumber']
            print 'Release type:  ', self.existing_new_group['group'][
                'releaseType']
            print
        else:
            print 'Artists:       ', ','.join(
                artist['name'] for artist, importance in zip(
                    self.payload['artists[]'], self.payload['importance[]'])
                if importance == 1  # Main
            )
            print 'Album title:   ', self.payload['title']
            print 'Year:          ', self.payload['year']
            print 'Record label:  ', self.payload['record_label']
            print 'Catalog number:', self.payload['catalogue_number']
            print 'Release type:  ', self.payload['releasetype']
            print
        if 'remaster' in self.payload:
            print '  Edition information'
            print '  Year:          ', self.payload['remaster_year']
            print '  Record label:  ', self.payload['remaster_record_label']
            print '  Catalog number:', self.payload[
                'remaster_catalogue_number']
            print
        print 'Scene:         ', 'yes' if 'scene' in self.payload else 'no'
        print 'Format:        ', self.payload['format']
        print 'Bitrate:       ', self.payload['bitrate']
        print 'Media:         ', self.payload['media']
        if 'groupid' not in self.payload:
            print 'Tags:          ', self.payload['tags']
            print 'Image:         ', self.payload['image']
            print 'Album desc:    ', self.payload['album_desc']
        print 'Release desc:  ', self.payload['release_desc']

    def find_existing_torrent_by_hash(self):
        try:
            existing_by_hash = self.what.request(
                'torrent', hash=self.torrent_new_infohash)
            if existing_by_hash['status'] == 'success':
                self.new_torrent = existing_by_hash['response']
        except RequestException:
            pass
        return None

    def find_existing_torrent_group(self):
        if self.existing_new_group is not None:
            return

        existing_group_id = None

        group_id = self.what_torrent_info['group']['id']
        try:
            mapping = TorrentGroupMapping.objects.get(what_group_id=group_id)
            mapping_group = self.what.request(
                'torrentgroup', id=mapping.pth_group_id)['response']
            if mapping_group['group']['id'] != mapping.pth_group_id:
                raise Exception('NOOOOO THIS CANNOT HAPPEN {} {}!'.format(
                    mapping_group['group']['id'],
                    mapping.pth_group_id,
                ))
            existing_group_id = mapping.pth_group_id
            print 'Found torrent group mapping with {}'.format(
                existing_group_id)
        except TorrentGroupMapping.DoesNotExist:
            pass
        except BadIdException:
            print 'Mapping has gone bad, deleting...'
            mapping.delete()

        if existing_group_id is None:
            group_year = self.what_torrent_info['group']['year']
            group_name = html_parser.unescape(
                self.what_torrent_info['group']['name']).lower()
            search_str = '{} {}'.format(wm_str(group_name),
                                        wm_str(str(group_year)))
            results = self.what.request(
                'browse', searchstr=search_str)['response']['results']
            for result in results:
                if html_parser.unescape(result['groupName']).lower() == group_name and \
                                result['groupYear'] == group_year:
                    if not existing_group_id:
                        existing_group_id = result['groupId']
                        print 'Found existing group', existing_group_id
                    else:
                        print 'Multiple matching existing groups!!!!!!!!!!'
                        existing_group_id = None
                        break
        if existing_group_id is None:
            existing_group_id = raw_input(
                u'Enter existing group id (empty if non-existent): ')
            if existing_group_id:
                TorrentGroupMapping.objects.get_or_create(
                    what_group_id=self.what_torrent_info['group']['id'],
                    pth_group_id=existing_group_id)
        if existing_group_id:
            self.existing_new_group = self.existing_new_group = self.what.request(
                'torrentgroup', id=existing_group_id)['response']

    def find_matching_torrent_within_group(self):
        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']

        existing_torrent_id = None
        for torrent in self.existing_new_group['torrents']:
            if torrent['size'] == t_info['size']:
                if not existing_torrent_id:
                    existing_torrent_id = torrent['id']
                else:
                    raw_input(
                        'Warning: Multiple matching torrent sizes ({} and {})! '
                        'Taking first.'.format(existing_torrent_id,
                                               torrent['id']))
        return existing_torrent_id

    def find_existing_torrent_within_group(self):
        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']

        existing_torrent_id = None
        original_catalog_number = normalize_for_matching(
            t_info['remasterCatalogueNumber'] or g_info['catalogueNumber'])
        for torrent in self.existing_new_group['torrents']:
            torrent_catalog_number = normalize_for_matching(
                torrent['remasterCatalogueNumber']
                or self.existing_new_group['group']['catalogueNumber'])
            torrent_catalog_number = torrent_catalog_number.lower()
            matching_media_format = \
                t_info['media'] == torrent['media'] and \
                t_info['format'] == torrent['format'] and \
                t_info['encoding'] == torrent['encoding']

            # Comparing log files
            if torrent['format'] == 'FLAC' and t_info[
                    'format'] == 'FLAC' and len(self.log_files):
                try:
                    torrent_log_files = {
                        LogFile(l)
                        for l in self.what.request(
                            'torrentlog', torrentid=torrent['id'])['response']
                    }
                    if torrent_log_files == self.log_files:
                        print 'Found matching log files with {}!!!'.format(
                            torrent['id'])
                        if not existing_torrent_id:
                            existing_torrent_id = torrent['id']
                            continue
                        else:
                            print 'Multiple existing catalog numbers ({} and {})'.format(
                                existing_torrent_id, torrent['id'])
                            existing_torrent_id = raw_input(
                                'Enter torrent id if dup: ')
                    else:
                        if len(torrent_log_files.intersection(self.log_files)):
                            raw_input(
                                'Log file sets are not exact matches, '
                                'but found matching log files between ours and {}!!!'
                                .format(torrent['id']))
                except InvalidRippingLogException:
                    raw_input('Log file for {} invalid!'.format(torrent['id']))
                except UnrecognizedRippingLogException:
                    raw_input('Log file for {} unrecognized!'.format(
                        torrent['id']))

            if original_catalog_number == torrent_catalog_number and matching_media_format:
                if not existing_torrent_id:
                    existing_torrent_id = torrent['id']
                    continue
                else:
                    print 'Multiple existing catalog numbers ({} and {})'.format(
                        existing_torrent_id, torrent['id'])
                    existing_torrent_id = raw_input(
                        'Enter torrent id if dup: ')

        return existing_torrent_id

    def find_dupes(self):
        response = None
        existing_torrent_id = None

        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']
        remaster = t_info['remastered']
        print 'What id:      ', self.what_torrent['id']
        print 'Title:        ', '; '.join(
            a['name'] for a in g_info['musicInfo']
            ['artists']), '-', html_parser.unescape(g_info['name'])
        print 'Year:         ', g_info['year']
        print 'Media:        ', t_info['media']
        print 'Format:       ', t_info['format']
        print 'Bitrate:      ', t_info['encoding']
        print 'Remaster:     ', 'yes ({})'.format(
            t_info['remasterYear']) if remaster else 'no'
        print 'Label:        ', t_info[
            'remasterRecordLabel'] if remaster else g_info['recordLabel']
        print 'Cat no:       ', t_info[
            'remasterCatalogueNumber'] if remaster else g_info[
                'catalogueNumber']
        print 'Remaster desc:', t_info['remasterTitle']
        print 'Torrent name: ', self.torrent_name
        print 'Torrent size: ', format_bytes_pth(self.get_total_size())
        print

        self.find_existing_torrent_by_hash()
        if self.new_torrent:
            print 'Found existing torrent by hash ' + str(
                self.new_torrent['torrent']['id']) + ' reseeding!!!'
            self.migration_status = WhatTorrentMigrationStatus.objects.create(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                pth_torrent_id=self.new_torrent['torrent']['id'],
            )
            return True

        self.find_existing_torrent_group()
        if self.existing_new_group:
            matching_torrent_id = self.find_matching_torrent_within_group()
            if matching_torrent_id:
                print 'Found matching torrent id:', matching_torrent_id
                response = 'reseed'
            else:
                existing_torrent_id = self.find_existing_torrent_within_group()
                if existing_torrent_id:
                    print 'Found existing torrent id:', existing_torrent_id
                    response = 'dup'

        if not response:
            response = raw_input(
                'Choose action [up/dup/skip/skipp/reseed/changetg]: ')
        else:
            if response != 'reseed':
                new_response = raw_input(response + '. Override: ')
                if new_response:
                    response = new_response

        if response == 'up':
            self.migration_status = WhatTorrentMigrationStatus(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_PROCESSING,
            )
            return True
        elif response == 'reseed':
            if not matching_torrent_id:
                matching_torrent_id = int(
                    raw_input('Enter matching torrent id: '))
            existing_torrent = WhatTorrent.get_or_create(
                dummy_request, what_id=matching_torrent_id)
            existing_info = bencode.bdecode(
                existing_torrent.torrent_file_binary)
            success = False
            try:
                if not torrentcheck.verify(existing_info['info'],
                                           self.full_location):
                    raise Exception('Torrent does not verify')
                success = True
            except Exception as ex:
                print 'Existing torrent does not verify with', ex
            if success:
                self.new_torrent = self.what.request(
                    'torrent', id=matching_torrent_id)['response']
                self.migration_status = WhatTorrentMigrationStatus.objects.create(
                    what_torrent_id=self.what_torrent['id'],
                    status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                    pth_torrent_id=matching_torrent_id,
                )
                return True
        self.migration_status = WhatTorrentMigrationStatus(
            what_torrent_id=self.what_torrent['id'], )
        if response == 'dup':
            if not existing_torrent_id:
                existing_torrent_id = int(
                    raw_input('Enter existing torrent id: '))
            existing_torrent = self.what.request(
                'torrent', id=existing_torrent_id)['response']
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = existing_torrent_id
            TorrentGroupMapping.objects.get_or_create(
                what_group_id=self.what_torrent_info['group']['id'],
                pth_group_id=existing_torrent['group']['id'],
            )
        elif response == 'skip':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED
        elif response == 'skipp':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED_PERMANENTLY
        elif response == 'reseed':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = matching_torrent_id
        elif response == 'changetg':
            existing_group_id = raw_input(
                u'Enter existing group id (empty if non-existent): ')
            if existing_group_id:
                self.existing_new_group = self.existing_new_group = self.what.request(
                    'torrentgroup', id=existing_group_id)['response']
            return self.find_dupes()
        else:
            raise Exception('Unknown response')
        self.migration_status.save()
        return False

    def _add_to_wm(self):
        new_id = self.new_torrent['torrent']['id']
        instance = ReplicaSet.get_what_master().get_preferred_instance()
        trans_torrent = add_torrent(dummy_request, instance,
                                    self.new_location_obj, new_id)
        print 'Added to', trans_torrent.instance.name

    def add_to_wm(self):
        for i in range(3):
            try:
                self._add_to_wm()
                return
            except Exception:
                print 'Error adding to wm, trying again in 5 sec...'
                time.sleep(5)
        self._add_to_wm()

    def enhance_torrent_data(self):
        if self.what_torrent_info['torrent']['media'] == 'Blu-ray':
            self.what_torrent_info['torrent']['media'] = 'Blu-Ray'
        if not any(self.what_torrent_info['group']['tags']):
            tags = raw_input('Enter tags (comma separated): ').split(',')
            self.what_torrent_info['group']['tags'] = tags
        if len(self.what_torrent_info['group']['wikiBody']) < 10:
            wiki_body = raw_input('Enter wiki body: ')
            self.what_torrent_info['group']['wikiBody'] = wiki_body
        if 'tinypic.com' in self.what_torrent_info['group']['wikiImage'].lower(
        ):
            self.what_torrent_info['group']['wikiImage'] = ''
        if self.what_torrent_info['torrent']['remastered'] and not \
                self.what_torrent_info['torrent']['remasterYear']:
            remaster_year = raw_input('Enter remaster year: ')
            self.what_torrent_info['torrent']['remasterYear'] = remaster_year

    def generate_spectrals(self):
        print 'Generating spectrals...'
        generate_spectrals_for_dir(self.full_location)

    def save_torrent_group_mapping(self):
        TorrentGroupMapping.objects.get_or_create(
            what_group_id=self.what_torrent_info['group']['id'],
            pth_group_id=self.new_torrent['group']['id'])

    def process(self):
        what_torrent_id = self.what_torrent['id']

        if self.what_torrent_info['group']['categoryName'] != 'Music':
            print 'Skipping non-Music torrent', what_torrent_id
            return

        if self.flac_only and self.what_torrent_info['torrent'][
                'format'] != 'FLAC':
            print 'Skipping non-FLAC torrent', what_torrent_id
            return

        try:
            status = WhatTorrentMigrationStatus.objects.get(
                what_torrent_id=what_torrent_id)
            if status.status == WhatTorrentMigrationStatus.STATUS_COMPLETE:
                print 'Skipping complete torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_DUPLICATE:
                print 'Skipping duplicate torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_SKIPPED:
                print 'Skipping skipped torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_SKIPPED_PERMANENTLY:
                print 'Skipping permanently skipped torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_FAILED_VALIDATION:
                print 'Skipping failed validation torrent', what_torrent_id
                return
            elif status.status == WhatTorrentMigrationStatus.STATUS_RESEEDED:
                print 'Skipping reseeded torrent', what_torrent_id
                return
            else:
                raise Exception(
                    'Not sure what to do with status {} on {}'.format(
                        status.status, what_torrent_id))
        except WhatTorrentMigrationStatus.DoesNotExist:
            pass
        if not self.check_valid():
            return
        self.mktorrent()
        if not self.find_dupes():
            return
        if not self.new_torrent:
            self.enhance_torrent_data()
            self.prepare_payload()
            self.print_info()
            self.prepare_payload_files()
            self.generate_spectrals()
            raw_input('Will perform upload (CHECK THE SPECTRALS)...')
            self.perform_upload()
        self.set_new_location()
        if self.REAL_RUN:
            os.makedirs(self.full_new_location)
            shutil.move(wm_str(self.torrent_dir_path),
                        wm_str(self.full_new_location))
            try:
                recursive_chmod(self.full_new_location, 0777)
            except OSError:
                print 'recursive_chmod failed'
        else:
            print 'os.makedirs({})'.format(self.full_new_location)
            print 'shutil.move({}, {})'.format(self.torrent_dir_path,
                                               self.full_new_location)
            print 'recursive_chmod({}, 0777)'.format(self.full_new_location)
        if self.REAL_RUN:
            self.add_to_wm()
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_COMPLETE
            self.migration_status.save()
            self.save_torrent_group_mapping()
        else:
            print 'add_to_wm()'
        print
        print
    def find_dupes(self):
        response = None
        existing_torrent_id = None

        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']
        remaster = t_info['remastered']
        print 'What id:      ', self.what_torrent['id']
        print 'Title:        ', '; '.join(
            a['name'] for a in g_info['musicInfo']['artists']), '-', html_parser.unescape(
            g_info['name'])
        print 'Year:         ', g_info['year']
        print 'Media:        ', t_info['media']
        print 'Format:       ', t_info['format']
        print 'Bitrate:      ', t_info['encoding']
        print 'Remaster:     ', 'yes ({})'.format(t_info['remasterYear']) if remaster else 'no'
        print 'Label:        ', t_info['remasterRecordLabel'] if remaster else g_info['recordLabel']
        print 'Cat no:       ', t_info['remasterCatalogueNumber'] if remaster else g_info[
            'catalogueNumber']
        print 'Remaster desc:', t_info['remasterTitle']
        print 'Torrent name: ', self.torrent_name
        print 'Torrent size: ', format_bytes_pth(self.get_total_size())
        print

        self.find_existing_torrent_by_hash()
        if self.new_torrent:
            print 'Found existing torrent by hash ' + str(
                self.new_torrent['torrent']['id']) + ' reseeding!!!'
            self.migration_status = WhatTorrentMigrationStatus.objects.create(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                pth_torrent_id=self.new_torrent['torrent']['id'],
            )
            return True

        self.find_existing_torrent_group()
        if self.existing_new_group:
            matching_torrent_id = self.find_matching_torrent_within_group()
            if matching_torrent_id:
                print 'Found matching torrent id:', matching_torrent_id
                response = 'reseed'
            else:
                existing_torrent_id = self.find_existing_torrent_within_group()
                if existing_torrent_id:
                    print 'Found existing torrent id:', existing_torrent_id
                    response = 'dup'

        if not response:
            response = raw_input('Choose action [up/dup/skip/skipp/reseed/changetg]: ')
        else:
            if response != 'reseed':
                new_response = raw_input(response + '. Override: ')
                if new_response:
                    response = new_response

        if response == 'up':
            self.migration_status = WhatTorrentMigrationStatus(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_PROCESSING,
            )
            return True
        elif response == 'reseed':
            if not matching_torrent_id:
                matching_torrent_id = int(raw_input('Enter matching torrent id: '))
            existing_torrent = WhatTorrent.get_or_create(dummy_request, what_id=matching_torrent_id)
            existing_info = bencode.bdecode(existing_torrent.torrent_file_binary)
            success = False
            try:
                if not torrentcheck.verify(existing_info['info'], self.full_location):
                    raise Exception('Torrent does not verify')
                success = True
            except Exception as ex:
                print 'Existing torrent does not verify with', ex
            if success:
                self.new_torrent = self.what.request('torrent', id=matching_torrent_id)['response']
                self.migration_status = WhatTorrentMigrationStatus.objects.create(
                    what_torrent_id=self.what_torrent['id'],
                    status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                    pth_torrent_id=matching_torrent_id,
                )
                return True
        self.migration_status = WhatTorrentMigrationStatus(
            what_torrent_id=self.what_torrent['id'],
        )
        if response == 'dup':
            if not existing_torrent_id:
                existing_torrent_id = int(raw_input('Enter existing torrent id: '))
            existing_torrent = self.what.request('torrent', id=existing_torrent_id)['response']
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = existing_torrent_id
            TorrentGroupMapping.objects.get_or_create(
                what_group_id=self.what_torrent_info['group']['id'],
                pth_group_id=existing_torrent['group']['id'],
            )
        elif response == 'skip':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED
        elif response == 'skipp':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED_PERMANENTLY
        elif response == 'reseed':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = matching_torrent_id
        elif response == 'changetg':
            existing_group_id = raw_input(u'Enter existing group id (empty if non-existent): ')
            if existing_group_id:
                self.existing_new_group = self.existing_new_group = self.what.request(
                    'torrentgroup', id=existing_group_id)['response']
            return self.find_dupes()
        else:
            raise Exception('Unknown response')
        self.migration_status.save()
        return False
    def find_dupes(self):
        response = None
        existing_torrent_id = None

        t_info = self.what_torrent_info['torrent']
        g_info = self.what_torrent_info['group']
        remaster = t_info['remastered']
        print 'What id:      ', self.what_torrent['id']
        print 'Title:        ', '; '.join(
            a['name'] for a in g_info['musicInfo']
            ['artists']), '-', html_parser.unescape(g_info['name'])
        print 'Year:         ', g_info['year']
        print 'Media:        ', t_info['media']
        print 'Format:       ', t_info['format']
        print 'Bitrate:      ', t_info['encoding']
        print 'Remaster:     ', 'yes ({})'.format(
            t_info['remasterYear']) if remaster else 'no'
        print 'Label:        ', t_info[
            'remasterRecordLabel'] if remaster else g_info['recordLabel']
        print 'Cat no:       ', t_info[
            'remasterCatalogueNumber'] if remaster else g_info[
                'catalogueNumber']
        print 'Remaster desc:', t_info['remasterTitle']
        print 'Torrent name: ', self.torrent_name
        print 'Torrent size: ', format_bytes_pth(self.get_total_size())
        print

        self.find_existing_torrent_by_hash()
        if self.new_torrent:
            print 'Found existing torrent by hash ' + str(
                self.new_torrent['torrent']['id']) + ' reseeding!!!'
            self.migration_status = WhatTorrentMigrationStatus.objects.create(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                pth_torrent_id=self.new_torrent['torrent']['id'],
            )
            return True

        self.find_existing_torrent_group()
        if self.existing_new_group:
            matching_torrent_id = self.find_matching_torrent_within_group()
            if matching_torrent_id:
                print 'Found matching torrent id:', matching_torrent_id
                response = 'reseed'
            else:
                existing_torrent_id = self.find_existing_torrent_within_group()
                if existing_torrent_id:
                    print 'Found existing torrent id:', existing_torrent_id
                    response = 'dup'

        if not response:
            response = raw_input(
                'Choose action [up/dup/skip/skipp/reseed/changetg]: ')
        else:
            if response != 'reseed':
                new_response = raw_input(response + '. Override: ')
                if new_response:
                    response = new_response

        if response == 'up':
            self.migration_status = WhatTorrentMigrationStatus(
                what_torrent_id=self.what_torrent['id'],
                status=WhatTorrentMigrationStatus.STATUS_PROCESSING,
            )
            return True
        elif response == 'reseed':
            if not matching_torrent_id:
                matching_torrent_id = int(
                    raw_input('Enter matching torrent id: '))
            existing_torrent = WhatTorrent.get_or_create(
                dummy_request, what_id=matching_torrent_id)
            existing_info = bencode.bdecode(
                existing_torrent.torrent_file_binary)
            success = False
            try:
                if not torrentcheck.verify(existing_info['info'],
                                           self.full_location):
                    raise Exception('Torrent does not verify')
                success = True
            except Exception as ex:
                print 'Existing torrent does not verify with', ex
            if success:
                self.new_torrent = self.what.request(
                    'torrent', id=matching_torrent_id)['response']
                self.migration_status = WhatTorrentMigrationStatus.objects.create(
                    what_torrent_id=self.what_torrent['id'],
                    status=WhatTorrentMigrationStatus.STATUS_RESEEDED,
                    pth_torrent_id=matching_torrent_id,
                )
                return True
        self.migration_status = WhatTorrentMigrationStatus(
            what_torrent_id=self.what_torrent['id'], )
        if response == 'dup':
            if not existing_torrent_id:
                existing_torrent_id = int(
                    raw_input('Enter existing torrent id: '))
            existing_torrent = self.what.request(
                'torrent', id=existing_torrent_id)['response']
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = existing_torrent_id
            TorrentGroupMapping.objects.get_or_create(
                what_group_id=self.what_torrent_info['group']['id'],
                pth_group_id=existing_torrent['group']['id'],
            )
        elif response == 'skip':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED
        elif response == 'skipp':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_SKIPPED_PERMANENTLY
        elif response == 'reseed':
            self.migration_status.status = WhatTorrentMigrationStatus.STATUS_DUPLICATE
            self.migration_status.pth_torrent_id = matching_torrent_id
        elif response == 'changetg':
            existing_group_id = raw_input(
                u'Enter existing group id (empty if non-existent): ')
            if existing_group_id:
                self.existing_new_group = self.existing_new_group = self.what.request(
                    'torrentgroup', id=existing_group_id)['response']
            return self.find_dupes()
        else:
            raise Exception('Unknown response')
        self.migration_status.save()
        return False