Fix youtube thumbnails, add youtube-dl support

This commit is contained in:
Juribiyan 2022-01-03 00:43:52 +05:00
parent 321bf99cf8
commit 3f443cbea5
3 changed files with 154 additions and 77 deletions

View File

@ -155,6 +155,7 @@ if (!$cache_loaded) {
// ---------------------------------- Attachment handling -----------------------------------
$cf['KU_FFMPEGPATH'] = '/usr/local/bin/ffmpeg'; //path to FFMPEG, on windows it's usually 'C:\ffmpeg\bin' (REQUIRED for videos)
$cf['KU_YOUTUBE_APIKEY'] = 'your_api_key'; //Your personal anal probe ID. Can be obtained it Google Dev. Console
$cf['I0_YOUTUBE_DL_PATH'] = ''; // Path to youtube-dl binary. If not empty, youtube-dl will be used instead of default API (in this case you won't need KU_YOUTUBE_APIKEY)
$cf['KU_THUMBWIDTH'] = 200; // Maximum thumbnail width
$cf['KU_THUMBHEIGHT'] = 200; // Maximum thumbnail height
$cf['KU_REPLYTHUMBWIDTH'] = 125; // Maximum thumbnail width (reply)

View File

@ -91,17 +91,20 @@ function createThumbnail($name, $filename, $new_w, $new_h) {
$system=explode(".", $filename);
$system = array_reverse($system);
if (preg_match("/jpg|jpeg/", $system[0])) {
$src_img=imagecreatefromjpeg($name);
$src_img=@imagecreatefromjpeg($name);
} else if (preg_match("/png/", $system[0])) {
$src_img=imagecreatefrompng($name);
$src_img=@imagecreatefrompng($name);
} else if (preg_match("/gif/", $system[0])) {
$src_img=imagecreatefromgif($name);
$src_img=@imagecreatefromgif($name);
} else {
return false;
}
if (!$src_img) {
exitWithErrorPage(_gettext('Unable to read uploaded file during thumbnailing.'), _gettext('A common cause for this is an incorrect extension when the file is actually of a different type.'));
// Check for the case if the image is actually wrong type
list($src_img, $actual_type)=imagecreatefromwhatever($name);
if (!$src_img)
exitWithErrorPage(_gettext('Unable to read uploaded file during thumbnailing.'), _gettext('A common cause for this is an incorrect extension when the file is actually of a different type.'));
}
$old_x = imageSX($src_img);
$old_y = imageSY($src_img);
@ -116,7 +119,18 @@ function createThumbnail($name, $filename, $new_w, $new_h) {
$dst_img = ImageCreateTrueColor($thumb_w, $thumb_h);
fastImageCopyResampled($dst_img, $src_img, 0, 0, 0, 0, $thumb_w, $thumb_h, $old_x, $old_y, $system);
if (preg_match("/png/", $system[0])) {
if ($actual_type) {
if (($actual_type == 'jpg' || $actual_type == 'webp') && !imagejpeg($dst_img, $filename, 70)) {
exitWithErrorPage('unable to imagejpg.');
return false;
} else if ($actual_type == 'png' && !imagepng($dst_img,$filename,0,PNG_ALL_FILTERS)) {
exitWithErrorPage('unable to imagepng.');
return false;
} else if ($actual_type == 'gif' && !imagegif($dst_img, $filename)) {
exitWithErrorPage('unable to imagegif.');
return false;
}
} else if (preg_match("/png/", $system[0])) {
if (!imagepng($dst_img,$filename,0,PNG_ALL_FILTERS) ) {
exitWithErrorPage('unable to imagepng.');
return false;
@ -142,6 +156,27 @@ function createThumbnail($name, $filename, $new_w, $new_h) {
return false;
}
// Sometimes the image is of wrong type, particularly thumbnails from Youtube
function imagecreatefromwhatever($fname) {
if ($img = @imagecreatefromjpeg($fname)) {
$type = 'jpg';
return array($img, $type);
}
if ($img = @imagecreatefromwebp($fname)) {
$type = 'webp';
return array($img, $type);
}
if ($img = @imagecreatefrompng($fname)) {
$type = 'png';
return array($img, $type);
}
if ($img = @imagecreatefromgif($fname)) {
$type = 'gif';
return array($img, $type);
}
return array(false, false);
}
/* Author: Tim Eckel - Date: 12/17/04 - Project: FreeRingers.net - Freely distributable. */
/**
* Faster method than only calling imagecopyresampled()
@ -210,94 +245,127 @@ function fetch_video_data($site, $code, $maxwidth, $thumb_tmpfile) {
if (!in_array($site, array('you', 'vim', 'cob', 'scl')))
return array('error' => 'unsupported_site');
$use_youtube_dl = I0_YOUTUBE_DL_PATH !== '' && $site === 'you';
// Pre-setup
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt ($ch, CURLOPT_TIMEOUT, 10);
if (I0_CURL_PROXY)
curl_setopt($ch, CURLOPT_PROXY, I0_CURL_PROXY);
// Getting a URL
switch ($site) {
case 'cob':
$url = "https://coub.com/api/v2/coubs/".$code.".json";
break;
case 'vim':
$url = 'https://vimeo.com/api/v2/video/'.$code.'.json';
break;
case 'you':
$url = 'https://www.googleapis.com/youtube/v3/videos?part=contentDetails%2Csnippet&id='.$code.'&key='.KU_YOUTUBE_APIKEY;
break;
case 'scl':
$url = 'https://soundcloud.com/oembed?url=https%3A%2F%2Fsoundcloud.com%2F' . urlencode($code) . '&format=json';
break;
default:
return array('error' => _gettext('No JSON URL specified.'));
if ($use_youtube_dl) {
putenv('PATH=' . I0_YOUTUBE_DL_PATH . PATH_SEPARATOR . getenv('PATH'));
}
curl_setopt($ch, CURLOPT_URL, $url);
// Fetching data
$result = curl_exec($ch);
switch (curl_getinfo($ch, CURLINFO_HTTP_CODE)) {
case 404: return array('error' => _gettext('Unable to connect to')); break;
case 303: return array('error' => _gettext('Invalid video ID.')); break;
case 302: break;
case 301: break;
case 200: break;
default: return array('error' => _gettext('Invalid response code ').' (JSON)'); break;
else {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt ($ch, CURLOPT_TIMEOUT, 10);
if (I0_CURL_PROXY)
curl_setopt($ch, CURLOPT_PROXY, I0_CURL_PROXY);
}
// Fetching the data
if ($use_youtube_dl) {
exec('youtube-dl --dump-json https://www.youtube.com/watch?v='.$code, $json, $er);
if (!$er) {
$ydl_info = json_decode($json[0]);
}
else {
return array('error' => _gettext('API returned invalid data.'));
}
}
else {
// Getting a URL
switch ($site) {
case 'cob':
$url = "https://coub.com/api/v2/coubs/".$code.".json";
break;
case 'vim':
$url = 'https://vimeo.com/api/v2/video/'.$code.'.json';
break;
case 'you':
$url = 'https://www.googleapis.com/youtube/v3/videos?part=contentDetails%2Csnippet&id='.$code.'&key='.KU_YOUTUBE_APIKEY;
break;
case 'scl':
$url = 'https://soundcloud.com/oembed?url=https%3A%2F%2Fsoundcloud.com%2F' . urlencode($code) . '&format=json';
break;
default:
return array('error' => _gettext('No JSON URL specified.'));
}
curl_setopt($ch, CURLOPT_URL, $url);
// Fetching data
$result = curl_exec($ch);
switch (curl_getinfo($ch, CURLINFO_HTTP_CODE)) {
case 404: return array('error' => _gettext('Unable to connect to')); break;
case 303: return array('error' => _gettext('Invalid video ID.')); break;
case 302: break;
case 301: break;
case 200: break;
default: return array('error' => _gettext('Invalid response code ').' (JSON)'); break;
}
curl_close($ch);
$data = json_decode($result, true);
if ($data == NULL)
return array('error' => _gettext('API returned invalid data.'));
}
curl_close($ch);
$data = json_decode($result, true);
if ($data == NULL)
return array('error' => _gettext('API returned invalid data.'));
// Find needed thumbnail width
switch ($site) {
case 'cob':
$widths_available = array(
if ($use_youtube_dl) {
$options_available = count($ydl_info->thumbnails);
$i = 0;
foreach($ydl_info->thumbnails as &$thumb) {
$i++;
if ($thumb->width >= $maxwidth || $options_available == $i) {
$thumb_url = $thumb->url;
$thumbwidth = $thumb->width;
break;
}
}
}
else {
switch ($site) {
case 'cob':
$widths_available = array(
'micro' => 70,
'tiny' => 112,
'small' => 400,
'med' => 640,
'big' => 1280
);
break;
case 'vim':
$widths_available = array(
);
break;
case 'vim':
$widths_available = array(
'small' => 100,
'medium' => 200,
'large' => 640
);
break;
case 'you':
$widths_available = array(
);
break;
case 'you':
$widths_available = array(
'default' => 120,
'medium' => 320,
'high' => 480,
'standard' => 640,
'maxres' => 1280
);
break;
case 'scl':
$widths_available = array(
);
break;
case 'scl':
$widths_available = array(
'default' => 250
);
break;
default:
return array('error' => _gettext('No thumbnails available.'));
}
$i = 0;
$options_available = count($widths_available);
foreach ($widths_available as $preset => $width) {
$i++;
if ($width >= $maxwidth || $options_available == $i) {
$chosen_preset = $preset;
$thumbwidth = $width;
break;
);
break;
default:
return array('error' => _gettext('No thumbnails available.'));
}
$i = 0;
$options_available = count($widths_available);
foreach ($widths_available as $preset => $width) {
$i++;
if ($width >= $maxwidth || $options_available == $i) {
$chosen_preset = $preset;
$thumbwidth = $width;
break;
}
}
}
// Get thumbnail URL
switch ($site) {
case 'cob':
@ -307,7 +375,9 @@ function fetch_video_data($site, $code, $maxwidth, $thumb_tmpfile) {
$thumb_url = preg_replace('/\.webp/', '.jpg', $data[0]['thumbnail_'.$chosen_preset]);
break;
case 'you':
$thumb_url = $data['items'][0]['snippet']['thumbnails'][$chosen_preset]['url'];
if (!$use_youtube_dl) {
$thumb_url = $data['items'][0]['snippet']['thumbnails'][$chosen_preset]['url'];
}
break;
case 'scl':
$thumb_url = $data['thumbnail_url'];
@ -356,8 +426,14 @@ function fetch_video_data($site, $code, $maxwidth, $thumb_tmpfile) {
case 'you':
$r['width'] = 1920;
$r['height'] = 1080;
$r['title'] = $data['items'][0]['snippet']['title'];
$duration = preg_replace_callback('/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/', 'ISO8601_callback', $data['items'][0]['contentDetails']['duration']);
if ($use_youtube_dl) {
$r['title'] = $ydl_info->title;
$duration = $ydl_info->duration;
}
else {
$r['title'] = $data['items'][0]['snippet']['title'];
$duration = preg_replace_callback('/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/', 'ISO8601_callback', $data['items'][0]['contentDetails']['duration']);
}
break;
case 'scl':
$r['width'] = 500;
@ -371,8 +447,8 @@ function fetch_video_data($site, $code, $maxwidth, $thumb_tmpfile) {
default:
return array('error' => _gettext('API returned invalid data.'));
}
if ($r['width'] <= 0 || $r['height'] <= 0) {
// var_dump($r);
return array('error' => _gettext('API returned invalid data.'));
}
// Convert duration into readable string

View File

@ -64,7 +64,7 @@
// ---------------------------------- Attachment handling -----------------------------------
$cf['KU_FFMPEGPATH'] = '/usr/local/bin/ffmpeg'; //path to FFMPEG, on windows it's usually 'C:\ffmpeg\bin' (REQUIRED for videos)
$cf['KU_YOUTUBE_APIKEY'] = 'your_api_key'; //Your personal anal probe ID. Can be obtained it Google Dev. Console
$cf['I0_YOUTUBE_DL_PATH'] = ''; // Path to youtube-dl binary. If not empty, youtube-dl will be used instead of default API (in this case you won't need KU_YOUTUBE_APIKEY)
// ------------------------------------- Misc settings --------------------------------------
$cf['I0_CURL_PROXY'] = false; // Proxy to use when fetching external resources, for example 'socks5h://127.0.0.1:9050' — to connect through TOR