Pull to refresh

RSS-фиды и торренты

Reading time5 min
Views8.1K
RSS-фиды для торрент-файлов позволили заменить старые-добрые файловые эхо-конференции Фидо. По ним новые файлы по заранее выбранной тематике «приходили сами», т.е. о новинках можно было узнавать не по обзорам на сайтах, а разбирая пришедшие файлы.

Удобство подобного трудно описать. Считайте, тот же ютуб, но с настоящим FullHD (которое FullHD, а не то, что ютуб HD называет), в своём, удобном, плеере, без лагов и рекламы… В свободное от работы время компьютер скачивает все новинки сам, а вы лишь выбираете, что из этого смотреть (а что прибить). Непозволительная трата интернета, роскошь, ставшая доступной лишь в последние годы с увеличением скоростей и почти повсеместной отменой тарификации по трафику.

Как это работает?


Сайт, сопровождающий трекер (mononova, rutracker, bakabt, thepiratebay, animesuki, demonoid и т.д.) имеет возможность формировать фиды — страницы в формате RSS [wiki], содержащие в себе ссылки на новые torrent-файлы.

Обычно при этом есть возможность отфильтровать (прямо на сайте, при выборе нужного RSS) что именно интересует. Например, на tokyotosho позволяют сформировать правильную ссылку RSS с выбором интересующих типов файлов: tokyotosho.info/rss_customize.php.

В хорошем случае, по ссылке будет torrent-файл. В плохом — ссылка на html-страницу, на которой уже будет ссылка на torrent-файл. (об этой тонкой подлости мы поговорим в разделе реализации).

Дальше всё просто: некий клиент (торрент-клиент с встроенным RSS или специализированная программа) скачивает периодически RSS, скачивает torrent-файлы из неё, скачивает содержимое торрентов (ну или передаёт на скачивание торрент-клиенту). RSS скачивается раз в N минут (у меня — раз в час), файлы появляются на диске сами собой.


