jeckman / YouTube-Downloader

PHP script for downloading videos from youtube; also parsing youtube feed into RSS enclosures for podcatchers
GNU General Public License v2.0
895 stars 474 forks source link

Error: ==== Decipher dictionary was not found ==== #306

Closed ahm786 closed 6 years ago

ahm786 commented 6 years ago

Description

It seems like there's an issue with the signature decipher. Whenever I want to download a cipher video, it returns the following error:

"==== Decipher dictionary was not found ===="

I can confirm that the latest playerscript file is downloaded in cache, so there's an issue with the code.

@StefansArya @Art4 Do you know what is causing this problem?

Steps to Reproduce

Try downloading a cipher video, such as:

https://www.youtube.com/watch?v=lvs68OKOquM

Expected behavior: Fetch download links

Actual behavior: Returns error: ==== Decipher dictionary was not found ====

Version

0.7-dev

Additional Information

Server info: NGINX, Ubuntu 17, PHP7.1

StefansArya commented 6 years ago

It seems that youtube has updated their signature script..

ahm786 commented 6 years ago

Yea seems like it. Do you think the issue can be fixed?

StefansArya commented 6 years ago

I still waiting until the pull request getting merged.. The new update is by adding this line

case 'var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c':
    $c = $processSignature[0];
    $processSignature[0] = $processSignature[$number%count($processSignature)];
    $processSignature[$number%count($processSignature)] = $c;
    $logger->debug(
        '{method}: (Swapping array)',
        ['method' => __METHOD__]
    );
break;

After line 306

https://github.com/jeckman/YouTube-Downloader/blob/52213e86ce69f0ee12a29d929e3228a5217e7367/src/Provider/Youtube/SignatureDecipher.php#L297-L306

ahm786 commented 6 years ago

Thanks! I added that code and the issue was fixed, however now the problem is that most of the cipher videos show permission error.

Examples: https://www.youtube.com/watch?v=lvs68OKOquM

StefansArya commented 6 years ago

Hmm.. Btw, I found that this code is called more than once as it download youtube video page and can lead to execution timeout

https://github.com/jeckman/YouTube-Downloader/blob/52213e86ce69f0ee12a29d929e3228a5217e7367/src/Provider/Youtube/Format.php#L132

It should be called once but I'm not sure where to place it after the restructuring by @Art4 ..

StefansArya commented 6 years ago

Temporary fix for above issue by replacing

https://github.com/jeckman/YouTube-Downloader/blob/52213e86ce69f0ee12a29d929e3228a5217e7367/src/Provider/Youtube/Format.php#L130-L162

with

if (isset($this->raw_data['s']) and $this->config['decipher_signature']) {

    // TODO: Remove signature decipher from Format
    $videoIds = $this->getCache()->get('videoIds', null);
    if(!$videoIds) $videoIds = [];
    if(!in_array($this->getVideoId(), $videoIds)) {
        $videoIds[] = $this->getVideoId();
        $this->getCache()->set('videoIds', $videoIds, 3600*24);

        $player_info = SignatureDecipher::getPlayerInfoByVideoId($this->getVideoId());

        $playerID = $player_info[0];
        $playerURL = $player_info[1];
        $this->getCache()->set('playerID', [$playerID, $playerURL], 3600*24);
    }
    else {
        $playerID = $this->getCache()->get('playerID', null);
        if($playerID){
            $playerURL = $playerID[1];
            $playerID = $playerID[0];
        } else {
            $this->getCache()->set('videoIds', false, 3600*24);
            $this->getCache()->set('playerID', false, 3600*24);
            return $this->parseUrl();
        }
    }

    $cache_key = 'playerscript_' . $playerID;
    $opcode = $this->getCache()->get($cache_key, null);

    if ($opcode === null) {
        $opcode = SignatureDecipher::downloadRawPlayerScript($playerURL);
        $opcode = json_encode(SignatureDecipher::extractDecipherOpcode($opcode, $this->getLogger()));

        $this->getCache()->set($cache_key, $opcode, 3600*24);
    }

    $opcode = json_decode($opcode, true);

    $sig = SignatureDecipher::executeSignaturePattern(
        $opcode['decipherPatterns'],
        $opcode['deciphers'],
        $this->raw_data['s'],
        $this->getLogger()
    );

    if (strpos($this->raw_data['url'], 'ratebypass=') === false) {
        $this->raw_data['url'] .= '&ratebypass=yes';
    }

    $signature = '&signature=' . $sig;
}
ahm786 commented 6 years ago

Thanks! I've replaced it. Now the only issue is that the download link of cipher videos are showing permission error. Before it would work fine :(

Edit: it only happens with a few videos such as https://youtu.be/fv9kIkgt9so

chadul commented 6 years ago

Same here, I have changed with the "temporary" update code above but still show only "==== Decipher dictionary was not found ===="

StefansArya commented 6 years ago

@chadul this update should work #309

@ahm786 Hmm, I have no problem on my localhost. Can you try clear the cache folder?

chadul commented 6 years ago

@StefansArya I saw its not yet ready

StefansArya commented 6 years ago

You could download it from my fork

freespirit83xyz commented 6 years ago

Hello,

I've checked this last version but it works on locale but not on server. Either using getvideo.php or index.php 0 byte file is retrieved.

Art4 commented 6 years ago

Fixed with #309