示例#1
0
文件: rs.py 项目: bookmine/reposeer
def loadlibgen(csvname):
    ''' Загружает в память csv-файл с базой Library Genesis и возвращает словарь,
    где ключ — md5-хеш файла (строка в нижнем регистре), а значение — кортеж (путь к файлу, размер файла) '''

    try:
        with open(csvname) as csvfile:
            # инициализируем прогрессбар
            pbar = ProgressBar(maxval=len(open(csvname).readlines()))
            csvfile.seek(0)

            data = csv.reader(csvfile, delimiter=',', quotechar='"')
            # определяем, есть ли в файле заголовок
            # формат csv: путь, размер, md5
            try:
                # пытаемся преобразовать размер к целому числа
                int(second(data.next()))
            except ValueError:
                # нашли заголовок, стоим уже на второй строке
                pass
            else:
                # заголовка нет, идём обратно
                csvfile.seek(0)

            print(u'Загружаем в память базу Library Genesis...')

            # заполняем словарь
            library = {}
            values = ((os.path.normpath(first(entry)), int(second(entry)), third(entry)) for entry in data)
            for name, size, md5 in values:
                library[md5.lower()] = (name, size)

                # если выводить прогресс на каждом шаге, получается очень медленно
                # поэтому будем обновляться каждый CSV_LOAD_DISPLAY_RATE'ый шаг
                if data.line_num % CSV_LOAD_DISPLAY_RATE == 0:
                    pbar.set(data.line_num)

            pbar.finish()
    except Exception as e:
        raise FatalError(u'Не удалось загрузить CSV-файл: {0!s}'.format(e))

    return library
示例#2
0
    def load(self, pbar_enabled):
        fobj = open(self.filename)
        pbar = ProgressBar(maxval=len(fobj.readlines()), enabled=pbar_enabled)
        fobj.seek(0)
        reader = csv.DictReader(fobj, fieldnames=self.fieldnames)

        # skip header
        header = reader.next()
        for fieldname in header:
            if fieldname != header[fieldname].lower():
                # header not found
                fobj.seek(0)
                break

        library = {}
        for entry in reader:
            library[entry['md5'].lower()] = (entry['filename'], int(entry['filesize']))
            if reader.line_num % PROGRESSBAR_UPDATE_INTERVAL == 0:
                pbar.set(reader.line_num)
        pbar.finish()
        fobj.close()
        return library
