Здравия желаю, Хабр!
В ответ на предыдущий топик про парсер RSS-ленты LostFilm.TV хочу выложить свой вариант работающий уже около 4х месяцев без каких-либо ошибок.
Суть идеи состоит в том, что сервер качает сериалы и раскладывает по папкам, оформляя при этом файлы с обложкой и нормальным заголовком.
Однако, в работе всей системы участвует не один скрипт, а целый набор скриптов. В такой системе скрипты разделены на pre-обработку и post-обработку.
И, конечно же, для эстетов: файлы каждой серии должны выглядеть красиво и быть разложены по папкам.
• Прочитать RSS-ленту
• Выполнить разбор на отдельные элементы
• Отсеять старые элементы
• Добавить новые элементы в базу и в очередь загрузки transmission
Далее, когда файл загружен его нужно привести в эстетический вид (моя жена предпочитает видеть все сериалы, разложенными по папкам с именем сериала и, имеющими имя файла, содержащее номер сезона/эпизода и название серии, а также с красивой обложкой-иконкой сериала).
После загрузки сериала срабатывает цепочка скриптов, направленных на обработку различного рода файлов, среди которых есть и lostfilm.tv.
• Выполнить проверку наличия в БД имени файла полученного от демона, иначе завершить работу
• Выгрузить обложку из базы
• Применить mkvtools (фильтр англ дорожки, вставка обложки, запись заголовка)
• Положить в папку по имени сериала (создать, если нет)
• Уведомить подписанных по почте и через SMS (мне на телефон, жене на почту)
Из скриптов видно, что работа идет с базой данных, в моем варианте используется SQLite3
Обложки хранятся внутри БД в виде base64, понятно, что от этого база станет жирнее, но все же я предпочел хранить все о сериалах внутри одной базы.
Осталось сделать те вещи, которые уже не так значимы для меня и может быть будут когда-то сделаны.
1. Перевести базу на MySQL/PostgreSQL
2. Сделать веб-интерфейс к базе
3. Сделать автоматическое добавление нового сериала в базу (с обложкой)
n. Будущие исправления в распознователь RSS-ленты
Остальное публике должно быть понятно. В коде есть комментарии.
Скрипт работает уже 4 месяца без сбоев и ошибок (хотя сегодня вот была Эврика с сезоном номер 0, но это был косяк на самом сайте). Сам я военнослужащий и дома бываю примерно раз в 1-2 недели, соответственно работает все в автоматическом режиме с редким контролем, я лишь приезжаю и сливаю новые серии на винт, чтобы что-то посмотреть в части.
Спасибо за внимание!
В ответ на предыдущий топик про парсер RSS-ленты LostFilm.TV хочу выложить свой вариант работающий уже около 4х месяцев без каких-либо ошибок.
Суть идеи состоит в том, что сервер качает сериалы и раскладывает по папкам, оформляя при этом файлы с обложкой и нормальным заголовком.
Однако, в работе всей системы участвует не один скрипт, а целый набор скриптов. В такой системе скрипты разделены на pre-обработку и post-обработку.
И, конечно же, для эстетов: файлы каждой серии должны выглядеть красиво и быть разложены по папкам.
pre-обработчик
Алгоритм работы парсера
• Прочитать RSS-ленту
• Выполнить разбор на отдельные элементы
• Отсеять старые элементы
• Добавить новые элементы в базу и в очередь загрузки transmission
Код парсера
#!/bin/bash export PRFX="/var/lib/transmission-daemon" export SELF=$(basename $(readlink -f $0)) # Загрузка конфигурации . $PRFX/.$SELF/config # Загрузка необходимых функций . $PRFX/.funcs/sqlite . $PRFX/.funcs/transmission # Проверка и запись значения последней даты check_last() { if [ ! -f $LFW_RSS_LAST ] || [ $1 -gt $(cat $LFW_RSS_LAST) ]; then printf "$1" > $LFW_RSS_LAST return 0 else return 1 fi } # Функция разбора заголовка parse_title() { echo "$1" | sed -r 's/^([^(]+)[. ]+\((.+)\)[. ]+([^(]+)[. ]+\((.+)\)[. ]*(\[720p\]){0,1}[. ]*\(S0*([0-9]+)E0*([0-9]+).*\)$/\1|\2|\3|\4|\5|\6|\7/' } logger -t $SELF -- 'Запрос данных RSS/Atom' # Запрос RSS-ленты rsstail -1NHlp -n 30 -u "$LFW_RSS_URL" | # Конвертация потока в совместимый со скриптом формат iconv -f cp1251 | sed -r '/^\s*$/d; s/^\s+//; s/\s+$//' | sed -r '$!N; s/\n/|/; $!N; s/\n/|/' | # Конвертация даты в UNIXTIME и сортировка по убыванию даты (IFS='|'; while read item_title item_link item_date; do printf '%s|%s|%s\n' $(date -d "$item_date" +%s) "$item_title" "$item_link" done) | sort | # Отсеивание новых элементов (IFS='|'; while read item_date item_title item_link; do if check_last $item_date; then printf '%s|%s|%s\n' $item_date "$(parse_title "$item_title")" "$item_link" fi done) | # Обработка новых элементов (IFS='|'; while read date name_ru name_en title_ru title_en hd season episode link; do # получение идентификатора сериала из базы id=$(printf 'SELECT id FROM series WHERE title_en = "%s";' "$name_en" | db_query $LFW_DB) # если есть то обрабатываем, иначе уходим if [ -n "$id" ]; then # загрузка торрент-файла в во временное расположение tr_file="/tmp/lostfilm_$(uuidgen).torrent" if wget -nv -q --header "$LFW_WGET_AUTH" "$link" -O "$tr_file"; then # проверяем добавляли ли ранее сведения о серии в базу, если нет то добавить if [ -z $(printf 'SELECT id FROM episodes WHERE series = %d AND season = %d AND episode = %d;' $id $season $episode | db_query $LFW_DB) ]; then printf 'INSERT INTO episodes (series, season, episode, title_en, title_ru) VALUES (%d, %d, %d, "%s", "%s");' \ $id $season $episode $title_en $title_ru | db_query $LFW_DB fi # здесь идет разделение для HD и SD вариантов серий if [ -z "$hd" ]; then file=$(transmission-show "$tr_file" | sed -r '/^Name:/!d; s/^Name:\s*(.+)\s*$/\1/') #' printf 'INSERT INTO files (id, date, filename) VALUES ((SELECT id FROM episodes WHERE series = %d AND season = %d AND episode = %d), %d, "%s");' \ $id $season $episode $date $file | db_query $LFW_DB if [ $(printf 'SELECT tracked FROM series WHERE id = %d;' $id | db_query $LFW_DB) -ne 0 ]; then transmission --add "$tr_file" --start > /dev/null fi logger -t $SELF -- $(printf 'Добавлена новая SD серия «%s» (сезон %s, серия %s) — «%s»' "$name_ru" "$season" "$episode" "$title_ru") #' else file=$(transmission-show "$tr_file" | sed -r '/^Name:/!d; s/^Name:\s*(.+)\s*$/\1/') #' printf 'INSERT INTO files_hd (id, date, filename) VALUES ((SELECT id FROM episodes WHERE series = %d AND season = %d AND episode = %d), %d, "%s");' \ $id $season $episode $date $file | db_query $LFW_DB if [ $(printf 'SELECT tracked_hd FROM series WHERE id = %d;' $id | db_query $LFW_DB) -ne 0 ]; then transmission --add "$tr_file" --start > /dev/null fi logger -t $SELF -- $(printf 'Добавлена новая HD серия «%s» (сезон %s, серия %s) — «%s»' "$name_ru" "$season" "$episode" "$title_ru") #' fi fi [ -f "$tr_file" ] && rm -f "$tr_file" fi done) logger -t $SELF -- 'Завершено'
post-обработчик
Далее, когда файл загружен его нужно привести в эстетический вид (моя жена предпочитает видеть все сериалы, разложенными по папкам с именем сериала и, имеющими имя файла, содержащее номер сезона/эпизода и название серии, а также с красивой обложкой-иконкой сериала).
После загрузки сериала срабатывает цепочка скриптов, направленных на обработку различного рода файлов, среди которых есть и lostfilm.tv.
Алгоритм работы скрипта пост-обработки
• Выполнить проверку наличия в БД имени файла полученного от демона, иначе завершить работу
• Выгрузить обложку из базы
• Применить mkvtools (фильтр англ дорожки, вставка обложки, запись заголовка)
• Положить в папку по имени сериала (создать, если нет)
• Уведомить подписанных по почте и через SMS (мне на телефон, жене на почту)
Скрипт post-обработки
#!/bin/bash export SELF="lostfilm-rss" # Загрузка конфигурации . $PRFX/.$SELF/config # Загрузка необходимых функций . $PRFX/.funcs/sqlite . $PRFX/.funcs/transmission . $PRFX/.funcs/mkv_tools . $PRFX/.funcs/mail_notify . $PRFX/.funcs/utils . $PRFX/.funcs/sms_notify MAIL_LIST_HD="me@a***n.ru" # выполняем запрос к БД о наличии файла data="$(printf 'SELECT s.title_ru, e.season, e.episode, e.title_ru, s.id FROM episodes e, series s, files_hd f WHERE e.series = s.id AND e.id = f.id AND f.filename = "%s";' "$TR_TORRENT_NAME" | db_query $LFW_DB)" # если есть то обрабатываем, иначе отбой if [ -n "$data" ]; then # разбор результата запроса name=$(echo $data | cut -d'|' -f1) s=$(echo $data | cut -d'|' -f2) e=$(echo $data | cut -d'|' -f3) part=$(echo $data | cut -d'|' -f4) id=$(echo $data | cut -d'|' -f5) # эстетическое имя файла mkv_file=$(printf '/mnt/videos/Series.HD/%s [%s.%s] — %s.mkv' "$name" "$s" "$e" "$part") # форматирование заголовка видео-файла mkv_title=$(printf '«%s» • Сезон %s, Серия %s • «%s»' "$name" "$s" "$e" "$part") # выгрузка обложки из базы mkv_poster="/tmp/mkv_poster_$(uuidgen).jpg" printf 'SELECT data FROM posters WHERE series = %d ORDER BY date DESC LIMIT 1;' $id | db_query $LFW_DB | base64 -d - > $mkv_poster logger -t $SELF -- $(printf 'Загружена HD серия «%s» (сезон %s, серия %s) — «%s»' "$name" "$s" "$e" "$part") #' # ремукс видео-файла с заданными параметрами if to_mkv "/mnt/torrent/$TR_TORRENT_NAME" "$mkv_file" "$mkv_title" "$mkv_poster"; then logger -t $SELF -- $(printf 'Обработана HD серия «%s» (сезон %s, серия %s) — «%s»' "$name" "$s" "$e" "$part") #' # я не раздаю файлы, поскольку подсчет рейтинга сломан уже два года, он у меня не меняется, удаляем торрент вместе с исходником transmission -t $TR_TORRENT_ID --remove-and-delete > /dev/null logger -t $SELF -- $(printf 'Удалена из торрента HD серия «%s» (сезон %s, серия %s) — «%s»' "$name" "$s" "$e" "$part") #' # уведомляем по почте mail_notify "$MAIL_LIST_HD" "$(printf 'Доступна новая серия «%s» (сезон %s, серия %s) — «%s»' "$name" "$s" "$e" "$part")" \ "$(printf '<h3>«%s» (сезон %s, серия %s) — «%s»</h3><br/><i>Качество: HD</i>' "$name" "$s" "$e" "$part")" # отправляем смс sms_notify a***n "$(printf 'Новая серия «%s» (сезон %s, серия %s) — «%s» \n[%s]' "$name" "$s" "$e" "$part" "$(disk_info)")" else logger -t $SELF -- $(printf 'Произошла ошибка при обработке HD серии «%s» (сезон %s, серия %s) — «%s»' "$name" "$s" "$e" "$part") #' fi rm -f $mkv_poster fi
База данных
Из скриптов видно, что работа идет с базой данных, в моем варианте используется SQLite3
Структура базы данных
CREATE TABLE episodes ( id INTEGER PRIMARY KEY AUTOINCREMENT, series INTEGER REFERENCES series(id) ON UPDATE CASCADE ON DELETE CASCADE, season INTEGER NOT NULL, episode INTEGER NOT NULL, title_en TEXT NOT NULL, title_ru TEXT NOT NULL, UNIQUE(series, season, episode) ); CREATE TABLE files ( id INTEGER PRIMARY KEY REFERENCES episodes(id) ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL, filename TEXT NOT NULL ); CREATE TABLE files_hd ( id INTEGER PRIMARY KEY REFERENCES episodes(id) ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL, filename TEXT NOT NULL ); CREATE TABLE posters ( id INTEGER PRIMARY KEY AUTOINCREMENT, series INTEGER REFERENCES series(id) ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL, data TEXT NOT NULL ); CREATE TABLE series ( id INTEGER PRIMARY KEY AUTOINCREMENT, title_en TEXT NOT NULL, title_ru TEXT NOT NULL, tracked INTEGER DEFAULT 0 , tracked_hd integer default 1);
Обложки хранятся внутри БД в виде base64, понятно, что от этого база станет жирнее, но все же я предпочел хранить все о сериалах внутри одной базы.
TODO и PS
Осталось сделать те вещи, которые уже не так значимы для меня и может быть будут когда-то сделаны.
1. Перевести базу на MySQL/PostgreSQL
2. Сделать веб-интерфейс к базе
3. Сделать автоматическое добавление нового сериала в базу (с обложкой)
n. Будущие исправления в распознователь RSS-ленты
Остальное публике должно быть понятно. В коде есть комментарии.
Скрипт работает уже 4 месяца без сбоев и ошибок (хотя сегодня вот была Эврика с сезоном номер 0, но это был косяк на самом сайте). Сам я военнослужащий и дома бываю примерно раз в 1-2 недели, соответственно работает все в автоматическом режиме с редким контролем, я лишь приезжаю и сливаю новые серии на винт, чтобы что-то посмотреть в части.
Спасибо за внимание!
