Source of file SoundCloud.php

Size: 6,469 Bytes - Last Modified: 2018-08-03T03:16:59+00:00

C:/xampp/htdocs/PodTube/src/SupportedSites/SoundCloud.php

1234567891011121314151617181920212223
Covered by 4 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testNonSoundCloudURL
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
242526
Covered by 4 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testNonSoundCloudURL
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
27
Covered by 4 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testNonSoundCloudURL
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
28
Covered by 1 test(s):
  • SoundCloudTest::testNonSoundCloudURL
2930
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
31
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
323334
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
35
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
36
Covered by 1 test(s):
  • SoundCloudTest::testBadURL
3738
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
39
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
40
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
41
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
42
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
43
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
44
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
4546
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
474849
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
5051
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
525354555657
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
58
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
59
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
60
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
61
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
62
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
63
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
64
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
6566
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
67
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
68
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
69707172
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
73747576
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
77
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
787980
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
81
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
828384
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
8586
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
87
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
88
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
8990
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
91
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
92
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
93
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
94
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
95
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
96
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
9798
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
99
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
100101
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
102
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
103
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
104105
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
106
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
107108109
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
110
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
111
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
112113114115
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
116
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
117
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
118
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
119
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
120
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
121
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
122
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
123
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
124125126127
Covered by 2 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testDownload
128129130
Covered by 3 test(s):
  • SoundCloudTest::testConstructor
  • SoundCloudTest::testBadURL
  • SoundCloudTest::testDownload
131132133
Covered by 1 test(s):
  • SoundCloudTest::testBadURL
134135
Covered by 1 test(s):
  • SoundCloudTest::testBadURL
136137138139140141142143144
Covered by 1 test(s):
  • SoundCloudTest::testDownload
145
Covered by 1 test(s):
  • SoundCloudTest::testDownload
146147148
Covered by 1 test(s):
  • SoundCloudTest::testDownload
149
Covered by 1 test(s):
  • SoundCloudTest::testDownload
150151152
Covered by 1 test(s):
  • SoundCloudTest::testDownload
153154155156157158159160
Covered by 1 test(s):
  • SoundCloudTest::testDownload
161162163164165166167
Covered by 1 test(s):
  • SoundCloudTest::testDownload
168
Covered by 1 test(s):
  • SoundCloudTest::testDownload
169
Covered by 1 test(s):
  • SoundCloudTest::testDownload
170171
Covered by 1 test(s):
  • SoundCloudTest::testDownload
172
Covered by 1 test(s):
  • SoundCloudTest::testDownload
173174175
Covered by 1 test(s):
  • SoundCloudTest::testDownload
176
Covered by 1 test(s):
  • SoundCloudTest::testDownload
177
Covered by 1 test(s):
  • SoundCloudTest::testDownload
178179
Covered by 1 test(s):
  • SoundCloudTest::testDownload
180181182183
Covered by 1 test(s):
  • SoundCloudTest::testDownload
184
Covered by 1 test(s):
  • SoundCloudTest::testDownload
185
Covered by 1 test(s):
  • SoundCloudTest::testDownload
186187
Covered by 1 test(s):
  • SoundCloudTest::testDownload
188
Covered by 1 test(s):
  • SoundCloudTest::testDownload
189190
Covered by 1 test(s):
  • SoundCloudTest::testDownload
191
Covered by 1 test(s):
  • SoundCloudTest::testDownload
192193
Covered by 1 test(s):
  • SoundCloudTest::testDownload
194195196197198199200201202203204
Covered by 1 test(s):
  • SoundCloudTest::testDownload
205206207
Covered by 1 test(s):
  • SupportedSitesTest::testSoundCloudSupportsURL
208209210211212
<?php

namespace AudioDidact\SupportedSites;

use AudioDidact\Video;

class SoundCloud extends SupportedSite {
	// Setup global variables
	private $streamsBaseURL = "https://api.soundcloud.com/tracks/XYZ/streams?client_id=";
	private $clientID;
	private $invalidURLMessage = "Invalid SoundCloud URL Entered.<br/>Valid URLs look like https://soundcloud.com/user_name/xxxxxxxxxxxx";
	private $thumbnailURL;
	private $audioJSON;

	/**
	 * SoundCloud constructor. Gets the audio information, checks for it in the user's feed.
	 *
	 * @param string $str
	 * @param boolean $isVideo
	 * @throws \Exception
	 */
	public function __construct($str, $isVideo){
		$this->video = new Video();

		// If there is a URL/ID, continue
		if($str != null){
			if(!filter_var($str, FILTER_VALIDATE_URL) || !mb_strpos($str, "soundcloud")){
				throw new \Exception($this->invalidURLMessage);
			}
			$this->video->setURL($str);
			$this->video->setIsVideo(false);

			// Set video ID and time to current time
			$info = $this->getVideoInfo($str);
			if(!$info){
				throw new \Exception($this->invalidURLMessage);
			}
			$this->video->setId($info["ID"]);
			$this->video->setFilename($this->video->getId());
			$this->video->setThumbnailFilename($this->video->getFilename() . ".jpg");
			$this->video->setTime(time());
			$this->video->setTitle($info["title"]);
			$this->video->setAuthor($info["author"]);
			$this->video->setDesc($info["description"]);
		}
	}

