Раздача на трекерах, где трудно раздавать, или как победить сидбоксера. Всегда анонсировать на все трекеры
10 советов, как добиться высокого рейтинга на трекере — TorrentNews
Первое, что бросается в глаза при регистрации на закрытом BitTorrent-трекере — изумительное качество торрентов: все они проходят строгий отбор и тщательно обрабатываются модераторами сайта. Но прежде чем кидаться загружать понравившийся файл, стоит уяснить несколько правил.
На закрытых трекерах все вращается вокруг рейтингов. Рейтинг 1:1 или 1,0 означает, что объем скачанных и отданных данных одинаков. Соответственно, рейтинг 0,80 указывает на то, что вы отдали меньше, чем скачали, а это плохо сказывается на здоровье торрента. С другой стороны, 3 говорит о том, что отдано данных в три раза больше. Желательно поддерживать рейтинг на уровне 1, поскольку на закрытых трекерах предусмотрены различные санкции по отношению к пользователям с низким рейтингом. Зато при рейтинге выше 1 вас ждут всевозможные поощрения и награды.
Новичкам добиться рейтинга 1 нелегко. К счастью, при регистрации им дают льготный период для достижения заветной отметки. Поскольку на закрытых трекерах сидов гораздо больше, чем личеров (в отличие от открытых), достичь высокого ратио оказывается намного сложнее по причине меньшего количества скачивающих.
Казалось бы, зачем вообще беспокоиться о рейтинге? Ответ прост: в глубине души все мы мечтаем стать достойными членами файлообменного сообщества. К тому же, помимо законной гордости, пользователи с высоким рейтингом получают целый ряд преимуществ по сравнению с простыми смертными, в том числе, улучшенную учетную запись (VIP-статус), повышенную скорость скачивания, инвайты на сайт и избавление от пауз между загрузками.
Наши советы помогут вам завоевать высокий рейтинг на закрытом трекере в рекордные сроки!
1. Начните с небольших файлов.
Поначалу выбирайте для скачивания небольшие файлы (менее 1 Гб). В таком случае более вероятно, что вслед за вами торрент скачает кто-нибудь еще, и тогда вы сможете повысить свой рейтинг с помощью раздачи. 700-мегабайтный фильм заинтересует других пользователей сайта явно больше, чем копия с Blu-Ray размером 30 Гб.
2. Скачивайте новинки.
Это прекрасный способ быстро поднять рейтинг на трекере. Регулярно посещайте закрытый сайт и обновляйте списки торрентов. У новых торрентов личеров гораздо больше чем сидов, а значит, вы сможете раздать больше. Чтобы извлечь из новинок максимум пользы, выбирайте мелкие файлы — например, отдельные серии телесериалов.
3. Выбирайте файлы с большим количеством личеров.
Это очень важно! Поначалу стоит скачивать только торренты с большим количеством личеров (чем больше, тем лучше). В таком случае вы сможете раздавать торрент уже в процессе скачивания, да и потом принимающих будет намного больше. Мы бы даже порекомендовали в первое время после регистрации на закрытом трекере скачивать любые файлы, в том числе, абсолютно ненужные, но со множеством личеров. По достижении рейтинга 1:1 их можно будет спокойно удалить.
Совет: Если один из торрентов на раздаче пользуется особой популярностью, продолжайте раздавать его, пока у вас есть такая возможность. Это значительно повысит ваш рейтинг на сайте.
4. Избегайте торрентов без личеров.
Новичкам стоит опасаться торрентов без личеров: при скачивании таких файлов повысить рейтинг невозможно, потому что некому раздавать. Просматривая список торрентов, обращайте особое внимание на столбец «Личеры» или «L» и избегайте файлов с цифрой «0». Когда добьетесь относительно стабильного ратио, можете скачивать все, что угодно.
5. Оставляйте торренты на раздаче.
Завершив скачивание торрента, оставьте его на раздаче, чтобы повысить рейтинг. Только ни в коем случае не перемещайте и не удаляйте файлы торрента! Извлекать файлы из архива или копировать их в другие папки можно. Более того, их можно записывать на диски и открывать — все это не влияет на раздачу.
Совет: Всегда держите на раздаче несколько торрентов. Если их перестают скачивать, заменяйте торренты на более актуальные.
6. Пользуйтесь бесплатными торрентами.
Многие закрытые сайты предлагают так называемые «бесплатные» торренты, скачивание которых никак не влияет на рейтинг. Обязательно обратите на них внимание при поиске файлов в первое время после регистрации.
7. Зарабатывайте баллы.
Популярные закрытые трекеры предлагают зарегистрированным пользователям баллы, бонусы или кредиты, на которые можно приобрести VIP-статус, повышенный рейтинг и другие привилегии. Правила накопления баллов на всех сайтах разные: где-то их можно получить за активность на IRC-канале сайта, а где-то — за раздачу торрентов.
8. Не пытайтесь обмануть закрытый трекер!
В Интернете можно найти немало советов о том, как обмануть закрытый трекер, но не стоит обольщаться: трекеры — механизмы сложные, и они постоянно развиваются. Если вас поймают на обмане, наказанием станет постоянный бан по IP-адресу без предупреждения.
9. Установите правильное ограничение скорости отдачи.
Правильное ограничение скорости имеет огромное значение для эффективного пользования закрытыми трекерами. Ограничение должно быть таким, чтобы обеспечить максимальную эффективность раздачи и в то же время не сокращать скорость скачивания. Как правило, ограничение устанавливают на уровне 80-85% от текущей скорости. Узнать скорость подключения к Интернету можно на сайте www.speedtest.net. Результат дается в килобитах, поэтому его нужно разделить на 8 и умножить на 0,85. Так вы узнаете, какую скорость отдачи в килобайтах в секунду (Кб/с) следует установить.
В µTorrent ограничение это можно задать в диалоговом окне «Параметры > Соединение», доступ к которому осуществляется из меню «Настройки» (Options > Preferences > Connection). Введите нужное число, нажмите кнопку «Применить» (Apply), а затем «OK», чтобы сохранить изменения. Попутно стоит проверить, какой для приложения выбран порт — рекомендуется использовать порты от 49152 до 65535.
10. Если ничего не помогает — внесите благотворительный взнос.
Большинство закрытых трекеров принимает от пользователей добровольные пожертвования на содержание сервера. Если вам очень нравится какой-то сайт, но вы никак не можете достичь приличного рейтинга, потому что вынуждены выключать компьютер на ночь/на время работы, делите его с детьми, супругом/супругой или братьями/сестрами, попробуйте добиться желаемого с помощью благотворительного взноса. Как правило, даже не самые щедрые взносы значительно повышают статус пользователя — и позволяют почувствовать себя ценным членом BitTorrent-сообщества.
Другие советы — Соблюдайте правила!
Конечно, мало кому нравится необходимость соблюдать какие бы то ни было правила. Именно поэтому мы получаем двойки за поведение, разъезжаемся с родителями и пользуемся пиринговыми сетями вместо того, чтобы честно покупать фильмы на DVD.
Тем не менее, правила — важный аспект существования закрытых трекеров. Только благодаря им торренты на таких сайтах остаются качественными, а скорость скачивания — высокой. Правила пользования трекером обычно публикуются на самом видном месте, поэтому не поленитесь с ними ознакомиться. Ниже приводятся самые распространенные из них.
Пользуйтесь только разрешенными клиентами BitTorrent.
Закрытые трекеры различаются, поэтому и списки “правильных” BitTorrent-клиентов у всех разные. На большинстве сайтов рекомендуется использовать µTorrent, но только определенных версий. Лучше всего пользоваться последней 1.7.7 или версией 1.6.1 — они принимаются на любом закрытом трекере. Не используйте промежуточные между ними версии. А вот BitComet на закрытых сайтах, как правило, запрещен.
Правильно настройте клиент BitTorrent.
На многих трекерах рекомендуется отключать в клиенте DHT и функцию обмена пирами (Peer Exchange, PEX). В µTorrent для этого откройте окно параметров (Options > Preferences) и снимите три флажка, связанных с функциями DHT и PEX на вкладке «BitTorrent» (см. рис.).
Не стоит совершать «набегов» на закрытый торрент-сайт.
«Набег» — это ситуация, в которой вновь зарегистрированный пользователь скачивает с закрытого трекера все, что только может, а потом скрывается в неизвестном направлении, не обеспечив раздачи. Такую практику осуждают даже открытые сайты вроде mininova.org, но на закрытых трекерах это приводит к плачевным результатам. Подобное поведение может закончиться (и в конечном счете, как правило, заканчивается) баном вашего IP-адреса на сайте.
Следуйте этим простым правилам — и беспроблемное пользование торрентами вам обеспечено!
torrentnews.ru
Отключаем блокировку DHT в популярных торрент-клиентах / Хабр
На многих так называемых «приватных» трекерах торренты раздаются с установленным флагом, не позволяющим использовать сеть DHT. Цель этого — не допускать раздачу материала клиентам, не зарегистрированным на данном трекере. Однако для пользователя это означает уменьшение количества сидеров, иногда — значительное.1. Вступление.
В сети в прошлом выкладывалось достаточно много информации касательно так называемых «патчей DHT», равно как выкладывались и сами патчи. Однако при анализе этих данных зачастую они оказываются противоречивыми и даже в ряде случаев полностью нерабочими. Связано это с постоянным обновлением клиентов, изменением структуры программ, а в ряде случаев — неправильным подходом авторов патчей.Мы попытаемся не просто создать готовое решение, а проанализировать основные шаги так, чтобы читатель мог даже в случае изменение в будущем самостоятельно снимать ограничения DHT в новых версиях клиентов.
2. Подготовка.
Нам понадобятся:- Актуальный дистрибутив торрент-клиента.
- Архиватор, способный распаковывать инсталляционные файлы, например в случае uTorrent и qBitTorrent — 7-zip.
- Распаковщик исполняемых файлов клиента, в случае uTorrent — UPX.
- IDA или любой другой дизассемблер.
- в случае uTorrent — файл Carrier.exe;
- В случае qBitTorrent — файлы qbittorrent.exe и qbittorrent.pdb (либо их 64-разрядные аналоги, если будет изменяться 64-битный клиент).
2. Поиск и изменение кода.
В общем, реализация блокировки DHT во всех клиентах на уровне Ассемблера выглядит одинаково, это вызов функции проверки флага, и если эта функция возвращает нулевое значение — переход на область кода, которая позволяет использовать DHT:call TestPrivate test eax, eax jz NotPrivate по этой причине сам патч будет выражаться в простом изменении одного байта кода 74 => EB, превращающего условный переход jz в безусловный и таким образом игнорирующий проверку на «приватность».Остаётся найти данную функцию.
На самом деле это совершенно не сложно, учитывая специфику данного кода и наличие ключевого слова «private». Откроем распакованный файл клиента uTorrent в IDA и выполним поиск по данному ключевому слову:
Видно, что с указанным ключом в uTorrent присутствует всего три участка кода. Вот как они выглядят:
Наша задача заключается в простом замене функции, как мы уже упоминали ранее: По сути, это замена характерной последовательности 68 00 FF 69 00 E8 19 F1 FA FF 85 C0 74 07 на68 00 FF 69 00 E8 19 F1 FA FF 85 C0 EB 07
В случае qBitTorrent задача упрощается ещё больше, поскольку разработчик вложил pdb-файл в установщик, так что названия функций будут более очевидными, и поиск по ключевому слову упрощается:
Так выглядит сам код проверки:
Как видите, по сути он неотличим от uTorrent. Патч будет аналогичным:
Это замена характерной последовательности E8 20 CB FA FF 84 C0 74 59 наE8 20 CB FA FF 84 C0 EB 59
qBitTorrent также предлагается в виде 64-разрядного клиента. Действия в отношении него буду совершенно аналогичными, за исключением того, что нам потребуется 64-разрядная версия IDA. Результат поиска по ключевому слову ожидаемо аналогичен:
Вид соответствующей функции несколько отличен, однако суть осталась та же:
Ну и соответствующий патч, здесь это будет три байта:
Это замена характерной последовательностиE8 8F 0E F8 FF 4C 8D 3D 54 E5 46 01 83 CB FF 84 C0 0F 84 DB 00 00 00 наE8 8F 0E F8 FF 4C 8D 3D 54 E5 46 01 83 CB FF 84 C0 E9 DC 00 00 00 00
3. Итоги
Нами было последовательно изучена процедура поиска и отключения функции ограничения использования DHT для приватных торрентов в популярных клиентах uTorrent и qBitTorrent. Думаю, что предложенный механизм будет аналогичен и для любых других клиентов — во всяком случае я проверил его и на ComboPlayer.Для автоматизации процесса мной были созданы два патчера для актуальных версий uTorrent и qBitTorrent. Для uTorrent патчер также распаковывает исходный инсталлятор. Файлы можно скачать здесь:
Патчер qBitTorrent версии x32Патчер qBitTorrent версии x64Патчер распакованного файла uTorrentSilent всё-в-одном патчер uTorrent: распаковывает, патчит и обратно упаковывает инсталлятор, а также распаковывает, патчит и упаковывает обратно уже установленный uTorrent (при условии, что установочная папка — по умолчанию, то есть "%userprofile%\AppData\Roaming\uTorrent\"
habr.com
5 трекеров времени, которые помогут победить прокрастинацию
Прокрастинация является главным врагом продуктивности. Для того, чтобы начать с ней бороться, необходимо сначала оценить масштабы проблемы. Сделать это можно с помощью одного из сервисов, умеющих отслеживать, на что уходит ваше время.
Harvest
Harvest стартовал в далёком 2006 году и за это время успел претерпеть множество изменений и улучшений. Однако основная функциональность осталась неизменной — это по-прежнему один из самых мощных сервисов для учёта времени, которым пользуются десятки тысяч пользователей по всему миру.
Основные функции
- Ручной и автоматический учёт рабочего времени.
- Разделение проектов на оплачиваемые и неоплачиваемые.
- Функция построения отчётов, которые показывают прогресс и потери времени.
- Создание гибких счетов-фактур на основе ваших рабочих часов.
- Интеграция с более чем 80 приложениями, в том числе IFTTT, Slack, QuickBooks и так далее.
Стоимость: 1 пользователь, 4 клиента, 2 проекта бесплатно. Узнать подробнее →
Цена: Бесплатно
Цена: Бесплатно
Toggl
Это один из самых популярных сервисов в своей категории. Он обладает практически всем необходимым, чтобы организовать работу фрилансера или даже небольшой компании. Отдельная благодарность разработчикам за то, что большинство функций сервиса доступны даже в бесплатной версии.
Основные функции
- Ручной и автоматический учёт рабочего времени.
- Разделение проектов на оплачиваемые и неоплачиваемые.
- Функция построения отчётов, которые показывают прогресс и затраты времени.
- Возможность разделения коллектива на отделы и группы.
- Таймеры работают в автономном режиме и синхронизируются, когда вы снова в интернете.
- Таймеры синхронизируются на всех подключённых устройствах, так что вы можете начать работу на вашем компьютере и продолжить на телефоне.
Стоимость: 5 пользователей бесплатно с небольшими ограничениями функциональности. Узнать подробнее →
RescueTime
RescueTime — это приложение совершенно особого рода. Оно заменит вам строгого начальника, который постоянно стоит за спиной и следит, какие сайты и приложения вы открываете. Потом он предъявит подробный отчёт о потраченном времени, от которого вам может стать жутко. И тогда вы сами попросите заблокировать все эти сайты, ворующие ваше время.
Основные функции
- RescueTime работает в фоновом режиме и постоянно отслеживает активное приложение или веб-сайт.
- Приложение автоматически определяет используемые приложения и сайты в одну из категорий, например «Продуктивные», «Развлекательные», «Информационные» и так далее.
- Встроенные отчёты, которые показывают, насколько вы были продуктивны.
- Дополнительные функции включают блокирование веб-сайтов в определённое время, блокирование страниц по чёрному списку, запрет на открытие сайтов из определённой категории.
Стоимость: 1 пользователь бесплатно с основными функциями и отчётами. Узнать подробнее →
Цена: Бесплатно
Цена: Бесплатно
LogMyHours
LogMyHours имеет не самый простой интерфейс, поэтому для освоения всех возможностей этого сервиса нужно потратить время и усилия. За это вы будете вознаграждены самыми полными и детализированными отчётами о своей рабочей деятельности.
Основные функции
- Ручное или автоматическое управление отслеживанием времени.
- Почасовые ставки по проекту, по задачам или исполнителям.
- Возможность настройки лимитов (времени или оплаты) для каждого проекта.
- Встроенные отчёты для отслеживания прогресса и затрат времени.
- Создание гибких счетов-фактур на основе зафиксированных рабочих часов.
- Импорт данных из Asana, Basecamp, FreshBooks и других подобных сервисов.
Стоимость: 1 пользователь, 4 клиента, 2 проекта бесплатно. Узнать подробнее →
Цена: Бесплатно
Цена: Бесплатно
PrimaERP
PrimaERP — это тайм-трекер для учёта времени, оценки его стоимости и выставления счетов. Созданные с помощью сервиса отчёты покажут, чем занимались вы и ваши коллеги. Довольно простой и удобный инструмент для управления временем, который повысит вашу продуктивность.
Основные функции
- Удобные инструменты для отслеживания занятости в рабочее время.
- Ежедневные, еженедельные или ежемесячные обзоры расхода времени у вас и ваших коллег.
- Синхронизирует все данные в облаке.
- Доступно через браузер, планшет или смартфон.
- Интеграция с Basecamp, MS Exchange, Google Calendar и другими приложениями.
Стоимость: функция учёта рабочего времени является бесплатной для трёх пользователей. Узнать подробнее →
Цена: Бесплатно
Цена: Бесплатно
А какому инструменту для отслеживания выполнения задач и управления временем отдаёте предпочтение вы?
lifehacker.ru
О хэшах и проблеме распространения в торрентах / Хабр
Наверняка многие из вас в процессе пользования торрентами сталкивались с такой досадной проблемой, когда торренты одного и того же контента имеют разные хэши, что не позволяет объединить в одной раздаче несколько с разных трекеров, сделав тем самым мультитрекерную раздачу.Что же является причиной различия хэшей?
Как известно, хэш торрента или info_hash — это хэш SHA-1 от секции info в торрент-файле. В этой секции обычно находится размер раздачи, список файлов и другая информация о раздаваемом контенте. Например, торрент, созданный нашим любимым uTorrent, изнутри выглядит примерно вот так:Действительно, ничего лишнего. А теперь посмотрим, что даст нам второй третий по популярности в мире битторрент-клиент Azureus от того же самого файла:
Ага… И нас уже преследуют неприятности. Как видно, секция info пополнилась фирменными азуреусовскими штучками в виде пункта name.utf-8, дублирующего не понятно для чего предыдущий пункт name. Действительно, стоит глянуть в спецификацию протокола, где ясно сказано, что метаинформация и так в utf-8. Еще один пункт, испортивший нам праздник хэш, это private=0. Замечу, что uTorrent в случае указания публичности торрента пункт private вообще не добавляет и правильно делает, ибо private=0 равнозначно его отсутствию. Также разнится и размер кусков.
В итоге мы получили два разных хэша от одного и того же файла еще на этапе лишь создания торрента. Дальше больше.
После загрузки торрента на трекер ситуация обычно усугубляется. Многие трекеры принудительно делают торренты приватными, т.е. добавляют private=1 в секцию info, тем самым портя хэш (кстати, на torrents.ru эта конструкция долгое время, видимо, по ошибке вставлялась вне секции info). Но это полбеды. Очень многие трекеры добавляют в эту архиважную секцию всякую дрянь вроде указания принадлежности торрента именно себе: tracker=***.ru и прочее, что опять же делает торрент уникальным.
Чем же губительно отличие хэшей?
Тем, что распространение контента в битторрент-сетях сильно тормозится различием хэшей в то время, как файлы раздачи идентичны, и можно было существенно оптимизировать весь процесс, унифицируя принцип создания торрентов. Такая картина не только портит распространение раздачи по DHT, но и не позволяет вам оптимально качать одну и ту же раздачу с нескольких трекеров, добавив новые адреса для анонсов. Получается, что раздавать один и тот же файл на несколько трекеров можно, а вот качать — нет.Сегодня многие трекеры, включая torrents.ru, отказались от практики «опривачивания» торрентов, что очень радует, но вышеназванная дрянь tracker=torrents.ru в секции info все усилия сводит на нет, потому как хэши торрентов с того же торрентс уникальны.
К слову также хотелось бы упомянуть проблему самого протокола битторрент, заключающуюся в том, что имена раздаваемых файлов (не говоря уж об их относительном расположении в раздаче) оказывают самое непосредственное влияние на хэш. Это на мой взгляд очень большая прореха во всем этом гениальном протоколе. Если не ошибаюсь, даже ed2k ее лишен.
Что делать?
Несомненно, с такой проблемой вселенского масштаба нужно бороться. Какие же способы для этого есть.- Трекерам на стадии загрузки торрента автоматически приводить его к стандартному виду, очищая секцию info от конструкций вроде name.utf-8 и не добавлять туда ничего лишнего от себя. И, если это не противоречит идеологии ресурса, не делать торрент приватным. Впрочем, даже приватные торренты с разных трекеров могут быть объединены в мультитрекерную раздачу, что уже хорошо.
- Разработчикам битторрент-клиентов придти к единому стандарту генерации торрентов.
- Нам с вами — рядовым пользователям — создавать торрент-файлы по возможности в едином клиенте, на роль которого лучше всего выбрать именно uTorrent как самого распространенного.
habr.com
Раздача на трекерах, где трудно раздавать, или как победить сидбоксера / Хабр
Как известно, на некоторых торрент-трекерах имеется так называемый рейтинг. 5 лет назад, когда в большинстве городов России только-только появился безлимитный интернет, и скорости его были весьма невысоки, рейтинг на некоторых трекерах было очень трудно поддерживать. Да что там поддерживать, даже хоть что-то раздать сложно. И вот тогда в поисках редкой музыки я попал как раз на такой трекер.
Канал у меня был 512/512 килобит/с (симметричный). Я почти сразу обнаружил, что на чужих раздачах с таким каналом мало что удаётся раздать. А точнее практически ничего. Конечно можно было начать создавать свои раздачи, но я решил узнать, а можно ли всё-таки что-то сделать с чужими. Оказалось, что очень даже можно.
Хотя прошло много лет, я по-прежнему встречаю сообщения о трудностях с рейтингом, и лично знаю нескольких человек, кто до сих пор не решается ничего скачивать с этого трекера, опасаясь, что ничего не получится раздать. Поэтому думаю эта информация будет полезной. Приведённые скриншоты и графики сделаны не 5 лет назад, а сейчас, чтобы схематично показать события, происходившие тогда. Естественно, при медленном канале нельзя качать несколько раздач одновременно, только одну. Но даже если раздачу ведет не сидбокс, а например человек с каналом «всего» 1-2 мегабита, получается следующая картина — качающие очень быстро мне раздают то, что они уже скачали у сида, этот поток легко заполняет весь мой канал, и сид мне ничего не отдает. Соответственно и я ничего не раздаю.
Видно, что качаются сегменты, которые уже у всех есть (на скриншоте availability=20).
Тогда я попробовал найти медленные раздачи. Чтобы не подключаться ко всем подряд, а потом быстро отключаться, когда станет ясно, что ловить нечего, я нашел такой способ: смотрим свежие раздачи, и если видим что сид — один, а личеров — несколько, притом раздача идет уже 1-2 часа, а они её ещё не скачали, значит сид раздает медленно, и тут можно что-то выиграть. Обычно такое бывает с достаточно большими раздачами, флаками, а лучше многодисковыми — чем больше объем, тем больше простора для маневров (об этом позже).
Оказалось, что даже если сид имеет крайне низкую скорость (к примеру как у меня, 60кбайт/с), то на раздаче всё равно ловить нечего. Потому что к тому моменту как я к ней подключаюсь, личеры уже скачали что-то, они мне тут же начинают это раздавать, и получается опять та же самая картина. Даже если мне удается их «догнать», (а это непросто) и сид начинает мне что-то отдавать, у личеров очень скоро появляются новые куски, и они активно мне их «впихивают», тут же забивая канал, и всё повторяется снова. Таким образом, чтобы что-то раздать, надо, чтобы скорость раздачи была раза в 2 меньше, чем моя, то есть около 30кбайт/с. А такое бывает на этом трекере крайне редко.
Однако, выход есть. Можно качать только часть песен из раздачи, например, всего одну. Это было не запрещено правилами именно этого трекера. И вот как выглядит процесс. Находим раздачу (см.выше), допустим это флак 500М, из 10 песен, его качают уже 1 час и скачали на 30% — типичная картина. Начинаю качать одну песню. Первое время я «догоняю» других личеров, весь поток идет от них, раздача нулевая. Так как я качаю всего одну песню, я довольно быстро скачиваю всё, что у них есть от неё (треть песни 50М — это 17М, скачивается за 5 минут). После этого обычно следует затишье, так как личерам больше нечего мне отдать, а сид пока меня «не замечает». Как правило это продолжается несколько минут, но иногда дольше. Иногда бывает сид вообще так и не «видит» меня, видимо полностью увлеченный другими личерами, но это бывает редко.
Итак, теперь сид начинает понемногу мне отдавать первый кусок. Это происходит медленно, так как, например, если его скорость отдачи 80кбайт/с, и всего 6 личеров — то каждому достается по 13кбайт/с. Рано или поздно кусок приходит, и (о чудо!) все остальные 6 личеров (обычно сидбоксов) набрасываются на него. И набрасываются одновременно, в идеальном случае забирая каждый кусок целиком, то есть — я скачал с сида 1Мб, раздал 6Мб. На практике так бывает не всегда, скорость у них всё же разная, и иногда некоторые успевают слить мой кусок раньше, и раздать его другим. А также не забываем, что хотя я и качаю всего 1 песню из 10, другие её тоже качают. И когда они скачивают кусок от «моей» песни, они его тут же мне отдают, что зачастую приводит сида «в замешательство», и он на какое-то время снова перестает мне раздавать.
График трафика выглядит примерно так:
Здесь красным цветом показан входящий трафик: видны узкие импульсы — сегменты, приходящие периодически от других пиров, и медленно, но постоянно идущие данные от сида. Зеленым цветом показана раздача: периодически уходящие одновременно ко всем пирам сегменты сливаются в широкие импульсы исходящего трафика.
В общем, в итоге через 2 часа раздачи она подходит к концу, все скачивают альбом полностью, а я — одну песню, имея при этом 50МБ даун, и от 50 до 200МБ ап, в среднем рейтинг на каждой раздачах получается около 2. При этом надо учитывать, что скорость раздачи может ещё и меняться: как повыситься, так и упасть, при этом желательно адекватно реагировать. Если видим, что наша единственная песня подходит к концу, а остальные ещё не всё скачали, можно добавить вторую, третью и т.д. Однако нельзя забываться, стоит лишь чуть превысить некий невидимый порог («заказать» слишком много песен), как приходящие от других личеров куски всё забивают и отдача резко падает на ноль.
График, приведенный выше, справедлив для случая, когда скорость канала сида гораздо меньше моей. Если его скорость будет выше, или я «закажу» для скачки больше песен, красных импульсов будет больше, и если они начнут перекрывать весь мой канал, зеленые импульсы отдачи практически пропадут:
Затем ищем следующую раздачу и всё повторяется снова. Упорные эксперименты позволили мне научиться точно выбирать не только количество песен, но и какие именно песни качать, исходя из их размера, чтобы заполнить исходящий канал полностью. Конечно не на любой раздаче можно такого достичь, но имея достаточный опыт и зная все параметры (скорость раздачи, её размер, размер кусков, скорость и «поведение» каждого пира), можно добиться этого чуткого равновесия, когда приходящий от сида очередной кусок тут же раздаётся злым сидбоксам, и пока он им раздаётся, от сида приходит следующий, и так далее, и так далее, притом к концу раздачи я как раз успеваю точнёхонько получить свои 1-2 песни нужного размера, скачав в итоге минимум мегабайт, и раздав при этом максимум, что было можно выжать. Но для этого фактически надо не отходить от экрана, всё время, постоянно наблюдая за процессом и управляя им, когда это требуется.
Конечно есть ещё разные нюансы, например пиры с клиентом libtorrent (которые имеют тенденцию скачивать раздачу слева направо), при этом надо выбрать песни, которые они ещё «не накрыли», а лучше с расчетом, чтобы они до них ещё и попозже дошли.
Здесь хорошо видно непрерывную область, которую качает сидбокс с libtorrent'ом, а остальные части торрента скачиваются остальными, «нормальными» клиентами в случайном порядке. А также иногда попадаются другие хитрые люди, которые тоже качают лишь одну песню. В таком случае надо постараться выбрать не то, что качают они. При этом надо помнить, что сортировка песен внутри торрента может быть как последовательной, как и случайной (это определяется автором раздачи при создании торрента). Так, например, из приведенного рисунка можно заключить, что сидбокс скорее всего качает песню номер 9 или 10. Значит надо начинать с песни 8. Если же расположение файлов случайное, то определить это можно только опытным путём.
И вот время от времени среди раздач попадаются «самые лучшие раздачи» — где нет сидбоксов. Так как я всё время качал только медленные раздачи, то рано или поздно попадал на такие. И тут начинается настоящий праздник. На такой раздаче, пока она ещё идет, можно скачать много песен, а иногда и весь альбом целиком. И даже бывает что вообще всё идет «в плюс», то есть сид раздает только мне, а я спокойно всё это передаю остальным, ещё более медленным чем я, личерам. Ну и последующая раздача в таком случае тоже бывает очень продуктивна, в отличие от раздач с сидбоксами, на которых, как известно, раздают только они.
Примерно так за 10 дней, исследовав тонкости пирингового обмена, я раздал 20гигабайт, а заодно получил по 1-2 песни из альбомов самых разных стилей, о которых я скорее всего никогда бы не узнал, и затем спокойно докачал те из них, которые мне понравились. Не обязательно, как описано выше, пытаться выжать максимум из каждого торрента, достаточно хотя бы немного раздавать. И тогда в комбинации с обычными советами для любых трекеров (оставаться на раздаче, создавать свои и т.д.) со временем можно достичь неплохих результатов.
p.s. напоминаю, что это статья о трекерах, где трудно раздавать, где обычные приемы поддержания рейтинга не помогают.
habr.com
Роскомнадзор пытается добить Rutracker. Блокировки серверов-анонсеров и методы обхода
udp://tracker.pirateparty.gr:6969/announceudp://tracker.cuntflaps.me:6969/announce
udp://tracker.coppersurfer.tk:6969/announce
udp://tracker.leechers-paradise.org:6969/announce
tracker.opentrackr.org:1337/announce
udp://tracker.opentrackr.org:1337/announce
udp://tracker.zer0day.to:1337/announce
p4p.arenabg.com:1337/announce
udp://p4p.arenabg.com:1337/announce
explodie.org:6969/announce
udp://inferno.demonoid.ooo:3389/announce
udp://explodie.org:6969/announce
tracker.videodrugproject.com:80/announce
udp://tracker.internetwarriors.net:1337/announce
tracker.internetwarriors.net:1337/announce
udp://9.rarbg.com:2710/announce
udp://tracker.mg64.net:6969/announce
udp://mgtracker.org:6969/announce
tracker.mg64.net:6881/announce
mgtracker.org:6969/announce
udp://tracker.grepler.com:6969/announce
tracker1.wasabii.com.tw:6969/announce
tracker.grepler.com:6969/announce
udp://tracker1.wasabii.com.tw:6969/announce
tracker2.wasabii.com.tw:6969/announce
udp://tracker2.wasabii.com.tw:6969/announce
ipv4.tracker.harry.lu:80/announce
udp://leecherhaven.zapto.org:6969/announce
udp://ipv4.tracker.harry.lu:80/announce
bt.artvid.ru:6969/announce
udp://tracker.tiny-vps.com:6969/announce
tracker.tiny-vps.com:6969/announce
retracker.mgts.by:80/announce
tracker.electro-torrent.pl:80/announce
t.nyaatracker.com:80/announce
retracker.telecom.by:80/announce
tracker.devil-torrents.pl:80/announce
tracker.vanitycore.co:6969/announce
tracker.kuroy.me:5944/announce
udp://tracker.vanitycore.co:6969/announce
udp://bt.xxx-tracker.com:2710/announce
agusiq-torrents.pl:6969/announce
udp://tracker.kuroy.me:5944/announce
grifon.info:80/announce
tracker.torrentyorg.pl:80/announce
91.218.230.81:6969/announce
tracker.filetracker.pl:8089/announce
udp://tracker.filetracker.pl:8089/announce
tracker.tlm-project.org:6969/announce
udp://peerfect.org:6969/announce
udp://open.stealth.si:80/announce
udp://zephir.monocul.us:6969/announce
udp://tracker.kamigami.org:2710/announce
udp://thetracker.org:80/announce
udp://public.popcorn-tracker.org:6969/announce
udp://tracker.swateam.org.uk:2710/announce
udp://tracker.skyts.net:6969/announce
udp://tracker.safe.moe:6969/announce
udp://open.facedatabg.net:6969/announce
udp://tracker.files.fm:6969/announce
udp://tracker2.christianbro.pw:6969/announce
udp://z.crazyhd.com:2710/announce
udp://retracker.lanta-net.ru:2710/announce
udp://tracker.torrent.eu.org:451/announce
udp://tracker.edoardocolombo.eu:6969/announce
udp://tracker.doko.moe:6969/announce
udp://tracker.cypherpunks.ru:6969/announce
udp://tracker.christianbro.pw:6969/announce
udp://oscar.reyesleon.xyz:6969/announce
torrentsmd.com:8080/announce
udp://allesanddro.de:1337/announce
fxtt.ru:80/announce
udp://tracker.bluefrog.pw:2710/announce
open.acgtracker.com:1096/announce
udp://tracker.piratepublic.com:1337/announce
udp://208.67.16.113:8000/announce
tracker2.itzmx.com:6961/announce
udp://tracker.justseed.it:1337/announce
udp://tr.cili001.com:6666/announce
udp://86.19.29.160:6969/announce
tracker.tfile.me:80/announce
tr.cili001.com:6666/announce
share.camoe.cn:8080/announce
retracker.omsk.ru:2710/announce
86.19.29.160:6969/announce
habr.com
Мониторинг торрентов и автоматическая скачка / Хабр
Совсем недавно на Хабре было 2 статьи о том, как автоматизировать процесс скачивания новых серий с торрентов. Авторы обеих статей поделились своими приложениями. Вот уже год мы тоже разрабатываем подобное приложение и мне кажется, пришло время рассказать хабрасообществу о нашем маленьком, но прекрасном проекте Monitorrent, который, возможно, сделает вашу жизнь настолько проще и удобнее, насколько сделал нашу.
Веб приложение написано на Python 2 (с поддержкой Python 3). Оно позволяет добавлять новые торренты для мониторинга, автоматически скачивать новые серии и добавлять их в торрент клиент.
Мы им пользуемся на постоянной основе с конца прошлого года, а 1 мая 2016 мы выпустили первую релизную версию, которая без каких-либо сбоев крутится до сих пор на cubietruck в docker контейнере.
За подробностями того как оно работает внутри прошу под кат.
Мне хочется прийти с работы домой и, сев ужинать, просто открыть Kodi, выбрать свежую серию любимого сериала и посмотреть её. Не прилагая никаких усилий для ее поиска на торрент трекерах и не тратя время на ожидание, пока она скачается.
Решений для данной автоматизации очень много. Сначала я пользовался плагином для Chrome, который следил за изменениями на rutracker, а изменённые торренты качал вручную и добавлял в uTorrent по RDC, а позже через их веб приложение.
Но после того, как я открыл для себя TorrentMonitor все стало намного проще. Он у меня работал на роутере больше года. Даже пару pull request’ов к нему было. Об этом приложении было 2 замечательные статьи на хабре от его автора (раз, два). Огромное спасибо автору.
TorrentMonitor прекрасен, но у меня постоянно была одна проблема. Иногда скачивался файл нулевого размера. Приходилось руками лезть в базу и исправлять информацию о том, что эта серия ещё не была скачана (вроде бы эту проблему уже исправили). Ну и в те времена он не мог сам добавлять скачанные торренты в торрент клиент (в Transmission в моем случае). Сейчас с этим тоже все хорошо.
Следующим открытием для меня был FlexGet. Очень мощный инструмент. В нем не было поддержки lostfilm.tv и прикрутить ее было то ещё приключение. В остальном он работал исправно, однако научить его следить за изменением торрента на rutracker’е у меня так и не вышло. Наверное и сейчас этого сделать нельзя. Зато у меня было настроенное правило, которое скачивало фильмы этого и предыдущего года с rutor, с качеством 720p (больше инет не позволял) и рейтингом imdb больше 6.0, при этом исключая фильмы из Японии (ну не люблю я японский синематограф, а рейтинг у них стабильно высокий). Всё это описывалось всего лишь парой строчек в yaml.
Долгое время оба сервиса (TorrentMonitor и FlexGet) работали рядом на роутере.
После того как мне подарили cubietruck, и я установил в него 2.5 винчестер на 2 Тб, он превратился в маленький, но очень практичный NAS, который кушает мало электричества и исправно качает торренты. А мобильная батарейка спасает от проблем с перебоями электричества. Скорость доступа к файлам около 30 Мб/с стабильно, этого достаточно для моих задач. TorrentMonitor и FlexGet перекочевали на cubietruck.
Однако, проблема со скачиванием торрентов нулевого размера никуда не делась.
И мне захотелось сделать свой проект для автоматизации скачивания новых серий. TorrentMonitor написан на PHP и вызывает curl для скачивания новых торрентов. Для настройки времени запуска использует вызов php через cron.
Мне же хотелось все из коробки, чтобы установил — и оно заработало.
Так появился Monitorrent. Как идея написать что-то полезное для себя на python. Маленький набор скриптов не в счет.
Это одностраничное веб приложение написанное на Python 2. В качестве front-end’а используется Angular 1.4 и angular-material. А back-end — это просто REST сервис, написанный с использованием falcon.
Все исходники лежат на github, и распространяются под лицензией Do What the Fuck You Want to Public License.
Сейчас поддерживаются следующие трекеры:
- lostfilm.tv c парсингом страницы сериала
- rutor.org (сейчас rutor.is и rutor.info) со слежением изменений торрента
- rutracker.org со слежением изменений торрента и авторизацией
- free-torrents.org со слежением изменений торрента
- tapochek.net со слежением изменений торрента и авторизацией
- unionpeer.org со слежением изменений торрента
Скачанные торренты можно добавлять в следующие торрент клиенты:
- Transmission
- Deluge
- uTorrent
- qbittorrent
Это покрывает мои нужды на 200% (в основном использую только 3 трекера и 2 торрент клиента).
Вообще, это двухстраничное приложение.
Одна страница для логина, вторая — все остальное приложение. Отдельная страница логина нужна только для того, чтобы нельзя было скачивать статические файлы (картинки, css или js) до того, как авторизируешься в систему. Я наверное параноик, смысла в этом мало, но мне нравится думать, что так слегка безопаснее.
Обе страницы генерируются из одного index.htm файла, которая потом трансформируется с помощью gulp-preprocess плагина.
Все внешние js файлы (фреймворки и js библиотеки) грузятся из CDN, для того чтобы облегчить доступ к Monitorrent’у извне, когда он развернут в домашней сети. Если дома ADSL, а скорость отдачи только 512 кбит/с, то гораздо быстрее скачать js из интернета, чем из домашней сети на ограниченной скорости, потому что канал и так забит раздачей торрентов. Все внутренние js файлы уже приходится скачивать из домашней сети, которые потом отлично кэшируются браузером.
А так как все остальное общение сделано через REST, то данных между front-end’ом и back-end’ом пересылается очень мало.
Авторизация сделана через JWT. Мне кажется, что это самая оптимальная технология авторизации. Она позволяет не хранить сессию на сервере и не дает клиенту видеть, какие именно данные у него хранятся. Если вы еще не используете JWT в своих приложениях, то настоятельно рекомендую это сделать. Особенно хорошо, как мне кажется, использовать JWT в микросервисной архитектуре.
Сборка сделана с помощью gulp, который заменил собой grunt. Все js файлы просто склеиваются вместе в один большой bundle, который пока даже не минифицируется. Но всё склеивается правильно, потому что основной файл называется app.js и первым попадает в финальный js. Всё остальное работает благодаря DI от angular.
Сейчас я бы прикрутил webpack. Но я не front-end разработчик и я не знал ничего о front-end разработке, когда этот проект только начинался.
Динамическая генерация форм
Из дополнительных особенностей имплементации можно упомянуть реализованную нами angular директиву для генерации динамических форм.
Настройки всех плагинов – это простые формы, например, вот так выглядит форма настройки соединения с Transmission:
Эта форма состоит из 2-х строк, в каждой из которых по 2 текстовых блока. Длина элемента host равно 80%, а длина port 20%. Текст блоки для логина и пароля размера 50%. Написание этой формы на angular-material — тривиальная задача.
Однако, нам хотелось упростить разработку плагинов и сосредоточиться на написании backend-логики, и не заморачиваться html’ом. Плагин должен поставляться в виде единственно файла, без дополнительного файла разметки.
Мы разработали простой формат для описания разметки формы в коде плагина:
form = [{ 'type': 'row', 'content': [{ 'type': 'text', 'label': 'Host', 'model': 'host', 'flex': 80 }, { 'type': 'text', 'label': 'Port', 'model': 'port', 'flex': 20 }] }, { 'type': 'row', 'content': [{ 'type': 'text', 'label': 'Username', 'model': 'username', 'flex': 50 }, { 'type': 'password', 'label': 'Password', 'model': 'password', 'flex': 50 }] }]Это описание формы редактирования настроек для Transmission. Здесь описаны 3 текстовых блока и один блок для ввода пароля. Назначение свойств type и label понятны из их названий. Имя свойства flex, было выбрано неудачно, правильнее его было назвать width – оно определяет длину элемента в процентах внутри строки. Оно было так названо, потому что angular-material использует flexbox для описания расположения элементов на странице.
После того как пользователь введёт данные в эту форму, и нажмет кнопку Save. На back-end будет послана модель следующего вида:
{ "host": "myhost", "port": "9091", "username": "username", "password": "******" }Имена свойств этой модели берутся из свойства model описания формы.
Это позволило сосредоточится на написании только логики плагинов back-end’а и упростило написание UI. В мобильной версии приложения все элементы будут располагаться друг за другом, т.е. элементы внутри одной строки разобьются на несколько строк. Этот функционал все ещё не реализован, но надеюсь появится в будущем.
Естественно, динамическая генерация форм – это не самое гибкое решение, но я считаю его правильным и обоснованным. Хотя наш front-end девелопер с этим не согласен по сегодняшний день и до сих пор спорит со мной об этом решении.
В одной из первых версий была реализована работа с Websocket’ами. Сначала полностью руками, потом на socket.io.
Для работы с Websocket’ами со стороны python была использована python библиотека для работы с socket.io. Она использует gevent, для создания coroutine (легковесных потоков, greenlet’ов и много других, название которые я уже не помню). Это отличная библиотека для написания асинхронных приложений, какими обязаны быть приложения, использующие Websocket’ы.
Но, к сожалению, python socket.io реализация требует библиотеку gevent больше 1.0 версии. А для домашних роутеров gevent есть только версии 0.13. Исключать возможность запуска Monitorrent’а на роутерах нам очень не хотелось несмотря на то, что я сам уже давно пользуюсь cubietruck. Поэтому от Websocket’ов пришлось отказаться и заменить их на long polling запросы в REST интерфейсе. Сейчас они используются только в одном месте, для получения статуса текущей проверки на новые серии.
Написан на python 2 с использованием falcon. Falcon обещает очень высокую производительность и он показался мне очень удобным. Первоначально Monitorrent был написан на cherrypy, потом переписан на flask, была попытка использование bottle, но тоже так и не сложилось и мы остановились на falcon.
К сожалению falcon – это фреймворк для написания REST сервисов в первую очередь, а отдавать статику тоже нужно. Такой функциональности falcon не предоставляет из коробки, в отличии от тех же flask и cherrypy. Пришлось реализовать этот функционал самим. К тому же все средства в falcon для этого есть.
@no_auth class StaticFiles(object): def __init__(self, folder=None, filename=None, redirect_to_login=True): self.folder = folder self.filename = filename self.redirect_to_login = redirect_to_login def on_get(self, req, resp, filename=None): if self.redirect_to_login and not AuthMiddleware.validate_auth(req): resp.status = falcon.HTTP_FOUND resp.location = '/login' return file_path = filename or self.filename if self.folder: file_path = os.path.join(self.folder, file_path) if not os.path.isfile(file_path): raise falcon.HTTPNotFound(description='Requested page not found') mime_type, encoding = mimetypes.guess_type(file_path) etag, last_modified = self._get_static_info(file_path) resp.content_type = mime_type or 'text/plain' headers = {'Date': formatdate(time.time(), usegmt=True), 'ETag': etag, 'Last-Modified': last_modified, 'Cache-Control': 'max-age=86400'} resp.set_headers(headers) if_modified_since = req.get_header('if-modified-since', None) if if_modified_since and (parsedate(if_modified_since) >= parsedate(last_modified)): resp.status = falcon.HTTP_NOT_MODIFIED return if_none_match = req.get_header('if-none-match', None) if if_none_match and (if_none_match == '*' or etag in if_none_match): resp.status = falcon.HTTP_NOT_MODIFIED return resp.stream_len = os.path.getsize(file_path) resp.stream = open(file_path, mode='rb') @staticmethod def _get_static_info(file_path): mtime = os.stat(file_path).st_mtime return str(mtime), formatdate(mtime, usegmt=True)Тут пришлось делать распознавание mimetype, а так же проверку if-modified-since и if-not-match заголовков для правильного кеширования браузером статики. Мне кажется, я украл это решение то ли у cherrypy, то ли у flask и просто переписал его для falcon. Не думаю, что ему место в falcon, потому и не слал им pull request.
Решение мне кажется ужасным, но более красивого мы пока не нашли.
Встроенный WSGI веб сервер falcon можно использовать только для разработки, поэтому всё крутится на WSGI имплементации из cherrypy, которая, насколько мне известно, очень стабильная:
d = wsgiserver.WSGIPathInfoDispatcher({'/': app}) server_start_params = (config.ip, config.port) server = wsgiserver.CherryPyWSGIServer(server_start_params, d)Если кто-то знает хороший и быстрый WSGI сервер для python, поделитесь пожалуйста в комментариях. Нужно кроссплатформенное решение, так как Monitorrent также работает и под Windows.
Это первый серьёзный проект на python, поэтому многих особенностей мы не знаем. Наверное, получение статики можно переложить на какой-то WSGI сервер, а всю работу по обработке запросов REST оставить на falcon. Будем благодарны, если кто-то подскажет, как это сделать правильно.
Мне сложно понять, как можно жить без DI контейнера, но в python-мире не принято их использовать. Было уже много холиваров на эту тему. К сожалению, хорошего решения не было найдено, так что мы воспользовались явной инъекцией зависимостей во все классы.
Все трекеры и торрент клиенты реализованы в виде плагинов. Пока это все типы плагинов, но в ближайшее время появятся плагины для уведомлений. Соответствующий pull request ожидает review и будет доступен в версии 1.1.
Мы не нашли красивой системы для загрузки плагинов, где можно было бы просто просканировать папку и каким-то образом загрузить оттуда все классы, поэтому идея реализации была украдена у FlexGet’а.
Каждый плагин сам себя регистрирует в системе. Хотя, как мне кажется, было бы правильнее, чтобы система сама искала плагины, а не плагин знал, как себя зарегистрировать в системе.
Плагин для торрент клиента
Интерфейс плагина очень простой:
class MyClientPlugin(object): name = "myclient" form = [{ ... }] def get_settings(self): pass def set_settings(self, settings): pass def check_connection(self): pass def find_torrent(self, torrent_hash): pass def add_torrent(self, torrent): pass def remove_torrent(self, torrent_hash): pass register_plugin('client', 'myclient', MyClientPlugin())Методы можно разбить на 2 группы, одна группа для хранения настроек торрент клиента, другая — для управления торрентами.
Методы set_settings() и get_settings() сохраняют и читаю данные из базы.
Методы *_torrent() управляют закачками. Торрент файл можно уникально идентифицировать по его хеш коду, поэтому для удаления и поиска уже скачанного или качающегося торрента достаточно передать хеш торрента. А вот для добавления торрена логично, что нужно передать весь торрент.
Библиотека для разбора торрент файла была взята из FlexGet’а. Откуда она появилась там я не смог выяснить (хотя и не сильно пытался). В неё была внесена парочка маленьких модификаций для поддержки python 3 и для чтения чистого не разобранного массива байт.
Поле form описывает форму настроек этого плагина на UI. О том как это работает можно почитать выше в разделе о динамической генерации форм.
Плагины достаточно компакты и просты в имплементации. Например transmission занимает всего 115 строчек, включая пару строк комментариев и 7 строк импортов.
Плагин для трекера
В терминах Monitorrent’а любая подписка на изменения торрентов называется темой (topic). Например для lostfilm мы следим за изменениями сериала на его странице, а не путём разбора RSS. После выхода новой серии мы будем скачивать новый торрент файл, а не изменённый. Поэтому называть подписку темой мне кажется более разумным.
Если контракт плагина для торрент клиента очень простой и поэтому для него нет базового класса, то для трекера все сложнее. Для начала рассмотрим простой интерфейс плагина для трекера:
class TrackerPluginBase(with_metaclass(abc.ABCMeta, object)): topic_form = [{ ... }] @abc.abstractmethod def can_parse_url(self, url): pass def prepare_add_topic(self, url): pass def add_topic(self, url, params): pass def get_topics(self, ids): pass def save_topic(self, topic, last_update, status=Status.Ok): pass def get_topic(self, id): pass def update_topic(self, id, params): pass @abc.abstractmethod def execute(self, topics, engine): passЗдесь также есть методы по работе с настройками определенного торрента *_topic() и отдельный метод для получения всех тем get_topics().
Добавление нового торрента для мониторинга происходит по URL темы. Например для rutracker – это адрес страницы форума, для lostfilm – это страница сериала. Для того, чтобы узнать какой плагин может обработать этот URL, у всех плагинов поочерёдно вызывается метод can_parse_url(), который через regex проверяет может ли он работать с этим URL’ом или нет. Если такой плагин не найден, то пользователь увидит сообщение, что тему добавить не удалось. Если плагин который понимает этот URL был найден, то сначала у него вызывается метод prepare_add_topic(), который возвращает модель с разобранными данными и позволяет пользователю отредактировать эти данные. Форма для редактирования данных описана в поле topic_form. После того как пользователь отредактирует данные темы и нажмёт кнопку Add, вызывается метод add_topic, которому передаётся отредактированная модель и он сохранит эту тему в базу для мониторинга.
Сейчас есть одно общее свойство для всех тем — это display_name. Заголовок который виден на главной странице. Для lostfilm ещё можно выбрать качество скачиваемых серий.
Самый большой и главный метод – это execute(self, topics, engine). Он отвечает за проверку изменений и скачивание новых серий. Ему передается список его тем для проверки и специальный объект engine. Объект engine позволяет добавлять новые торренты в торрент клиент, а так же предоставляет объект для логирования. Торрент клиент для скачиваний может быть только один. И плагину не важно какой-то это клиент, за выбор клиента отвечает engine, плагин просто передает скачанный торрент в engine. В случае когда сериал раздаётся путем добавления новых серий, engine удаляет предыдущую раздачу и добавляет новую.
Так как некоторые трекеры требуют авторизации, для них реализован отдельный тип плагинов который может сохранять информацию для логина WithCredentialsMixin. Как видно из названия этот класс является миксином (почему именно миксин рассказано ниже). Только эти типы плагинов сейчас имеют настройку на UI. Этот класс добавляет к интерфейсу плагина ещё пару методов:
class WithCredentialsMixin(with_metaclass(abc.ABCMeta, TrackerPluginMixinBase)): credentials_form = [{ ... }] @abc.abstractmethod def login(self): pass @abc.abstractmethod def verify(self): pass def get_credentials(self): pass def update_credentials(self, credentials): pass def execute(self, ids, engine): if not self._execute_login(engine): return super(WithCredentialsMixin, self).execute(ids, engine) def _execute_login(self, engine): passМетоды для хранения и загрузки данных авторизации *_credentials. Методы для логина и проверки введенных данных login() и verify() соответственно. Так же он переопределяет метод execute(), для того чтобы сначала авторизоваться на трекере (вызовом метода _execute_login()) и только потом проверять темы на изменения.
Для редактирования настроек используется динамически генерируемая форма из поля credentials_form.
Сейчас проверка изменений на всех трекерах, кроме lostfilm, ведется путём скачивания торрент файла и сравнения его хеша с тем, что был скачан в прошлый раз. Если хеш отличается, то скачивается новый торрент и добавляется в торрент клиент. Наверное, достаточно было сделать проверку самой страницы, посылая HEAD запрос или что-то ещё, но этот вариант надежнее. Размер страницы, как оказалось, больше, чем сам торрент файл, а простое добавление комментария, не являясь изменением торрента, изменит страницу. К тому же rutor не поддерживал HEAD совсем.
Эта логика вынесена в метод execute класса ExecuteWithHashChangeMixin. Это снова миксин, как и WithCredentialsMixin. Это позволяет писать плагины, наследуя 1 или 2 миксина в зависимости от трекера, и переопределять только пару методов.
Вот так определён плагин для free-torrents.org:
class FreeTorrentsOrgPlugin(WithCredentialsMixin, ExecuteWithHashChangeMixin, TrackerPluginBase): ... topic_form = [{ ... }] def login(self): pass def verify(self): pass def can_parse_url(self, url): return self.tracker.can_parse_url(url) def parse_url(self, url): return self.tracker.parse_url(url) def _prepare_request(self, topic): headers = {'referer': topic.url, 'host': "dl.free-torrents.org"} cookies = self.tracker.get_cookies() request = requests.Request('GET', self.tracker.get_download_url(topic.url), headers=headers, cookies=cookies) return request.prepare()В результате только пару методов требуют переопределения, а самая сложная логика по проверке новых торрентов остается неизменной и сосредоточена в миксинах WithCredentialsMixin и ExecuteWithHashChangeMixin.
Плагин для rutor.org использует только ExecuteWithHashChangeMixin:
class RutorOrgPlugin(ExecuteWithHashChangeMixin, TrackerPluginBase): passА плагин для lostfilm использует только WithCredentialsMixin, потому что реализация по поиску изменений у него своя:
class LostFilmPlugin(WithCredentialsMixin, TrackerPluginBase): passПлагин для lostfilm довольно сложный, на целых 640 строк. Особенно сложен логин через bogi, но всё работает как часы уже более 7 месяцев.
В других языках это было бы реализовано слегка по-другому, но я рад, что в python можно использовать множественное наследование, которое стоит делать только через миксины. И обязательно стоит указывать правильный порядок всех наследуемых классов. Это наверное единственный случай, когда мне кажется, что множественное наследование упрощает написание кода.
К сожалению на rutor иногда удаляют раздачи и приходится искать новую, Monitorrent может отследить удалённые раздачи и подсвечивает такие темы пользователю на главном экране. За эту логику тоже отвечает метод execute().
В качестве базы данных используется sqlite. У нас есть тикет для поддержки других баз данных, но я не думаю, что в этом есть необходимость, сложность системы это увеличит не сильно, но придется написать много тестов для тестирования различных баз данных. К тому же сейчас есть небольшое количество кода которое строго завязано на sqlite.
В качестве ORM используется sqlalchemy. Это мощная и удобная ORM, которая поддерживает наследование классов с отображением их на базу. Именно sqlalchemy упростит переход на другую базу данных, если когда-то мы соберёмся добавить поддержку других баз данных.
Код в Monitorrent’е поддерживает миграции данных и схем. К сожалению sqlalchemy из коробки не имеет этого функционала, но есть другой проект от авторов sqlachemy – alembic, который мы и используем для этих целей.
Sqlite драйвер для python имеет пару ограничений. Одно из них это то, что нельзя использовать транзакции вместе с модификацией схемы данных. Иногда это критично при миграции базы данных на новую версию. Решение этой проблемы описано на сайте sqlalchemy. Оттуда этот код был перенесен в Monitorrent. Сейчас миграции работают без каких-либо проблем.
Уже почти все плагины трекеров обзавелись своими миграциями, с самых старых версий до последнего релиза. Реализована поддержка миграций через метод upgrade, который передается при регистрации плагина.
Метод upgrade сначала определяет текущую версию путём различных проверок вроде существования столбцов и таблиц, а потом производит непосредственно миграцию с этой версии до последней.
Пример кода миграции для rutor:
def upgrade(engine, operations_factory): if not engine.dialect.has_table(engine.connect(), RutorOrgTopic.__tablename__): return version = get_current_version(engine) if version == 0: upgrade_0_to_1(engine, operations_factory) version = 1 if version == 1: upgrade_1_to_2(operations_factory) version = 2 def get_current_version(engine): m = MetaData(engine) t = Table(RutorOrgTopic.__tablename__, m, autoload=True) if 'url' in t.columns: return 0 if 'hash' in t.columns and not t.columns['hash'].nullable: return 1 return 2 def upgrade_0_to_1(engine, operations_factory): m0 = MetaData() rutor_topic_0 = Table("rutororg_topics", m0, Column('id', Integer, primary_key=True), Column('name', String, unique=True, nullable=False), Column('url', String, nullable=False, unique=True), Column('hash', String, nullable=False), Column('last_update', UTCDateTime, nullable=True)) m1 = MetaData() topic_last = Table('topics', m1, *[c.copy() for c in Topic.__table__.columns]) rutor_topic_1 = Table('rutororg_topics1', m1, Column("id", Integer, ForeignKey('topics.id'), primary_key=True), Column("hash", String, nullable=False)) def topic_mapping(topic_values, raw_topic): topic_values['display_name'] = raw_topic['name'] with operations_factory() as operations: if not engine.dialect.has_table(engine.connect(), topic_last.name): topic_last.create(engine) operations.upgrade_to_base_topic(rutor_topic_0, rutor_topic_1, PLUGIN_NAME, topic_mapping=topic_mapping)В одной из самых первых версий все плагины имели свою таблицу для хранения тем. Позже общие поля, такие как url и display_name были вынесены в таблицу topics. В коде это реализовано в виде наследования всех классов тем от базового Topic класса.
Поэтому все имеющиеся данные нужно было мигрировать, путём удаления старых столбцов и переноса их в общую таблицу topics. Так как для всех плагинов нужно было проделать аналогичные операции, то она была вынесена в общее место MonitorrentOperations.upgrade_to_base_topic:
def upgrade_to_base_topic(self, v0, v1, polymorphic_identity, topic_mapping=None, column_renames=None): from .plugins import Topic self.create_table(v1) topics = self.db.query(v0) for topic in topics: raw_topic = row2dict(topic, v0) # insert into topics topic_values = {c: v for c, v in list(raw_topic.items()) if c in Topic.__table__.c and c != 'id'} topic_values['type'] = polymorphic_identity if topic_mapping: topic_mapping(topic_values, raw_topic) result = self.db.execute(Topic.__table__.insert(), topic_values) # get topic.id inserted_id = result.inserted_primary_key[0] # insert into v1 table concrete_topic = {c: v for c, v in list(raw_topic.items()) if c in v1.c} concrete_topic['id'] = inserted_id if column_renames: column_renames(concrete_topic, raw_topic) self.db.execute(v1.insert(), concrete_topic) # drop original table self.drop_table(v0.name) # rename new created table to old one self.rename_table(v1.name, v0.name)На самом деле миграции пока не нужны, делать их для 2.5 пользователей не имело смысла. Но мне было обязательно обкатать этот функционал с самого начала, чтобы потом было проще. А миграции ещё явно понадобятся.
Для работы с базой данных был создан специальный класс DBSession который расширен поддержкой python оператора with, для того чтобы можно было писать код следующим образом:
with DBSession() as db: cred = db.query(self.credentials_class).first() cred.c_uid = self.tracker.c_uid cred.c_pass = self.tracker.c_pass cred.c_usess = self.tracker.c_usessЗа основу как обычно брался код из FlexGet’а. Все плагины напрямую работают с базой данных через DBSession(). Никаких репозиториев или других вспомогательных классов не создавалось.
Monitorrent из коробки умеет запускаться периодически для проверки обновлений тем. По умолчанию запуск происходит раз в 2 часа, но это значение можно изменить.
Это реализовано с помощью обертки над threading.Thread. Реализация очень похожа на реализацию threading.Timer, но в нашей реализации есть stop(), который завершит этот поток для правильной остановки приложения. И имеется возможность запустить исполнение по требованию, не дожидаясь запуска по расписанию. Запуск по требованию сбросит таймер, и следующий запуск произойдет спустя 2 часа (если значение не изменено) с момента завершения запуска по требованию.
Для запуска Monitorrent’а нужно запустить файл server.py. Он поднимет вебсервер через cherrypy на порту 6687 по умолчанию.
Отдельно стоит рассказать про параметры запуска:
- debug – режим, в котором ключ для JWT всегда один и тот же, чтобы каждый раз не авторизовываться во время разработки. По умолчанию false. Это всё за что сейчас отвечает этот параметр.
- ip – адрес, на котором сервер слушает входящие соединения. По умолчанию 0.0.0.0.
- port – порт, на котором сервер слушает входящие соединения. По умолчанию 6687
- db_path – путь к файлу базы данных. По умолчанию monitorrent.db. Т.е. база данных расположена в той же папке где и приложение.
- сonfig – путь к файлу конфигурации, где можно указать параметры описанные выше. По умолчанию config.py
Конфигурировать запуск можно 3-мя способами.
Первый, это собственно аргументы запуска описанные выше.
Второй способ — это с помощью файла конфигурации (config.py по умолчанию если не указано другое через командную строку). Это простой python файл, в котором описаны глобальные переменные описанные выше.
Читается он через python exec команду. Для работы с python 3 он был заменён на вызов метода exec_ пакета six.
with open(config_path) as config_file: six.exec_(compile(config_file.read(), config_path, 'exec'), {}, parsed_config)Если файл прочитать не удалось по какой-то причине, выводится ошибка и он игнорируется, на запуск это никак не влияет.
Третий способ конфигурации — переменные окружения: MONITORRENT_DEBUG, MONITORRENT_IP, MONITORRENT_PORT и MONITORRENT_DB_PATH. Файл конфигурации нельзя указывать через переменные окружения.
Аргументы запуска имеют наивысший приоритет, потом следуют переменные окружения и только потом данные из файла конфигурации, если такой существует.
Для запуска в docker контейнере гораздо проще использовать либо аргументы, либо переменные окружения.
Для запуска из папки проще написать config.py, базовой реализации этого файла пока нет.
Весь python код покрыт юнит тестами на 100%. За исключения входной точки –файла server.py. Но в нем тестировать имеет смысл только логику по разбору параметров запуска и чтения их из конфигурационного файла или из переменных окружения. Всё остальное — обычные настройки приложения. Поэтому все это тестировалось лишь один раз при реализации этого функционала.
Чтобы не портить красивую цифру в 100% покрытия кода тестами, этот файл исключен из подсчёта.
В качестве тестового фреймворка используется пакет unittest из стандартной библиотеки python.
Тестируется весь функционал, даже функционал по работе с базой данных. Sqlite позволяет создавать базу в памяти, что очень сильно ускоряет тестирование. Тесты над кодом, работающим с базой данных, обычно следуют называть интеграционными, но в нашем случает это действительно юнит тесты, которые тестируют только одну функциональность.
Существуют также тесты, которые проверяют корректность кода, отвечающего за миграцию данных на новую схему базы.
Основной функционал Monitorrent’а – это закачка торрент файлов с различных трекеров и тестировать в первую очередь нужно именно его.
Мы использовали библиотеку vcrpy, которая упрощает написание тестов для кода, загружающего данные с удалённых серверов. Она делает monkey патчинг пакета requests и может возвращать готовый ответ с файловой системы, не выполняя запрос на удаленный сервер. Т.е. во время первого запуска теста он ходит в настоящий back-end, сохраняет ответ в файл, который потом может быть использован, чтобы быстро вернуть этот же ответ. Это очень сильно ускоряет тесты, так как не нужно ходить за данными в настоящий back-end каждый раз. А если нужно, то всегда можно удалить эти файлы и прогнать тесты на настоящих данных. Правда, это уже стоит называть интеграционными тестами, а не юнит тестами.
Для некоторых тестов реальных данных не достаточно. И тогда нужно формировать html на основе подготовленных фальшивых данных. Или, к примеру, нужно возвращать 404 ошибку. Для этих целей используется библиотека httpretty. С помощью httpretty можно указать, что возвращать, по какому адресу и с каким статусом.
Как обычно, работа тестов через vcrpy была подсмотрена у FlexGet’а. У нас около 97% тестов используют vcrpy и только пару специфических используют httpretty.
Мы используем 2 сервиса, которые показывают процент покрытия кода тестами. Это coveralls.io и codecov.io.
Раньше у нас был небольшой кусочек кода, внутри плагина lostfilm, отвечающий за выбор парсера html:
parser = None # lxml have some issue with parsing lostfilm on Windows if sys.platform == 'win32': parser = 'html5lib' soup = get\_soup(r.text, parser)Это платформозависимый код, поэтому покрытие тестами на Linux для этого файла было не 100%. В отличии от coveralls.io, codecov.io позволяет объединять результаты покрытия тестами с нескольких билд систем. Именно поэтому у нас появилась вторая система. Сейчас этот код заменён на следующий:
# lxml have some issue with parsing lostfilm on Windows, so replace it on html5lib for Windows soup = get\_soup(r.text, 'html5lib' if sys.platform == 'win32' else None)Модуль подсчета покрытия тестами python проверят покрытие всей строки, а не отдельных логических ветвей. Это можно считать жульничеством, но зато теперь можно оставить только один сервис. Какой именно мы ещё не решили. На самом деле они оба хороши. У codecov.io есть плагин для Chrome, который показывает покрытие прямо в github, что оказалось очень удобным.
Тестирование front-end сейчас отсутствует полностью. И я считаю это большой проблемой. Из-за этого уже было пару мелких багов, которые легко было бы отловить тестами.
Также мне хотелось бы проводить полное автоматизированное тестирование всего приложения, используя vcrpy, т.е. без хождения в настоящие back-end’ы.
Monitorrent – кроссплатформенное приложение. Поэтому нам понадобилось 2 билд сервера: один на Windows – это ci.appveyor.com, второй — travis-ci.org на Linux. Appveyor собирает исталлятор для Windows при каждом билде. Но основной – это travis, он не только запускает тесты, но и загружает отчёты по покрытию кода в coveralls.io и codecov.io.
В планах подключить drone.io для автоматической сборки docker контейнеров для x86/x64 и для ARM. Насколько я понял, он это умеет. Если у кого есть опыт, поделитесь пожалуйста в комментариях.
Хотелось бы добавить пару слов про систему контроля версий. Мы пользуемся git flow и хостим все исходники на github. В ветке master есть мерджи только релизов, все мерджи помечены тегами и доступны с кратким описанием и списком закрытых issue. Вся текущая разработка ведётся в ветке develop.
Именование версий ведётся по Semantic Versioning. Последняя версия на момент написания статьи — 1.0.0. До неё было 4 релиз кандидата, несколько альф и бет.
Для планирования следующих версий мы пользуемся плагином ZenHub для Chrome & Firefox, который добавляет вкладки Boards и Burndown прямо на страницу github и позволяет организовать все issue. До этого мы пытались воспользоваться waffle.io, но остановились на ZenHub.
Monitorrent работает бесперебойно уже больше 9 недель со дня релиза.
До этого была одна большая проблема с периодическим зависанием поиска изменений. Она проявлялась только на очень нестабильном соединении с интернетом. Пока к нам в дом вели оптику, разрывы случались каждые несколько минут. Если в этот момент Monitorrent проверял наличие новых серий, то был большой шанс, что он просто зависнет в модуле requests. Почему-то соединение не сбрасывалось по таймауту. Воспроизвести проблему не удавалось на Windows, зато легко воспроизводилось на cubietruck. Выключение модема или разрыв соединения с интернетом вручную тоже не позволяли воспроизвести зависание.
Проблема решилась явным указанием таймаута запроса. Сейчас таймаут равен 10 секундам, и это значение хранится в базе, UI для его редактирования пока отсутствует.
Есть ещё пару не раскрытых тем (логирование, UX вопросы и их решение и другое), но статья и так получилось очень большой и слегка сумбурной, оставлю это на следующий раз.
Планов по развитию много, можно следить за тикетом на github. Также приветствуются советы, pull request’ы и предложения по улучшению, создавайте тикеты на github’е. Или просто запросы на добавление новых трекеров.
Спасибо за то, что дочитали до конца. Надеюсь вам понравится Monitorrent.
habr.com