<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Неофициальный форум DLNA Home Media Server &mdash; Decrunching fmovies.is]]></title>
		<link>https://hms.lostcut.net/viewtopic.php?id=430</link>
		<atom:link href="https://hms.lostcut.net/extern.php?action=feed&amp;tid=430&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «Decrunching fmovies.is».]]></description>
		<lastBuildDate>Sun, 16 Jul 2017 09:35:24 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9541#p9541</link>
			<description><![CDATA[<p>Ко мне обратились зарубежные друзья с просьбой посмотреть защиту fmovies, которая сменилась.</p><p>На странице фильма есть ссылки на источники &quot;Server F2&quot;, в конце ссылки есть ID видео.</p><p>ht_ps://fmovies.is/film/the-expanse-2.qxm3n/<strong>n89qkm</strong></p><p>В коде html можно найти значение ts (timestamp) в&nbsp; свойстве &quot;data-ts&quot; тега &quot;body&quot;.</p><p>Этот ts нужен для подписывания всех url, которые вызываются через метод ajax объекта jQuery. Перед вызовом запроса в метод ajaxPrefilter добавляется вызов функции подписывания ссылок - добавляется параметр ts и знак подчёркивания _, значение которого - это и есть вычисленная подпись всех параметров в ссылке.</p><p>Функции в JavaScript коде запакованы и обфусцированы, находятся в едином файле /assets/min/public/all.js<br />Который можно распаковать через jsbeautifier.org.</p><p>Для того, чтобы можно было ставить точки прерывания на функции вычисления подписи, можно сохранить веб страницу локально на диск и заменить подгружаемый локально js скрипт на распакованный. При этом такая страница работать не будет но попытки обращения ajax будут, которые браузер будет блокировать с сообщением:<br />XMLHttpRequest cannot load file:///D:/user/ajax/menu-bar?ts=1500184800&amp;_=1743. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.</p><p>Т.е. не давать делать запрос на другой домен. Но нам и не нужно. Нам нужно только посмотреть, как именно формируется значение параметра _.<br />И мы можем поставить точки останова в скрипте и посмотреть пошагово, как выполняется этот подсчёт.<br />Пользователь <strong>Clonex</strong> даже дал наводку на место, где этот подсчёт, вероятно, делается. Это около строк с 10656 по 10709. Достаточно расставить там точки останова и посмотреть как идут вычисления. И переписать эти вычисления на своём языке, который хотим использовать.</p><p>На данный момент, нам интересен такой участок распакованного js кода:<br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>        function(t, e, i) {
            &quot;use strict&quot;;

            function n() {
                return eD
            }

            function r(t) {
                var e, i = iD,
                    n = {};
                if (t[ed][l](cd) &gt; -1)
                    do e = i[re](t[ed]), e &amp;&amp; (n[e[1]] = decodeURIComponent(e[2] || T)[b](nD, J)); while (e);
                if (t[Vr])
                    do e = i[re](t[Vr]), e &amp;&amp; (n[e[1]] = decodeURIComponent(e[2] || T)[b](nD, J)); while (e);
                return n
            }

            function a(t, e) {
                var i, n = 0;
                for (i = 0; i &lt; Math[K](t[S], e[S]); i++) n += i &lt; e[S] ? e[rD](i) : 0, n += i &lt; t[S] ? t[rD](i) : 0;
                return Number(n)[u](16)
            }

            function s(t) {
                var e, i = 0;
                for (e = 0; e &lt; t[S]; e++) i += t[rD](e) * e;
                return i
            }

            function o(t) {
                var i, r, o = s(n()),
                    l = {},
                    u = {};
                u[m] = T + y, r = e[x](!0, {}, t, u);
                for (i in r) Object[g][c][b](r, i) &amp;&amp; (o += s(a(n() + i, r[i])));
                return l[m] = y, l[h] = o, l
            }

            function d(t, e) {
                var i, n = T;
                for (i in e) Object[g][c][b](e, i) &amp;&amp; (n += ud + i + Mt + e[i]);
                return t + (t[l](cd) &lt; 0 ? cd : ud) + n[YH](1)
            }
            var p = e(Ir),
                f = Zk,
                h = fp,
                m = tD,
                v = ed,
                y = p[Vr](m);
            e[f](function(t) {
                var e = o(r(t));
                t[v] = d(t[v], e)
            })
        }(t, t.jQuery, t.FW),</code></pre></div></div></div><p>Функция &quot;o&quot; сначала подсчитывает значение с указанной переменной, которая возвращается функцией n и это всегда (пока) значение &quot;bLeqpV&quot; с помощью функции s. Потом подсчитывается значение ts через функцию &quot;a&quot;, добавляя к имени параметра всё то же значение &quot;bLeqpV&quot; в самое начало.</p><p>После переписывания и упрощения до одной функции, получилось вот такая функция подсчёта на PHP:<br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>&lt;?php
ini_set(&quot;log_errors&quot;, 1); ini_set(&quot;error_log&quot;, $_SERVER[&#039;SCRIPT_FILENAME&#039;].&quot;.log&quot;); ini_set(&#039;error_reporting&#039;, E_ALL); ini_set(&quot;display_errors&quot;, 1);

$url     = isset($_REQUEST[&#039;url&#039;]) ? $_REQUEST[&#039;url&#039;] : &quot;&quot;; // url like https://fmovies.is/film/fare.prln6/olm748

if (!$url) die(&quot;No film url in parameters.&quot;);

$cookies = array();
$headers = &quot;Accept-Encoding: gzip, deflate\r\n&quot; .
           &quot;Accept: application/json, text/javascript, */*; q=0.01\r\n&quot; .
           &quot;Referer: https://fmovies.is/\r\n&quot; .
           &quot;User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36\r\n&quot;;

if (!preg_match(&#039;#.*/(\w+)#&#039;, $url, $m)) die(&quot;Epic fail. No video ID in url.&quot;);
$ID   = $m[1]; // Video ID

// Get timestamp from loaded page
$data = LoadPage($url, &quot;GET&quot;, $headers);
if (!preg_match(&#039;#data-ts=&quot;(\d+)&quot;#&#039;, $data, $m)) die(&quot;Epic fail. Not timestamp in loaded page.&quot;);
$timestamp = $m[1];

// Get json info about sources
$url  = SignUrl(&quot;https://fmovies.is/ajax/episode/info?id=&quot;.$ID, $timestamp); // add singnature _=...&amp;ts=...
$data = LoadPage($url, &quot;GET&quot;, $headers);
$answ = json_decode($data, true);

if (isset($answ[&quot;grabber&quot;])) {
    $url = $answ[&quot;grabber&quot;];
    if (isset($answ[&quot;params&quot;])) {
        $url .= &quot;?&quot;.http_build_query($answ[&quot;params&quot;]);
    }
    // If exists direct link - get data for this
    if ($answ[&quot;type&quot;]==&quot;direct&quot;) {
        $url  = SignUrl($url, $timestamp); // add signature to parameters
        $data = LoadPage($url, &quot;GET&quot;, $headers);
        $answ = json_decode($data, True);
        if (isset($answ[&quot;data&quot;])) {
            $files = $answ[&quot;data&quot;];
            $data = $files[count($files)-1][&quot;file&quot;];
        }
    }
} else {
    echo &#039;{url:&quot;&#039;.$url.&#039;&quot;}&#039;;
}

echo $data;

///////////////////////////////////////////////////////////////////////////////
// Load page with specific method and headers
function LoadPage($url, $method, $headers, $data=&#039;&#039;) {
    global $cookies;

    // If exists cookies - add it to HTTP headers
    $coo = &quot;&quot;;
    foreach($cookies as $key =&gt; $val) $coo .= $key.&quot;=&quot;.urlencode($val).&quot;; &quot;;
    if ($coo) $headers .= &quot;Cookie: $coo\r\n&quot;;

    $options = array();
    $options[&#039;http&#039;] = array(&#039;method&#039; =&gt; $method ,
                             &#039;header&#039; =&gt; $headers,
                             &#039;content&#039;=&gt; $data   );
    $context = stream_context_create($options);
    $page    = file_get_contents($url, false, $context);
    // Get cookies from HTTP answer headers
    foreach($http_response_header as $c =&gt; $h) {
        if (stristr($h, &#039;content-encoding&#039;) and stristr($h, &#039;gzip&#039;)) {
            $page = gzdecode($page);
        } else if (preg_match(&#039;#^Set-Cookie:\s*([^;]+)#&#039;, $h, $matches)) {
            parse_str($matches[1], $tmp);
            $cookies += $tmp;
        }
    }
    return $page;
}

////////////////////////////////////////////////////////////////////
// Add signature to url (add params ts and _)
function SignUrl($url, $timestamp) {
    $parameters = &quot;&quot;;
    if (preg_match(&quot;#^(.*?)\?(.*)#&quot;, $url, $m)) {
        $url        = $m[1];
        $parameters = $m[2];
    }
    // sign the url
    $signature = CalcSignature(&quot;&quot;, &quot;&quot;);
    $signature += CalcSignature(&quot;ts&quot;, &quot;&quot;.$timestamp);
    parse_str($parameters, $array);
    foreach ($array as $key =&gt; $value) {
        $signature += CalcSignature($key, $value);
    }
    return $url.&quot;?ts=&quot;.$timestamp.&quot;&amp;_=&quot;.$signature.&quot;&amp;&quot;.$parameters;
}

////////////////////////////////////////////////////////////////////
// Calculate the signature of parameter
function CalcSignature($name, $val) {
  $name = &quot;bLeqpV&quot; . $name; // value: eD = &quot;bLeqpV&quot;, line: 1942

  // function a() line: 10673 (upacked) file: /assets/min/public/all.js?596aac49
  if ($val) {
    $n = 0;
    for ($i=0; $i &lt; max(strlen($name), strlen($val)); $i++) {
      $n += ($i &lt; strlen($name)) ? ord($name[$i]) : 0; // charCodeAt
      $n += ($i &lt; strlen($val )) ? ord($val [$i]) : 0; // charCodeAt
    }
    $name = dechex($n); // int to hex (with lowercase liters)
  }

  // function s() line: 10679 (upacked) file: /assets/min/public/all.js?596aac49
  $i = 0;
  for ($e=0; $e &lt; strlen($name); $e++) {
    //$i += ord($name[$e]) * $e + $e;
    $i += ord($name[$e]) * $e;
  }
  return $i;
}</code></pre></div></div></div><p>Проверка: <br /><a href="http://wonky.lostcut.net/fmovies.php?url=https://fmovies.is/film/the-expanse-2.qxm3n/n89qkm">http://wonky.lostcut.net/fmovies.php?ur … m3n/n89qkm</a></p>]]></description>
			<author><![CDATA[null@example.com (WendyH)]]></author>
			<pubDate>Sun, 16 Jul 2017 09:35:24 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9541#p9541</guid>
		</item>
		<item>
			<title><![CDATA[Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9534#p9534</link>
			<description><![CDATA[<p>Тема создана для переноса сообщений, касающихся ресурса&nbsp; fmovies.is (fmovies.se, ...)</p>]]></description>
			<author><![CDATA[null@example.com (WendyH)]]></author>
			<pubDate>Sun, 16 Jul 2017 08:11:04 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9534#p9534</guid>
		</item>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9540#p9540</link>
			<description><![CDATA[<p>Openload.co повержен.</p><p>Функция раскодирования зашифрованных данных написана. Закодированные данные есть в html странице openload.co/embed/--NvddZFdlM/ в:<br /></p><div class="codebox"><pre><code>&lt;div style=&quot;display:none;&quot;&gt;
  &lt;span id=&quot;wRdOAuzXK0&quot;&gt;7D4500d5275h5380L7931W7931k2190Q6336R4220i4352l6468B3156A2104I3321U6360g2266H6462C3255n2148J4460o3261m3177V2118F3321N2118X4228O5315G6582K5420c3159e3159Y4212S6378E1107M1056f6330Z7448P3189T4224b3174j7903&lt;/span&gt;
  &lt;span id=&quot;streamurl&quot;&gt;HERE IS THE LINK&lt;/span&gt;
&lt;/div&gt;</code></pre></div><p>В первом span - нужные зашифрованные данные.<br />Во втором span после отработки js скриптов появляется значение, типа &quot;--NvddZFdlM~1488110004~2.93.0.0~_iavnA5k&quot;.<br />После чего полная ссылка на поток выглядит вот так:<br />&quot;ht_ps://openload.co/stream/--NvddZFdlM~1488110004~2.93.0.0~_iavnA5k?mime=true&quot;.</p><p>Вот функции на C++Script для получения ссылки на медиа-поток из ссылок вида <a href="https://openload.co/embed/ceKFetMsUPM/">https://openload.co/embed/ceKFetMsUPM/</a><br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>///////////////////////////////////////////////////////////////////////////////
// Получение ссылки на медиа-поток с сайта openload.co
void GetLink_Openload(string sLink) {
  string sHtml, sData, sStream;
  
  sHtml = HmsDownloadURL(sLink, &#039;Referer: &#039;+mpFilePath, true);
  if (!HmsRegExMatch(&#039;&lt;div[^&gt;]+style=&quot;display:none;&quot;&gt;\\s*&lt;span.*?&gt;(.*?)&lt;&#039;, sHtml, sData)) {
    HmsLogMessage(2, mpTitle+&quot;: Невозможно найти зашифрованные данные сайта openload.co.&quot;);
    return;
  }
  sStream = OpenloadDecode(sData);
  MediaResourceLink = &#039;https://openload.co/stream/&#039;+sStream+&#039;?mime=true&#039;;
}

///////////////////////////////////////////////////////////////////////////////
// Декодирование данных сайта openload.co
string OpenloadDecode(string sEncoded) {
  string sResult; int i, a, _, d, e, w, nbufLen;
  if (sEncoded==&quot;&quot;) return;
  nbufLen = Int((Length(sEncoded)-1)/5);
  sResult = PadRight(&quot;&quot;, nbufLen, &#039; &#039;);
  w = StrToIntDef(sEncoded[1], 0);
  for (d=1; d&lt;Length(sEncoded); d+=5) {
    i = Ord(sEncoded[d+1]);
    if      (i &lt;= 90) e = i - 65;
    else if (i &gt;= 97) e = i - 72;
    else              e = 0;
    _ = StrToIntDef(Copy(sEncoded, d+2, 1), 0);
    a = StrToIntDef(Copy(sEncoded, d+3, 3), 0);
    sResult[e+1] = Chr(Int(a/_) - w);
  }
  return sResult;
}</code></pre></div></div></div><p>Как я понимаю, закодированные данные на странице содержат в себе типа хеша или подписи, который привязан к IP. Поэтому скрипт на стороннем сервере для получения таких ссылок сделать можно, но бесполезно:</p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;Скрипт для openload.co на PHP</div><div class="fancy_spoiler"><div class="codebox"><pre><code>&lt;?php ini_set(&quot;log_errors&quot;, 1); ini_set(&quot;error_log&quot;, $_SERVER[&#039;SCRIPT_FILENAME&#039;].&quot;.log&quot;); ini_set(&#039;error_reporting&#039;, E_ALL); ini_set(&quot;display_errors&quot;, 1);

$ID      = isset($_REQUEST[&#039;id&#039;]) ? $_REQUEST[&#039;id&#039;] : &quot;&quot;; // film ID in url like https://openload.co/embed/--NvddZFdlM/

if (!$ID) die(&quot;No film id in parameters.&quot;);

$cookies = array();
$headers = &quot;Accept-Encoding: gzip, deflate\r\n&quot; .
           &quot;Accept: application/json, text/javascript, */*; q=0.01\r\n&quot; .
           &quot;Referer: https://fmovies.se/\r\n&quot; .
           &quot;User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36\r\n&quot;;

// Загружаем страницу фильма
$data    = LoadPage(&quot;https://openload.co/embed/$ID/&quot;, &quot;GET&quot;, $headers);

// Ищем в HTML коде зашифрованные данные для потока
if (!preg_match(&#039;#&lt;div[^&gt;]+style=&quot;display:none;&quot;&gt;\s*&lt;span.*?&gt;(.*?)&lt;#s&#039;, $data, $m)) die(&quot;Epic fail. No encoded text found.&quot;);

// Расшифровываем
$decoded = OpenloadDecode($m[1]);
$url     = &quot;https://openload.co/stream/$decoded?mime=true&quot;;

// Попробуем получить ссылку редиректа
$context = stream_context_create(array(&#039;http&#039;=&gt;array(&#039;follow_location&#039; =&gt; false)));
$page    = file_get_contents($url, false, $context);
// Ищем в полученных заголовках значение Location
foreach($http_response_header as $c =&gt; $h) {
    if (preg_match(&#039;#^Location:\s*([^\r\n]+)#&#039;, $h, $m)) {
        $url = $m[1];
        break;
    }
}

echo $url;

///////////////////////////////////////////////////////////////////////////////
// Декодирование данных сайта openload.co
function OpenloadDecode($encoded) {
    if (!$encoded) return;
    $bufLen = (strlen($encoded)-1)/5;
    $result = str_pad(&quot;&quot;, $bufLen, &#039; &#039;);
    $w = intval($encoded[0]);
    for ($d=1; $d &lt; strlen($encoded); $d+=5) {
        $i = ord($encoded[$d]);
        if      ($i &lt;= 90) $e = $i - 65;
        else if ($i &gt;= 97) $e = $i - 72;
        else               $e = 0;
        $_ = intval(substr($encoded, $d+1, 1));
        $a = intval(substr($encoded, $d+2, 3));
        $result[$e] = chr(($a/$_) - $w);
    }
    return $result;
}

///////////////////////////////////////////////////////////////////////////////
// Получение страницы с указанными методом и заголовками
function LoadPage($url, $method, $headers, $data=&#039;&#039;) {
    global $cookies;

    // Если есть кукисы - добавляем их значения в HTTP заголовки
    $coo = &quot;&quot;;
    foreach($cookies as $key =&gt; $val) $coo .= $key.&quot;=&quot;.urlencode($val).&quot;; &quot;;
    if ($coo) $headers .= &quot;Cookie: $coo\r\n&quot;;

    $options = array();
    $options[&#039;http&#039;] = array(&#039;method&#039; =&gt; $method ,
                             &#039;header&#039; =&gt; $headers,
                             &#039;content&#039;=&gt; $data   );
    $context = stream_context_create($options);
    $page    = file_get_contents($url, false, $context);
    // Перебираем HTTP заголовки ответа, чтобы установить кукис
    foreach($http_response_header as $c =&gt; $h) {
        if (stristr($h, &#039;content-encoding&#039;) and stristr($h, &#039;gzip&#039;)) {
            $page = gzdecode($page);
        } else if (preg_match(&#039;#^Set-Cookie:\s*([^;]+)#&#039;, $h, $matches)) {
            parse_str($matches[1], $tmp);
            $cookies += $tmp;
        }
    }
    return $page;
}</code></pre></div></div></div><p>Но полученные ссылки на другом сервере не будут проигрываться на клиенте с другим IP.<br /><a href="http://wonky.lostcut.net/openload.php?id=--NvddZFdlM">http://wonky.lostcut.net/openload.php?id=--NvddZFdlM</a></p><p>Так что можно писать подкаст для fmovies.se.</p>]]></description>
			<author><![CDATA[null@example.com (WendyH)]]></author>
			<pubDate>Sat, 25 Feb 2017 12:01:21 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9540#p9540</guid>
		</item>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9539#p9539</link>
			<description><![CDATA[<p><strong>WendyH</strong>, openload.co не смотрел. Я пытался скриптом запустить ie, c отключенными картинками, и с добавленным в надёжные узлы fmovies.se, чтоб после загрузки сразу вытащить ссылку на видео... пока не вышло</p>]]></description>
			<author><![CDATA[null@example.com (slim8020)]]></author>
			<pubDate>Thu, 23 Feb 2017 15:56:00 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9539#p9539</guid>
		</item>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9538#p9538</link>
			<description><![CDATA[<p>Я разобрался с fmovies.se.<br />Для каждого параметра нужно подсчитывать значение подписи. Все значения суммируются.</p><p>Чтобы сделать запрос на fmovies.se/ajax/episode/info?ts=1487689200&amp;_=8520&amp;id=j2z3p4<br />а потом что-то вроде<br />fmovies.se/grabber-api/?ts=1487757600&amp;_=1550755&amp;id=olm748&amp;token=&lt;blabla&gt;&amp;options=&lt;blabla&gt;&amp;mobile=0</p><p>Нужно установить значения:<br /><strong>ts</strong> - timestamp округлённое до часов с учётом того, что сервер находится в Америке и должно учитываться смещение по Гринвичу (это -12 часов от московского времени).<br /><strong>_</strong> - это суммарное значение подписи параметров &quot;ts&quot; и &quot;id&quot;.</p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;Вот такая функция на C++Script получилась</div><div class="fancy_spoiler"><div class="codebox"><pre><code>///////////////////////////////////////////////////////////////////////////////
// Подсчёт значения подписи конкретного имени и значения параметра
int CalcSignature(string name, string val) {
  int n, r, i, nTmp, o; Variant a[256];
  for (i=0; i&lt;256; i++) a[i]=i;
  for (i=0, n=0; i&lt;256; i++) {
    n = (n + a[i] + Ord(name[i % Length(name) + 1])) % 256;
    nTmp = a[i];
    a[i] = a[n];
    a[n] = nTmp;
  }
  for (i=0, n=0, r=0; i&lt;Length(val); i++) {
    r = (r + 1   ) % 256;
    n = (n + a[r]) % 256;
    nTmp = a[r];
    a[r] = a[n];
    a[n] = nTmp;
    o += Ord(val[i+1]) ^ (a[(a[r]+a[n]) % 256] * i + i);
  }    
  return o;
}</code></pre></div></div></div><p>Чтобы заценить, с чем пришлось работать, вот изначальный распакованный скрипт на JS (тот самый участок):<br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>function n(t, e) {
    var i, n, r, a, s, o;
    for (i = [], n = +yn, a = yn - 0, s = yn - 0; s &lt; +(Sk + nk); s++) i[s] = s;
    for (s = +yn; s &lt; Sk + nk - 0; s++) n = (n + i[s] + t[iN.P(+(Jl + JD))](iN.A(s, t[iN[lk](+(Jl + uk))]))) % (Sk + nk - 0), r = i[s], i[s] = i[n], i[n] = iN.g(r);
    for (s = yn - 0, n = +yn, o = +yn; o &lt; e[iN.P(+(Jl + QD))]; o++) s = iN.O(iN.h(s, 1 * Jl), +(QD + ek + nk)), n = iN[HC]((n + i[s]) % +(QD + Ck)), r = i[s], i[s] = i[n], i[n] = r, a += e[iN.T(+(Jl + JD))](o) ^ i[iN.R(i[s], i[n]) % +wk] * o + o;
    return a
}

function r(t) {
    for (var e = - +(Pk + Ak + Mk), i = 1 * (UD + xk + Gk + yn), r = +QD, a = +Jl; iN.A9(a[u](), a[u]()[S], qD + Ik + QD - 0) !== e; a++) {
        for (s in t) t[iN.T(1 * KD)](s) &amp;&amp; (o /= iN[Hk](n(s, iN.v(t[s], iN.P(+Ck)))));
        return o
    }
    if (iN.g9(r[u](), r[u]()[S], QD + $k + qD + nk - 0) !== i) {
        var s, o;
        o = +yn;
        for (s in t) t[iN.T(qD - 0)](s) &amp;&amp; (o += iN[Hk](n(s, iN.v(t[s], iN.P(Jl + ek | 0)))))
    }
    return o
}</code></pre></div></div></div><p>Вот из такого вот ... э.. кода пришлось делать свою функцию. Но одно из самых сложных было просто найти этот нужный кусок.</p><p>Получился вот такой вот PHP скрипт:<br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>&lt;?php
ini_set(&quot;log_errors&quot;, 1); ini_set(&quot;error_log&quot;, $_SERVER[&#039;SCRIPT_FILENAME&#039;].&quot;.log&quot;); ini_set(&#039;error_reporting&#039;, E_ALL); ini_set(&quot;display_errors&quot;, 1);

$url     = isset($_REQUEST[&#039;url&#039;]) ? $_REQUEST[&#039;url&#039;] : &quot;&quot;; // url like https://fmovies.se/film/fare.prln6/olm748

if (!$url) die(&quot;No film url in parameters.&quot;);

$cookies = array();
$headers = &quot;Accept-Encoding: gzip, deflate\r\n&quot; .
           &quot;Accept: application/json, text/javascript, */*; q=0.01\r\n&quot; .
           &quot;Referer: https://fmovies.se/\r\n&quot; .
           &quot;User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36\r\n&quot;;

if (!preg_match(&#039;#.*/(\w+)#&#039;, $url, $m)) die(&quot;Epic fail. No video ID in url.&quot;);
$ID   = $m[1]; // Video ID

// Узнаём timestamp из загруженной страницы
$data = LoadPage($url, &quot;GET&quot;, $headers);
if (!preg_match(&#039;#data-ts=&quot;(\d+)&quot;#&#039;, $data, $m)) die(&quot;Epic fail. Not timestamp in loaded page.&quot;);
$timestamp = $m[1];

// Загружаем json информацию об источнике
$url  = SignUrl(&quot;https://fmovies.se/ajax/episode/info?id=&quot;.$ID, $timestamp); // Подпись ссылки
$data = LoadPage($url, &quot;GET&quot;, $headers);
$answ = json_decode($data, true);

if (isset($answ[&quot;grabber&quot;])) {
    $url = $answ[&quot;grabber&quot;];
    if (isset($answ[&quot;params&quot;])) {
        $url .= &quot;?&quot;.http_build_query($answ[&quot;params&quot;]);
    }
    // Если есть прямая ссылка на видео - загружаем json данные о ней
    if ($answ[&quot;type&quot;]==&quot;direct&quot;) {
        $url  = SignUrl($url, $timestamp); // Подпись ссылки
        $data = LoadPage($url, &quot;GET&quot;, $headers);
        $answ = json_decode($data, True);
        if (isset($answ[&quot;data&quot;])) {
            $files = $answ[&quot;data&quot;];
            $data = $files[count($files)-1][&quot;file&quot;];
        }
    }
} else {
    echo &#039;{url:&quot;&#039;.$url.&#039;&quot;}&#039;;
}

echo $data;

///////////////////////////////////////////////////////////////////////////////
// Получение страницы с указанными методом и заголовками
function LoadPage($url, $method, $headers, $data=&#039;&#039;) {
    global $cookies;

    // Если есть кукисы - добавляем их значения в HTTP заголовки
    $coo = &quot;&quot;;
    foreach($cookies as $key =&gt; $val) $coo .= $key.&quot;=&quot;.urlencode($val).&quot;; &quot;;
    if ($coo) $headers .= &quot;Cookie: $coo\r\n&quot;;

    $options = array();
    $options[&#039;http&#039;] = array(&#039;method&#039; =&gt; $method ,
                             &#039;header&#039; =&gt; $headers,
                             &#039;content&#039;=&gt; $data   );
    $context = stream_context_create($options);
    $page    = file_get_contents($url, false, $context);
    // Перебираем HTTP заголовки ответа, чтобы установить кукис
    foreach($http_response_header as $c =&gt; $h) {
        if (stristr($h, &#039;content-encoding&#039;) and stristr($h, &#039;gzip&#039;)) {
            $page = gzdecode($page);
        } else if (preg_match(&#039;#^Set-Cookie:\s*([^;]+)#&#039;, $h, $matches)) {
            parse_str($matches[1], $tmp);
            $cookies += $tmp;
        }
    }
    return $page;
}

////////////////////////////////////////////////////////////////////
// Подпись ссылки (добавление ts и _)
function SignUrl($url, $timestamp) {
    $parameters = &quot;&quot;;
    if (preg_match(&quot;#^(.*?)\?(.*)#&quot;, $url, $m)) {
        $url        = $m[1];
        $parameters = $m[2];
    }
    $signature = CalcSignature(&quot;ts&quot;, &quot;&quot;.$timestamp);
    parse_str($parameters, $array);
    foreach ($array as $key =&gt; $value) {
        $signature += CalcSignature($key, $value);
    }
    return $url.&quot;?ts=&quot;.$timestamp.&quot;&amp;_=&quot;.$signature.&quot;&amp;&quot;.$parameters;
}

////////////////////////////////////////////////////////////////////
// Подсчёт значения подписи конкретного имени и значения параметра
function CalcSignature($name, $val) {
    $o = 0;
    $a = array(256);
    for ($i=0; $i&lt;256; $i++) $a[$i]=$i;
    for ($i=0, $n=0; $i&lt;256; $i++) {
      $n = ($n + $a[$i] + Ord($name[$i % strlen($name)])) % 256;
      $tmp   = $a[$i];
      $a[$i] = $a[$n];
      $a[$n] = $tmp;
    }
    for ($i=0, $n=0, $r=0; $i&lt;strlen($val); $i++) {
      $r = ($r + 1     ) % 256;
      $n = ($n + $a[$r]) % 256;
      $tmp   = $a[$r];
      $a[$r] = $a[$n];
      $a[$n] = $tmp;
      $o += Ord($val[$i]) ^ ($a[($a[$r]+$a[$n]) % 256] * $i + $i);
    }    
    return $o;
}</code></pre></div></div></div><p>Который вот так вот работает:<br /><a href="http://wonky.lostcut.net/fmovies.php?url=https://fmovies.se/film/billions-2.qxmjv/j2z3p4">http://wonky.lostcut.net/fmovies.php?ur … mjv/j2z3p4</a></p><p>Так что упёртость и упоротость не оставляет шансов для создателей сайтов. )<br />На самом деле, если бы не крутой отладчик в chrome, фиг бы я разобрался, наверно.</p><div class="quotebox"><cite>baat пишет:</cite><blockquote><p>а не проще на ютубе искать?.. или поиск это не выдаст?..</p></blockquote></div><p>Нет. Тут вопрос в другом - в том, что неправомерный контент находится на серверах компании известной как одной из самых активно борящейся с таким контентом.</p><p><strong>slim8020</strong>, не смотрел openload.co? Я даже не приступал. Там тоже развлечения с раскодировкой предстоят, как я понял.</p><p><strong>UPDATE</strong>: Обновил скрипт, оказывается вычислять timestamp была плохая идея. Надёжней брать из загруженной страницы видео. Это значение там есть. Поэтому переделал и обновил скрипт.</p>]]></description>
			<author><![CDATA[null@example.com (WendyH)]]></author>
			<pubDate>Wed, 22 Feb 2017 22:34:47 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9538#p9538</guid>
		</item>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9537#p9537</link>
			<description><![CDATA[<div class="quotebox"><cite>WendyH пишет:</cite><blockquote><p>В общем, боги шифрования. Это вызов.</p></blockquote></div><p>а не проще на ютубе искать?.. или поиск это не выдаст?..</p>]]></description>
			<author><![CDATA[null@example.com (baat)]]></author>
			<pubDate>Tue, 21 Feb 2017 20:47:30 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9537#p9537</guid>
		</item>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9536#p9536</link>
			<description><![CDATA[<p><strong>slim8020</strong>, что это за сайт такой, который содержит последние серии свежих сериалов, а отдаёт ссылку на поток, которая сильно знакомого вида:<br />ht_ps://redirector.googlevideo.com/videoplayback?id=b5e1a0de46ecdc9a&amp;itag=18&amp;source=webdrive&amp;requiressl=yes&amp;ttl=transient&amp;mm=30&amp;mn=sn-5hnednel&amp;ms=nxu&amp;mv=m&amp;pl=36&amp;mime=video/mp4&amp;lmt=1487434781132897&amp;mt=1487687807&amp;ip=2a00:1768:2001:2::1f&amp;ipbits=128&amp;expire=1487702281&amp;sparams=ip%2Cipbits%2Cexpire%2Cid%2Citag%2Csource%2Crequiressl%2Cttl%2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Cmime%2Clmt&amp;signature=9B0854BD16725FA4734E372124049FE91141F584.9034B5FD308E2DA80573058958048F944AD980E2&amp;key=ck2&amp;app=explorer&amp;xmi=50</p><p>Капец, это ж видео с youtube?<br />Да, качество, похоже, 720. Субтитры английские прилагаются.</p><p>А загадки разгадывать - откуда ссылки берутся и как расшифровать, так это моё любимое дело. Прям спасибо за интересный квест.<br />В общем, там код JS жутко обфусцирован и главный вопрос, как в ссылке:<br />ht_ps://fmovies.se/ajax/episode/info?ts=1487689200&amp;_=8520&amp;id=j2z3p4&amp;update=0<br />Значение _=8520 получить. Ибо это токен, который зависит от всех параметров, типа подписи запроса.</p><p>В общем, развлечение на вечер (а мне работать надо).</p><p>P.S.: Там источники разные. Не только с googlevideo (на сайте как &quot;Server F2&quot;), но и с Openload.co (<a href="https://openload.co/embed/--NvddZFdlM/">https://openload.co/embed/--NvddZFdlM/</a>).<br />&quot;Server F1&quot; всегда не доступен был.</p><p>С оpenload тоже развлечения предстоят. В общем, боги шифрования. Это вызов.</p>]]></description>
			<author><![CDATA[null@example.com (WendyH)]]></author>
			<pubDate>Tue, 21 Feb 2017 16:25:12 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9536#p9536</guid>
		</item>
		<item>
			<title><![CDATA[Re: Decrunching fmovies.is]]></title>
			<link>https://hms.lostcut.net/viewtopic.php?pid=9535#p9535</link>
			<description><![CDATA[<p>Сообщники!<br />Нашел вот такой ресурс с, вроде бы, честным 720p, проверил на нескольких потоках.<br /><a href="https://fmovies.se/film/billions-2.qxmjv">https://fmovies.se/film/billions-2.qxmjv</a><br />вот только запутался я в их скриптах, я так понял они должны генерировать div&#039;ы, один из которых будет &quot;video&quot; и будет содержать заветный srс на поток. Никак не могу понять который из них...</p>]]></description>
			<author><![CDATA[null@example.com (slim8020)]]></author>
			<pubDate>Tue, 21 Feb 2017 14:26:27 +0000</pubDate>
			<guid>https://hms.lostcut.net/viewtopic.php?pid=9535#p9535</guid>
		</item>
	</channel>
</rss>
