<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Неофициальный форум DLNA Home Media Server &mdash; Работа с torrent файлами]]></title>
	<link rel="self" href="https://hms.lostcut.net/extern.php?action=feed&amp;tid=628&amp;type=atom" />
	<updated>2019-04-26T17:12:47Z</updated>
	<generator>PunBB</generator>
	<id>https://hms.lostcut.net/viewtopic.php?id=628</id>
		<entry>
			<title type="html"><![CDATA[Re: Работа с torrent файлами]]></title>
			<link rel="alternate" href="https://hms.lostcut.net/viewtopic.php?pid=14382#p14382" />
			<content type="html"><![CDATA[<p>Спасибо за статью! <img src="https://hms.lostcut.net/extensions/k_smiles/img/ab.gif" alt=":)" /></p>]]></content>
			<author>
				<name><![CDATA[михаил]]></name>
				<uri>https://hms.lostcut.net/profile.php?id=760</uri>
			</author>
			<updated>2019-04-26T17:12:47Z</updated>
			<id>https://hms.lostcut.net/viewtopic.php?pid=14382#p14382</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Работа с torrent файлами]]></title>
			<link rel="alternate" href="https://hms.lostcut.net/viewtopic.php?pid=14341#p14341" />
			<content type="html"><![CDATA[<div class="wh_markdown"><div class="markdown-body"><p>По просьбам телезрителей и как обещано опишу на примере как работать с торрент ресурсами и самими торрент-файлами.</p>
<p>На самом деле всё очень просто и всё можно описать в одном предложении: скачиваем torrent-файл и указываем в создаваемой ссылке на видео такую строку <code>"torrent:&lt;Путь до скачанного torrent файла&gt;?index=&lt;Номер видео файла в файле torrent&gt;"</code>.
Где <code>&lt;Номер видео файла в файле torrent&gt;</code> - можно не указывать, если в раздаче всего-лишь один файл.</p>
<p>На этом всё. До новых встреч.</p>
<p>Правда, просившие люди всё разъяснить, вряд ли будут довольны таким изложением и ждут что я напишу целую книгу про это. Поэтому я всё-таки разберу это дело на примере сайта и напишем целый подкаст. За пример возьму предложенный <strong>михаил</strong>ом сайт <a href="http://toreents.club" target="_blank">toreents.club</a>.</p>
<p>Для начала немного теории. Я буду краток, чтобы информация была предельно простой, не вдаваясь в некоторые подробности и сложности, которые могут быть. Так, мне кажется, будет лучше для понимания принципа. А усложнить кодеры и без меня смогут при написании скриптов.
Правда большая часть текста будет посвящена общим вопросам написания подкастов.</p>
<p>Итак.</p>
<h3><a href="#Общая_информация_о_торрентфайлах" name="Общая_информация_о_торрентфайлах" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Общая информация о торрент-файлах</h3>
<p>В самих торрент файлах содержится информация о том, сколько и какие файлы присутствуют в раздаче. Их имя и размер. Собственно и всё. Конечно также и адреса, откуда идёт раздача.
Торрент файлы могут быть двух типов: </p>
<ul>
<li>Однофайловый - там содержится информация об одном файле, его имя и размер. </li>
<li>Многофайловый - содержится информация о количестве файлов, их расположении в подпапках, их имена и размер.</li>
</ul>
<h3><a href="#Создание_подкаста" name="Создание_подкаста" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Создание подкаста</h3>
<p>Теперь приступим к написанию самого подкаста для работы с этими файлами.</p>
<p>Для начала добавим папку с названием "toreents.club", в которой будут подкасты разделов, например "Каталог фильмов" со ссылкой <code>"http://toreents.club/katalog-torrent-films/"</code> и "Зарубежные сериалы" со ссылкой <code>"http://toreents.club/serialy/zarubezhnye-serialy/"</code>.<br />
Добавим в созданную папку эти подкасты и зададим им вышеуказанные значения.<br />
Или если вы такой же лентяй как и я, то можно написать простейший скрипт, который создаст их за нас.</p>
<h4><a href="#Скрипт_создания_подкастлент_Alt1" name="Скрипт_создания_подкастлент_Alt1" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Скрипт создания подкаст-лент (Alt+1)</h4>
<p>Для этого нажав правой клавишей мышки на корневой папке подкаста выберем "Изменить название / Настройки F2". Внизу выбираем вкладку "Скрипты" и выставляем следующие значения:<br />
"Скрипт создания подкаст лент" - "Включён" и нажимаем кнопку редактирования скрипта.</p>
<p>Там в редакторе выставляем язык "JScript" и вставляем простейший скрипт:</p>
<pre><code class="language-hmsjs">///////////////////////////////////////////////////////////////////////////////
//                     Г Л А В Н А Я   П Р О Ц Е Д У Р А                     //
{
  FolderItem.DeleteChildItems();
  
  base = 'http://toreents.club/';

  FolderItem.AddFolder(base+'katalog-torrent-films/'              )[mpiTitle] = 'Каталог фильмов';
  FolderItem.AddFolder(base+'katalog-torrent-films/russkie-fylmy/')[mpiTitle] = 'Русские фильмы';
  
  FolderItem.AddFolder(base+'serialy/russkie-serialy/'    )[mpiTitle] = 'Русские сериалы';
  FolderItem.AddFolder(base+'serialy/zarubezhnye-serialy/')[mpiTitle] = 'Зарубежные сериалы';
}
</code></pre>
<p>После нажатия ОК и сохранения этого всего дела можем нажав правой клавишей мышки на корневой папке выбрать пункт "Создать ленты подкастов", после чего указанные разделы будут созданы автоматически.<br />
Доработать подобный скрипт по своему усмотрению всё также не трудно.</p>
<h4><a href="#Скрипт_обновления_раздела_подкаста_Alt2" name="Скрипт_обновления_раздела_подкаста_Alt2" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Скрипт обновления раздела подкаста (Alt+2)</h4>
<p>Теперь переходим к созданию скрипта, который непосредственно будет создавать в существующих разделах списки фильмов или сериалов.
На самом деле вот то, что я сейчас рассказываю вообще к работе с torrent-файлами отношения никакого не имеет, это просто создание обычного подкаста, который ищет информацию на сайте и создаёт список найденных видео или папок, как в нашем случае, с наименованиями фильмов или сериалов.<br />
Но деваться некуда, ведь подкаст нужно сделать, да так, чтобы он работал. Поэтому создадим простой скрипт, который при обновлении раздела будет искать на сайте информацию о фильмах и создавать нам этот список в подкасте.</p>
<p>Именно этот этап очень сильно зависит от того, что за сайт мы обрабатываем, какой он структуры и прочее. Поэтому как и что делать тут сильно зависит от того, в каком виде и как именно информация представлена на сайте.<br />
Именно в нашем этом конкретном случае на сайте есть список фильмов, при заходе на страницу фильма там выложены разные торрент-файлы этого фильма или сериала. А в сериалах сразу выложены торрент-файлы всего сезона или нескольких серий.<br />
Поэтому в нашем случае логичнее всего сделать следующее:</p>
<ul>
<li>При обновлении подкаста раздела - будут созданы папки с именем фильма/сериала. </li>
<li>При заходе в такую папку - будут созданы папки с именем найденных торрент-файлов на странице фильма.</li>
<li>А уже при заходе в папку торрент-файла - будут созданы ссылки на видео, которые уже непосредственно будут воспроизводиться.</li>
</ul>
<p>Итак, создадим скрипт обновления раздела, который создаст список фильмов.<br />
Для этого идём в всё туда же - встаём на корневую папку подкаста и нажимаем F2, на вкладке "Скрипты" ставим "Режим чтения списка ресурсов" в значение "Специальный (скрипт)", в разделе "Скрипт чтения списка ресурсов (Alt+2)" выставляем "Включен" и нажимаем кнопку редактирования скрипта.<br />
Там выставляем язык "C++Script" и можем сразу набрать шаблон с главной процедурой и объявлением единственной переменной gsUrlBase, которая будет равна <code>"http://toreents.club"</code>.<br />
А в главной процедуре пишем пару строк:<br />
Стандартная <code>FolderItem.DeleteChildItems()</code> - для удаления ранее созданных элементов в подкасте раздела и вызов функции <code>LoadAndParse()</code>, которую мы напишем для загрузки и обработки данных:</p>
<pre><code class="language-hmscpp">string gsUrlBase = 'http://toreents.club'; // База для относительных ссылок

///////////////////////////////////////////////////////////////////////////////
//                    Г Л А В Н А Я    П Р О Ц Е Д У Р А                     //
{
  FolderItem.DeleteChildItems(); // Удаляем созданные ранее элементы в текущей папке
  LoadAndParse();                // Запускаем загрузку страниц и создание папок видео
}
</code></pre>
<p>Перед главной процедурой добавляем функцию <code>LoadAndParse()</code> и пока просто объявляем переменные в ней:</p>
<pre><code class="language-hmscpp">///////////////////////////////////////////////////////////////////////////////
// Загрузка страниц и парсинг
void LoadAndParse() {
  string sHtml, sLink, sName, sImg, sYear; int i, nPages; TRegExpr RegEx; // Объявление переменных

}
</code></pre>
<p>Если мы полазим по сайту, то обнаружим, что переходя на следующие страницы с фильмами, окончание ссылки будет выглядеть вот так:
<code>/page/2/</code> и проч. Это значит, что мы можем в цикле загрузить несколько страниц, чтобы в них уже искать имена и ссылки на выложенные фильмы.</p>
<p>Можно написать вот такую функцию цикла загрузки страниц раздела:</p>
<pre><code class="language-hmscpp">  sHtml  = ''; // Общий текст загруженных страниц сайта
  nPages = 2 ; // Количество загружаемых страниц

  // Загружаем первые сколько-то страниц (указано в nPages)
  for (i=1; i&lt;=nPages; i++) {
    HmsSetProgress(Trunc(i*100/nPages));          // Устанавливаем позицию прогресса загрузки
    HmsShowProgress(Format('%s: Страница %d из %d', [mpTitle, i, nPages])); // Показываем окно прогресса выполнения
    sLink = mpFilePath+'page/'+IntToStr(i)+'/';   // Формируем ссылку для загрузки, включающую номер страницы
    sHtml+= HmsUtf8Decode(HmsDownloadUrl(sLink)); // Загружаем страницу
    if (HmsCancelPressed()) break;                // Если в окне прогресса нажали "Отмена" - прерываем цикл
  }
  HmsHideProgress();                              // Убираем окно прогресса с экрана
</code></pre>
<p>Т.е. мы задаём количество страниц, которые хотим загрузить и в цикле в нашей ссылке раздела добавляем строку <code>page/2/</code>, <code>page/3/</code> и т.д.<br />
Заодно показывая прогресс загрузки с указанием какую из скольки страниц мы загрузили.<br />
За это отвечают функции <code>HmsSetProgress()</code> (устанавливает позицию полосы прогресса), <code>HmsShowProgress()</code> (отображение самого прогресса и его заголовка), а после цикла скрываем прогресс функцией <code>HmsHideProgress()</code>.
В итоге в переменной sHtml у нас будет содержаться весь html текст страниц, которые мы загрузили.</p>
<p>И вот в этом html мы будем искать, как обычно - по регулярным выражениям, блоки с информацией о фильме.
Посмотрев исходники страниц сайта, можно убедиться, что блоки с информацией заключены между словами "shortstory" и "bsep". Поэтому создаём объект типа <em>TRegExpr</em> для поиска таких блоков. А внутри найденных блоков уже ищем информацию об имени, ссылке на страницу фильма и изображении.</p>
<p>Вот такой код получился для поиска фильмов на странице:</p>
<pre><code class="language-hmscpp">  RegEx = TRegExpr.Create('shortstory(.*?)bsep', PCRE_SINGLELINE);
  try {
    if (RegEx.Search(sHtml)) do {            // Если нашли совпадение, запускаем цикл
      sLink=''; sName=''; sImg=''; sYear=''; // Очищаем переменные от предыдущих значений
      // Получаем значения в переменные по регулярным выражениям
      HmsRegExMatch('&lt;a[^&gt;]+href="(.*?)"'  , RegEx.Match, sLink); // Ссылка
      HmsRegExMatch('(&lt;a[^&gt;]+href=.*?&lt;/a&gt;)', RegEx.Match, sName); // Наименование
      HmsRegExMatch('&lt;img[^&gt;]+src="(.*?)"' , RegEx.Match, sImg ); // Картинка
      HmsRegExMatch('(\\d{4})\\)'          , sName      , sYear); // Год

      if (sLink=='') continue;          // Если нет ссылки, значит что-то не так

      sLink = HmsExpandLink(sLink, gsUrlBase);             // Делаем ссылку полной, если она таковой не является
      if (sImg!='') sImg = HmsExpandLink(sImg, gsUrlBase); // Если есть ссылка на картинку, делаем ссылку полной
      sName = HmsHtmlToText(sName);                        // Преобразуем html в простой текст
      HmsRegExMatch('(.*?)/' , sName, sName);              // Обрезаем слишком длинные названия (на англ. языке)

      // Если в названии нет года, добавляем год выхода
      if ((sYear!='') &amp;&amp; (Pos(sYear, sName)&lt;1)) sName += ' ('+sYear+')';

      THmsScriptMediaItem Item = FolderItem.AddFolder(sLink); // Создаём папку с указанной ссылкой
      Item[mpiTitle     ] = sName; // Присваиваем наименование
      Item[mpiThumbnail ] = sImg;  // Картинка

    } while (RegEx.SearchAgain);        // Повторяем цикл, если найдено следующее совпадение

  } finally { RegEx.Free; }             // Что бы ни случилось, освобождаем объект из памяти
</code></pre>
<p>Всё, скрипт для поиска фильмов создания папок для них готов.
<div class="md_spoiler_switcher"><div class="md_spoiler_header"><strong>+</strong>&nbsp;<a href="#Итоговый_скрипт_обновления_раздела_подкаста_Alt2" name="Итоговый_скрипт_обновления_раздела_подкаста_Alt2" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Итоговый скрипт обновления раздела подкаста Alt+2</div><div name="Итоговый_скрипт_обновления_раздела_подкаста_Alt2" class="md_spoiler"></p>
<pre><code class="language-hmscpp">string gsUrlBase = 'http://toreents.club'; // База для относительных ссылок

///////////////////////////////////////////////////////////////////////////////
// Загрузка страниц и парсинг
void LoadAndParse() {
  string sHtml, sLink, sName, sImg, sYear; int i, nPages; TRegExpr RegEx;
  
  sHtml  = ''; // Текст загруженных страниц сайта
  nPages = 2 ; // Количество загружаемых страниц

  // Загружаем первые сколько-то страниц (указано в nPages)
  for (i=1; i&lt;=nPages; i++) {
    HmsSetProgress(Trunc(i*100/nPages));          // Устанавливаем позицию прогресса загрузки
    HmsShowProgress(Format('%s: Страница %d из %d', [mpTitle, i, nPages])); // Показываем окно прогресса выполнения
    sLink = mpFilePath+'page/'+IntToStr(i)+'/';   // Формируем ссылку для загрузки, включающую номер страницы
    sHtml+= HmsUtf8Decode(HmsDownloadUrl(sLink)); // Загружаем страницу
    if (HmsCancelPressed()) break;                // Если в окне прогресса нажали "Отмена" - прерываем цикл
  }
  HmsHideProgress();                              // Убираем окно прогресса с экрана

  RegEx = TRegExpr.Create('shortstory(.*?)bsep', PCRE_SINGLELINE);
  try {
    if (RegEx.Search(sHtml)) do {            // Если нашли совпадение, запускаем цикл
      sLink=''; sName=''; sImg=''; sYear=''; // Очищаем переменные от предыдущих значений
      // Получаем значения в переменные по регулярным выражениям
      HmsRegExMatch('&lt;a[^&gt;]+href="(.*?)"'  , RegEx.Match, sLink); // Ссылка
      HmsRegExMatch('(&lt;a[^&gt;]+href=.*?&lt;/a&gt;)', RegEx.Match, sName); // Наименование
      HmsRegExMatch('&lt;img[^&gt;]+src="(.*?)"' , RegEx.Match, sImg ); // Картинка
      HmsRegExMatch('(\\d{4})\\)'          , sName      , sYear); // Год

      if (sLink=='') continue;          // Если нет ссылки, значит что-то не так

      sLink = HmsExpandLink(sLink, gsUrlBase);             // Делаем ссылку полной, если она таковой не является
      if (sImg!='') sImg = HmsExpandLink(sImg, gsUrlBase); // Если есть ссылка на картинку, делаем ссылку полной
      sName = HmsHtmlToText(sName);                        // Преобразуем html в простой текст
      HmsRegExMatch('(.*?)/' , sName, sName);              // Обрезаем слишком длинные названия (на англ. языке)

      // Если в названии нет года, добавляем год выхода
      if ((sYear!='') &amp;&amp; (Pos(sYear, sName)&lt;1)) sName += ' ('+sYear+')';

      THmsScriptMediaItem Item = FolderItem.AddFolder(sLink); // Создаём папку с указанной ссылкой
      Item[mpiTitle     ] = sName; // Присваиваем наименование
      Item[mpiThumbnail ] = sImg;  // Картинка

    } while (RegEx.SearchAgain);        // Повторяем цикл, если найдено следующее совпадение

  } finally { RegEx.Free; }             // Что бы ни случилось, освобождаем объект из памяти
}

///////////////////////////////////////////////////////////////////////////////
//                    Г Л А В Н А Я    П Р О Ц Е Д У Р А                     //
{
  FolderItem.DeleteChildItems(); // Удаляем созданные ранее элементы в текущей папке
  LoadAndParse();                // Запускаем загрузку страниц и создание папок видео
}
</code></pre>
<p></div></div></p>
<p>Сохраняем это всё и теперь вызывать этот скрипт для редактирования можно выделив конкретный раздел и нажав Alt+2.</p>
<p>Ура, если обновить раздел "Каталог фильмов" у нас будут созданы папки с именами фильмов.</p>
<h4><a href="#Скрипт_получения_ссылки_на_ресурс_Alt4" name="Скрипт_получения_ссылки_на_ресурс_Alt4" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Скрипт получения ссылки на ресурс (Alt+4)</h4>
<p>Теперь нужно написать скрипт, который будет срабатывать при заходе в такую папку фильма, а также который будет срабатывать при запуске ссылки видео на просмотр.
Включается он тут: встаём на корневую папку подкаста и нажимаем F2, на вкладке "Скрипты" раздел "Скрипт получения ссылки на ресурс (Alt+4)" ставим значение "Включен" и нажимаем кнопку редактирования скрипта.
Выбираем язык "C++Script" и зададим для начала всего-лишь пустой шаблон вида:</p>
<pre><code class="language-hmscpp">///////////////////////////////////////////////////////////////////////////////
//                     Г Л А В Н А Я   П Р О Ц Е Д У Р А                     //
{

  // Проверяем, при каком событии было вызвано выполнение скрипта (не вход ли в папку это?)
  if (PodcastItem.IsFolder) {
    
    PodcastItem.DeleteChildItems(); // Удаляем в текущей папке все элементы
    
  } else {

    MediaResourceLink = mpFilePath; // Это просто запустили ссылку видео на просмотр

  }

}
</code></pre>
<p>В этом скрипте, как обычно, нужно проверять, сработал ли он при событии захода в пустую подпапку подкаста или это запустили фильм на просмотр. Переменная <code>PodcastItem</code> содержит значение элемента базы данных программы - либо это папка, либо это запущенная ссылка. Поэтому проверив у этого элемента свойство IsFolder мы можем определить, является ли текущий элемент папкой. Если является - удаляем на всякий случай все в ней элементы (полезно при отладке) и потом нужно будет вызвать функцию, в которой мы загрузим страницу фильма, поищем там торрент файлы и создадим папки с их именем и ссылкой на скачивание этих файлов.</p>
<p>Для этого создадим такую функцию:</p>
<pre><code class="language-hmscpp">///////////////////////////////////////////////////////////////////////////////
// Поиск торрент-файлов на странице фильма и создание папок для них
void CreateTorrentFolders() {
  string sLink;
  string sHtml = HmsUtf8Decode(HmsDownloadURL(mpFilePath));

  // Поиск торрент-файлов на странице фильма / сериала
  TRegExpr RegEx = TRegExpr.Create('"attachment"&gt;(.*?)&lt;/div&gt;', PCRE_SINGLELINE);
  if (RegEx.Search(sHtml)) do {
    HmsRegExMatch('&lt;a[^&gt;]+href="(.*?)"', RegEx.Match, sLink);
    THmsScriptMediaItem Item = PodcastItem.AddFolder(sLink);
    Item[mpiTitle] = HmsHtmlToText(RegEx.Match);
  } while (RegEx.SearchAgain());

}
</code></pre>
<p>Т.е. мы командой <code>sHtml = HmsUtf8Decode(HmsDownloadURL(mpFilePath))</code> загружаем страницу фильма.<br />
Потом создаём объект типа <em>TRegExpr</em> для поиска блоков между <code>"attachment"&gt;</code> и <code>&lt;/div&gt;</code>. Там как раз попадается ссылка на скачивание торрент-файлов.<br />
В каждом таком найденном блоке мы получаем ссылку href из html тега <code>&lt;a&gt;</code>. И командой<br />
<code>THmsScriptMediaItem Item = PodcastItem.AddFolder(sLink);</code><br />
мы создаём папку торрент файла, где в ссылке будет указано ссылка на скачивание вида <code>"http://toreents.club/engine/download.php?id=&lt;Номер&gt;"</code>.</p>
<p>Т.к. при заходе в пустую папку это может быть как фильм, так и папка торрент файла такого вида, то нам нужно также проверять, в какую именно вида папку мы зашли и вызывать разные для этого функции. Поэтому главную процедуру можно сделать такого вида:</p>
<pre><code class="language-hmscpp">///////////////////////////////////////////////////////////////////////////////
//                     Г Л А В Н А Я   П Р О Ц Е Д У Р А                     //
{

  // Проверяем, при каком событии было вызвано выполнение скрипта (не вход ли в папку это?)
  if (PodcastItem.IsFolder) {
    
    PodcastItem.DeleteChildItems(); // Удаляем в текущей папке все элементы
    
    if (Pos('download.php', mpFilePath)&gt;0) 
      CreateFilesFromTorrentFile(); // Скачиваем сам torrent файл и создаём ссылки на видео из него
    else                                   
      CreateTorrentFolders();       // Ищем ссылки на torrent файлы и создаём папки с их наименованиями

  } else {

    MediaResourceLink = mpFilePath; // Это просто запустили ссылку видео на просмотр

  }

}
</code></pre>
<p>Где функция <code>CreateTorrentFolders()</code> у нас уже написана, а функцию <code>CreateFilesFromTorrentFile()</code> мы пока сделаем пустой, но напишем потом там самое интересное - обработку torrent-файла.</p>
<pre><code class="language-hmscpp">///////////////////////////////////////////////////////////////////////////////
// Создание ссылок видео из torrent-файла
void CreateFilesFromTorrentFile() {
}
</code></pre>
<p>Теперь логика главной процедуры такая:</p>
<ul>
<li>Если зашли в папку - проверяем, содержит ли ссылка этой папки слово "download.php", </li>
<li>если содержит, то это папка со ссылкой на конкретный torrent-файл,</li>
<li>а если не содержит - то это считаем папка фильма/сериала, где мы вызываем CreateTorrentFolders для загрузки страницы фильма и поиска там ссылок на скачивание торрент-файлов.</li>
</ul>
<p>Ну а теперь нам осталось написать функцию, которая при заходе в папку со ссылкой на скачивание торрент-файла - скачивала бы его, анализировала и создавала бы ссылки на видео, которые этот торрент-файл раздаёт. Т.е. мы подошли наконец-то к сути нашего урока - работы с торрент файлами и каким видом ссылки могут быть у подобных видео.</p>
<p>Для начала нам нужно скачать сам торрент-файл.<br />
Сделать это удобнее всего командой <code>HmsDownloadUrlToFile()</code>, где в параметрах указывается ссылка на торрент и сам файл на диске, который им станет после скачивания. Также, кстати, в этой команде передаются http заголовки, которые помогут нам не обломаться со скачиванием.</p>
<p>Поэтому для начала объявляем переменные и присваиваем переменной sHeaders значение с "Referer":<br />
<code>sHeaders = 'Referer: '+PodcastItem.ItemParent[mpiFilePath]+'\r\n';</code><br />
После этого будет указан Referer со значением ссылки самого фильма.</p>
<p>Также задаём имя, в который будет скачан торрент-файл:<br />
<code>sFile = HmsTranscodingTempDirectory+mpTitle;</code></p>
<p>Как не трудно догадаться <code>HmsTranscodingTempDirectory()</code> - это функция получения директории для хранения временных файлов программы.</p>
<p>После этого переменная sFile может содержать что-то вроде
<code>"C:\Users\body\AppData\Local\Home Media Server\HMS\Temp\kinosvit.net.city.of.gold.2018.p.dvdrip.14oomb.avi.torrent 81 чел."</code></p>
<p>Т.к. название в данном случае не совсем хорошее для файла (лишнее в конце), то сделаем обрезку ненужного с помощью всё той же регулярки:<br />
<code>HmsRegExMatch('^(.*?.torrent)', sFile, sFile);</code></p>
<p>После этого у нас в переменной sFile будет уже что-то вроде:<br />
<code>"C:\Users\body\AppData\Local\Home Media Server\HMS\Temp\kinosvit.net.city.of.gold.2018.p.dvdrip.14oomb.avi.torrent"</code><br />
Что более подходит для имени файла.</p>
<p>Теперь можно его скачать:<br />
<code>HmsDownloadUrlToFile(mpFilePath, sFile, sHeaders);</code></p>
<p>Если всё удачно, у нас появится скачанный торрент-файл. Это очень важный момент и переменная sFile нам ещё пригодится для формировании ссылки видео далее.</p>
<h3><a href="#Работа_с_torrentфайлами" name="Работа_с_torrentфайлами" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Работа с torrent-файлами</h3>
<p>Ну а теперь непосредственная работа со скачанным торрент файлом.
Для работы с ним в программе существуют два класса: <em>TTorrentFile</em> и <em>TTorrentSubFile</em>. Второй нужен только для того, чтобы обработать вложенные файлы, если в скачанном torrent-файле будет их несколько.</p>
<p>Работа с ними имеет такой вид.<br />
Создаём объект:<br />
<code>TORRENT = TTorrentFile.Create();</code></p>
<p>Загружаем в него скачанный на диск торрент-файл:<br />
<code>TORRENT.LoadFromFile(sFile);</code></p>
<p>У класса <em>TTorrentFile</em> (наша переменная TORRENT) есть несколько свойств:  </p>
<ul>
<li>TORRENT.MultiFile - истина, если это многофайловый торрент.</li>
<li>TORRENT.Count - количество файлов в торренте (если однофайловый - всегда 1)</li>
<li>TORRENT.Length - длина раздаваемого файла и TORRENT.Name - имя раздаваемого файла.<br />
Последние два свойства установлены, только если это однофайловый торрент.</li>
</ul>
<p>Если это многофайловый, то работа с ним должна вестись следующим способом. Нужно перебрать все файлы в нём через TORRENT.Files[n], где n - номер файла.</p>
<pre><code class="language-hmscpp">    if (TORRENT.MultiFile) {
      // Перебираем все файлы
      for (int i=0; i &lt; TORRENT.Count; i++) {
        SUBTORRENT = TORRENT.Files[i];
        ... ... работаем с объектом SUBTORRENT
      }
    }
</code></pre>
<p>У объекта SUBTORRENT всего несколько свойств:  </p>
<ul>
<li>SUBTORRENT.Length - длина раздаваемого файла </li>
<li>SUBTORRENT.Name - имя раздаваемого файла</li>
<li>SUBTORRENT.Path - путь (папки) в подкаталогах, если таковая структура имеется (например, если раздача идёт с подкаталогами).</li>
</ul>
<p>В нашем случае нужно создать ссылки на все <strong>видео</strong> файлы, раздаваемые скачанным торрентом.</p>
<p>И теперь ещё один ключевой момент. Программа HMS поддерживает работу с торрент-файлами из коробки. Для того, чтобы программа могла на лету скачивать раздачу и отправлять на телек, <strong>ссылка должна начинаться на "torrent:" где далее идёт ссылка на скачанный локальный торрент файл</strong>. Также можно добавить знак вопроса и строку "index=" с указанием индекса файла, если мы хотим посмотреть не первый в списке, а конкретный в многофайловом торрент-файле.</p>
<p>Поэтому код для создания ссылок на видео будет таким:</p>
<pre><code class="language-hmscpp">  TTorrentFile TORRENT = TTorrentFile.Create();  
  try {
    TORRENT.LoadFromFile(sFile);
    // Проверяем, в этом торренте несколько файлов?
    if (TORRENT.MultiFile) {
      // Перебираем все файлы
      for (int i=0; i &lt; TORRENT.Count; i++) {

        SUBTORRENT = TORRENT.Files[i];

        // Проверяем тип файла по расширению
        if (HmsFileMediaType(SUBTORRENT.Name)==mtVideo) {

          // Создаём ссылку с указанием локального файла и его индексом
          sLink = Format('torrent:%s?index=%d', [sFile, i]);

          // Создаём элемент видео в программе
          Item = HmsCreateMediaItem(sLink, PodcastItem.ItemID);
          Item[mpiTitle   ] = SUBTORRENT.Name;
          Item[mpiFileSize] = SUBTORRENT.Length;

        }
      }

    } else {
      // В торренте раздаётся единственный файл
      Item = HmsCreateMediaItem('torrent:'+sFile, PodcastItem.ItemID);
      Item[mpiTitle   ] = TORRENT.Name;
      Item[mpiFileSize] = TORRENT.Length;

    }
  } finally { TORRENT.Free; }
</code></pre>
<p>Т.к. в раздачах могут присутствовать не только видео файлы но и любые другие, то следует проверять тип раздаваемых файлов по расширению. Это делает функция <code>HmsFileMediaType()</code>, где она должна в нашем случае возвращать тип <code>mtVideo</code>.</p>
<p>Вот и всё. Т.е. в нашей последней функции мы по-сути делаем следующее:</p>
<ul>
<li>Загружаем файл по ссылке на локальный диск во временную папку;</li>
<li>Потом создаём объект типа <em>TTorrentFile</em>, загружаем в него скачанный torrent-файл;</li>
<li>Проверяем, не является ли он многофайловым и если является, перебираем все файлы в нём, создавая ссылки вида <code>"torrent:&lt;Путь до локального файла&gt;?index=&lt;Номер файла&gt;"</code>;</li>
<li>Если тип торрент-файла - однофайловый, то просто создаём видео ссылку <code>"torrent:&lt;Путь до локального файла&gt;"</code>.</li>
</ul>
<p><div class="md_spoiler_switcher"><div class="md_spoiler_header"><strong>+</strong>&nbsp;<a href="#Вот_итоговый_скрипт_получения_ссылки_на_медиаресурс_по_Alt4" name="Вот_итоговый_скрипт_получения_ссылки_на_медиаресурс_по_Alt4" class="anchor" target="_blank"><span class="octicon octicon-link"></span></a>Вот итоговый скрипт получения ссылки на медиа-ресурс по Alt+4</div><div name="Вот_итоговый_скрипт_получения_ссылки_на_медиаресурс_по_Alt4" class="md_spoiler"></p>
<pre><code class="language-hmscpp">///////////////////////////////////////////////////////////////////////////////
// Создание ссылок видео из torrent-файла
void CreateFilesFromTorrentFile() {
  string sFile, sLink, sName, sHeaders;
  TTorrentFile TORRENT; TTorrentSubFile SUBTORRENT; THmsScriptMediaItem Item;
  sHeaders = 'Referer: '+PodcastItem.ItemParent[mpiFilePath]+'\r\n';
  
  HmsRegExMatch('^(.*?.torrent)', mpTitle, mpTitle); // В данном случае очищаем название, оставляя только реальное имя файла торрента

  sFile = HmsTranscodingTempDirectory+mpTitle;

  if (!FileExists(sFile) || (Length(HmsStringFromFile(sFile))==0))
    HmsDownloadUrlToFile(mpFilePath, sFile, sHeaders);
  
  TORRENT = TTorrentFile.Create();  
  try {
    TORRENT.LoadFromFile(sFile);
    // Проверяем, в этом торренте несколько файлов?
    if (TORRENT.MultiFile) {
      // Перебираем все файлы
      for (int i=0; i &lt; TORRENT.Count; i++) {
        SUBTORRENT = TORRENT.Files[i];
        // Проверяем тип файла по расширению
        if (HmsFileMediaType(SUBTORRENT.Name)==mtVideo) {
          sLink = Format('torrent:%s?index=%d', [sFile, i]);
          Item = HmsCreateMediaItem(sLink, PodcastItem.ItemID);
          Item[mpiTitle   ] = SUBTORRENT.Name;
          Item[mpiFileSize] = SUBTORRENT.Length;
        }
      }
    } else {
      // В торренте раздаётся единственный файл
      Item = HmsCreateMediaItem('torrent:'+sFile, PodcastItem.ItemID);
      Item[mpiTitle   ] = TORRENT.Name;
      Item[mpiFileSize] = TORRENT.Length;
    }
  } finally { TORRENT.Free; }
}

///////////////////////////////////////////////////////////////////////////////
// Поиск торрент-файлов на странице фильма и создание папок для них
void CreateTorrentFolders() {
  string sLink;
  string sHtml = HmsUtf8Decode(HmsDownloadURL(mpFilePath));
  // Поиск торрент-файлов на странице фильма / сериала
  TRegExpr RegEx = TRegExpr.Create('"attachment"&gt;(.*?)&lt;/div&gt;', PCRE_SINGLELINE);
  if (RegEx.Search(sHtml)) do {
    HmsRegExMatch('&lt;a[^&gt;]+href="(.*?)"', RegEx.Match, sLink);
    THmsScriptMediaItem Item = PodcastItem.AddFolder(sLink);
    Item[mpiTitle] = HmsHtmlToText(RegEx.Match);
  } while (RegEx.SearchAgain());
}

///////////////////////////////////////////////////////////////////////////////
//                     Г Л А В Н А Я   П Р О Ц Е Д У Р А                     //
{

  // Проверяем, при каком событии было вызвано выполнение скрипта (не вход ли в папку это?)
  if (PodcastItem.IsFolder) {
    
    PodcastItem.DeleteChildItems(); // Удаляем в текущей папке все элементы
    
    if (Pos('download.php', mpFilePath)&gt;0) 
      CreateFilesFromTorrentFile(); // Скачиваем сам torrent файл и создаём ссылки на видео из него
    else                                   
      CreateTorrentFolders();       // Ищем ссылки на torrent файлы и создаём папки с их наименованиями

  } else {

    MediaResourceLink = mpFilePath; // Это просто запустили ссылку видео на просмотр

  }

}
</code></pre>
<p></div></div></p>
<p>Для кучи прикладываю получившийся подкаст. Его хорошо бы довести до ума сделать нормальным. Но это уже пусть кто-нибудь сделает сам.</p>
<p>P.S.: Пока занимался написанием подкаста и отладкой - доработал и выложил новую версию <a href="https://github.com/WendyH/HMSEditor_addon/releases/tag/2.0.3.6" target="_blank">HMSEditor 2.0.3.6</a> - сделал так, что при отладке и наведении мыши на объект подсказка сразу показывала все доступные свойства объекта. Удобно смотреть объекты TORRENT и SUBTORRENT при отладке.</p>
</div></div>]]></content>
			<author>
				<name><![CDATA[WendyH]]></name>
				<uri>https://hms.lostcut.net/profile.php?id=2</uri>
			</author>
			<updated>2019-04-22T22:05:56Z</updated>
			<id>https://hms.lostcut.net/viewtopic.php?pid=14341#p14341</id>
		</entry>
</feed>