示例#3
0
文件: rs.py 项目: user135711/reposeer
def main():
    global config, log
    oparser = optparse.OptionParser(
        usage='%prog [options] <source> <destination>',
        version=APP_VERSION_STRING,
        prog=APP_SHORT_NAME)

    oparser.add_option('-n',
                       '--dry-run',
                       action='store_true',
                       dest='dry_run',
                       default=False,
                       help="don't perform write actions, just simulate")
    oparser.add_option('-v',
                       '--verbose',
                       action='store_true',
                       dest='verbose',
                       default=False,
                       help="show operations log")
    oparser.add_option('',
                       '--no-progressbar',
                       action='store_false',
                       dest='pbar',
                       default=True,
                       help="don't show progress bar")

    optgroup = optparse.OptionGroup(oparser, 'File handling options')
    optgroup.add_option('-m',
                        '--method',
                        dest='method',
                        default=M_COPY,
                        help='file processing method ({0})'.format('|'.join(
                            config.methods)))
    optgroup.add_option('-r',
                        '--remove-empty',
                        action='store_true',
                        dest='remove_empty',
                        default=False,
                        help='remove empty directories')
    optgroup.add_option('',
                        '--remove-duplicates',
                        action='store_true',
                        dest='remove_duplicates',
                        default=False,
                        help='remove files that already exist in repository')
    oparser.add_option_group(optgroup)

    optgroup = optparse.OptionGroup(oparser, 'CSV options')
    optgroup.add_option('',
                        '--csv',
                        dest='csv',
                        metavar='FILENAME',
                        default='libgen.csv',
                        help='path to csv (%default)')
    oparser.add_option_group(optgroup)

    optgroup = optparse.OptionGroup(oparser, "DB connection options")
    optgroup.add_option('',
                        '--db-host',
                        default='localhost',
                        help='DB host (%default)')
    optgroup.add_option('',
                        '--db-name',
                        default='bookwarrior',
                        help='DB name (%default)')
    optgroup.add_option('', '--db-user', help='DB user')
    optgroup.add_option('',
                        '--db-passwd',
                        metavar='PASSWD',
                        default='',
                        help='DB password (empty)')
    oparser.add_option_group(optgroup)

    (options, args) = oparser.parse_args()
    if len(args) != 2:
        oparser.error('Wrong number of arguments')
    if options.method not in config.methods:
        oparser.error(u'Unknown file processing method "{0}"'.format(
            options.method))
    if config.methods[options.method] is None:
        return error(config.get_error_message(options.method))

    config.src, config.dst = (os.path.abspath(arg).decode(config.encoding)
                              for arg in args)

    if not os.path.isdir(config.src):
        return error(u'Directory {0} not found'.format(config.src))
    if not os.path.isdir(config.dst):
        return error(u'Directory {0} not found'.format(config.dst))

    if not os.access(config.src, os.R_OK):
        return error(u'Not enough rights for reading from %s' % config.src)
    if ((options.remove_empty or options.remove_duplicates
         or options.method == M_MOVE) and not os.access(config.src, os.W_OK)):
        return error(u'Not enough rights for writing to %s' % config.src)
    if not os.access(config.dst, os.W_OK):
        return error(u'Not enough rights for writing to %s' % config.dst)

    # проверим, поддерживает ли файловая система создание ссылок
    # в Windows мягкие и жёсткие ссылки можно создавать только на NTFS
    # (жёсткие — только в пределах одного диска)
    if config.windows and options.method in (M_SYMLINK, M_HARDLINK):
        message = config.checkfs(options.method)
        if message:
            return error(message)

    if options.db_user:
        worker = loader.DBLoader(options.db_host, options.db_name,
                                 options.db_user, options.db_passwd)
    else:
        if not os.path.isfile(options.csv):
            return error(u'File {0} not found'.format(options.csv))
        worker = loader.CSVLoader(options.csv)

    print('Loading Library Genesis...')
    library = worker.load(options.pbar)
    library_filesizes = set(value[1] for value in library.values())
    print('{0} books loaded'.format(len(library)))

    print('Analyzing total size of files for processing...', end=' ')
    src_size = dirsize(config.src)
    print(bytes_to_human(src_size))
    print('Scanning...')

    processed, added, duplicate = ProgressCounter(), ProgressCounter(
    ), ProgressCounter()
    pbar = ProgressBar(maxval=src_size, displaysize=True, enabled=options.pbar)
    log.set_pbar(pbar)
    delta = src_size / CHECK_PROGRESS_DIVIDER
    for path, dirs, files in os.walk(config.src):
        for file in files:
            fullpath = os.path.join(path, file)
            filesize = os.path.getsize(fullpath)

            # если в базе есть файл такого размера
            if filesize in library_filesizes:
                md5 = md5hash(fullpath)
                # и совпал по хешу
                if md5 in library:
                    # то обрабатываем его
                    already_in_repo = process(fullpath, library[md5][0],
                                              options)
                    if already_in_repo:
                        duplicate.add(filesize)
                    else:
                        added.add(filesize)

            processed.add(filesize)
            # будем обновлять, только если накопилось достаточно файлов
            if processed.size - pbar.curval >= delta:
                pbar.set(processed.size)
        if not options.dry_run and options.remove_empty and dirsize(path) == 0:
            shutil.rmtree(path)

    pbar.finish()
    log.unset_pbar()

    print('Processed: {0} ({1})'.format(processed.count,
                                        bytes_to_human(processed.size)))
    print('Added to repository ({0}): {1} ({2})'.format(
        config.method_descriptions[options.method], added.count,
        bytes_to_human(added.size)))
    print('Duplicates {0}: {1} ({2})'.format(
        'removed' if options.remove_duplicates else 'found', duplicate.count,
        bytes_to_human(duplicate.size)))

    return 0
