Переименование скачанных файлов с rutracker.org

в 5:26, , рубрики: python, torrent, Программирование, метки:

Хочу поделиться небольшим скриптом, который делает для меня простую, но весьма полезную вещь — производит групповое переименование скачанных файлов так, что файлы получают удобно читаемое имя со страницы на сайте торрент трекера.
В итоге вместо "God.Bless.America.2011.HDTVRiP720.mkv" я получаю файл с именем "Боже, Благослови Америку God Bless America (Боб Голдтуэйт Bobcat Goldthwait) (2011) США, триллер, чёрная комедия, криминал, HDTVRip-AVC.mkv"
В продолжение к теме Можно ли прибраться на компе раз и навсегда?

В общем вот что делает скрипт: производит поиск по каталогу Downloads, ищет скачанные файлы и соответствующие им .torrent файлы. Затем берет из .torrent файла URL странички на rutracker.org, загружает эту страничку и получает название закачки. Затем, на основании полученного текста, скрипт и переименовывает скачанный файл.

Для успешной работы скрипта понадобится Python 2.7 и uTorrent клиент с небольшой настройкой:
Prefferences -> Other -> Store .torrent files in:
Здесь необходимо указать каталог, куда uTorrent будет копировать .torrent файлы. Дел в том, что uTorrent, при копировании .torrent файлов в этот каталог, дает им такое-же имя как и скачиваемый файл. Чем я собственно и воспользовался.
В скрипте этот каталог необходимо указать как TORRENT_TORRENT_DIR.

Также необходимо прописать каталог, где скрипт будет искать и переименовывать скачанные файлы, см. переменную TORRENT_COMPLETED_DIR.

# coding=UTF-8
import os
import re
import urllib2
import shutil

TORRENT_COMPLETED_DIR = u'D:/Загрузки'
TORRENT_TORRENT_DIR = u'D:/Загрузки/uTorrent/torrent'

def Print(toPrint):
    toPrint = unicode(toPrint)
    toPrint = toPrint.encode('cp866', 'replace')
    print toPrint

def GetTorrentFilePath(sFileName):
    sFileName = unicode(sFileName)
    sFilePath = os.path.join(TORRENT_TORRENT_DIR, sFileName + u'.torrent')
    if not os.path.exists(sFilePath):
        Print(u'Skiped, .torrent is not found: "%s' % sFilePath)
        return None
    return sFilePath

def GetTrackerUrl(sTorrentFilePath):
    sTorrentFilePath = unicode(sTorrentFilePath)
    try:
        aTorrentFile = open(sTorrentFilePath, 'r')
        sFileData = aTorrentFile.read()
        sTrackerUrlLen, sTrackerUrl = re.search(r'comment([0-9]{2}):(.+)', sFileData).groups()
        sTrackerUrl = re.search(r'(.{' + sTrackerUrlLen + '})', sTrackerUrl).groups()[0]
        return sTrackerUrl
    except:
        Print(u"Error, can't extract tracker url from .torrent file %s" % sTorrentFilePath)
        return None

def LoadTrackerPage(sTrackerUrl):
    try:
        response = urllib2.urlopen(sTrackerUrl)
        sHtmlPage = response.read()
    except:
        Print(u"Error, Can't load tracker page '%s'" % sTrackerUrl)
        return None
    sHtmlPage = unicode(sHtmlPage, "cp1251")
    return sHtmlPage

def PrepareFileName(sFileName):
    sFileName = unicode(sFileName)
    try:
        #remove special symbols
        sFileName = re.sub(ur'[\/:"*?<>|]+', '', sFileName, 0, re.UNICODE)
        #remove repeating spaces
        sFileName = re.sub(ur'[ ]+', ' ', sFileName, 0, re.UNICODE)
        sFileName = sFileName.strip()
    except:
        Print(u"Error, can't prepare file name '%s'" % sFileName)
        return None
    return sFileName

class FileInfo:
    pass

