Ejemplo n.º 1
0
    def prepare_libtorrent_params(self,
                                  mod,
                                  force_sync=False,
                                  just_seed=False):
        """Prepare mod for download over bittorrent.
        This effectively downloads the .torrent file if its contents are not
        already cached.
        Also set all the parameters required by libtorrent.
        """

        # TODO: Add the check: mod name == torrent directory name

        # === Metadata handling ===
        metadata_file = MetadataFile(mod.foldername)
        metadata_file.read_data(
            ignore_open_errors=True
        )  # In case the mod does not exist, we would get an error

        # Clear the force clean flag
        metadata_file.set_force_creator_complete(False)

        # A little bit of a workaround. If we intend to seed, we can assume the data is all right.
        # This way, if the torrent is closed before checking_resume_data is finished, and the post-
        # download hook is not fired, the torrent is not left in a state marked as dirty.
        if not just_seed and not force_sync:
            metadata_file.set_dirty(
                True
            )  # Set as dirty in case this process is not terminated cleanly

        # If the torrent url changed, invalidate the resume data
        old_torrent_url = metadata_file.get_torrent_url()
        if old_torrent_url != mod.torrent_url or force_sync:
            metadata_file.set_torrent_resume_data('')
            metadata_file.set_torrent_content('')
            # print "Setting torrent url to {}".format(mod.torrent_url)
            metadata_file.set_torrent_url(mod.torrent_url)

        metadata_file.write_data()
        # End of metadata handling

        # === Torrent parameters ===
        params = {
            'save_path': encode_utf8(mod.parent_location),
            'storage_mode': libtorrent.storage_mode_t.
            storage_mode_allocate,  # Reduce fragmentation on disk
            'flags': torrent_utils.create_add_torrent_flags(just_seed)
        }

        torrent_info, torrent_content = self.get_mod_torrent_metadata(
            mod, metadata_file)
        params['ti'] = torrent_info

        # Cache it for future requests
        metadata_file.set_torrent_content(torrent_content)
        metadata_file.write_data()

        # Add optional resume data
        resume_data = metadata_file.get_torrent_resume_data()
        if resume_data:  # Quick resume torrent from data saved last time the torrent was run
            params['resume_data'] = resume_data

        mod.libtorrent_params = params

        if not just_seed:
            # Ensure the mod directory is correct (no bad links and read-write)
            # This should have been already done with preparer.py but it doesn't
            # hurt to do that again in case something changed in the meantime.
            torrent_utils.prepare_mod_directory(mod.get_full_path())
Ejemplo n.º 2
0
def is_complete_quick(mod):
    """Performs a quick check to see if the mod *seems* to be correctly installed.
    This check assumes no external changes have been made to the mods.

    1. Check if metadata file exists and can be opened (instant)
    1a. WORKAROUND: Check if the file has just been created so it must be complete
    2. Check if torrent is not dirty [download completed successfully] (instant)
    3. Check if torrent url matches (instant)
    4. Check if files have the right size and modification time (very quick)
    5. Check if there are no superfluous files in the directory (very quick)"""

    Logger.info('Is_complete: Checking mod {} for completeness...'.format(
        mod.foldername))

    metadata_file = MetadataFile(mod.foldername)

    # (1) Check if metadata can be opened
    try:
        metadata_file.read_data(ignore_open_errors=False)
    except (IOError, ValueError):
        Logger.info(
            'Is_complete: Metadata file could not be read successfully. Marking as not complete'
        )
        return False

    # Workaround
    if metadata_file.get_force_creator_complete():
        Logger.info(
            'Is_complete: Torrent marked as (forced) complete by the creator. Treating as complete'
        )
        return True

    # (2)
    if metadata_file.get_dirty():
        Logger.info(
            'Is_complete: Torrent marked as dirty (not completed successfully). Marking as not complete'
        )
        return False

    # (3)
    if metadata_file.get_torrent_url() != mod.torrent_url:
        Logger.info(
            'Is_complete: Torrent urls differ. Marking as not complete')
        return False

    # Get data required for (4) and (5)
    torrent_content = metadata_file.get_torrent_content()
    if not torrent_content:
        Logger.info(
            'Is_complete: Could not get torrent file content. Marking as not complete'
        )
        return False

    try:
        torrent_info = get_torrent_info_from_bytestring(torrent_content)
    except RuntimeError:
        Logger.info(
            'Is_complete: Could not parse torrent file content. Marking as not complete'
        )
        return False

    resume_data_bencoded = metadata_file.get_torrent_resume_data()
    if not resume_data_bencoded:
        Logger.info(
            'Is_complete: Could not get resume data. Marking as not complete')
        return False
    resume_data = libtorrent.bdecode(resume_data_bencoded)

    # (4)
    file_sizes = resume_data['file sizes']
    files = torrent_info.files()
    # file_path, size, mtime
    files_data = map(lambda x, y: (y.path.decode('utf-8'), x[0], x[1]),
                     file_sizes, files)

    if not check_files_mtime_correct(mod.parent_location, files_data):
        Logger.info(
            'Is_complete: Some files seem to have been modified in the meantime. Marking as not complete'
        )
        return False

    # (5) Check if there are no additional files in the directory
    # TODO: Check if these checksums are even needed now
    checksums = dict([(entry.path.decode('utf-8'), entry.filehash.to_bytes())
                      for entry in torrent_info.files()])
    files_list = checksums.keys()
    if not check_mod_directories(
            files_list, mod.parent_location, on_superfluous='warn'):
        Logger.info(
            'Is_complete: Superfluous files in mod directory. Marking as not complete'
        )
        return False

    if not are_ts_plugins_installed(mod.parent_location, files_list):
        Logger.info('Is_complete: TS plugin out of date or not installed.')
        return False

    return True