Потенциальные проблемы


  • Файл может быть выложен на нескольких трекерах. Если мы скачали торрент-файл несколько раз, то мы должны его несколько раз закачать. Большинство торрент-клиентов могут это отслеживать, однако, для этого они должны помнить о всех скачанных торрент-файлах. Через год-другой история становится слишком обширной и тормозит (да, даже в μTorrent'е). Если же торренты «забывать», то они либо будут качаться несколько раз, либо (если торрент-клиент достаточно умный) находиться в «скачанных» и сидиться. При этом возникает проблема отсутствия пиров, и файл сидится ОЧЕНЬ долго. Причём, второй-третий раз.
  • Торренты могут быть от разных релизеров, а мы хотим иметь файл в единственном числе, нужно отлавливать повторы
  • Хочется сделать так, чтобы торренты качались без участия человека (даже когда он вылогинился)
  • Хочется иметь графическую полнофункциональную морду и возможность наблюдать за процессом когда нужно
  • Среди скачиваемых фидов с большой вероятностью будут неинтересные торренты, хочется настроить фильтр, чтобы не качать лишнее
  • Фид может содержать косвенные ссылки (т.е. ссылки на html-страницу, с которой уже можно скачать torrent-файл)
  • Трекер может быть приватным и требовать куки (логин/пароль) для даунлоада фида и/или торрент-файлов


Теоретическая модель


В полном виде я такого нигде не видел, так что можно это считать «сферической в вакууме моделью».

  1. RSS-сервер скачивает все фиды, раздельно для каждого пользователя. Фиды передаются клиенту загрузки.
  2. Клиент загрузки скачивает торрент-файлы.
  3. Клиент передаёт скачанные торрент-файлы на фильтрацию по признаку повтора, нежелательности
  4. После фильтрации, торрент-файлы передаются торрент-клиенту в серверном режиме, поддерживающем несколько очередей для пользователей и способного находить «одинаковые» вещи у разных пользователей, чтобы не скачивать их дважды.
  5. По окончании загрузки файлы хардлинком кладутся в «входящие» пользователю, с сохранением копии в личных потрохах торрент-клиента до момента заверешния сидинга
  6. Торрент-клиент предоставляет каждому пользователю либо веб-морду, либо Rich-application интерфейс (лучше и то и то)


Практическая реализация


(под линукс)

Сразу говорю, моя текущая реализация довольно далека от желаемой, и является компромиссом по объёму работы, функционалу и удобству.

Итак, первое: RSS. Я использую для этого пакет rsstail с ключиком -N1l (просто выводит хвост RSS). Далее, я решаю проблему «html-ссылкок» — это wget, который может скачать рекурсивно всё по ссылке (глубина вложенности 1, так что далеко мы не уйдём, если ссылка — торрент, то и рекурсии не будет). Ещё я решаю одну дурацкую проблему, которую создал nyaatorrents, отдавая торренты не в виде файлов, а формируя их динамически с заголовком Content-Disposition.

Общая строка выглядит так:

rsstail -u http://www.nyaatorrents.org/?page=rss\&catid=1\&subcat=37 -N1l|grep http|wget -i - -r -l 1 -nd --content-disposition -A torrent >/dev/null 2>/dev/null

В силу природной лени писать обработку списка фидов было лень. Хотя надо. Так что в скрипте однотипные строки, для всех трекеров, различающиеся лишь адресом.

Я не пользуюсь приватными трекерами (по мере возможности) и у меня нет нескольких пользователей на машине (по-крайней мере, пользователей торрентов), так что этого функционала мне достаточно.

Все торренты скачиваются в /srv/unsorted-torrents. Отсюда их фильтруют (пока у меня очень примитивная фильтрация find'ом) методом «удаления лишнего». И переносят.

Вот процесс отлова повторов чуть более интересен. Я использую самописную программу singlemv, которая в очень компактном виде смотрит, был ли такой файл раньше, или нет. И переносит только при условии, что файла не было (после каждого переноса база повторов обновляется).

После чего всё лишнее в /srv/unsorted-torrents прибивается.

Торренты переносятся в каталог /srv/torrents-queue, которая назначена pickup-folder для торрент-клиента. В моём случае это deluge, но, в принципе, схема должна работать с любым торрент-клиентом.

Планы на будущее


Уже написан на Си lstorrent, хотя и без правильной обвязки (по сравнению с питоновской версией — трёхкратная экономия по памяти и 10-кратная по скорости), позволяющий смотреть содержимое торрентов.

В далёкой перспективе — проект gattai (так и не дополз до состояния alpha-версии), который будет определять одинаковые по названию произведения файлы с разными релизерами/переводчиками, и который будет автоматически выбирать среди них лучшее качество.

Совсем не решён вопрос в мордой. С одной стороны хочется иметь полноценный сервер закачек, с другой стороны, не хочется терять вполне приятную морду deluge'и.

Зачем все эти сложности?


Лучше день потерять, потом за час долететь.

После того, как я закончил делать эту систему у себя в районе февраля месяца, вот уже почти пол-года система работает без каких-либо проблем и нареканий, аккуратно складывая новинки в incoming. Более того, если по какой-то причине с deluge'ой возникают проблемы (например, затык из-за пачки медленных торрентов, которые неделями не могут докачаться), то torrent-файлы продолжают собираться, т.е. потери в «фиде» не возникает. (именно этим подобная схема интереснее, чем встроенный в торрент-клиент автокачатель фидов).

UPD: забыл самое главное, скрипт singlemv:

#!/usr/bin/python
import sys,os, cPickle


#minimalistic command line:
#1st argument - memory file
#2nd - pre-last - files to be moved
#last - destignation (where to be moved)

def singlemv(memory,from_list,to):
#return new memory mode
    to_move=frozenset(from_list) - memory
    errors=set()
    for f in to_move:
        try:
            os.rename(f, os.path.join(to,os.path.basename(f)))
        except:
            print "error move %s to %s", f, to
            errors.add(f)
    return memory|(to_move-errors)


def __main__():
    if len(sys.argv)<4:
        print "Usage: singlemv.py memory_file from to"
        exit(-1)
    try:
        memory_file=file(sys.argv[1],"r")
        memory=cPickle.load(memory_file)
        memory_file.close()
        if type(memory) != type (frozenset()):
            print "bad memory file"
            exit(1)
    except IOError, OSError:
        memory=frozenset()
    newmem=singlemv(memory,sys.argv[2:-1],sys.argv[-1])
    memory_file=file(sys.argv[1],"w")
    cPickle.dump(newmem,memory_file)
    memory_file.close()

__main__()

Вся прелесть программы — в строчке to_move=frozenset(from_list) - memory (разность множеств).
Tags:
Hubs:
Total votes 15: ↑11 and ↓4+7
Comments5

Articles