def ParseTrackerPage(sHtmlPage):
    sHtmlPage = unicode(sHtmlPage)
    try:
        sPageTitle = re.search(r'<title>(.+?) :: .+?</title>', sHtmlPage, re.UNICODE).groups()[0]
    except:
        Print(u"Error, Can't parse <title>")
        return None
    file_info = FileInfo()
    file_info.name = u""
    file_info.year = u""
    file_info.descr = u""
    try:
        file_info.name, file_info.year, file_info.descr = re.search(ur'(.+?) [([0-9]{4}).*?, (.+?)]', sPageTitle, re.UNICODE).groups()
    except:
        Print(u"Warning, Can't parse page title: %s" % sPageTitle)
        try:
            file_info.name, file_info.year, file_info.descr = re.search(ur'(.+?)([0-9]{4}).*?, (.+?)$', sPageTitle, re.UNICODE).groups()
        except:
            Print(u"Warning, Can't parse page title: %s" % sPageTitle)
            file_info.name = sPageTitle
    file_info.name = unicode(file_info.name)
    file_info.year = unicode(file_info.year)
    file_info.descr = unicode(file_info.descr)
    return file_info

def GetDataFromTorrent(sFileName):
    sTorrentFilePath = GetTorrentFilePath(sFileName)
    if not sTorrentFilePath:
        return None
    sTrackerUrl = GetTrackerUrl(sTorrentFilePath)
    if not sTrackerUrl:
        return None
    sHtmlPage = LoadTrackerPage(sTrackerUrl)
    if not sHtmlPage:
        return None
    return ParseTrackerPage(sHtmlPage)

def PrepareNewFileName(fileName, file_info):
    fileName = unicode(fileName)
    tmp, ext = os.path.splitext(fileName)
    toPrepare = file_info.name + u' (' + file_info.year + u') ' + file_info.descr
    toPrepare = unicode(toPrepare)
    cleanName = PrepareFileName(toPrepare)
    newFileName = cleanName + ext
    return newFileName
    
def main():
    Print(u'Hello, Find downloads in "%s" :' % TORRENT_COMPLETED_DIR)
    total = 0
    renamed = 0
    for sFileName in os.listdir(TORRENT_COMPLETED_DIR):
        total = total + 1
        unicode(sFileName)
        Print(u'Process a file: "%s"' % sFileName)
        file_info = GetDataFromTorrent(sFileName)
        if file_info is None:
            continue
        sNewFileName = PrepareNewFileName(sFileName, file_info)                         
        if sNewFileName:
            sOldFilePath = unicode(os.path.join(TORRENT_COMPLETED_DIR, sFileName))
            sNewFilePath = unicode(os.path.join(TORRENT_COMPLETED_DIR, sNewFileName))
            try:
                shutil.move(sOldFilePath, sNewFilePath)
                renamed = renamed + 1
            except:
                Print(u"Error, Can't rename %s to %s" % (sOldFilePath, sNewFilePath))
    Print(u"%d friles were renamed from %d total found files" % (renamed, total))

if __name__ == "__main__":
    main()

Работа скрипта проверялась на Windows 7 x86 и Windows 7 x64
В теории скрипт может заработать под Linux, но у меня на этот счет есть сомнения.

Скрипт заточен под rutracker, но возможно будет работать и с другими сайтами.
По крайней мере после доработки напильником.

Для скачивания html странички я использовал библиотеку urllib2.
А для парсинга .torrent файлов и html я использовал регулярные выражения.
Оказалось, что на Python их использовать весьма удобно.
В принципи для парсинга html лучше было бы использовать css селекторы, но пока и так сойдет.

Конструкцию следующего типа

fileName = unicode(fileName)

я использовал для отладки, когда столкнулся с проблемой, когда создается не юникодная строчка с юникодными символоами и после этого программа начинает падать в непонятных местах. Эту проблему похоже исправили в Python 3.

Так как Python это не мой основной язык, то буду рад советам опытных разработчиков.

Автор: Ryadovoy


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js