示例#4
0
文件: ddcp.py 项目: ShadowPrince/ddcp
 def __init__(self, cmdo):
     self.pbar = ProgressBar(BAR_COLOR, block=BAR_CHAR_FULL, empty=BAR_CHAR_EMPTY, width=BAR_WIDTH)
     self.cmdo = cmdo
     self.tmp = {}
     self.tmp['speed'] = ['', '']
示例#5
0
文件: ddcp.py 项目: ShadowPrince/ddcp
class DDOutput:
    def __init__(self, cmdo):
        self.pbar = ProgressBar(BAR_COLOR, block=BAR_CHAR_FULL, empty=BAR_CHAR_EMPTY, width=BAR_WIDTH)
        self.cmdo = cmdo
        self.tmp = {}
        self.tmp['speed'] = ['', '']
    
    """
    Update progress
    """
    def put(self, **kwargs):
        if kwargs.get('f') and kwargs.get('state') == 'ft_finished':
            self.tmp['speed'] = kwargs.get('f').speed

        if self.cmdo.quiet:
            pass
        elif self.cmdo.verbose:
            self.put_verbose(*kwargs.values())
        else:
            if self.cmdo.detailed:
                self.put_bar_extended(*kwargs.values())
            else:
                self.put_bar(*kwargs.values())

    """
    Print -v(erbose) 
    """
    def put_verbose(self, state, task, instance, counter):
        print '{c}/{ca} {state} \'{from_path}\' \'{to_path}\' {speed}'.format(
            c=counter+1,
            ca=task.count(),
            state=state,
            from_path=instance.from_path,
            to_path=instance.to_path,
            speed=''.join(self.tmp['speed'])
        )

    """
    Print bar
    """
    def put_bar(self, state, task, instance, counter):
        counter = counter+(state == 'ft_finished' and 1 or 0)
        percent = int(float(counter)/task.count()*100)

        self.pbar.render(percent, '100%\n[{c}/{ca}] {state} {f}'.format(
            c=counter,
            ca=task.count(),
            f=instance.file(),
            state=(state == 'ft_finished' and 'Finished' or 'Copying')
        ))

    """
    Print -d(etailed) bar
    """
    def put_bar_extended(self, state, task, instance, counter):
        counter = counter+(state == 'ft_finished' and 1 or 0)
        percent = int(float(counter)/task.count()*100)

        self.pbar.render(percent, '100%\n[{c}/{ca}] {speed} {state} {basepath}/{f}'.format(
            c=counter,
            ca=task.count(),
            f=instance.file(),
            state=(state == 'ft_finished' and 'Finished' or 'Copying'),
            basepath=instance.base_path,
            speed=''.join(self.tmp['speed']),
        ))

    """
    Called when task finished, sends notify 
    """
    def finished(self, task):
        if not self.cmdo.quiet:
            os.system('notify-send %s' % quote('ddcp finished task (%s)' % task.count()))
