Completed
Push — master ( 1e1aac...d6bf2c )
by C
05:36
created

Youtubecom::fetchLinkList()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 35
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 35
ccs 17
cts 17
cp 1
rs 8.439
cc 6
eloc 17
nc 5
nop 1
crap 6
1
<?php
2
namespace Tartana\Host;
3
use GuzzleHttp\Psr7\Request;
4
use GuzzleHttp\RequestOptions;
5
use Symfony\Component\DomCrawler\Crawler;
6
use Tartana\Entity\Download;
7
use Tartana\Host\Common\Http;
8
use Tartana\Util;
9
10
class Youtubecom extends Http
11
{
12
13 3
	public function fetchLinkList ($link)
14
	{
15 3
		if (! Util::startsWith($link, 'https://www.youtube.com/playlist?'))
16
		{
17 1
			return parent::fetchLinkList($link);
18
		}
19
20 2
		$resp = $this->getClient()->request('get', $link);
21
22 2
		$crawler = new Crawler($resp->getBody()->getContents());
23
24
		// Extracting the links which belong to the playlist
25 2
		$links = $crawler->filter('a.pl-video-title-link')->extract([
26
				'href'
27 2
		]);
28
29 2
		$data = [];
30 2
		foreach ($links as $link)
31
		{
32 2
			$uri = parse_url($link);
33
34 2
			if (! key_exists('path', $uri) || $uri['path'] != '/watch')
35
			{
36 1
				continue;
37
			}
38
39 1
			$params = [];
40 1
			parse_str($uri['query'], $params);
41 1
			if (key_exists('v', $params))
42
			{
43 1
				$data[] = 'https://www.youtube.com/watch?v=' . $params['v'];
44
			}
45
		}
46 2
		return array_unique($data);
47
	}
48
49 4
	public function fetchDownloadInfo (array $downloads)
50
	{
51 4
		foreach ($downloads as $download)
52
		{
53
			// Connection check
54
			try
55
			{
56 4
				$data = $this->getStreamData($download);
57 3
				if (! empty($data['title']) && empty($download->getFileName()))
58
				{
59 1
					$download->setFileName($this->makeSafe($data['title'] . '.mp4'));
60
				}
61
62 3
				if (key_exists('errorcode', $data) && $data['errorcode'] > 0 && key_exists('reason', $data))
63
				{
64 1
					$download->setMessage($data['reason']);
65 3
					$download->setState(Download::STATE_DOWNLOADING_ERROR);
66
				}
67
			}
68 1
			catch (\Exception $e)
69
			{
70 1
				$this->log('Exception fetching head for connection test: ' . $e->getMessage());
71 1
				$download->setMessage('TARTANA_DOWNLOAD_MESSAGE_INVALID_URL');
72 4
				$download->setState(Download::STATE_DOWNLOADING_ERROR);
73
			}
74
		}
75 4
	}
76
77 3
	protected function getUrlToDownload (Download $download)
78
	{
79 3
		$data = $this->getStreamData($download);
80
81 3
		if (! key_exists('url_encoded_fmt_stream_map', $data))
82
		{
83 1
			return null;
84
		}
85
86 2
		foreach (explode(',', $data['url_encoded_fmt_stream_map']) as $streamData)
87
		{
88 2
			parse_str($streamData, $streamData);
89
90 2
			if (key_exists('url', $streamData))
91
			{
92 1
				$url = urldecode($streamData['url']);
93 1
				$this->log('Youtube real url: ' . $url);
94 2
				return $url;
95
			}
96
		}
97 1
		return null;
98
	}
99
100 7
	private function getStreamData (Download $download)
101
	{
102 7
		if (preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $download->getLink(),
103
				$match))
104
		{
105
			$headers = [
106 6
					'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20150101 Firefox/44.0 (Chrome)',
107 6
					'Referer' => $download->getLink(),
108 6
					'Accept-Language' => 'en-us,en;q=0.5',
109 6
					'Accept-Encoding' => 'gzip, deflate',
110 6
					'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
111 6
					'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
112 6
					'Connection' => 'close',
113 6
					'Origin' => 'https://www.youtube.com',
114 6
					'Host' => 'www.youtube.com'
115
			];
116
			// Getting the link information initializing the cookie
117 6
			$this->getClient()->request('get', $download->getLink() . '&gl=US&hl=en&has_verified=1&bpctr=9999999999',
118
					[
119 6
							RequestOptions::HEADERS => $headers
120
					]);
121
122
			// Fetching the video information
123 6
			$res = $this->getClient()->request('get',
124 6
					'http://www.youtube.com/get_video_info?video_id=' . $match[1] . '&el=info&ps=default&eurl=&gl=US&hl=en',
125
					[
126 6
							RequestOptions::HEADERS => $headers
127
					]);
128
129 5
			parse_str($res->getBody()->getContents(), $videoData);
130 5
			return $videoData;
131
		}
132
133
		return [
134 1
				'title' => '',
135
				'url_encoded_fmt_stream_map' => ''
136
		];
137
	}
138
139
	/**
140
	 *
141
	 * @param string $file
142
	 * @return string
143
	 * @see http://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe
144
	 * @see http://stackoverflow.com/a/24812812/356375
145
	 */
146 1
	private function makeSafe ($file)
147
	{
148
		// Remove any trailing dots, as those aren't ever valid file names.
149 1
		$file = rtrim($file, '.');
150
151
		$regex = array(
152 1
				'#(\.){2,}#',
153
				'#[^A-Za-z0-9\.\_\- ]#',
154
				'#^\.#'
155
		);
156
157 1
		return trim(preg_replace($regex, '', $file));
158
	}
159
}
160