288 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
|     defined('BASEPATH') OR exit('No direct script access allowed');
 | |
| 
 | |
|     class Youtube extends MY_Controller
 | |
|     {
 | |
| 
 | |
|         public function __construct()
 | |
|         {
 | |
|             parent::__construct('tools');
 | |
|             $this->load->model('YoutubeDownloadModel', '', TRUE);
 | |
|             $this->load->model('RedirectModel', '', TRUE);
 | |
|         }
 | |
| 
 | |
|         public function index()
 | |
|         {
 | |
|             $this->load->view('header', ['active' => 'youtube-downloader', 'title' => lang('ytdl_site_title')]);
 | |
|             $this->load->view('youtube_downloader');
 | |
|             $this->load->view('footer');
 | |
|         }
 | |
| 
 | |
|         public function download()
 | |
|         {
 | |
|             if (empty($_GET['mime']) OR empty($_GET['token'])) {
 | |
|                 header("Location: /youtube");
 | |
|             }
 | |
|             $mime = filter_var($_GET['mime']);
 | |
|             $ext = str_replace(array('/', 'x-'), '', strstr($mime, '/'));
 | |
|             $url = base64_decode(filter_var($_GET['token']));
 | |
|             $name = urldecode($_GET['title']) . '.' . $ext;
 | |
|             echo $url;
 | |
|             if ($url) {
 | |
|                 $size = $this->YoutubeDownloadModel->get_size($url);
 | |
|                 // Generate the server headers
 | |
|                 if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) {
 | |
|                     header('Content-Type: "' . $mime . '"');
 | |
|                     header('Content-Disposition: attachment; filename="' . $name . '"');
 | |
|                     header('Expires: 0');
 | |
|                     header('Content-Length: ' . $size);
 | |
|                     header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
 | |
|                     header("Content-Transfer-Encoding: binary");
 | |
|                     header('Pragma: public');
 | |
|                 } else {
 | |
|                     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');
 | |
|                 }
 | |
| 
 | |
|                 readfile($url);
 | |
|                 exit;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public function video()
 | |
|         {
 | |
|             echo $this->load->view('header', ['title' => lang('ytdl_site_title'), 'active' => 'youtube-downloader'], true);
 | |
|             if (isset($_REQUEST['videoid'])) {
 | |
|                 $my_id = $_REQUEST['videoid'];
 | |
|                 if (preg_match('/^https:\/\/w{3}?.youtube.com\//', $my_id)) {
 | |
|                     $url = parse_url($my_id);
 | |
|                     $my_id = NULL;
 | |
|                     if (is_array($url) && count($url) > 0 && isset($url['query']) && !empty($url['query'])) {
 | |
|                         $parts = explode('&', $url['query']);
 | |
|                         if (is_array($parts) && count($parts) > 0) {
 | |
|                             foreach ($parts as $p) {
 | |
|                                 $pattern = '/^v\=/';
 | |
|                                 if (preg_match($pattern, $p)) {
 | |
|                                     $my_id = preg_replace($pattern, '', $p);
 | |
|                                     break;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                         if (!$my_id) {
 | |
|                             header("Location: /tools/youtube?error=1");
 | |
|                             exit;
 | |
|                         }
 | |
|                     } else {
 | |
|                         header("Location: /tools/youtube?error=2");
 | |
|                         exit;
 | |
|                     }
 | |
|                 } elseif (preg_match('/^https?:\/\/youtu.be/', $my_id)) {
 | |
|                     $url = parse_url($my_id);
 | |
|                     $my_id = NULL;
 | |
|                     $my_id = preg_replace('/^\//', '', $url['path']);
 | |
|                 }
 | |
|             } else {
 | |
|                 header("Location: /tools/youtube?error=1");
 | |
|                 exit;
 | |
|             }
 | |
| 
 | |
|             if (isset($_REQUEST['type'])) {
 | |
|                 $my_type = $_REQUEST['type'];
 | |
|             } else {
 | |
|                 $my_type = 'redirect';
 | |
|             }
 | |
| 
 | |
|             if ($my_type == 'Download') {
 | |
|                 ?>
 | |
| 
 | |
|                 <section class="container">
 | |
|                 <h1 class="center"><?= lang('ytdl_title'); ?></h1>
 | |
|                 <p class="lead center"><?= lang('ytdl_description'); ?></p>
 | |
|                 <div class="row center">
 | |
| 
 | |
|                 <?php
 | |
|             } // end of if for type=Download
 | |
| 
 | |
|             /* First get the video info page for this video id */
 | |
|             //$my_video_info = 'http://www.youtube.com/get_video_info?&video_id='. $my_id;
 | |
|             $my_video_info = 'http://www.youtube.com/get_video_info?&video_id=' . $my_id . '&asv=3&el=detailpage&hl=' . lang('ytdl_language'); //video details fix *1
 | |
|             $my_video_info = $this->YoutubeDownloadModel->curlGet($my_video_info);
 | |
| 
 | |
|             /* TODO: Check return from curl for status code */
 | |
|             if (empty($my_video_info)) {
 | |
|                 header("Location: /tools/youtube?error=3");
 | |
|             }
 | |
| 
 | |
|             $thumbnail_url = $title = $view_count = $author = $length_seconds = $url_encoded_fmt_stream_map = $type = $url = '';
 | |
| 
 | |
|             parse_str($my_video_info);
 | |
|             $length_seconds = date("i:s", $length_seconds);
 | |
|             $view_count = number_format($view_count, 0, ',', '.');
 | |
|             if ($status == 'fail') {
 | |
|                 header("Location: /tools/youtube?error=3");
 | |
|                 exit();
 | |
|             } ?>
 | |
|             <div id="info">
 | |
|                 <div class="row">
 | |
|                     <div class="col-sm-4">
 | |
|                         <a href="/file/thumbnail/<?= $my_id; ?>" target="_blank">
 | |
|                             <img class="float-right" style="max-width:100%" src="/file/thumbnail/<?= $my_id; ?>">
 | |
|                         </a>
 | |
|                     </div>
 | |
|                     <div class="col-sm-8">
 | |
|                         <a href="https://youtu.be/<?= $my_id ?>" target="_blank">
 | |
|                             <h3 align="left"><?= $title; ?></h3>
 | |
|                         </a>
 | |
|                         <h4 align="left"><?= lang('ytdl_views'); ?>: <?= $view_count; ?></h4>
 | |
|                         <h4 align="left"><?= lang('ytdl_length') . ': ' . $length_seconds . ' ' . lang('ytdl_minutes'); ?></h4>
 | |
|                         <h4 align="left"><?= lang('ytdl_author') ?>:
 | |
|                             <a href="http://youtube.com/<?= $author; ?>"
 | |
|                                target="_blank"><?= $author; ?></a>
 | |
|                         </h4>
 | |
|                         <a align="left" href="https://youtu.be/<?= $my_id; ?>" target="_blank"
 | |
|                            class="btn btn-primary raised pull-left"><?= lang('ytdl_watch'); ?></a>
 | |
|                     </div>
 | |
|                 </div>
 | |
|             </div>
 | |
|             </div>
 | |
|             <div class="row">
 | |
|             <?php
 | |
|             $my_title = $title;
 | |
|             $cleanedtitle = $this->YoutubeDownloadModel->clean($title);
 | |
| 
 | |
|             if (isset($url_encoded_fmt_stream_map)) {
 | |
|                 /* Now get the url_encoded_fmt_stream_map, and explode on comma */
 | |
|                 $my_formats_array = explode(',', $url_encoded_fmt_stream_map);
 | |
|             } else {
 | |
|                 echo '<p>No encoded format stream found.</p>';
 | |
|                 echo '<p>Here is what we got from YouTube:</p>';
 | |
|                 echo $my_video_info;
 | |
|             }
 | |
|             if (count($my_formats_array) == 0) {
 | |
|                 echo '<p>' . lang('ytdl_error_no_downloads') . '</p>';
 | |
|                 exit;
 | |
|             }
 | |
| 
 | |
|             /* create an array of available download formats */
 | |
|             $avail_formats[] = '';
 | |
|             $i = 0;
 | |
|             $ipbits = $ip = $itag = $sig = $quality = '';
 | |
|             $expire = time();
 | |
| 
 | |
|             foreach ($my_formats_array as $format) {
 | |
|                 parse_str($format);
 | |
|                 $avail_formats[$i]['itag'] = $itag;
 | |
|                 $avail_formats[$i]['quality'] = $quality;
 | |
|                 $type = explode(';', $type);
 | |
|                 $avail_formats[$i]['type'] = $type[0];
 | |
|                 $avail_formats[$i]['url'] = urldecode($url) . '&signature=' . $sig;
 | |
|                 parse_str(urldecode($url));
 | |
|                 $avail_formats[$i]['expires'] = date("d.m.Y G:i:s", $expire);
 | |
|                 $avail_formats[$i]['ipbits'] = $ipbits;
 | |
|                 $avail_formats[$i]['ip'] = $ip;
 | |
|                 $i++;
 | |
|             }
 | |
| 
 | |
|             if ($my_type == 'Download') {
 | |
|                 echo '<p align="left"><b>' . lang('ytdl_available_formats') . ':</b></p>
 | |
|                     <div class="table-responsive"><table class="table table-hover table-striped"><thead><tr><td>' . lang('ytdl_format') . '</td><td>' . lang('ytdl_quality') . '</td><td>' . lang('ytdl_size') . '</td><td>' . lang('ytdl_download_link') . '</td><td>' . lang('ytdl_available_until') . '</td></tr></thead><tbody>';
 | |
| 
 | |
|                 $formats = [
 | |
|                     '22' => '720p',
 | |
|                     '18' => '360p',
 | |
|                     '43' => '360p',
 | |
|                     '5' => '240p',
 | |
|                     '36' => '240p',
 | |
|                     '17' => '144p'
 | |
|                 ];
 | |
|                 /* now that we have the array, print the options */
 | |
|                 for ($i = 0; $i < count($avail_formats); $i++) {
 | |
|                     $type = explode('/', $avail_formats[$i]['type'])[1];
 | |
|                     $thisurl = base_url('tools/youtube/download?mime=' . $avail_formats[$i]['type'] . '&title=' . urlencode(htmlspecialchars($my_title)) . '&token=' . base64_encode($avail_formats[$i]['url']));
 | |
|                     $url = base_url('r/' . $this->RedirectModel->addRandomItem($thisurl, true, 6));
 | |
|                     echo '<tr><td>';
 | |
|                     echo '<a href="' . base_url('r/' . $this->RedirectModel->addRandomItem($avail_formats[$i]['url'] . '&title=' . $cleanedtitle, true, 6)) . '" class="mime">' . $type . '</a> ';
 | |
|                     echo '</td> ' .
 | |
|                         '<td>' . $formats[$avail_formats[$i]['itag']] . '</td><td><span class="size">' . $this->YoutubeDownloadModel->formatBytes($this->YoutubeDownloadModel->get_size($avail_formats[$i]['url'])) . '</span></td>';
 | |
|                     echo '<td><a href="' . $url . '" class="dl btn btn-default btn-sm">' . lang('ytdl_download_link') . '</a></td><td>' . $avail_formats[$i]['expires'] . '</td>';
 | |
|                     echo '</tr>';
 | |
|                 }
 | |
|                 echo '</tbody></table></div><small>' . lang('ytdl_not_related_youtube') . '</small><br><small>' . lang('ytdl_no_haftung') . '</small><br><small>Der Betreiber nimmt Abstand von jeglichen urheberrechtsverletzenden Handlungen, die mit dem YouTube-Downloader durchgeführt werden könnten und unterstützt diese keinesfalls.</small>';
 | |
|                 ?>
 | |
|                 </div>
 | |
|                 </section>
 | |
| 
 | |
|                 <?php
 | |
| 
 | |
|             } else {
 | |
| 
 | |
|                 /* 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/
 | |
|                  */
 | |
| 
 | |
|                 $format = $_REQUEST['format'];
 | |
|                 $target_formats = '';
 | |
|                 switch ($format) {
 | |
|                     case "best":
 | |
|                         /* largest formats first */
 | |
|                         $target_formats = array('38', '37', '46', '22', '45', '35', '44', '34', '18', '43', '6', '5', '17', '13');
 | |
|                         break;
 | |
|                     case "free":
 | |
|                         /* Here we include WebM but prefer it over FLV */
 | |
|                         $target_formats = array('38', '46', '37', '45', '22', '44', '35', '43', '34', '18', '6', '5', '17', '13');
 | |
|                         break;
 | |
|                     case "ipad":
 | |
|                         /* here we leave out WebM video and FLV - looking for MP4 */
 | |
|                         $target_formats = array('37', '22', '18', '17');
 | |
|                         break;
 | |
|                     default:
 | |
|                         /* If they passed in a number use it */
 | |
|                         if (is_numeric($format)) {
 | |
|                             $target_formats[] = $format;
 | |
|                         } else {
 | |
|                             $target_formats = array('38', '37', '46', '22', '45', '35', '44', '34', '18', '43', '6', '5', '17', '13');
 | |
|                         }
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 /* Now we need to find our best format in the list of available formats */
 | |
|                 $best_format = '';
 | |
|                 for ($i = 0; $i < count($target_formats); $i++) {
 | |
|                     for ($j = 0; $j < count($avail_formats); $j++) {
 | |
|                         if ($target_formats[$i] == $avail_formats[$j]['itag']) {
 | |
|                             //echo '<p>Target format found, it is '. $avail_formats[$j]['itag'] .'</p>';
 | |
|                             $best_format = $j;
 | |
|                             break 2;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //echo '<p>Out of loop, best_format is '. $best_format .'</p>';
 | |
|                 if ((isset($best_format)) &&
 | |
|                     (isset($avail_formats[$best_format]['url'])) &&
 | |
|                     (isset($avail_formats[$best_format]['type']))
 | |
|                 ) {
 | |
|                     $redirect_url = $avail_formats[$best_format]['url'] . '&title=' . $cleanedtitle;
 | |
|                     $content_type = $avail_formats[$best_format]['type'];
 | |
|                 }
 | |
|                 if (isset($redirect_url)) {
 | |
|                     header("Location: $redirect_url");
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             $this->load->view('footer');
 | |
|         }
 | |
|     }
 |