示例#6
0
文件: rs.py 项目: bookmine/reposeer
def main(argv):

    # инициализируем парсер опций командной строки
    parser_usage = u'%prog [опции] <источник> <приёмник>'
    parser = OptionParser(parser_usage, version=APP_VERSION_STRING, prog=APP_SHORT_NAME,
        formatter=OptionFormatter(APP_VERSION, APP_LONG_NAME), add_help_option=False)
    parser.disable_interspersed_args()

    def usage():
        # временное решение (пока нету gettext)
        print(parser.format_help()[:-1].replace('Options', u'Опции'))
        return 0

    parser.add_option('-h', '--help', action='store_true', dest='help', default=False,
        help=u'показать это сообщение и выйти')
    parser.add_option('-c', '--csv', dest='filename', default='libgen.csv', help=u'путь к CSV-файлу')
    parser.add_option('-m', '--method', dest='method', default=M_COPY,
        help=u'метод обработки файлов (' + u'|'.join(config.methods.keys()) + ')')
    parser.add_option('-r', '--remove-empty', action='store_true', dest='remove_empty', default=False,
        help=u'удалять пустые обработанные каталоги')

    try:
        (options, args) = parser.parse_args()
    except OptionError as e:
        return error(e.msg)

    if empty(args) or options.help:
        return usage()
    if len(args) != 2:
        return error(u'Количество аргументов не равно двум (источник и приёмник)')

    if options.method not in config.methods:
        return error(u'Неверный аргумент у опции --method')
    if config.methods[options.method] is None:
        return error(config.method_errors[options.method])

    # источник и приёмник
    config.source = os.path.abspath(first(args)).decode(config.encoding)
    config.dest = os.path.abspath(second(args)).decode(config.encoding)

    # проверим, поддерживает ли файловая система создание ссылок
    # в Windows мягкие и жёсткие ссылки можно создавать только на NTFS
    # (жёсткие — только в пределах одного диска) 
    if config.windows and options.method in (M_SYMLINK, M_HARDLINK):
        try:
            config.checkfs(options.method)
        except FatalError as e:
            return error(e.msg)

    # проверяем, все ли пути существуют
    if not os.path.isfile(options.filename):
        return error(u'CSV-файл {0} не найден'.format(options.filename))
    if not os.path.isdir(config.source):
        return error(u'Директория {0} не найдена'.format(config.source))
    if not os.path.isdir(config.dest):
        return error(u'Директория {0} не найдена'.format(config.dest))

    if not os.access(config.source, os.R_OK):
        return error(u'Недостаточно привилегий для чтения из ' + config.source)
    if (options.method == M_MOVE or options.remove_empty) and not os.access(config.source, os.W_OK):
        return error(u'Недостаточно привилегий для записи в ' + config.source)
    if not os.access(config.dest, os.W_OK):
        return error(u'Недостаточно привилегий для записи в ' + config.dest)

    try:
        # загружаем базу
        library = loadlibgen(options.filename) # library[md5] == (filename, size)
        libsizes = set(second(value) for value in library.values())

        print(u'Оцениваем общий размер анализируемых файлов...')
        source_size = dirsize(config.source)
        print(bytes_to_human(source_size))

        def process(source, dest):
            ''' Обрабатываем (копируем, перемещаем и т.д.) файл '''
            errmsg = u'Ошибка при обработке файла {0}'.format(source) + u': {0!s}'
            try:
                source = os.path.join(config.source, source)
                dest = os.path.join(config.dest, dest)

                # если такой директории ещё нет, то создадим
                if not os.path.isdir(os.path.dirname(dest)):
                    os.makedirs(os.path.dirname(dest))
                
                duplicate = os.path.isfile(dest)
                if not duplicate:
                    try:
                        config.methods[options.method](source, dest)
                    except OSError as e:
                        raise FatalError(errmsg.format(e))
            except IOError as e:
               raise FatalError(errmsg.format(e))
            return duplicate

        def remove_if_empty(path):
            if options.remove_empty and dirsize(path) == 0:
                shutil.rmtree(path)

        print(u'Обрабатываем...')

        class ProgressCounter(object):
            def __init__(self):
                self.count, self.size = 0, 0

        processed, added, duplicate = ProgressCounter(), ProgressCounter(), ProgressCounter()

        # инициализируем индикатор прогресса
        pbar = ProgressBar(maxval=source_size, displaysize=True, width=40)
        delta = source_size / CHECK_PROGRESS_DIVIDER

        for path, dirs, files in os.walk(config.source):
            for file in files:
                fullpath = os.path.join(path, file)
                filesize = os.path.getsize(fullpath)

                # если в базе есть файл такого размера
                if filesize in libsizes:
                    md5 = md5hash(fullpath)
                    # и совпал по хешу
                    if md5 in library:
                        # то обрабатываем его
                        isduplicate = process(fullpath, first(library[md5]))
                        if isduplicate:
                            duplicate.count += 1
                            duplicate.size += filesize
                        else:
                            added.count += 1
                            added.size += filesize

                processed.count += 1
                processed.size += filesize

                # будем обновлять, только если накопилось достаточно файлов
                if processed.size - pbar.curval >= delta:
                    pbar.set(processed.size)
        
            remove_if_empty(path)
    
        remove_if_empty(config.source)
        pbar.finish()

    except FatalError as e:
        return error(e.msg)

    print(u'Обработано: {0} ({1})'.format(processed.count, bytes_to_human(processed.size)))
    print(u'Добавлено в репозиторий ({0}): {1} ({2})'.format(
        config.method_descriptions[options.method], added.count, bytes_to_human(added.size)))
    print(u'Пропущено дублей при добавлении: {0} ({1})'.format(duplicate.count, bytes_to_human(duplicate.size)))

    return 0
