<?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'); } }