diff --git a/common.php b/bootstrap.php similarity index 85% rename from common.php rename to bootstrap.php index 0fde48cd..fff8aed2 100644 --- a/common.php +++ b/bootstrap.php @@ -66,6 +66,14 @@ function($custom = 'custom') $container->set('template', $template); + // Create Application\ControllerFactory + $factory = new \YoutubeDownloader\Application\ControllerFactory; + + $container->set('controller_factory', $factory); + + // Create Toolkit + $container->set('toolkit', new \YoutubeDownloader\Toolkit); + return $container; }, [getenv('CONFIG_ENV') ?: 'custom'] @@ -80,4 +88,4 @@ function($custom = 'custom') date_default_timezone_set($container->get('config')->get('default_timezone')); -return $container; +return new \YoutubeDownloader\Application\App($container); diff --git a/download.php b/download.php index 082cc977..cf5ba349 100644 --- a/download.php +++ b/download.php @@ -1,105 +1,4 @@ get('config'); -$template = $container->get('template'); - -// Check download token -if (empty($_GET['mime']) OR empty($_GET['token'])) -{ - echo $template->render('error.php', [ - 'error_message' => 'Invalid download token 8{', - ]); - exit(); -} - -// Set operation params -$mime = filter_var($_GET['mime']); -$ext = str_replace(['/', 'x-'], '', strstr($mime, '/')); -$url = base64_decode(filter_var($_GET['token'])); -$name = urldecode($_GET['title']) . '.' . $ext; - -// Fetch and serve -if ($url) -{ - global $config; - // prevent unauthorized download - if($config->get('VideoLinkMode') === "direct" and !isset($_GET['getmp3'])) - { - echo $template->render('error.php', [ - 'error_message' => 'VideoLinkMode: proxy download not enabled', - ]); - exit; - } - if($config->get('VideoLinkMode') !== "direct" and !isset($_GET['getmp3']) and !preg_match('@https://[^\.]+\.googlevideo.com/@', $url)) - { - echo $template->render('error.php', [ - 'error_message' => 'unauthorized access (^_^)', - ]); - exit; - } - - // check if request for mp3 download - if(isset($_GET['getmp3'])) - { - if($config->get('MP3Enable')) - { - $mp3_info = array(); - $mp3_info = \YoutubeDownloader\YoutubeDownloader::getDownloadMP3($url, $config); - if(isset($mp3_info['mp3'])) - { - $url = $mp3_info['mp3']; - } - else - { - if($config->get('debug') && isset($mp3_info['debugMessage'])) - { - var_dump($mp3_info['debugMessage']); - } - echo $template->render('error.php', [ - 'error_message' => $mp3_info['message'], - ]); - exit; - } - } - else - { - echo $template->render('error.php', [ - 'error_message' => 'Option for MP3 download is not enabled.', - ]); - exit; - } - } - - if(isset($mp3_info['mp3'])) - { - $size = filesize($mp3_info['mp3']); - } - else - { - $size = \YoutubeDownloader\YoutubeDownloader::get_size($url, $config); - } - - // Generate the server headers - header('Content-Type: "' . $mime . '"'); - header('Content-Disposition: attachment; filename="' . $name . '"'); - header("Content-Transfer-Encoding: binary"); - header('Expires: 0'); - header('Content-Length: '.$size); - header('Pragma: no-cache'); - - if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) - { - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Pragma: public'); - } - - readfile($url); - exit; -} - -// Not found -echo $template->render('error.php', [ - 'error_message' => 'File not found 8{', -]); -exit; +$app->runWithRoute('download'); diff --git a/getimage.php b/getimage.php index 2aa341c8..33aa8b28 100644 --- a/getimage.php +++ b/getimage.php @@ -1,57 +1,4 @@ -get('config'); -$template = $container->get('template'); - -if ( ! isset($_GET['videoid']) ) -{ - echo $template->render('error.php', [ - 'error_message' => 'No video id passed in', - ]); - exit; -} - -$my_id = \YoutubeDownloader\YoutubeDownloader::validateVideoId($_GET['videoid']); - -if ( $my_id === null ) -{ - echo $template->render('error.php', [ - 'error_message' => 'Invalid video id passed in', - ]); - exit; -} - -$szName = 'default'; - -/** - * Player Background Thumbnail (480x360px) : http://i1.ytimg.com/vi/VIDEO_ID/0.jpg - * Normal Quality Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/default.jpg - * Medium Quality Thumbnail (320x180px) : http://i1.ytimg.com/vi/VIDEO_ID/mqdefault.jpg - * High Quality Thumbnail (480x360px) : http://i1.ytimg.com/vi/VIDEO_ID/hqdefault.jpg - * Start Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/1.jpg - * Middle Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/2.jpg - * End Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/3.jpg - */ -if (!empty($_GET['sz'])) -{ - $arg = $_GET['sz']; - - switch ($arg) - { - case 'hd': - $szName = 'hqdefault'; - break; - case 'sd': - $szName = 'default'; - break; - default: - $szName = $arg; - break; - } -} - -$thumbnail_url = "http://i1.ytimg.com/vi/" . $my_id . "/$szName.jpg"; // make image link - -header("Content-Type: image/jpeg"); // set headers -readfile($thumbnail_url); // show image +$app->runWithRoute('image'); diff --git a/getvideo.php b/getvideo.php index 6b4cf52f..2e622e41 100644 --- a/getvideo.php +++ b/getvideo.php @@ -1,225 +1,4 @@ get('config'); -$template = $container->get('template'); - -if( ! isset($_GET['videoid']) ) -{ - echo $template->render('error.php', [ - 'error_message' => 'No video id passed in', - ]); - exit; -} - -$my_id = $_GET['videoid']; - -if( \YoutubeDownloader\YoutubeDownloader::isMobileUrl($my_id) ) -{ - $my_id = \YoutubeDownloader\YoutubeDownloader::treatMobileUrl($my_id); -} - -$my_id = \YoutubeDownloader\YoutubeDownloader::validateVideoId($my_id); - -if ( $my_id === null ) -{ - echo $template->render('error.php', [ - 'error_message' => 'Invalid url', - ]); - exit; -} - -if (isset($_GET['type'])) -{ - $my_type = $_GET['type']; -} -else -{ - $my_type = 'redirect'; -} - -if ( $my_type !== 'Download' ) -{ - /* In this else, the request didn't come from a form but from something else - * like an RSS feed. - * As a result, we just want to return the best format, which depends on what - * the user provided in the url. - * If they provided "format=best" we just use the largest. - * If they provided "format=free" we provide the best non-flash version - * If they provided "format=ipad" we pull the best MP4 version - * - * Thanks to the python based youtube-dl for info on the formats - * http://rg3.github.com/youtube-dl/ - */ - - $redirect_url = \YoutubeDownloader\YoutubeDownloader::getDownloadUrlByFormats($avail_formats, $_GET['format']); - - if ( $redirect_url !== null ) - { - header("Location: $redirect_url"); - } - - exit; -} - -$template_data = []; - -/* First get the video info page for this video id */ -// $my_video_info = 'http://www.youtube.com/get_video_info?&video_id='. $my_id; -// thanks to amit kumar @ bloggertale.com for sharing the fix -$video_info_url = 'http://www.youtube.com/get_video_info?&video_id=' . $my_id . '&asv=3&el=detailpage&hl=en_US'; -$video_info_string = \YoutubeDownloader\YoutubeDownloader::curlGet($video_info_url, $config); - -/* TODO: Check return from curl for status code */ -$video_info = \YoutubeDownloader\VideoInfo::createFromString($video_info_string); - -if ($video_info->getStatus() == 'fail') -{ - echo $template->render('error.php', [ - 'error_message' => 'Error in video ID: ' . $video_info->getErrorReason(), - ]); - - if ($config->get('debug')) - { - echo '
'; - var_dump($video_info); - echo ''; - } - - exit; -} - -switch ($config->get('ThumbnailImageMode')) -{ - case 2: - $template_data['show_thumbnail'] = true; - $template_data['thumbnail_src'] = 'getimage.php?videoid=' . $my_id; - $template_data['thumbnail_anchor'] = 'getimage.php?videoid=' . $my_id . '&sz=hd'; - break; - case 1: - $template_data['show_thumbnail'] = true; - $template_data['thumbnail_src'] = $video_info->getThumbnailUrl(); - $template_data['thumbnail_anchor'] = 'getimage.php?videoid=' . $my_id . '&sz=hd'; - break; - case 0: - default: - $template_data['show_thumbnail'] = false; -} - -$my_title = $video_info->getTitle(); -$cleanedtitle = $video_info->getCleanedTitle(); - -$template_data['video_title'] = $video_info->getTitle(); - -if ( $video_info->getStreamMapString() === null ) -{ - $template_data['no_stream_map_found'] = true; - $template_data['no_stream_map_found_dump'] = var_export($video_info_string, true); -} - -$stream_map = \YoutubeDownloader\StreamMap::createFromVideoInfo($video_info); - -if ($config->get('debug')) -{ - $debug1 = ''; - - if ($config->get('multipleIPs') === true) - { - $debug1 .= 'Outgoing IP: ' . print_r(\YoutubeDownloader\StreamMap::getRandomIp($config), true); - } - - $template_data['show_debug1'] = true; - $template_data['debug1'] = var_export($stream_map, true); -} - -if (count($stream_map->getStreams()) == 0) -{ - echo $template->render('error.php', [ - 'error_message' => 'No format stream map found - was the video id correct?', - ]); - exit; -} - -/* create an array of available download formats */ -$avail_formats = $stream_map->getStreams(); - -if ($config->get('debug')) -{ - $template_data['show_debug2'] = true; - $template_data['debug2_expires'] = $avail_formats[0]['expires']; - $template_data['debug2_ip'] = $avail_formats[0]['ip']; - $template_data['debug2_ipbits'] = $avail_formats[0]['ipbits']; -} - -$template_data['streams'] = []; -$template_data['formats'] = []; -$template_data['showBrowserExtensions'] = ( \YoutubeDownloader\YoutubeDownloader::is_chrome() and $config->get('showBrowserExtensions') == true ); - -/* now that we have the array, print the options */ -foreach ($avail_formats as $avail_format) -{ - $directlink = $avail_format['url']; - // $directlink = explode('.googlevideo.com/', $avail_format['url']); - // $directlink = 'http://redirector.googlevideo.com/' . $directlink[1] . '&ratebypass=yes&gcr=sg'; - $directlink .= '&title=' . $cleanedtitle; - - $proxylink = 'download.php?mime=' . $avail_format['type'] . '&title=' . urlencode($my_title) . '&token=' . base64_encode($avail_format['url']); - - $size = \YoutubeDownloader\YoutubeDownloader::get_size($avail_format['url'], $config); - $size = \YoutubeDownloader\YoutubeDownloader::formatBytes($size); - - $template_data['streams'][] = [ - 'show_direct_url' => ($config->get('VideoLinkMode') === 'direct' || $config->get('VideoLinkMode') === 'both'), - 'show_proxy_url' => ($config->get('VideoLinkMode') === 'proxy' || $config->get('VideoLinkMode') === 'both'), - 'direct_url'=> $directlink, - 'proxy_url'=> $proxylink, - 'type'=> $avail_format['type'], - 'quality'=> $avail_format['quality'], - 'size'=> $size, - ]; -} - -foreach ($stream_map->getFormats() as $avail_format) -{ - $directlink = $avail_format['url']; - // $directlink = explode('.googlevideo.com/', $avail_format['url']); - // $directlink = 'http://redirector.googlevideo.com/' . $directlink[1] . '&ratebypass=yes&gcr=sg'; - $directlink .= '&title=' . $cleanedtitle; - - $proxylink = 'download.php?mime=' . $avail_format['type'] . '&title=' . urlencode($my_title) . '&token=' . base64_encode($avail_format['url']); - - $size = \YoutubeDownloader\YoutubeDownloader::get_size($avail_format['url'], $config); - $size = \YoutubeDownloader\YoutubeDownloader::formatBytes($size); - - $template_data['formats'][] = [ - 'show_direct_url' => ($config->get('VideoLinkMode') === 'direct' || $config->get('VideoLinkMode') === 'both'), - 'show_proxy_url' => ($config->get('VideoLinkMode') === 'proxy' || $config->get('VideoLinkMode') === 'both'), - 'direct_url'=> $directlink, - 'proxy_url'=> $proxylink, - 'type'=> $avail_format['type'], - 'quality'=> $avail_format['quality'], - 'size'=> $size, - ]; -} - -if($config->get('MP3Enable')) -{ - $mp3_url = sprintf( - 'download.php?mime=audio/mp3&token=%s&title=%s&getmp3=true', - base64_encode($my_id), - $cleanedtitle - ); - - $template_data['showMP3Download'] = true; - $template_data['mp3_download_url'] = $mp3_url; - $template_data['mp3_download_quality'] = $config->get('MP3Quality'); -} - -echo $template->render('getvideo.php', $template_data); +$app->runWithRoute('results'); diff --git a/index.php b/index.php index a08fbc49..f227e595 100644 --- a/index.php +++ b/index.php @@ -1,10 +1,4 @@ get('config'); -$template = $container->get('template'); - -echo $template->render('index.php', [ - 'is_chrome' => \YoutubeDownloader\YoutubeDownloader::is_chrome(), - 'showBrowserExtensions' => $config->get('showBrowserExtensions'), -]); +$app->runWithRoute('index'); diff --git a/src/Application/App.php b/src/Application/App.php new file mode 100644 index 00000000..1d87f3bd --- /dev/null +++ b/src/Application/App.php @@ -0,0 +1,69 @@ +container = $container; + } + + /** + * Returns the App version + * + * @return string + */ + public function getVersion() + { + return $this->version; + } + + /** + * Returns the Controller + * + * @return Controller + */ + public function getContainer() + { + return $this->container; + } + + /** + * Runs the app with a specific route + * + * @param string $route + * + * @return void + */ + public function runWithRoute($route) + { + $controller_factory = $this->getContainer()->get('controller_factory'); + + $controller = $controller_factory->make($route, $this); + + $controller->execute(); + } +} diff --git a/src/Application/Controller.php b/src/Application/Controller.php new file mode 100644 index 00000000..f8cd7c10 --- /dev/null +++ b/src/Application/Controller.php @@ -0,0 +1,28 @@ +app = $app; + } + + /** + * Get an entry from the container + * + * @param string $id + * + * @return mixed + */ + protected function get($id) + { + return $this->app->getContainer()->get($id); + } +} diff --git a/src/Application/ControllerFactory.php b/src/Application/ControllerFactory.php new file mode 100644 index 00000000..f71c6fb6 --- /dev/null +++ b/src/Application/ControllerFactory.php @@ -0,0 +1,44 @@ + '\\YoutubeDownloader\\Application\\DownloadController', + 'image' => '\\YoutubeDownloader\\Application\\ImageController', + 'index' => '\\YoutubeDownloader\\Application\\MainController', + 'results' => '\\YoutubeDownloader\\Application\\ResultController', + ]; + + /** + * Create the Controller + * + * @param string $route + * @param YoutubeDownloader\Application\App $app + * + * @throws Exception if a route was not found + * + * @return Controller + */ + public function make($route, App $app) + { + $route = strval($route); + + if ( ! array_key_exists($route, $this->controller_map) ) + { + throw new Exception( + sprintf('No controller was found for route "%s"', $route) + ); + } + + $controller_name = $this->controller_map[$route]; + + return new $controller_name($app); + } +} diff --git a/src/Application/DownloadController.php b/src/Application/DownloadController.php new file mode 100644 index 00000000..1d535216 --- /dev/null +++ b/src/Application/DownloadController.php @@ -0,0 +1,123 @@ +get('config'); + $template = $this->get('template'); + $toolkit = $this->get('toolkit'); + + // Check download token + if (empty($_GET['mime']) OR empty($_GET['token'])) + { + echo $template->render('error.php', [ + 'error_message' => 'Invalid download token 8{', + ]); + exit(); + } + + // Set operation params + $mime = filter_var($_GET['mime']); + $ext = str_replace(['/', 'x-'], '', strstr($mime, '/')); + $url = base64_decode(filter_var($_GET['token'])); + $name = urldecode($_GET['title']) . '.' . $ext; + + // Fetch and serve + if ($url) + { + // prevent unauthorized download + if($config->get('VideoLinkMode') === "direct" and !isset($_GET['getmp3'])) + { + echo $template->render('error.php', [ + 'error_message' => 'VideoLinkMode: proxy download not enabled', + ]); + exit; + } + if($config->get('VideoLinkMode') !== "direct" and !isset($_GET['getmp3']) and !preg_match('@https://[^\.]+\.googlevideo.com/@', $url)) + { + echo $template->render('error.php', [ + 'error_message' => 'unauthorized access (^_^)', + ]); + exit; + } + + // check if request for mp3 download + if(isset($_GET['getmp3'])) + { + if($config->get('MP3Enable')) + { + $mp3_info = array(); + $mp3_info = $toolkit->getDownloadMP3($url, $config); + if(isset($mp3_info['mp3'])) + { + $url = $mp3_info['mp3']; + } + else + { + if($config->get('debug') && isset($mp3_info['debugMessage'])) + { + var_dump($mp3_info['debugMessage']); + } + echo $template->render('error.php', [ + 'error_message' => $mp3_info['message'], + ]); + exit; + } + } + else + { + echo $template->render('error.php', [ + 'error_message' => 'Option for MP3 download is not enabled.', + ]); + exit; + } + } + + if(isset($mp3_info['mp3'])) + { + $size = filesize($mp3_info['mp3']); + } + else + { + $size = $toolkit->get_size($url, $config); + } + + // Generate the server headers + header('Content-Type: "' . $mime . '"'); + header('Content-Disposition: attachment; filename="' . $name . '"'); + header("Content-Transfer-Encoding: binary"); + header('Expires: 0'); + header('Content-Length: '.$size); + header('Pragma: no-cache'); + + if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) + { + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + } + + readfile($url); + exit; + } + + // Not found + echo $template->render('error.php', [ + 'error_message' => 'File not found 8{', + ]); + exit; + } +} diff --git a/src/Application/ImageController.php b/src/Application/ImageController.php new file mode 100644 index 00000000..0c09855a --- /dev/null +++ b/src/Application/ImageController.php @@ -0,0 +1,76 @@ +get('config'); + $template = $this->get('template'); + $toolkit = $this->get('toolkit'); + + if ( ! isset($_GET['videoid']) ) + { + echo $template->render('error.php', [ + 'error_message' => 'No video id passed in', + ]); + exit; + } + + $my_id = $toolkit->validateVideoId($_GET['videoid']); + + if ( $my_id === null ) + { + echo $template->render('error.php', [ + 'error_message' => 'Invalid video id passed in', + ]); + exit; + } + + $szName = 'default'; + + /** + * Player Background Thumbnail (480x360px) : http://i1.ytimg.com/vi/VIDEO_ID/0.jpg + * Normal Quality Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/default.jpg + * Medium Quality Thumbnail (320x180px) : http://i1.ytimg.com/vi/VIDEO_ID/mqdefault.jpg + * High Quality Thumbnail (480x360px) : http://i1.ytimg.com/vi/VIDEO_ID/hqdefault.jpg + * Start Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/1.jpg + * Middle Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/2.jpg + * End Thumbnail (120x90px) : http://i1.ytimg.com/vi/VIDEO_ID/3.jpg + */ + if (!empty($_GET['sz'])) + { + $arg = $_GET['sz']; + + switch ($arg) + { + case 'hd': + $szName = 'hqdefault'; + break; + case 'sd': + $szName = 'default'; + break; + default: + $szName = $arg; + break; + } + } + + $thumbnail_url = "http://i1.ytimg.com/vi/" . $my_id . "/$szName.jpg"; // make image link + + header("Content-Type: image/jpeg"); // set headers + readfile($thumbnail_url); // show image + } +} diff --git a/src/Application/MainController.php b/src/Application/MainController.php new file mode 100644 index 00000000..4a158083 --- /dev/null +++ b/src/Application/MainController.php @@ -0,0 +1,29 @@ +get('config'); + $template = $this->get('template'); + $toolkit = $this->get('toolkit'); + + echo $template->render('index.php', [ + 'is_chrome' => $toolkit->is_chrome(), + 'showBrowserExtensions' => $config->get('showBrowserExtensions'), + ]); + } +} diff --git a/src/Application/ResultController.php b/src/Application/ResultController.php new file mode 100644 index 00000000..1419da04 --- /dev/null +++ b/src/Application/ResultController.php @@ -0,0 +1,237 @@ +get('config'); + $template = $this->get('template'); + $toolkit = $this->get('toolkit'); + + if( ! isset($_GET['videoid']) ) + { + echo $template->render('error.php', [ + 'error_message' => 'No video id passed in', + ]); + exit; + } + + $my_id = $_GET['videoid']; + + if( $toolkit->isMobileUrl($my_id) ) + { + $my_id = $toolkit->treatMobileUrl($my_id); + } + + $my_id = $toolkit->validateVideoId($my_id); + + if ( $my_id === null ) + { + echo $template->render('error.php', [ + 'error_message' => 'Invalid url', + ]); + exit; + } + + if (isset($_GET['type'])) + { + $my_type = $_GET['type']; + } + else + { + $my_type = 'redirect'; + } + + $template_data = []; + + /* First get the video info page for this video id */ + // $my_video_info = 'http://www.youtube.com/get_video_info?&video_id='. $my_id; + // thanks to amit kumar @ bloggertale.com for sharing the fix + $video_info_url = 'http://www.youtube.com/get_video_info?&video_id=' . $my_id . '&asv=3&el=detailpage&hl=en_US'; + $video_info_string = $toolkit->curlGet($video_info_url, $config); + + /* TODO: Check return from curl for status code */ + $video_info = \YoutubeDownloader\VideoInfo::createFromString($video_info_string); + + if ($video_info->getStatus() == 'fail') + { + echo $template->render('error.php', [ + 'error_message' => 'Error in video ID: ' . $video_info->getErrorReason(), + ]); + + if ($config->get('debug')) + { + echo '
'; + var_dump($video_info); + echo ''; + } + + exit; + } + + if ( $my_type !== 'Download' ) + { + /* In this else, the request didn't come from a form but from something else + * like an RSS feed. + * As a result, we just want to return the best format, which depends on what + * the user provided in the url. + * If they provided "format=best" we just use the largest. + * If they provided "format=free" we provide the best non-flash version + * If they provided "format=ipad" we pull the best MP4 version + * + * Thanks to the python based youtube-dl for info on the formats + * http://rg3.github.com/youtube-dl/ + */ + $stream_map = \YoutubeDownloader\StreamMap::createFromVideoInfo($video_info); + $redirect_url = $toolkit->getDownloadUrlByFormats($stream_map->getStreams(), $_GET['format']); + + if ( $redirect_url !== null ) + { + header("Location: $redirect_url"); + } + + exit; + } + + switch ($config->get('ThumbnailImageMode')) + { + case 2: + $template_data['show_thumbnail'] = true; + $template_data['thumbnail_src'] = 'getimage.php?videoid=' . $my_id; + $template_data['thumbnail_anchor'] = 'getimage.php?videoid=' . $my_id . '&sz=hd'; + break; + case 1: + $template_data['show_thumbnail'] = true; + $template_data['thumbnail_src'] = $video_info->getThumbnailUrl(); + $template_data['thumbnail_anchor'] = 'getimage.php?videoid=' . $my_id . '&sz=hd'; + break; + case 0: + default: + $template_data['show_thumbnail'] = false; + } + + $my_title = $video_info->getTitle(); + $cleanedtitle = $video_info->getCleanedTitle(); + + $template_data['video_title'] = $video_info->getTitle(); + + if ( $video_info->getStreamMapString() === null ) + { + $template_data['no_stream_map_found'] = true; + $template_data['no_stream_map_found_dump'] = var_export($video_info_string, true); + } + + $stream_map = \YoutubeDownloader\StreamMap::createFromVideoInfo($video_info); + + if ($config->get('debug')) + { + $debug1 = ''; + + if ($config->get('multipleIPs') === true) + { + $debug1 .= 'Outgoing IP: ' . print_r(\YoutubeDownloader\StreamMap::getRandomIp($config), true); + } + + $template_data['show_debug1'] = true; + $template_data['debug1'] = var_export($stream_map, true); + } + + if (count($stream_map->getStreams()) == 0) + { + echo $template->render('error.php', [ + 'error_message' => 'No format stream map found - was the video id correct?', + ]); + exit; + } + + /* create an array of available download formats */ + $avail_formats = $stream_map->getStreams(); + + if ($config->get('debug')) + { + $template_data['show_debug2'] = true; + $template_data['debug2_expires'] = $avail_formats[0]['expires']; + $template_data['debug2_ip'] = $avail_formats[0]['ip']; + $template_data['debug2_ipbits'] = $avail_formats[0]['ipbits']; + } + + $template_data['streams'] = []; + $template_data['formats'] = []; + $template_data['showBrowserExtensions'] = ( $toolkit->is_chrome() and $config->get('showBrowserExtensions') == true ); + + /* now that we have the array, print the options */ + foreach ($avail_formats as $avail_format) + { + $directlink = $avail_format['url']; + // $directlink = explode('.googlevideo.com/', $avail_format['url']); + // $directlink = 'http://redirector.googlevideo.com/' . $directlink[1] . '&ratebypass=yes&gcr=sg'; + $directlink .= '&title=' . $cleanedtitle; + + $proxylink = 'download.php?mime=' . $avail_format['type'] . '&title=' . urlencode($my_title) . '&token=' . base64_encode($avail_format['url']); + + $size = $toolkit->get_size($avail_format['url'], $config); + $size = $toolkit->formatBytes($size); + + $template_data['streams'][] = [ + 'show_direct_url' => ($config->get('VideoLinkMode') === 'direct' || $config->get('VideoLinkMode') === 'both'), + 'show_proxy_url' => ($config->get('VideoLinkMode') === 'proxy' || $config->get('VideoLinkMode') === 'both'), + 'direct_url'=> $directlink, + 'proxy_url'=> $proxylink, + 'type'=> $avail_format['type'], + 'quality'=> $avail_format['quality'], + 'size'=> $size, + ]; + } + + foreach ($stream_map->getFormats() as $avail_format) + { + $directlink = $avail_format['url']; + // $directlink = explode('.googlevideo.com/', $avail_format['url']); + // $directlink = 'http://redirector.googlevideo.com/' . $directlink[1] . '&ratebypass=yes&gcr=sg'; + $directlink .= '&title=' . $cleanedtitle; + + $proxylink = 'download.php?mime=' . $avail_format['type'] . '&title=' . urlencode($my_title) . '&token=' . base64_encode($avail_format['url']); + + $size = $toolkit->get_size($avail_format['url'], $config); + $size = $toolkit->formatBytes($size); + + $template_data['formats'][] = [ + 'show_direct_url' => ($config->get('VideoLinkMode') === 'direct' || $config->get('VideoLinkMode') === 'both'), + 'show_proxy_url' => ($config->get('VideoLinkMode') === 'proxy' || $config->get('VideoLinkMode') === 'both'), + 'direct_url'=> $directlink, + 'proxy_url'=> $proxylink, + 'type'=> $avail_format['type'], + 'quality'=> $avail_format['quality'], + 'size'=> $size, + ]; + } + + if($config->get('MP3Enable')) + { + $mp3_url = sprintf( + 'download.php?mime=audio/mp3&token=%s&title=%s&getmp3=true', + base64_encode($my_id), + $cleanedtitle + ); + + $template_data['showMP3Download'] = true; + $template_data['mp3_download_url'] = $mp3_url; + $template_data['mp3_download_quality'] = $config->get('MP3Quality'); + } + + echo $template->render('getvideo.php', $template_data); + } +} diff --git a/src/StreamMap.php b/src/StreamMap.php index 406b05fd..f1a00dcc 100644 --- a/src/StreamMap.php +++ b/src/StreamMap.php @@ -47,6 +47,8 @@ private function __construct(array $streams, array $formats, VideoInfo $video_in */ private function parseStreams(array $streams, VideoInfo $video_info) { + $formats = []; + if (count($streams) === 1 and $streams[0] === '' ) { return $formats; diff --git a/src/YoutubeDownloader.php b/src/Toolkit.php similarity index 87% rename from src/YoutubeDownloader.php rename to src/Toolkit.php index 53497ea9..8cbe9b10 100644 --- a/src/YoutubeDownloader.php +++ b/src/Toolkit.php @@ -3,14 +3,16 @@ namespace YoutubeDownloader; /** - * YouTubeDownloader + * Toolkit + * + * This class contains all functionallities that must be refactored. */ -class YoutubeDownloader +class Toolkit { /** * @var string random IP */ - private static $outgoing_ip; + private $outgoing_ip; /** * Select random IP from config @@ -21,21 +23,21 @@ class YoutubeDownloader * @param Config $config * @return string|null The IP or null */ - public static function getRandomIp(Config $config) + public function getRandomIp(Config $config) { if ($config->get('multipleIPs') !== true) { return null; } - if (static::$outgoing_ip === null) + if ($this->outgoing_ip === null) { // randomly select an ip from the $config->get('IPs') array $ips = $config->get('IPs'); - static::$outgoing_ip = $ips[mt_rand(0, count($ips) - 1)]; + $this->outgoing_ip = $ips[mt_rand(0, count($ips) - 1)]; } - return static::$outgoing_ip; + return $this->outgoing_ip; } @@ -47,7 +49,7 @@ public static function getRandomIp(Config $config) * @param string $video_id * @return string|null The validated video ID or null, if the video ID is invalid */ - public static function validateVideoId($video_id) + public function validateVideoId($video_id) { if (strlen($video_id) <= 11) { @@ -71,7 +73,7 @@ public static function validateVideoId($video_id) * @param string $string * @return bool */ - public static function isMobileUrl($string) + public function isMobileUrl($string) { if (strpos($string, "m.")) { @@ -85,7 +87,7 @@ public static function isMobileUrl($string) * @param string $string * @return string */ - public static function treatMobileUrl($string) + public function treatMobileUrl($string) { return str_replace("m.", "www."); } @@ -95,7 +97,7 @@ public static function treatMobileUrl($string) * @param int $precision * @return string */ - public static function formatBytes($bytes, $precision = 2) + public function formatBytes($bytes, $precision = 2) { $units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; $bytes = max($bytes, 0); @@ -109,7 +111,7 @@ public static function formatBytes($bytes, $precision = 2) /** * @return bool */ - public static function is_chrome() + public function is_chrome() { $agent = $_SERVER['HTTP_USER_AGENT']; @@ -137,7 +139,7 @@ public static function is_chrome() * @param Config $config * @return string */ - public static function curlGet($url, Config $config) + public function curlGet($url, Config $config) { $ch = curl_init(); @@ -166,7 +168,7 @@ public static function curlGet($url, Config $config) * @param Config $config * @return string */ - public static function get_size($url, Config $config) + public function get_size($url, Config $config) { $my_ch = curl_init($url); @@ -199,7 +201,7 @@ public static function get_size($url, Config $config) * @param string $format * @return bool */ - public static function getDownloadUrlByFormats(array $avail_formats, $format) + public function getDownloadUrlByFormats(array $avail_formats, $format) { $target_formats = ''; @@ -261,7 +263,7 @@ public static function getDownloadUrlByFormats(array $avail_formats, $format) return $redirect_url; } - public static function getDownloadMP3($video_id, Config $config) + public function getDownloadMP3($video_id, Config $config) { // generate new url, we can re-use previously generated link and pass it to "token" parameter but it too dangerous to use it with exec() // TODO: Background conversion, Ajax and Caching @@ -297,8 +299,10 @@ public static function getDownloadMP3($video_id, Config $config) } else { - return array("status" => "failed", - "message" => "Failed, adaptive audio format not available, try to set \$config->get('MP3ConvertVideo') = true;"); + return array( + "status" => "failed", + "message" => "Failed, adaptive audio format not available, try to set \$config->get('MP3ConvertVideo') = true;" + ); } } @@ -323,17 +327,21 @@ public static function getDownloadMP3($video_id, Config $config) if(strpos(implode(" ", $output), "Output #0, mp3") !== FALSE || file_exists("$mp3dir/$mp3Name")) { // Convert media to .mp3 success - return array("status" => "success", - "message" => "Convert media to .mp3 success", - "mp3" => "$mp3dir/$mp3Name", - "debugMessage" => $output); + return array( + "status" => "success", + "message" => "Convert media to .mp3 success", + "mp3" => "$mp3dir/$mp3Name", + "debugMessage" => $output + ); } } else { - return array("status" => "failed", - "message" => "Download media url from youtube failed.", - "debugMessage" => $output); + return array( + "status" => "failed", + "message" => "Download media url from youtube failed.", + "debugMessage" => $output + ); } } } diff --git a/tests/Unit/Application/AppTest.php b/tests/Unit/Application/AppTest.php new file mode 100644 index 00000000..682cf43c --- /dev/null +++ b/tests/Unit/Application/AppTest.php @@ -0,0 +1,62 @@ +createMock('\\YoutubeDownloader\\Container\\Container'); + + $app = new App($container); + + $this->assertSame($container, $app->getContainer()); + } + + /** + * @test getVersion + */ + public function getVersion() + { + $container = $this->createMock('\\YoutubeDownloader\\Container\\Container'); + + $app = new App($container); + + $this->assertSame('0.1.0', $app->getVersion()); + } + + /** + * @test runWithRoute + */ + public function runWithRoute() + { + $controller = $this->createMock( + '\\YoutubeDownloader\\Application\\Controller' + ); + $controller->expects($this->once())->method('execute'); + + $factory = $this->createMock( + '\\YoutubeDownloader\\Application\\ControllerFactory' + ); + $factory->expects($this->once()) + ->method('make') + ->willReturn($controller); + + $container = $this->createMock('\\YoutubeDownloader\\Container\\Container'); + $container->expects($this->once()) + ->method('get') + ->with('controller_factory') + ->willReturn($factory); + + $app = new App($container); + + $app->runWithRoute('test'); + } +} diff --git a/tests/Unit/Application/ControllerFactoryTest.php b/tests/Unit/Application/ControllerFactoryTest.php new file mode 100644 index 00000000..6f4fe73c --- /dev/null +++ b/tests/Unit/Application/ControllerFactoryTest.php @@ -0,0 +1,42 @@ +createMock('\\YoutubeDownloader\\Application\\App'); + + $factory = new ControllerFactory; + + $this->assertInstanceOf( + '\\YoutubeDownloader\\Application\\Controller', + $factory->make('index', $app) + ); + } + + /** + * @test make throws Exception + */ + public function makeThrowsException() + { + $app = $this->createMock('\\YoutubeDownloader\\Application\\App'); + + $factory = new ControllerFactory; + + $this->expectException('\\Exception'); + $this->expectExceptionMessage('No controller was found for route "fail"'); + + $this->assertInstanceOf( + '\\YoutubeDownloader\\Application\\Controller', + $factory->make('fail', $app) + ); + } +} diff --git a/tests/Unit/YoutubeDownloaderTest.php b/tests/Unit/ToolkitTest.php similarity index 91% rename from tests/Unit/YoutubeDownloaderTest.php rename to tests/Unit/ToolkitTest.php index 6f242d9e..0de79801 100644 --- a/tests/Unit/YoutubeDownloaderTest.php +++ b/tests/Unit/ToolkitTest.php @@ -2,9 +2,9 @@ namespace YoutubeDownloader\Tests\Unit; -use YoutubeDownloader\YoutubeDownloader; +use YoutubeDownloader\Toolkit; -class YoutubeDownloaderTest extends \YoutubeDownloader\Tests\Fixture\TestCase +class ToolkitTest extends \YoutubeDownloader\Tests\Fixture\TestCase { /** * @test validateVideoId() @@ -12,7 +12,9 @@ class YoutubeDownloaderTest extends \YoutubeDownloader\Tests\Fixture\TestCase */ public function validateVideoId($str, $expected) { - $this->assertSame($expected, YoutubeDownloader::validateVideoId($str)); + $toolkit = new Toolkit; + + $this->assertSame($expected, $toolkit->validateVideoId($str)); } /** @@ -46,7 +48,9 @@ public function VideoIdProvider() */ public function isMobileUrl($str, $expected) { - $this->assertSame($expected, YoutubeDownloader::isMobileUrl($str)); + $toolkit = new Toolkit; + + $this->assertSame($expected, $toolkit->isMobileUrl($str)); } /**