Как я научил родителей качать турецкие сериалы одним щелчком

в 11:46, , рубрики: rutracker, Программирование, торренты, метки: , ,

Добрый день!
У многих из нас есть родители, которые не очень дружат с техникой, и дружить приходится за них. Моя семья в полном составе смотрит сериал "Великолепный век", серии которого выходят раз в неделю. Вроде не так часто, но субботу за субботой слышать «Иди проверь, нет ли серии», искать раздачу, запускать торрент и так далее стало утомительно, и я решил переложить это на цифровые плечи четвертого .NetFramework-а.
Что нам понадобится:
Visual Studio 2010 или выше
— Консольный торрент-клиент Aria2c.

Осторожно, местами присутствует индусский код! Я предупреждал.

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

Для начала нам нужно понять, какую серию мы хотим скачать. Сериал выходит в Турции по средам, у нас с переводом в субботу-воскресение. На днях вышла 96 серия. Сейчас по календарю идет 18 неделя. Значит, к номеру текущей недели надо прибавить 78, если программу запускают в будний день, и 79, если в выходные.
Выглядеть это будет так:

        DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
        DateTime date1 = DateTime.Now;
        Calendar cal = dfi.Calendar;
        var week = cal.GetWeekOfYear(date1, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
        var day = (int)cal.GetDayOfWeek(date1) == 0 ? 6 : (int)cal.GetDayOfWeek(date1) - 1; //В США недели начинаются с воскресения, поэтому метод GetDayOfWeek возвращает 0 для воскресения, расставим  дни в привычном порядке. GetWeekOfYear же возвращаем правильное значание, так как применена локаль
        var epnumber = week + 79 - ((day < 5) ? 1 : 0);

Теперь, когда нам известен номер серии, можем идти на треккер.
Сперва нужно авторизоваться, для этого создаем POST-запрос на страничку login.php, и передаем ему пару логин-пароль.

byte[] buffer = Encoding.ASCII.GetBytes("login_username=ВАШ_ЛОГИН&login_password=ВАШ_ПАРОЛЬ&login=%C2%F5%EE%E4");
        HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create("http://login.rutracker.org/forum/login.php");//Строка для Post-запроса
        var cc = new CookieContainer();
        WebReq.CookieContainer = cc;//включаем куки
        WebReq.Method = "POST";
        WebReq.ContentType = "application/x-www-form-urlencoded";
        WebReq.ContentLength = buffer.Length;
        HttpWebResponse WebResp;

        try
        {
            Stream PostData = WebReq.GetRequestStream();
            PostData.Write(buffer, 0, buffer.Length);
            PostData.Close();
            WebResp = (HttpWebResponse)WebReq.GetResponse();
        }
        catch (Exception e)
        {
            MessageBox.Show("Ошибка сети", " ", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

Сервер в ответ плюнул в нас кукой авторизации, которая хранится у нас в cc. Теперь с этой кукой можно сделать запрос на поиск серии:

        var url = @"http://rutracker.org/forum/tracker.php?nm=%D0%92%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D0%BB%D0%B5%D0%BF%D0%BD%D1%8B%D0%B9%20%D0%B2%D0%B5%D0%BA%20sub%20"+epnumber;
 WebReq = (HttpWebRequest)WebRequest.Create(url);
        WebReq.CookieContainer = cc;
        WebReq.Method = "GET";
        WebReq.ContentType = "application/x-www-form-urlencoded";
        WebResp = (HttpWebResponse)WebReq.GetResponse();

        string result;
        Encoding responseEncoding = Encoding.GetEncoding(WebResp.CharacterSet);
        try
        {
            using (StreamReader sr = new StreamReader(WebResp.GetResponseStream(), responseEncoding))
            {
                result = sr.ReadToEnd();
            }
        }
        catch (Exception e)
        {
            MessageBox.Show("Ошибка сети", "Заголовок сообщения", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

Страницу поиска парсим на наличие ссылок на торрент файлы вида dl.rutracker.org/forum/dl.php?12345:

 string pattern = @"http://dl.rutracker.org/forum/dl.php?t=d+";
        Regex regex = new Regex(pattern);
        Match match = regex.Match(result);
        if (match.Length == 0)
        {

            MessageBox.Show("Новая серия еще не вышла!", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }
        else 
          AutoClosingMessageBox.Show("Новая серия вышла! Начинаем закачку.", "Caption", 3000);

Торрент-файл найден, сохраняем его на жесткий диск:

 try
        {
            WebReq = (HttpWebRequest)WebRequest.Create(match.ToString());
            WebReq.CookieContainer = cc;
            WebReq.AllowAutoRedirect = false;
            WebReq.Method = "POST";
            WebReq.Referer = url;
            WebReq.ContentType = "application/x-www-form-urlencoded";

            /*Пишем его в файл*/
            Stream ReceiveStream = WebReq.GetResponse().GetResponseStream();
            string filename = @"C:123.torrent";
            byte[] buffer1 = new byte[1024];
            FileStream outFile = new FileStream(filename, FileMode.Create);
            int bytesRead;
            while ((bytesRead = ReceiveStream.Read(buffer1, 0, buffer.Length)) != 0)
                outFile.Write(buffer1, 0, bytesRead);
            outFile.Close();
            ReceiveStream.Close();
            

        }
        catch (Exception e)
        {
            MessageBox.Show("Ошибка при скачке торрент-файла!", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

Теперь проверяем, не забыли ли незадачливые родственники вставить флешку, и достаточно ли на ней места:

string letter = "";
        foreach (DriveInfo i in System.IO.DriveInfo.GetDrives())
        {


            try
            {
                if (i.DriveType.ToString() == "Removable" && i.ToString() != "A:\")
                {
                    if (i.TotalFreeSpace < 3000000000)
                    {
                        MessageBox.Show("На флешке мало место, нужно 3гб!", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }

                    letter = String.Copy(i.ToString());
                    break;
                }
                //Console.WriteLine(i.DriveType);

            }
            catch (Exception E)
            {
                return;
            }
        }
        if (letter == "")
        {
            MessageBox.Show("Вставь флешку!", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

Наконец, все готово к скачке, можно приступать!

 string par = @"--seed-time=0 -d " + letter + " --select-file="+(epnumber-3)+ @" ""C:123.torrent"" ";
//--seed-time=0 - выход сразу после загрузки, не сидируя. Нужно для сигнализации о завершения загрузки, да простят меня личи.
//-d - указывает в качестве папки загрузки найденную ранее свободную флешку
//--select-file - номер файла, нужного для скачки. В раздаче три серии пропущены, поэтому уменьшаем индекс на 3.

        Process P = Process.Start(@"C:aria2-1.17.0-win-32bit-build1aria2-1.17.0-win-32bit-build1aria2c.exe", par);
        P.WaitForExit();
        int result1 = P.ExitCode;
        Console.WriteLine(result1);
        if (result1 == 0)
        {
            MessageBox.Show("Фильм скачан! Можно вытаскивать флешку!", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        else
        {
            MessageBox.Show("Неизвестная ошибка!", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

Все, сериал скачан и ждет просмотра.
Полный текст скрипта на http://pastebin.com/8L03vkJg.
Берегите ваших родителей.

P.S. Да, понятно, что на Per/PHP/Python/… можно уменьшить количество строчек в несколько раз. Код написан с целью самообразования.

Автор: Yogami

Источник

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


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