示例#7
0
文件: ljrss.py 项目: twigil/ljrss
def main(argv):
    if len(argv) > 3:
        return error('ljrss.py <lj-username> <password> [filename]')
    config.user, config.password = argv[0], argv[1]
    config.filename = argv[2] if len(argv) == 3 else 'lj_mutual.xml'

    print('Getting the list of mutual friends...')
    try:
        livejournal = lj.LJServer('lj.py; [email protected]', 'Python-PyLJ/0.0.1')
        livejournal.login(config.user, config.password)
        
        def getusernames(response):
            return (item['username'] for item in response)
        
        friendof = getusernames(livejournal.friendof()['friendofs'])
        friends = getusernames(livejournal.getfriends()['friends'])
        mutualfriends = list(set(friendof) & set(friends))
    except lj.LJException as e:
        return error(e)
    print('User {0} has {1} mutual friends'.format(config.user, len(mutualfriends)))

    browser = mechanize.Browser()
    
    def getrssurl(url):
        browser.open(FMF_URL)
        browser.select_form(nr=FMF_FORM_ID)
        browser['url'] = url
        browser['user'] = config.user
        browser['pass'] = config.password
        response = browser.submit()
    
        url_re = r'\<p id="viewrss"\>\<a href="(.*)" onclick.*\<\/p\>'
        return re.search(url_re, response.read()).group(1)

    data = ((username, getrssurl(LJ_RSS_URL.format(username))) for username in mutualfriends)

    document = xml.dom.minidom.Document()
    opml = document.createElement('opml')
    opml.setAttribute('version', '1.1')
    document.appendChild(opml)
    body = document.createElement('body')
    opml.appendChild(body)
    folder = document.createElement('outline')
    folder.setAttribute('text', 'lj_mutual')
    body.appendChild(folder)

    print('Working with FreeMyFeed...')
    progressbar = ProgressBar(maxval=len(mutualfriends))
    for username, url in data:
        entry = document.createElement('outline')
        entry.setAttribute('title', username)
        entry.setAttribute('text', username)
        entry.setAttribute('xmlUrl', url)
        folder.appendChild(entry)
        progressbar.update(1)
    progressbar.finish()

    print('Creating OPML-file...')
    with open(config.filename, 'w') as opmlfile:
        opmlfile.write(document.toprettyxml(indent=' ' * 2))
    
    return 0
