1

Rewrite as standard Python CLI app and more

Now this app supports configuration via lib/config.py. No more
hardcode!

Now torrent files sorted by last moderator check date, and torrents
that haven't been checked will be skipped with log message.
This commit is contained in:
Valdos Sine 2014-12-26 23:08:52 +04:00 committed by Vladimir Hodakov
parent 795d7846bf
commit d391c3ddea
3 changed files with 118 additions and 72 deletions

10
lib/config.py.example Executable file
View File

@ -0,0 +1,10 @@
# user editable values
username = 'username'
password = 'password'
# system values, edit at your own risk
domain = 'http://nnm-club.me'

49
lib/messages.py Executable file
View File

@ -0,0 +1,49 @@
# *-* encoding: utf-8 *-*
"""
Note, all script messages must be formatted as:
[status] #status_number: message
where:
status: "I" = information, "W" - warning, "E" - error.
status_number - error number:
0xx -- script environment messages
1xx -- authentication messages
2xx -- grabbing and parsing messages
3xx -- torrents downloading messages
4xx -- torrents check messages
Last message in log must be ended with "Stopped" word.
Information code numbers starts from x00, success messages from x20, warnings from x40 and errors from x66. Console messages have same numbers starting from prefix c. Log messages start from prefix m
"""
c000 = "massdl.sh — скрипт для пакетной загрузки торрент-файлов из разделов NNM-club.ru.\nИспользование:\n\n\tpython massdl.py [номер_раздела]\n\nгде [номерорума] — номер раздела на NNM-club.ru (например, для форума '*Nix Игры' это 316).\nПримеры:\n\n\tpython massdl.py 316 — скачивание форума '*Nix Игры'\n\tpython massdl.py 332 — скачивание форума 'Русский рок'\n\nАвтор: Valdos 'fat0troll' Sine.\nСкрипт использует Python версии 2.7. При запуске убедитесь, что используете правильный интерпретатор Python!\nКонфигурация скрипта производится в конфигурационном файле lib/config.py, имеющем опции с очевидными названиями.\nВерсия %s\n"
c010 = "Выполняется скрипт %s.\nВерсия скрипта %s."
c020 = "Параметры командной строки: %s"
c021 = "Скрипт завершен успешно."
c066 = "Ваша версия Python не поддерживается. Используйте Python 2.7!"
c067 = "У вас не установлен PycURL. Обратитесь к справке вашего дистрибутива для подробностей, как его установить."
c120 = "Вы залогинились успешно как пользователь %s."
c166 = "Не удалось залогиниться как пользователь %s. Проверьте ваши данные в файле lib/config.py!"
c200 = "Начинается загрузка форума..."
c210 = "Скачиваем страницу %s..."
c220 = "Скачиваем форум %s"
c221 = "Скачивание страниц завершено. Найдено топиков: %s."
c300 = "Начинаем загрузку торрентов..."
c310 = "Скачиваю топик %s/%s: %s (обновлён %s)."
c340 = "Топик %s/%s: %s не проверен модератором. Пропускается."
m000 = '================================================================================\n= Скрипт скачки раздела NNM-Club для Linux и Unix-like ОС. =\n= Версия: %s =\n================================================================================\n'
m020 = "[I] #020: окружение скрипта в порядке.\n"
m021 = "[I] #021: работа завершена успешно. Завершено.\n"
m025 = "[I] #100: пытаемся войти на %s...\n"
m066 = "[E] #066: версия Python не поддерживается. Завершено.\n"
m067 = "[E] #067: не установлен cURL. Завершено\n"
m120 = "[I] #120: выполнен успешный вход на сайт. Cookie лежит по адресу %s.\n"
m166 = "[E] #166: неправильное имя пользователя или пароль. Завершено.\n"
m210 = "[I] #200: загружаем страницу %s..."
m220 = "[I] #220: успешно загружена стартовая страница форума '%s'.\n"
m221 = "[I] #221: успешно загружены все страницы форума. Найдено топиков: %s.\n"
m310 = "[I] #310 загружаем торрент %s из %s по ссылке %s.\n"
m340 = "[W] #340 топик %s из %s [%s, %s] не проверен модераторами. Пропуск.\n"