	private function cURLHTTPGet($url, $ssl = false){
		$ch = curl_init($url);
		$headers = [
			"User-Agent: curl/7.16.3 (i686-pc-cygwin) libcurl/7.16.3 OpenSSL/0.9.8h zlib/1.2.3 libssh2/0.15-CVS",
			"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			"Accept-Language: en-us;q=0.5,en;q=0.3",
			"Keep-Alive: 115",
			"Connection: keep-alive"
		];
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($ch, CURLOPT_TIMEOUT, 30);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		if($ssl){
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
		}
		$response = curl_exec($ch);
		$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		if($responseCode != 200 && $responseCode != 302 && $responseCode != 304){
			$response = false;
		}

		return $response;
	}

	private function getVideoInfo($str){
		$str = str_replace("http://", "https://", $str);
		$webpage = $this->cURLHTTPGet($str, true);

		// Find javascript URLs to get a client ID
		preg_match_all("/<script.*src=\"(.*app-.*)\"\s*>/i", $webpage, $jsURLs);
		if(!isset($jsURLs[1][0])){
			return false;
		}
		$jsURL = $jsURLs[1][0];
		// Grab the client ID from te javascript
		$jsFile = file_get_contents($jsURL);
		preg_match_all("/\Wclient_id:\"(.*)\"/iU", $jsFile, $clientIDs);
		$this->clientID = $clientIDs[1][0];

		preg_match("/var\s+c\s*=\s*(\[.*\]),/i", $webpage, $matches);
		$brackets = 0;
		$firstRun = true;
		$strlen = mb_strlen($matches[1]);
		for($i = 0; $i < $strlen; $i++){
			if(!$firstRun && $brackets == 0){
				break;
			}
			if($firstRun){
				$firstRun = false;
			}
			$char = $matches[1][$i];
			if($char == "["){
				$brackets += 1;
			}
			else if($char == "]"){
				$brackets -= 1;
			}
		}
		$json = mb_substr($matches[1], 0, $i);
		$this->audioJSON = json_decode($json, true);
		if(empty($this->audioJSON)){
			return false;
		}

		foreach($this->audioJSON as $a){
			$a = $a["data"][0];
			if(isset($a["title"]) && isset($a["uri"]) && isset($a["description"])){
				$id = explode("/", $a["uri"]);
				$videoId = $id[count($id) - 1];
				$description = $a["description"];
				$title = $a["title"];
				$author = $a["user"]["username"];
				if(isset($a["artwork_url"]) && $a["artwork_url"] != null){
					$this->thumbnailURL = str_replace("large.jpg", "t500x500.jpg", $a["artwork_url"]);
				}
				else{
					$this->thumbnailURL = str_replace("large.jpg", "t500x500.jpg", $a["user"]["avatar_url"]);
				}

				return ["ID" => $videoId, "description" => $description, "title" => $title, "author" => $author];
			}
		}
		error_log("SoundCloud failed to parse JSON for URL: " . $str);

		return false;
	}

	/**
	 * Checks if all thumbnail, video, and mp3 are downloaded and have a length (ie. video or audio are not null)
	 *
	 * @return bool
	 */
	public function allDownloaded(){
		$downloadPath = DOWNLOAD_PATH . DIRECTORY_SEPARATOR;
		$fullDownloadPath = $downloadPath . $this->video->getFilename() . $this->video->getFileExtension();

		// If the thumbnail has not been downloaded, go ahead and download it
		if(!file_exists($downloadPath . $this->video->getThumbnailFilename())){
			$this->downloadThumbnail();
		}
		// If the mp3 check if the mp3 has a duration that is not null
		if(file_exists($fullDownloadPath) && SupportedSite::getDuration($fullDownloadPath)){
			// Before returning true, set the duration since convert will not be run
			$this->video->setDuration(SupportedSite::getDurationSeconds($fullDownloadPath));

			return true;
		}

		// If all else fails, return false
		return false;
	}

	/**
	 * Download thumbnail
	 */
	public function downloadThumbnail(){
		$path = getcwd() . DIRECTORY_SEPARATOR . DOWNLOAD_PATH . DIRECTORY_SEPARATOR;
		$thumbnail = $path . $this->video->getThumbnailFilename();
		file_put_contents($thumbnail, fopen($this->thumbnailURL, "r"));
		// Set the thumbnail file as publicly accessible
		@chmod($thumbnail, 0775);
	}

	private function getDownloadURL(){
		$streamsURL = str_replace("/XYZ/", "/" . $this->video->getId() . "/", $this->streamsBaseURL);
		$streamsJSON = file_get_contents($streamsURL.$this->clientID);
		$streamsJSON = json_decode($streamsJSON, true);

		return $streamsJSON["http_mp3_128_url"];
	}

	public function downloadVideo(){
		$path = getcwd() . DIRECTORY_SEPARATOR . DOWNLOAD_PATH . DIRECTORY_SEPARATOR;
		$videoPath = $path . $this->video->getFilename() . $this->video->getFileExtension();
		$url = $this->getDownloadURL();

		if($this->downloadWithPercentage($url, $videoPath)){
			$this->applyArt();
			// Send progress to UI
			$response = ['stage' => 1, 'progress' => 100];
			echo json_encode($response);

			return true;
		}

		return false;
	}

	/**
	 * Since SoundCloud is audio only, we do not convert, but only add the album artwork
	 */
	public function convert(){

	}

	public static function supportsURL($url){
		return mb_strpos($url, "soundcloud.com") > -1;
	}


}