示例#8
0
文件: rs.py 项目: refaim/reposeer
def main():
    global config, log
    oparser = optparse.OptionParser(
        usage='%prog [options] <source> <destination>',
        version=APP_VERSION_STRING,
        prog=APP_SHORT_NAME)

    oparser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', default=False,
        help="don't perform write actions, just simulate")
    oparser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
        help="show operations log")
    oparser.add_option('', '--no-progressbar', action='store_false', dest='pbar', default=True,
        help="don't show progress bar")

    optgroup = optparse.OptionGroup(oparser, 'File handling options')
    optgroup.add_option('-m', '--method', dest='method', default=M_COPY,
        help='file processing method ({0})'.format('|'.join(config.methods)))
    optgroup.add_option('-r', '--remove-empty', action='store_true',
        dest='remove_empty', default=False, help='remove empty directories')
    optgroup.add_option('', '--remove-duplicates', action='store_true',
        dest='remove_duplicates', default=False,
        help='remove files that already exist in repository')
    oparser.add_option_group(optgroup)

    optgroup = optparse.OptionGroup(oparser, 'CSV options')
    optgroup.add_option('', '--csv', dest='csv', metavar='FILENAME', default='libgen.csv',
        help='path to csv (%default)')
    oparser.add_option_group(optgroup)

    optgroup = optparse.OptionGroup(oparser, "DB connection options")
    optgroup.add_option('', '--db-host', default='localhost', help='DB host (%default)')
    optgroup.add_option('', '--db-name', default='bookwarrior', help='DB name (%default)')
    optgroup.add_option('', '--db-user', help='DB user')
    optgroup.add_option('', '--db-passwd', metavar='PASSWD', default='', help='DB password (empty)')
    oparser.add_option_group(optgroup)

    (options, args) = oparser.parse_args()
    if len(args) != 2:
        oparser.error('Wrong number of arguments')
    if options.method not in config.methods:
        oparser.error(u'Unknown file processing method "{0}"'.format(options.method))
    if config.methods[options.method] is None:
        return error(config.get_error_message(options.method))

    config.src, config.dst = (os.path.abspath(arg).decode(config.encoding)
        for arg in args)

    if not os.path.isdir(config.src):
        return error(u'Directory {0} not found'.format(config.src))
    if not os.path.isdir(config.dst):
        return error(u'Directory {0} not found'.format(config.dst))

    if not os.access(config.src, os.R_OK):
        return error(u'Not enough rights for reading from %s' % config.src)
    if ((options.remove_empty or options.remove_duplicates or options.method == M_MOVE)
        and not os.access(config.src, os.W_OK)
    ):
        return error(u'Not enough rights for writing to %s' % config.src)
    if not os.access(config.dst, os.W_OK):
        return error(u'Not enough rights for writing to %s' % config.dst)

    # проверим, поддерживает ли файловая система создание ссылок
    # в Windows мягкие и жёсткие ссылки можно создавать только на NTFS
    # (жёсткие — только в пределах одного диска)
    if config.windows and options.method in (M_SYMLINK, M_HARDLINK):
        message = config.checkfs(options.method)
        if message:
            return error(message)

    if options.db_user:
        worker = loader.DBLoader(options.db_host, options.db_name, options.db_user, options.db_passwd)
    else:
        if not os.path.isfile(options.csv):
            return error(u'File {0} not found'.format(options.csv))
        worker = loader.CSVLoader(options.csv)

    print('Loading Library Genesis...')
    library = worker.load(options.pbar)
    library_filesizes = set(value[1] for value in library.values())
    print('{0} books loaded'.format(len(library)))

    print('Analyzing total size of files for processing...', end=' ')
    src_size = dirsize(config.src)
    print(bytes_to_human(src_size))
    print('Scanning...')

    processed, added, duplicate = ProgressCounter(), ProgressCounter(), ProgressCounter()
    pbar = ProgressBar(maxval=src_size, displaysize=True, enabled=options.pbar)
    log.set_pbar(pbar)
    delta = src_size / CHECK_PROGRESS_DIVIDER
    for path, dirs, files in os.walk(config.src):
        for file in files:
            fullpath = os.path.join(path, file)
            filesize = os.path.getsize(fullpath)

            # если в базе есть файл такого размера
            if filesize in library_filesizes:
                md5 = md5hash(fullpath)
                # и совпал по хешу
                if md5 in library:
                    # то обрабатываем его
                    already_in_repo = process(fullpath, library[md5][0], options)
                    if already_in_repo:
                        duplicate.add(filesize)
                    else:
                        added.add(filesize)

            processed.add(filesize)
            # будем обновлять, только если накопилось достаточно файлов
            if processed.size - pbar.curval >= delta:
                pbar.set(processed.size)
        if not options.dry_run and options.remove_empty and dirsize(path) == 0:
            shutil.rmtree(path)

    pbar.finish()
    log.unset_pbar()

    print('Processed: {0} ({1})'.format(
        processed.count, bytes_to_human(processed.size)))
    print('Added to repository ({0}): {1} ({2})'.format(
        config.method_descriptions[options.method], added.count, bytes_to_human(added.size)))
    print('Duplicates {0}: {1} ({2})'.format(
        'removed' if options.remove_duplicates else 'found',
        duplicate.count, bytes_to_human(duplicate.size)))

    return 0