131
massdl.py Normal file → Executable file
View File

@ -1,90 +1,76 @@
# *-* encoding: utf-8 *-*
# For NNM-Club Uploaders
# Copyright (c) 2012-2013 Valdos Sine <iam@toofat.ru>
# Copyright (c) 2012-2014 Valdos Sine <iam@toofat.ru>
#
# Usage:
#
# python2 ./massdl.py [user] [forum_number]
# python2 ./massdl.py [forum_number]
#
# For getting help, execute "python2 ./massdl.py" without params
import time, tempfile, os, sys, commands
version = 0.61
import lib.config as uconfig
import lib.messages as umessages
import dateutil
from dateutil.parser import *
version = 0.80
unixtime = int(time.time())
cookie = tempfile.mkstemp()
curdir = os.getcwd()
log_file = "/%i-massdl.log" % unixtime
# Anti-Zapret
domain = "http://nnm-club.me"
domain = uconfig.domain
def write_to_log(imessage):
"""
Note, all script messages must be formatted as:
[status] #status_number: message
where:
status: "I" = information, "W" - warning, "E" - error.
status_number - error number:
0xx -- script environment messages
1xx -- authentication messages
2xx -- grabbing and parsing messages
3xx -- torrents downloading messages
4xx -- torrents check messages
Last message in log must be ended with "Stopped" word.
Information starts from x00, success messages from x20, warnings from x40 and errors from x66.
"""
log = open(curdir + log_file, 'a')
log.write(imessage)
log.close()
def cnsl_message(imessage, *args):
if imessage == "invpyver":
print "Ваша версия Python не поддерживается. Используйте Python 2.7!"
write_to_log("[E] #066: версия Python не поддерживается. Завершено.\n")
print umessages.c066
write_to_log(umessages.m066)
sys.exit(666)
elif imessage == "nocurl":
print "У вас не установлен PycURL. Обратитесь к справке вашего дистрибутива для подробностей, как его установить."
write_to_log("[E] #067: не установлен cURL. Завершено\n")
print umessages.c067
write_to_log(umessages.m067)
sys.exit(666)
elif imessage == "help":
print "massdl.sh — скрипт для пакетной загрузки торрент-файлов из разделов NNM-club.ru.\nИспользование:\n\n\tpython massdl.py [режим] [номер_раздела]\n\nгде [режим] это режим загрузки (от имени пользователя, указанного в конфигурации скрипта — значение user, или же от имени фрилич-пользователя — значение freeleech), аомерорума] — номер раздела на NNM-club.ru (например, для форума '*Nix Игры' это 316).\nПримеры:\n\n\tpython massdl.py freeleech 316 — скачивание форума '*Nix Игры' от фрилич-пользователя\n\tpython massdl.py user 332 — скачивание форума 'Русский рок' от собственного, указанного в скрипте, имени\n\nАвтор: Valdos 'fat0troll' Sine.\nСкрипт использует Python версии 2.7. При запуске убедитесь, что используете правильный интерпретатор Python!\nВерсия %s\n" % version
print umessages.c000 % version
sys.exit(0)
elif imessage == "start":
print "Выполняется скрипт %s.\nВерсия скрипта %s." % (sys.argv[0], version)
print "Параметры командной строки: %s %s" % (sys.argv[1], sys.argv[2])
write_to_log("[I] #020: окружение скрипта в порядке.\n")
print umessages.c010 % (sys.argv[0], version)
print umessages.c020 % sys.argv[1]
write_to_log(umessages.m020)
elif imessage == "login_ok":
print "Вы залогинились успешно как пользователь %s." % set_username()[0]
write_to_log("[I] #120: выполнен успешный вход на сайт. Cookie лежит по адресу %s.\n" % cookie[1])
print umessages.c120 % set_username()[0]
write_to_log(umessages.m120 % cookie[1])
elif imessage == "login_failed":
print "Не удалось залогиниться как пользователь %s. Проверьте ваши данные внутри скрипта!" % set_username()[0]
write_to_log("[E] #166: неправильное имя пользователя или пароль. Завершено.\n")
print umessages.c166 % set_username()[0]
write_to_log(umessages.m166)
sys.exit(666)
elif imessage == "parsing_started":
print "Начинается загрузка форума..."
print umessages.c200
elif imessage == "forum":
print "Скачиваем форум " + args[0]
write_to_log('[I] #220: успешно загружена стартовая страница форума "%s".\n' % args[0])
print umessages.c220 % args[0]
write_to_log(umessages.m220 % args[0])
elif imessage == "pages":
print "Скачиваем страницу " + args[0]
write_to_log('[I] #200: загружаем страницу ' + args[0] + '...\n')
print umessages.c210 % args[0]
write_to_log(umessages.m210 % args[0])
elif imessage == "found_topics":
print "Скачивание страниц завершено. Найдено топиков: " + args[0] + "."
write_to_log('[I] #221: успешно загружены все страницы форума. Найдено топиков: ' + args[0] + '.\n')
print umessages.c221 % args[0]
write_to_log(umessages.m221 % args[0])
elif imessage == "download_started":
print "Начинаем загрузку торрентов..."
print umessages.c300
elif imessage == "downloading_torrent":
print "Скачиваю топик " + args[0] + "/" + args[1] + ": " + args[2] + "."
write_to_log("[I] #300 загружаем торрент " + args[0] + " из " + args[1] + " по ссылке " + args[3] + ".\n")
print umessages.c310 % (args[0], args[1], args[2], args[4])
write_to_log(umessages.m310 % (args[0], args[1], args[3]))
elif imessage == "skip_non_approved":
print umessages.c340 % (args[0], args[1], args[2])
write_to_log(umessages.m340 % (args[0], args[1], args[2], args[3]))
elif imessage == "done":
print "Скрипт завершен успешно."
write_to_log("[I] #021: работа завершена успешно. Завершено.\n")
print umessages.c021
write_to_log(umessages.m021)
sys.exit(0)
def check_requirements():
@ -108,36 +94,27 @@ def check_requirements():
def check_params(params):
"""
Checking script parameters: if there is less or more than 2 params -- show help. If there's 2 params: check it's consistency!
Checking script parameters: if there is less or more than one param -- show help. If there's one param: check ones consistency!
"""
if len(params) != 3:
if len(params) != 2:
cnsl_message("help")
else:
if params[1] in ["freeleech", "user"]:
if str(params[2]).isdigit():
pass;
else:
cnsl_message("help")
if str(params[1]).isdigit():
pass;
else:
cnsl_message("help")
def start_log():
log = open(curdir + log_file, 'w')
log.write('================================================================================\n= Скрипт скачки раздела NNM-Club для Linux и Unix-like ОС. =\n= Версия: %s =\n================================================================================\n' % version)
log.write(umessages.m000 % version)
log.close()
def set_username():
if sys.argv[1] == "freeleech":
username = "freeleech_user"
password = "freeleech_password"
else:
username = "username"
password = "password"
return (username, password)
return (uconfig.username, uconfig.password)
def connect():
cookiefile = open(cookie[1], 'r+w')
write_to_log("[I] #100: пытаемся войти на " + domain + "...\n")
write_to_log(umessages.m025 % domain)
cookie_txt = commands.getoutput('curl -c - -d "username=' + set_username()[0] + '&password=' + set_username()[1] + '&autologin=on&login=%C2%F5%EE%E4&redirect=index.php" "' + domain + '/forum/login.php" 2>>' + curdir + log_file )
if cookie_txt.find("Cookie") != -1:
# If it's -1, then there is no cookie!
@ -153,7 +130,7 @@ def iteratorium(links_array, offset):
Links array -- array with links to topics containing torrents. Offset -- load parameter (for pages)
"""
cnsl_message("pages", str((offset / 50) + 1))
forum_page = commands.getoutput('curl -b ' + cookie[1] + ' "' + domain + '/forum/viewforum.php?f=' + sys.argv[2] + '&start=' + str(offset) + '" | iconv -f cp1251 -t utf-8')
forum_page = commands.getoutput('curl -b ' + cookie[1] + ' "' + domain + '/forum/viewforum.php?f=' + sys.argv[1] + '&start=' + str(offset) + '" | iconv -f cp1251 -t utf-8')
for line in forum_page.splitlines():
if 'viewtopic.php' in line:
if 'DL:' in line:
@ -181,7 +158,7 @@ def download():
"""
# Firstly, we need to download forum's startpage
cnsl_message("parsing_started")
startpage = commands.getoutput('curl -b ' + cookie[1] + ' ' + domain + '/forum/viewforum.php?f=' + sys.argv[2] + ' | iconv -f cp1251 -t utf-8')
startpage = commands.getoutput('curl -b ' + cookie[1] + ' ' + domain + '/forum/viewforum.php?f=' + sys.argv[1] + ' | iconv -f cp1251 -t utf-8')
# Finding forum name :D
for line in startpage.splitlines():
if 'maintitle' in line:
@ -192,7 +169,7 @@ def download():
topics = iteratorium([], 0)
cnsl_message("found_topics", str(len(topics)))
# Aaaand... the first real actions is here
torrentsdir = "%s/%s" % (curdir, sys.argv[2])
torrentsdir = "%s/%s" % (curdir, sys.argv[1])
os.mkdir(torrentsdir)
get_torrent(topics, torrentsdir, forumname)
@ -202,17 +179,27 @@ def parse_topic(topic, forumname, topics, torrents_count, torrentsdir):
if 'maintitle' in line:
tname_raw = line
topicname = tname_raw.split('>')[3].split('<')[0]
for line in topicpage.splitlines():
if 'не проверено модератором!' in line:
cnsl_message("skip_non_approved", str(torrents_count), str(len(topics)), topicname, (domain + "/" + topic))
return 340
for line in topicpage.splitlines():
if 'проверено модератором' in line:
tdate_raw = line
# fix for russian months names (dateutil doesn't parse it, damnnt)
tdate_raw = tdate_raw.replace('Янв', '01').replace('Фев', '02').replace('Мар', '03').replace('Апр', '04').replace('Май', '05').replace('Июн', '06').replace('Июл', '07').replace('Авг', '08').replace('Сен', '09').replace('Окт', '10').replace('Ноя', '11').replace('Дек', '12')
topicdate = dateutil.parser.parse(tdate_raw.split('>')[1].split('<')[0].split(' ',3)[3]).strftime("%Y-%m-%d")
for line in topicpage.splitlines():
if 'download.php' in line:
for lvl2 in line.split('>'):
if 'download.php' in lvl2:
dl_raw = lvl2
downlink = dl_raw.split('"')[1]
cnsl_message("downloading_torrent", str(torrents_count), str(len(topics)), topicname, (domain + "/" + topic))
cnsl_message("downloading_torrent", str(torrents_count), str(len(topics)), topicname, (domain + "/" + topic), topicdate)
os.chdir(torrentsdir)
if not os.path.exists("./%i00" % (torrents_count / 100)):
os.makedirs("./%i00" % (torrents_count / 100))
os.chdir("./%i00" % (torrents_count / 100))
if not os.path.exists("./%s" % topicdate):
os.makedirs("./%s" % topicdate)
os.chdir("./%s" % topicdate)
download_torrent(downlink)
def download_torrent(downlink):