YouTube Media Converter PHP Script Documentation

Getting Started

What is YouTube Media Converter?

YouTube Media Converter is a very fast, high-quality YouTube to MP3 Converter and Video Downloader.

Minimum Requirements

  • Linux Server (All Linux distributions supported)
  • Works with any hosting plan (Shared*, Dedicated, VPS, etc.)
  • Apache or Nginx
  • PHP 5.3 or later
  • PHP exec() and proc_open() functions enabled
  • PHP GD extension
  • cURL and PHP cURL extension
  • FFmpeg and libmp3lame codec
  • Apache's mod_rewrite (Nginx rewriting instructions)
  • YouTube API Key (free)
  • 50 MB Disk Space on Server

* Note: If you are using a shared hosting plan, please ensure that FFmpeg and cURL are installed.

Features

  • Converts YouTube video to MP3 in milliseconds, at qualities up to 320kbps
  • Leverages the power of FFmpeg to create crisp, clean, quality, video-to-MP3 conversions
  • Downloads YouTube videos directly to MP4, WEBM, MKV, M4A, and 3GP formats
  • Supports the download of HD and Ultra HD video streams (2k and 4k), if available
  • Allows users to download all but MP3 formats directly from YouTube, bypassing your server and saving bandwidth
  • Downloads/Converts encrypted YouTube (e.g., Vevo channel) videos
  • Provides the means to optionally cache "popular" MP3 files, significantly reducing the consumption of server resources (primarily CPU and bandwidth)
  • Enables video preview as well as audio playback (via Integrated Music Player) prior to download/conversion
  • Integrates YouTube Search (accepts search term, video page URL, or playlist URL)
  • Displays Top Videos (filterable by Country)
  • Fully optimized for SEO, featuring dynamic Meta and Open Graph tags, dynamic image shares, automatic generation of robots.txt and XML sitemaps, video search URLs/links, and progressive enhancement to facilitate search bot crawling
  • Includes a JSON RESTful API and Button/Iframe API to facilitate software integration in a variety of use-case scenarios
  • Enables multi-language support via easy-to-add (and easy-to-edit!) translation files
  • Requires very little disk space because downloaded/converted files are not stored on server (when MP3 caching is disabled)!
  • Effortlessly configure a multitude of software options via an easy-to-read Config file
  • Includes a "config check" utility to facilitate the software's installation and help resolve any issues with the server configuration
  • Features a simple, one-click installation of both FFmpeg and cURL (via the included "config check" utility)!
  • Facilitates the addition of more pages via common header, footer, and CSS files
  • Optionally rotates between multiple outgoing IPs to prevent temporary IP bans and/or CAPTCHAs imposed by YouTube
  • Optionally rotates between multiple YouTube API keys to effectively extend API usage limits
  • Automatically caches YouTube API requests to further extend API limits, reduce the number of API keys required, and speed up load time of video charts and search results pages
  • Provides mechanism to block the download/conversion of specific videos at the behest of copyright holders
  • Features a completely "responsive" default design (leveraging the Bootstrap framework) to provide optimal viewing for ALL device types and sizes!
  • Programmed entirely in easy-to-read PHP OOP (Object Oriented Programming), JavaScript/jQuery, and CSS
  • Enables effortless editing/customization of code
  • Leverages MVC coding principles to enable templating and clear separation of presentation and business logic

Server Configuration

When in doubt, have a pro admin or hosting provider install the required dependency packages for you. Alternatively, we can also perform the server setup for an additional cost.

For the "Do-It-Yourselfers", general command-line instructions (for installing ALL required software dependencies) are available for the following, popular Linux distributions:

(Note: These instructions are provided as a convenience and courtesy to you. They are not a substitute for a professional server configuration. Generally, it is not my responsibility to teach you how to install and configure packages on, or administer and maintain, a Linux system.)


Debian 7 (Wheezy) and Debian 8 (Jessie)

Update Sources

apt-get update

Install Apache Webserver and PHP 5

apt-get install apache2 php5

Create your Domain Directory

mkdir /var/www/YOURDOMAIN.COM

Change Domain Directory Owner

chown www-data:www-data /var/www/YOURDOMAIN.COM

Install text editor "nano"

apt-get install nano

Create Apache vHost

nano /etc/apache2/sites-enabled/YOURDOMAIN.COM.conf

Add the following to the file (via nano), then Press Ctrl + O to save the file and Ctrl + X to close the nano editor:

<VirtualHost *:80>
	DocumentRoot "/var/www/YOURDOMAIN.COM"
	ServerName YOURDOMAIN.COM
	ErrorLog ${APACHE_LOG_DIR}/error_YOURDOMAIN.log
<Directory /var/www/YOURDOMAIN.COM> AllowOverride All </Directory> </VirtualHost>

Enable Apache's "mod_rewrite"

a2enmod rewrite
/etc/init.d/apache2 restart

Install GD PHP Extension

apt-get install php5-gd

Install cURL and cURL PHP Extension

apt-get install curl php5-curl

Note: The following steps are optional. The software already has a built-in FFmpeg auto-installer!

Add Debian Multimedia Repo Sources List for FFmpeg and Codecs

nano /etc/apt/sources.list.d/deb-multimedia.org.list

Add the following to the file (via nano):

  • For Debian 7 (Wheezy)
    • # Debian Multimedia Repository 
      deb http://www.deb-multimedia.org wheezy main non-free
      deb http://www.deb-multimedia.org wheezy-backports main
  • For Debian 8 (Jessie)
    • # Debian Multimedia Repository 
      deb http://www.deb-multimedia.org jessie main non-free
      deb http://www.deb-multimedia.org jessie-backports main
  • Press Ctrl + O to save the file
  • Press Ctrl + X to close the nano Editor

Update Sources

apt-get update

Install "deb-multimedia-keyring"

apt-get install deb-multimedia-keyring

Update Sources

apt-get update

Install FFmpeg

apt-get install ffmpeg

Ubuntu 12.04, Ubuntu 14.04, and Ubuntu 16.04

Update Sources

sudo apt-get update

Install Apache Webserver and PHP

  • For Ubuntu 12.04 and 14.04
    • sudo apt-get install apache2 php5
  • For Ubuntu 16.04
    • sudo apt-get install apache2 php7.0

Create your Domain Directory

sudo mkdir /var/www/YOURDOMAIN.COM

Change Domain Directory Owner

sudo chown www-data:www-data /var/www/YOURDOMAIN.COM

Install text editor "nano"

sudo apt-get install nano

Create Apache vHost

sudo nano /etc/apache2/sites-enabled/YOURDOMAIN.COM.conf

Add the following to the file (via nano), then Press Ctrl + O to save the file and Ctrl + X to close the nano editor:

<VirtualHost *:80>
	DocumentRoot "/var/www/YOURDOMAIN.COM"
	ServerName YOURDOMAIN.COM
	ErrorLog ${APACHE_LOG_DIR}/error_YOURDOMAIN.log
<Directory /var/www/YOURDOMAIN.COM> AllowOverride All </Directory> </VirtualHost>

Enable Apache's "mod_rewrite"

sudo a2enmod rewrite
sudo /etc/init.d/apache2 restart

Install GD PHP Extension

  • For Ubuntu 12.04 and 14.04
    • sudo apt-get install php5-gd
  • For Ubuntu 16.04
    • sudo apt-get install php7.0-gd

Install cURL and cURL PHP Extension

  • For Ubuntu 16.04
    • sudo apt-get install curl php7.0-curl
  • For Ubuntu 12.04 and 14.04
    • sudo apt-get install curl php5-curl
  • For Ubuntu 12.04
    • Open '/etc/php5/apache2/php.ini' and add this line

      extension=curl.so
    • Restart Apache

      sudo /etc/init.d/apache2 restart

Note: The following steps are optional. The software already has a built-in FFmpeg auto-installer!

Install FFmpeg

  • For Ubuntu 12.04 and 16.04
    • sudo apt-get install ffmpeg
  • For Ubuntu 14.04
    • Add FFmpeg Repo

      sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next
    • Update Sources

      sudo apt-get update
    • Install FFmpeg

      sudo apt-get install ffmpeg

CentOS 6.x and CentOS 7.x

Install Apache

yum install httpd

Install wget & gcc

yum install wget gcc

Install epel repo

  • For CentOS 6.x
    • wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm 
      rpm -Uvh epel-release-6-8.noarch.rpm
  • For CentOS 7.x
    • wget http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-11.noarch.rpm 
      rpm -Uvh epel-release-7-11.noarch.rpm

Install PHP and the cURL and GD PHP extensions

yum install php php-devel php-gd php-common

Enable mod_rewrite

nano /etc/httpd/conf.modules.d/00-base.conf
  • Add or uncomment the following line:
    • LoadModule rewrite_module modules/mod_rewrite.so

Create Apache vHost

nano /etc/httpd/sites-available/YOURDOMAIN.COM.conf

Add the following to the file (via nano), then Press Ctrl + O to save the file and Ctrl + X to close the nano editor:

<VirtualHost *:80>
	DocumentRoot "/var/www/YOURDOMAIN.COM"
	ServerName YOURDOMAIN.COM
	ErrorLog ${APACHE_LOG_DIR}/error_YOURDOMAIN.log
<Directory /var/www/YOURDOMAIN.COM> AllowOverride All </Directory> </VirtualHost>

Restart Apache

/etc/init.d/httpd restart

Note: The following steps are optional. The software already has a built-in FFmpeg auto-installer!

Install FFmpeg

  • Download a precompiled version of FFmpeg
    • If you want a precompiled version of FFmpeg + codecs for your CentOS server, then you can download a recent static build of FFmpeg here.
    • Use the x86_64 build for 64-bit servers and the x86 build for 32-bit servers.
    • Decompress the corresponding tar.xz distribution, and locate the 'ffmpeg' binary file.
    • To install this build, simply upload the 'ffmpeg' binary file to your "/usr/bin" directory and change permissions of the file to chmod 0755 or higher. And, presto, you have a fully-functioning CentOS build of FFmpeg + codecs, compatibile with my software, that you did not have to compile yourself!
  • OR, Compile FFmpeg from source
    • Get the dependencies

      yum install autoconf automake gcc-c++ libtool make nasm pkgconfig zlib-devel git
    • Make a directory in “/root/” to put all of the source code into:

      cd /root 
      mkdir ~/ffmpeg_sources
    • Build/Install FFmpeg and codecs as follows

      • Yasm

        cd ~/ffmpeg_sources 
        curl -O http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz
        tar xzvf yasm-1.2.0.tar.gz
        cd yasm-1.2.0
        ./configure --prefix="$HOME/ffmpeg_build" --bindir="$HOME/bin"
        make
        make install
        make distclean
        export "PATH=$PATH:$HOME/bin"
      • libmp3lame

        MP3 audio encoder.
        Requires FFmpeg to be configured with --enable-libmp3lame

        cd ~/ffmpeg_sources 
        curl -L -O http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz
        tar xzvf lame-3.99.5.tar.gz
        cd lame-3.99.5
        ./configure --prefix="$HOME/ffmpeg_build" --bindir="$HOME/bin" --disable-shared --enable-nasm
        make
        make install
        make distclean
      • FFmpeg

        cd ~/ffmpeg_sources 
        git clone --depth 1 git://source.ffmpeg.org/ffmpeg
        cd ffmpeg
        PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig"
        export PKG_CONFIG_PATH
        ./configure --prefix="$HOME/ffmpeg_build" --extra-cflags="-I$HOME/ffmpeg_build/include" --extra-ldflags="-L$HOME/ffmpeg_build/lib" --bindir="$HOME/bin" --extra-libs=-ldl --enable-gpl --enable-nonfree --enable-libmp3lame
        make
        make install
        make distclean
        hash -r
        . ~/.bash_profile
      • After all of this, FFmpeg will be compiled into "/root/bin/ffmpeg".

      • Move the FFmpeg binary file from “/root/bin/ffmpeg” to “/usr/bin/ffmpeg”. Then set permissions of “/usr/bin/ffmpeg” to chmod 0777.

        mv /root/bin/ffmpeg /usr/bin/ffmpeg
        chmod 0777 /usr/bin/ffmpeg

Software Installation

Get YouTube API Key

1. Navigate to the Google Developers Console and click "Create Project".

2. Enter a Project Name and click the "Create" button.

3. Click on the "YouTube Data API" link.

4. Click the "Enable" button.

5. Click the "Go to Credentials" button.

6. Select "Web server" from the "Where will you be calling the API from?" menu, select "Public data" for "What data will you be accessing?", and then click the "What credentials do I need?" button.

7. Copy and save your API key to a safe place, and then click the "Restrict key" link.

8. For "Key restriction", choose "None", and then click the Save button. (Note: It may take up to 5 minutes for the API key settings to take effect. So, please wait at least 5 minutes before running the software's "config check" utility, to ensure that the "YouTube API Keys" test passes!)


Using Multiple API Keys

You may use one or more YouTube API keys with this software. The use of multiple keys enables you to effectively extend the daily API quota/limit and is recommended for sites with moderate-to-heavy traffic. In fact, as a general precaution, we recommend that you have 1 key for every 1,000 daily website visitors.

A new, separate Google account should be created for each new API key that you use with this software. For each Google account, please follow the provided instructions for generating a YouTube API key.

Your API key(s) must be inserted into the $_youtubeApiKeys array in "lib/Config.php". If you supply multiple keys, then one key is randomly selected from this array per request.


Configure Settings

Unpack/Unzip the distribution file, open "lib/Config.php", and edit:


Required Settings

Set the FFmpeg path

// FFmpeg Server Path - usually "/usr/bin/ffmpeg" or "/usr/local/bin/ffmpeg"
const _FFMPEG_PATH = "/usr/bin/ffmpeg";

Set the cURL path

// cURL Server Path
const _CURL_PATH = "/usr/bin/curl";

Set your YouTube API Key or Keys

// YouTube API Keys (Get API Keys from https://console.developers.google.com and/or review '/docs/#youtubeAPI' and '/docs/#youtubeAPIMultiple').
// You may have one or more API keys. If you have multiple keys, then one is randomly selected from the array per request.
// The use of multiple keys enables you to effectively extend the daily API quota/limit and is recommended for sites with moderate-to-heavy traffic.
public static $_youtubeApiKeys = array(
	"123abc456dfg789HiJkL0",
	"0LkJiH987gfd654cba321"
);

Set the App Root directory

// The root directory and location of the application, relative to the web root.
const _APPROOT = '/'; // Directory names must be preceded and followed by a '/'. A value of '/' indicates the web root directory.

Advanced Settings

Website Name (appears in navbar)

// Website Name (appears in navbar)
const _WEBSITE_NAME = "MyConverterSite";

Website Domain (appears in footer and downloaded/converted file name branding)

// Website Domain (appears in footer and downloaded/converted file name branding)
const _WEBSITE_DOMAIN = "MyConverterSite.com";

Default "Country Group", e.g., "Americas", "Europe", or Add Your Own (Required for Charts feature!)

// Default "Country Group"
// Value can be a continent name or any name that you choose to categorize a group of countries in the Config::$_countries array.
// The default available values are "Africa", "Asia", "Americas", "Europe", and "Oceania".
const _DEFAULT_COUNTRY_GROUP = "Americas";

Default Country (Must be within the Default "Country Group"!)

// Default Country
// Must be a valid, lowercase, ISO 3166-1 alpha-2 country code
// Scroll down to $_countries array to see default list of available countries.
const _DEFAULT_COUNTRY = "us";

Default Language (Must be included in "app/Languages/index.php"!)

// Default Website Language
const _DEFAULT_LANGUAGE = "en"; // You MUST choose from available languages in "app/Languages/index.php"

Social Network settings

const ENABLE_FACEBOOK_LIKE_BOX = true; // Enable or disable Facebook Like Box in Sidebar

Facebook Page URL Name (e.g., https://facebook.com/facebook)

const FACEBOOK_PAGE_NAME = "facebook";  // E.g., https://facebook.com/{Facebook page name}

Active Site Template ("default" and "xeon" templates available)

// Template Folder Name
const _TEMPLATE_NAME = "default"; // "default" and "xeon" templates available

Video Results per Page (number of initial results and results returned by "Load more videos" button)

// Number of additional video results returned when the "Load more videos" button is clicked
// Maximum number is 50 !!
const _RESULTS_PER_PAGE = 5;

Enable YouTube Direct download (download directly from YouTube servers)

// Enable YouTube Direct download (true = enabled, false = disabled)
const _YOUTUBE_DIRECT_DOWNLOAD = true;

Set Website Interface and Access Control (e.g., if you only need API interface)

// Access Control and Interface for website
// This constant accepts 3 possible values: "web", "api", or "hybrid".
// 1) When set to "web", the default front-end website interface displays. If either or both APIs are "publicly" enabled (see Config::$_apiAllowedDomains, below), then an additional "API" instructions page is visible in site menu links.
// 2) When set to "api", access to front-end website interface is disabled completely, and only direct API access is allowed.
// 3) When set to "hybrid", and either or both APIs are "publicly" enabled (see Config::$_apiAllowedDomains, below), then the default front-end website interface is replaced with an alternate interface that consists of only API, FAQ, and Contact pages. (The "API" instructions page serves as the homepage.) If neither API is "publicly" enabled, then the "hybrid" value behaves the same as "web"!
// See Config::$_apiAllowedDomains, below, to regulate and whitelist API access
const _WEBSITE_INTERFACE = 'web';

Enable/Disable JSON and/or Button/Iframe APIs

// List of domains and/or IP addresses, separated by commas, that are allowed access to the JSON and Button APIs.
// In general, for both APIs, add IP address for PHP consumption and domain for AJAX/HTML consumption.
// If a domain/IP needs access to both APIs, then it must be included in BOTH the 'json' AND 'button' subarrays!
// If the 'json' or 'button' subarray is empty, then this enables unrestricted, public access to the corresponding API.
// Do NOT prepend domains/IPs with 'http://' or 'https://'!!
// Do NOT prepend domains with 'www' or any other subdomain!!
public static $_apiAllowedDomains = array(
	'json' => array(
		// These are examples. Replace as needed.
		'localhost',
		'mysite.com',
		'123.45.6.789',
		'anothersite.com',
		'187.65.4.321'
	),
	'button' => array(
		// These are examples. Replace as needed.
		'localhost',
		'mysite.com',
		'123.45.6.789',
		'anothersite.com',
		'187.65.4.321'
	)
);

Configure MP3 File Caching

// MP3 Caching Constants
const _CACHE_FILES = false;  // When true, IF a given MP3 file has been converted before AND it is still stored on the server, then the file is delivered directly from the server rather than being downloaded/converted again. This establishes a MP3 file cache on your server, which can significantly save server resources (i.e., bandwidth used for downloading and CPU used for FFmpeg conversions). Note: Only MP3 files are cached at this time because only MP3 downloads require FFmpeg.
const _CACHE_AFTER_X = 2;  // The number of times (greater than zero!!) that a video can be converted to any quality MP3 before it is eventually saved to the cache. (DO NOT set this value to zero!!) E.g., a value of 5 saves an MP3 in the cache after 5 downloads of the same video. This setting ensures that only "more popular" files are cached, which subsequently ensures more efficient use of available cache space (and a generally more effective cache).
const _MAX_ALLOWED_DURATION_DIFFERENCE = 2;  // Value, measured in seconds, used to determine and delete incomplete files in your cache (when caching is enabled). I.e., YouTube's reported video duration is compared to the duration of the cached file on your server. If the difference in durations is more than _MAX_ALLOWED_DURATION_DIFFERENCE seconds, then the corresponding cached file is 1) deemed "incomplete" and 2) deleted from your server.
const _MAX_CACHE_SIZE = 100000000;  // The maximum size, in KB, that the cache folder size can become before the oldest cached files are deleted (via "inc/schedule.php" cron job). Note: Because file deletions are performed as a regularly scheduled task on the server, the actual size of the cache folder may exceed this value between scheduled tasks. So, it is IMPORTANT that this value is set to significantly lower than the actual space available for the cache folder on the hard drive! You can further mitigate this issue by increasing the _CACHE_SIZE_BUFFER constant value, running the scheduled task more often, and/or ensuring that you always have plenty of unused, available hard disk space.
const _CACHE_SIZE_BUFFER = 1000000;  // If the cache folder size is greater than _MAX_CACHE_SIZE, then the oldest files in the cache are deleted one at a time (via "inc/schedule.php" cron job) until the cache size is less than _MAX_CACHE_SIZE minus this value, in KB.

Now upload all files to your web server

Follow the prompts in the "config check" utility, to help resolve any remaining issues with the server or software configuration.

Don't forget to set "store" folder permissions to chmod 0777!


FAQ

I opened index.php and see a blank page. What should I do?
  • Enable debug mode in "lib/Config.php", like so:
  • // Debug Mode shows errors
    const _DEBUG_MODE = true;
  • This will enable the output of PHP errors to the browser.
  • Also, check your Apache error log for PHP errors and warnings.
  • If you see a PHP error or warning that you don't understand, please copy and paste the error into Google and behold the plethora of other people who have experienced -- and overcome -- similar errors. Leverage Google to your advantage in this case, and benefit from the experiences of others who have had the same problem.
I opened index.php, but I see no YouTube video results in the page body. What should I do?
  • Ensure that you have generated a valid YouTube API key or keys and that you have configured the corresponding software setting correctly.
  • Ensure that "url rewriting" is enabled on your web server and that your rewrite rules correspond to your specific web server software (e.g., Apache or Nginx).
  • Finally, ensure that the PHP "allow_url_fopen" directive is set to "On" or "1".
  • On cPanel servers (or servers that support a custom php.ini file), you can create a new file and add the following content:
  • allow_url_fopen = On
  • ...then save this file as "php.ini" and upload it to your web root directory.
I opened index.php and see something like: "Parse error: syntax error, unexpected T_FUNCTION in /var/www/html/index.php on line...". What should I do?
  • This is generally an indication that you do not have at least PHP 5.3 installed. Anonymous functions usually cause this error, and they were not introduced until PHP 5.3. You need to install PHP 5.3+ to eliminate this error.
When I run the "config check" utility prior to software installation, I see the error "DNS is OK?: No". What is wrong with my DNS? What should I do?
  • An improperly configured DNS can cause HTTP requests (made from your server to your server's domain) to fail. To test this possibility, save the following code to a file, and then load the file in a web browser:
  • <?php
    
    // create a new cURL resource
    $ch = curl_init();
    
    // set URL and other appropriate options
    curl_setopt($ch, CURLOPT_URL, "http://www.your-domain-here.com");
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    
    // grab URL and pass it to the browser
    curl_exec($ch);
    
    // print out any cURL errors as well as HTTP response information
    echo 'Curl error: (' . curl_errno($ch) . ') ' . curl_error($ch) . '<br>';
    print_r(curl_getinfo($ch));
    
    // close cURL resource, and free up system resources
    curl_close($ch);
    
    ?>
    		
  • Now repeat the process, substituting "http://www.your-domain-here.com" with "http://www.google.com" (or any other domain name other than your site's domain name!) this time.
  • If the above code consistently fails for any reason, in any way, when CURLOPT_URL is set to "http://www.your-domain-here.com", but consistently works when CURLOPT_URL is set to "http://www.google.com" (or any other domain name other than your site's domain name!), then you likely have an issue with your DNS. Evidently, HTTP requests made from your server are able to correctly resolve the DNS of all sites except your own -- indicating an issue with your own DNS configuration. Possible fixes include using another DNS provider, changing nameservers, and/or having a professional configure your DNS for you.
When I click the MP3 and/or MP4 buttons for a given video, I get an error message and the download links don't appear. Why is this?
  • Verify that software.xml exists in the "store" directory, and that the file is chmod to 0777 permissions. Also, ensure that "store" directory permissions allow programmatic modification of software.xml. If software.xml exists, try deleting the file and allowing it to automatically regenerate.
  • Try executing a simple PHP cURL request to the corresponding video page URL, and return the contents of the page to the screen. For example, place the following code in a new file, replacing the "vidID" URL query string parameter value with a valid YouTube video ID:
  • <?php
    
    // create a new cURL resource
    $ch = curl_init();
    
    // set URL and other appropriate options
    curl_setopt($ch, CURLOPT_URL, "http://www.youtube.com/watch?v=vidID");
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    
    // grab URL and pass it to the browser
    curl_exec($ch);
    
    // print out any cURL errors as well as HTTP response information
    echo 'Curl error: (' . curl_errno($ch) . ') ' . curl_error($ch) . '<br>';
    print_r(curl_getinfo($ch));
    
    // close cURL resource, and free up system resources
    curl_close($ch);
    
    ?>
    		
  • (Note: You can retrieve the video page URL and corresponding ID for any given video by clicking the "Preview Video" button underneath the video thumbnail image!)
  • Save the file, upload it to your server, and open it in a browser. Do you see the HTML page located at that URL? If the video is blocked in your server's country, then this will be indicated in the screen's output. A blank page or CAPTCHA screen could indicate that your IP has either been temporarily banned or flagged (via the CAPTCHA) for exceeding video pull quota limits. It could also mean that your server is having networking issues.
When I click a MP3 or Video download link, 1) nothing happens, 2) the page reloads and nothing happens, 3) a bunch of strange characters are printed to the screen, or 4) I see an error message. What should I do?
  • First, check that the _FFMPEG_PATH and _CURL_PATH constant values in "lib/Config.php" point to the correct locations of the corresponding binary files on your server. On Linux, you can locate FFmpeg and cURL via the command line interface as follows, e.g.:
  • root@server:~# type ffmpeg
    ffmpeg is /usr/bin/ffmpeg
  • root@server:~# which ffmpeg
    /usr/bin/ffmpeg
  • root@server:~# type curl
    curl is /usr/bin/curl
  • root@server:~# which curl
    /usr/bin/curl
  • Does FFmpeg work from the command console? Try running a FFmpeg command directly in the command line interface. Preferably, run a command that is executed by my software during conversions.
  • Are you running the most recent version of FFmpeg? (Check your version of FFmpeg by typing "ffmpeg" in the command console. If the dates shown in the resulting output are more than 1-2 years old, then you may have an outdated version of FFmpeg.) Also, the software may not work as expected with FFmpeg builds downloaded from the apt-get repository on Debian and Ubuntu. Instead, for these Linux distributions, try downloading a recent, static build of FFmpeg. To install the static build, simply upload the downloaded FFmpeg binary file to your "/usr/bin" directory.
  • You may need to set permissions of the FFmpeg binary to chmod 0777, or lower -- if possible, so that my software has permission to access FFmpeg. This especially holds true for people using a static build of FFmpeg.
  • If Debug Mode is enabled in the software, then try disabling it in "lib/Config.php":
  • // Debug Mode shows errors
    const _DEBUG_MODE = false;
  • Debug Mode prints PHP errors to the screen, and, if you have any such errors during a file's download, then the error message output will conflict with the subsequent downloaded file headers.
  • If you are using CloudFlare SSL and you have created a "Page Rule" that forwards all http:// requests to https://, then you must disable or delete this Page Rule. Instead, you can enable automatic forwarding to https:// via the provided .htaccess file:
  •     #Uncomment the following lines as instructed to redirect all http:// requests to https://
        #If using Cloudflare SSL, uncomment this line
        	#RewriteCond %{HTTP:CF-Visitor} {"scheme":"http"}
        #If NOT using Cloudflare SSL, uncomment this line
        	#RewriteCond %{HTTPS} off
        #Always uncomment these lines
        	#RewriteCond %{REQUEST_URI} !(.mp3|.m4a|.mp4|.webm|.flv|.3gp)$
        	#RewriteCond %{QUERY_STRING} !(.mp3|.m4a|.mp4|.webm|.flv|.3gp)$
        	#RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
        			
  • Also ensure that:
  • On cPanel servers (or servers that support a custom php.ini file), you can create a new file and add the following content:
  • output_buffering = On
    memory_limit = 128M
  • ...then save this file as "php.ini" and upload it to your web root directory.
How and where do I edit the default template and design?
  • This software employs many principles of the MVC paradigm, so all "presentation logic" is located in the "/app/Templates/default" and "/app/Views" directories.
  • In terms of customization, most of your efforts should focus on editing the "default" template in the "/app/Templates/default" directory. Here you will find common header and footer files as well as all CSS, JavaScript, images, and other related dependencies. You can create an entirely different look for the software by editing only the files in this directory and its subdirectories.
  • If you want to create your own, brand-new template, then you can copy the "/app/Templates/default" folder to a new folder named, e.g., "/app/Templates/mytemplate". Then you must change the following constant value in "/lib/Config.php" to (per the example):
  • // Template Folder Name
    const _TEMPLATE_NAME = "mytemplate";
  • Additional presentation-related code is located in the "/app/Views" directory and its subdirectories. But take care when editing code here because some of this code is vital for the display of crucial software functionality.
  • Subdirectories of "/app/Views" that are worth noting:
    1. "/app/Views/pages":
      • Files in this folder effectively embody new "pages" in the software. Pages can either be served synchronously or asynchronously (via AJAX), but they are all pages nonetheless. Each page file corresponds to a function (of the same name) in the "/app/Controllers/PagesController.php" file, and these functions perform "pre-presentation" logic before passing resulting PHP variable values to the pages.
      • For example, the faq() function in "/app/Controllers/PagesController.php":
      • function faq()
        {
        	$this->SetVars(array('uppercase' => true));
        	return $this->render(dirname(__DIR__) . "/" . self::_VIEWS_PATH . "/" . self::_PAGES_DIR, __FUNCTION__, TEMPLATE_NAME);
        }						
      • ...creates an $uppercase PHP variable (with boolean value 'true') that can be used anywhere in "/app/Views/pages/faq.php". And "return $this->render()" is what renders and ultimately displays the "faq.php" page.
      • To add a new page to the software, you can add a similar, new function to "/app/Controllers/PagesController.php" and then create a corresponding page file (with the same name!) in "/app/Views/pages".
    2. "/app/Views/elements":
      • "Elements" are small chunks of (often reusable) markup (or presentation code) that can be inserted inside page files in "/app/Views/pages" and inside template header/footer files (e.g., in "/app/Templates/default").
      • For example, the default template consumes a "navbar_links" element in "/app/Templates/default/header.php" like so:
      • <?php echo $this->element('navbar_links'); ?>
      • This code automatically includes and renders the file "/app/Views/elements/navbar_links.php" inside "header.php".
      • To add a new element to the software, create a new file in "/app/Views/elements", insert your custom markup/code, and then render it inside a page or header/footer file via "echo $this->element('element_name')". (Ensure that 'element_name', per the preceding example, is the same name as the new, corresponding file in "/app/Views/elements"!)
Are downloaded/converted files saved on the server?
  • No! You need very little hard disk space because nothing is stored on the server. A mere 50 MB (minimum) of disk space is required.
I think YouTube is blocking or banning my IP address, and/or I am experiencing a CAPTCHA page when trying to connect to a YouTube video page. What can I do?
  • First of all, bans are usually temporary. In my experience, YouTube only blocks/bans your IP for a finite period of time. The amount of time will vary -- generally, anywhere from a few minutes to a few days.
  • If you are frequently getting blocked by YouTube, OR you are experiencing a CAPTCHA page, then you can rotate between multiple outgoing IPs for HTTP requests made to YouTube's servers. My software facilitates this process for you.
  • First, you need to purchase some additional IP (IPv4) addresses from your hosting provider. (Often your hosting provider will include additional IPs for free with your hosting plan!) Extra IP addresses generally only cost a couple of dollars apiece, and it's reasonable to "start" with 4-5 IPs for the purpose of IP rotation. You can always buy more IPs later and add them to the rotation as needed. That said, the more IPs you have, the better off you will be. In general, the number of additional IPs required for your site is directly proportional to the amount of traffic to your site.
  • (Note: Do NOT use "proxy" IPs purchased from a dedicated, 3rd-party proxy provider! The intent of IP rotation is not to hide or obscure your server's identity, but merely to change the outgoing IP address seen by YouTube. Also, dedicated proxy IPs are much slower than IPs used as outgoing network interfaces, so you will see a marked decrease in speed and performance if you use proxies.)
  • Next, you need to configure these additional IP addresses so that they can be used as "outgoing network interfaces". Simply put, your server needs to be configured so that it can "bind" to these extra IPs for HTTP requests. The easiest way to accomplish this is to have your hosting provider do this for you. If you must do this yourself, then you can refer to OVH's guide for setting up "Network IP Aliasing" for a number of different Linux distributions (and Windows): https://docs.ovh.com/ca/en/dedicated/network-ipaliasing/.
  • Once your additional IPs are set up, then you can configure the corresponding constant values in "lib/Config.php" in preparation for IP rotation. This file is well-documented, and all constants related to IP rotation and the database are throroughly explained in the associated comment sections.
  • Finally, you must use the SQL provided in "docs/ips.sql" to create the required database table that will hold your IPs. Ensure that you replace the IPs in the SQL INSERT command with your own IP addresses "before" executing the SQL! Additional IP addresses can be added to the INSERT command by copying the format and adding lines to the command. In the future, whenever you want to add another IP address to the rotation, then you simply add the new IP or IPs to this database table.
  • If you find that, with IP rotation enabled, you are still experiencing IP bans and/or CAPTCHAs, then that is generally a sign that you need to add more IP addresses to the rotation (to the corresponding database table). You must keep adding IPs until YouTube downloads/conversions start working normally.
  • If you suspect that there is a problem with the IPs themselves, or the IP configuration on your server, then you should first test each additional IP using the following, simple PHP cURL code:
  • <?php
    	// create a new cURL resource
    	$ch = curl_init();
    
    	// set URL and other appropriate options
    	curl_setopt($ch, CURLOPT_URL, "http://www.youtube.com/watch?v=vidID");
    	curl_setopt($ch, CURLOPT_HEADER, 0);
    	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    	curl_setopt($ch, CURLOPT_REFERER, '');
    	curl_setopt($ch, CURLOPT_INTERFACE, '23.232.234.2');  // Your extra IP goes here!
    	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    	curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
    	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    
    	// grab URL and pass it to the browser
    	curl_exec($ch);
    
    	// print out any cURL errors as well as HTTP response information
    	echo 'Curl error: (' . curl_errno($ch) . ') ' . curl_error($ch) . '<br>';
    	print_r(curl_getinfo($ch));
    
    	// close cURL resource, and free up system resources
    	curl_close($ch);
    ?>
    		
  • Ensure that you change the CURLOPT_INTERFACE value to your IP address. Then save the code to a .php file and run it on your server. If you see a video but it won't play, you don't see a video, or you get a cURL error and/or curious HTTP response, then there is something wrong with the IP or its configuration as an outgoing network interface on your server.
  • To address this issue, on some servers, you can try commenting out this line of code, like so:
  • //curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);  
  • If all else fails, you can try completely disabling IPv6 on your server. Please consult with your hosting company or server admin to do this.
I think a video or group of videos is blocked in my server's country. What can I do?
  • All countries have some blocked videos. All of them. The only way that you could "unblock" all of these videos is to leverage a global proxy network like Tor. In fact, Tor is the only global proxy network that I am aware of at this time, and it is notoriously known for its slow connection speeds.
  • A more practical approach is to unblock as many videos as you can without spending a lot of extra money, making a lot of extra work for youself, and generally inducing massive, debilitating headaches.
  • The easiest way to avoid blocked videos is to choose a web server in a country that, generally, has few blocked videos. In my experience, the USA, Canada, and France have the least number of blocked videos. You would do yourself a favor to choose a datacenter located in one of these countries.
  • Another way to thwart blocked videos is to use dedicated proxy IPs in your HTTP and download requests. In this case, you can buy one or more proxy IPs from a dedicated, 3rd-party proxy service like InstantProxies. Again, perferably, the proxies should be located in the USA, Canada, or France. Integrate proxy IPs into your PHP cURL requests like so, i.e.:
  • curl_setopt($ch, CURLOPT_PROXY, '208.67.222.222');
    curl_setopt($ch, CURLOPT_USERAGENT, '');
    curl_setopt($ch, CURLOPT_REFERER, '');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    		
  • When using proxies, you should test for a blocked video first by scraping the content of the video (or video info) page and checking for text that indicates the video is blocked. If the test indicates that a given video is in fact blocked, then you should use a proxy IP. If not, then don't use a proxy IP. The goal is to only use proxy IPs when you need to because, like Tor, using proxies will always be slower than not using proxies.
  • When choosing proxies, ideally you'll want to do the following:
    1. Choose proxies that are geographically very near to your web server. Ideally, the proxy server would be sitting right next to the web server in the same data center.
    2. You are the only person using the proxy server, and you are not using it for anything more than proxy requests.
    3. Your proxy server is not a virtual server running on a physical server that is hosting other virtual proxy instances (that you don't operate).
    4. Spread out your requests to multiple, numerous proxies instead of only having a couple of proxies, for example.
    5. The proxy server(s) should be running with modest CPU load averages and comparable network bandwidth and connection speeds (to your web server).
  • Do NOT use free proxy IPs. You are sharing those proxies with the rest of the world, and they get banned quickly by popular sites (like YouTube).
  • I have not yet implemented proxy integration with my software. That said, it is on my "To-Do" list, among other things!
How can I convert the URL rewriting rules in the included .htaccess file to Nginx rewriting rules?
  • Place the following rewrite rules and code in the respective Nginx vhost file (in "/etc/nginx/sites-available"):
  • server {
    listen 80;
    listen [::]:80;
    
    server_name example.com;
    
    root /var/www/example.com;
    index index.html index.php;
    
    # If NOT using Cloudflare SSL or HTTP Proxy (e.g., OVH Load Balancer), uncomment this line to force SSL (Valid SSL Cert required e.g. Lets Encrypt)
    # return 301 https://$server_name$request_uri;
    
    location / {
    	try_files $uri $uri/ =404;
    
    	# If NOT using Cloudflare SSL and using HTTP Proxy (e.g., OVH Load Balancer), uncomment this line
    	#if ($http_x_forwarded_proto !~ "https"){
    	#	set $rule_0 1$rule_0;
    	#}
    
    	# If using Cloudflare SSL, uncomment this line
    	#if ($http_cf_visitor ~ '{"scheme":"http"}'){
    	#	set $rule_0 1$rule_0;
    	#}
    
    	if ($uri ~ "(.*[^\.][^m][^p][^3])$"){
    		set $rule_0 2$rule_0;
    	}
    	if ($rule_0 = "21"){
    		return 301 https://$server_name$request_uri;
    	}
    	if ($http_cf_visitor ~ '{"scheme":"https"}'){
    		set $rule_1 1$rule_1;
    	}
    	if ($uri ~ "(\.mp3)$"){
    		set $rule_1 2$rule_1;
    	}
    	if ($rule_1 = "21"){
    		return 301 http://$server_name$request_uri;
    	}
    	# END Cloudflare Configuration
    
    	if (!-d $request_filename){
    		set $rule_2 1$rule_2;
    	}
    	if (!-f $request_filename){
    		set $rule_2 2$rule_2;
    	}
    	if ($rule_2 = "21"){
    		rewrite ^/(robots\.txt)$ /store/$1 last;
    	}
    	if (!-d $request_filename){
    		set $rule_3 1$rule_3;
    	}
    	if (!-f $request_filename){
    		set $rule_3 2$rule_3;
    	}
    	if ($rule_3 = "21"){
    		rewrite /(test-url-rewriting)$ /inc/version.php last;
    	}
    	if (!-d $request_filename){
    		set $rule_4 1$rule_4;
    	}
    	if (!-f $request_filename){
    		set $rule_4 2$rule_4;
    	}
    	if ($rule_4 = "21"){
    		rewrite ^/(.*)$ /index.php?req=$1&$args last;
    	}
    }
    
    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
    #	include snippets/fastcgi-php.conf;
    #
    #	# With php5-cgi alone:
    #	fastcgi_pass 127.0.0.1:9000;
    #	# With php5-fpm:
    #	fastcgi_pass unix:/var/run/php5-fpm.sock;
    
    	try_files $uri =404;
    	fastcgi_pass unix:/var/run/php5-fpm.sock;
    	fastcgi_index index.php;
    	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    	include fastcgi_params;
    }
    }
    
    server {
    # SSL configuration
    #
    	listen 443 ssl default_server;
    	listen [::]:443 ssl default_server;
    #
    # Self signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    include snippets/snakeoil.conf;
    
    server_name example.com;
    
    root /var/www/example.com;
    index index.html index.php;
    
    location / {
    	try_files $uri $uri/ =404;
    
    	if (!-d $request_filename){
    		set $rule_0 1$rule_0;
    	}
    	if (!-f $request_filename){
    		set $rule_0 2$rule_0;
    	}
    	if ($rule_0 = "21"){
    		rewrite ^/(robots.txt)$ /store/$1 last;
    	}
    	if (!-d $request_filename){
    		set $rule_1 1$rule_1;
    	}
    	if (!-f $request_filename){
    		set $rule_1 2$rule_1;
    	}
    	if ($rule_1 = "21"){
    		rewrite /(test-url-rewriting)$ /inc/version.php last;
    	}
    	if (!-d $request_filename){
    		set $rule_2 1$rule_2;
    	}
    	if (!-f $request_filename){
    		set $rule_2 2$rule_2;
    	}
    	if ($rule_2 = "21"){
    		rewrite ^/(.*)$ /index.php?req=$1&$args last;
    	}
    }
    
    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
    #	include snippets/fastcgi-php.conf;
    #
    #	# With php5-cgi alone:
    #	fastcgi_pass 127.0.0.1:9000;
    #	# With php5-fpm:
    #	fastcgi_pass unix:/var/run/php5-fpm.sock;
    
    	try_files $uri =404;
    	fastcgi_pass unix:/var/run/php5-fpm.sock;
    	fastcgi_index index.php;
    	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    	include fastcgi_params;
    }
    }
    		
How do I add/edit language translations?
  • There are 2 primary components of the software's language translation engine:
    1. "app/Languages/index.php":
      • This file lists all available languages in a PHP array. Each array key is the corresponding ISO 639-1 language code, and each array value is another array containing additional information about the language.
    2. "app/Languages/{language code}.php":
      • These files are named using the corresponding ISO 639-1 language code (e.g., "en.php" or "de.php"). Each file contains a PHP array of translations for a given language. Array keys are used to display translations in other parts of the software (e.g., $translations['website_title'] will return the 'website_title' translation).
  • To add a new language: Add the language to "app/Languages/index.php" (via a new array element), open "app/Languages/en.php" and replace all translations with the new language's translations, and then save the file as {language code}.php. For example, to add the French language:
    • "app/Languages/index.php"
    • return array(
          'en' => array(
              'language' => 'English(US)',
              'country_code' => 'us',
              'lang_code' => 'en',
              'country_name' => 'United States',
              'direction' => 'ltr'
          ),
          'de' => array(
              'language' => 'Deutsch',
              'country_code' => 'de',
              'lang_code' => 'de',
              'country_name' => 'Deutschland',
              'direction' => 'ltr'
          ),
          'fr' => array(
              'language' => 'Français',
              'country_code' => 'fr',
              'lang_code' => 'fr',
              'country_name' => 'France',
              'direction' => 'ltr'
          )
      );
      				
    • "app/Languages/fr.php"
    • return array(
          // Meta Data - (app/Views/helpers)
          'website_title' => 'french translation',
          'website_description' => 'french translation',
          'website_keywords' => 'french translation',
          'search_description' => 'french translation',
      
          // Navbar - (app/Views/elements)
          'navbar_home' => 'french translation',
          'navbar_faq' => 'french translation',
          'navbar_contact' => 'french translation',
      
          // More Translations, etc., here
      );
      				
  • To edit a language: Open "app/Languages/{language code}.php" and add and/or modify translations as needed.
  • To remove a language: Open "app/Languages/index.php" and remove the array element that corresponds to a given language.
  • (Note: Languages that read right-to-left are not yet supported.)
How do I enable the JSON REST API and/or the Button/Iframe API?
  • The software comes with 2 ready-to-consume APIs: A JSON RESTful API and a Button/Iframe API.
  • The APIs are effectively disabled by default (and only accessible to 'localhost'). To enable either API, you must edit the $_apiAllowedDomains array in 'lib/Config.php' per the instructions provided in the corresponding code comments.
  • You can whitelist (restrict) access to either API by adding specific domains and/or IPs to the $_apiAllowedDomains 'json' or 'button' subarray. If either subarray is left empty, then this enables unrestricted, public access to the corresponding API. When an API is made public in this way, an 'API' menu link and page is automatically added to your site. This page provides your website users with detailed instructions for consuming all available public APIs.
  • For further information related to the consumption of each API, please review a preview of the 'API' page here.
How do I enable MP3 file caching, and how does the cache work?
  • By default, the software is configured with MP3 caching disabled. To enable it, you must edit the _CACHE_FILES constant value in 'lib/Config.php'.
  • In a nutshell, this feature stores and reuses previously converted MP3 files, so that the same files aren't downloaded and converted over and over again. This ultimately results in a significant savings of resources (foremost, CPU and bandwidth) on your server!
  • To increase the overall efficiency and effectiveness of your cache, MP3 files are only cached after the "nth" conversion of a given video, per the _CACHE_AFTER_X constant value. (E.g., a value of 2 only saves an MP3 in the cache after 2 prior conversions of the same video.) This setting ultimately ensures that only "more popular" files are cached, thereby making more efficient use of available cache space and saving CPU (required to run FFmpeg) only where you most need it -- for popular videos!
  • To maintain and control cache size, the _MAX_CACHE_SIZE and _CACHE_SIZE_BUFFER constant values are leveraged. In addition, you'll need to set up "inc/schedule.php" to run as a regular cron job on your server (ideally, every 15-60 minutes). Some cron command examples include:
  • # Once every 15 minutes
    */15 * * * * /usr/bin/php -q /absolute/path/to/schedule.php
    
    # Once every 30 minutes
    0,30 * * * * /usr/bin/php -q /absolute/path/to/schedule.php
    
    # Once every hour
    0 * * * * /usr/bin/php -q /absolute/path/to/schedule.php
    				
  • (Prior to scheduling the cron job, you must set file permissions of "inc/schedule.php" to chmod 0755 and uncomment all unlink() and rmdir() commands in "inc/schedule.php" to ensure that cached files are actually deleted!)
  • Essentially, _MAX_CACHE_SIZE is the maximum size that the cache can grow on your server, measured in kilobytes, before the oldest cached files are deleted by the cron job. Note: Because file deletions are only performed when the cron job is run, the actual size of the cache may exceed this value between cron jobs. So, it is IMPORTANT that this value is set to significantly lower than the actual space available on the hard drive! You can further mitigate this issue by increasing the _CACHE_SIZE_BUFFER constant value (see below), running the scheduled task more often, and/or ensuring that you always have plenty of unused, available hard disk space.
  • _CACHE_SIZE_BUFFER (also measured in kilobytes) is in fact a buffer of sorts, and it is used to help keep the actual size of the cache as close to _MAX_CACHE_SIZE as possible (in between regular executions of the cron job). So, if caching is enabled and the cache size is greater than _MAX_CACHE_SIZE (when the cron job is run), then the oldest files in the cache are deleted one at a time until the cache size is less than _MAX_CACHE_SIZE minus the _CACHE_SIZE_BUFFER value.
  • Ultimately, the goal is to make the cache size a little less than _MAX_CACHE_SIZE after each execution of the cron job, so that the cache size consistently stays under or as close as possible to the _MAX_CACHE_SIZE value. That said, it's not a perfect science, so you'll have to experiment with different values for _MAX_CACHE_SIZE, _CACHE_SIZE_BUFFER, and the frequency with which the cron job runs, to maintain optimal cache size on your server.
  • Note: Only MP3 files are cached at this time because only MP3 downloads require FFmpeg.
How can I block certain videos at the behest of copyright holders?
  • The software is equipped with a mechansim to easily disable the download/conversion of any given video or videos. To "block" a video in this way, simply edit the corresponding section of "lib/Config.php":
  • // List of YouTube video IDs that are intentionally "blocked" and thus cannot be downloaded/converted
    // E.g., this can be used to disable video download/conversion at the copyright holder's request
    // Each video ID added to the array must be in the format, e.g.: 'J_ub7Etch2U' => 'block'
    public static $_blockedVideos = array(
    	'J_ub7Etch2U' => 'block',
    	'YOUTUBE_VIDEO_ID_HERE' => 'block'
    );
    				
  • Each video ID "element" added to the array must be separated by commas and appear in the following format, e.g.: 'J_ub7Etch2U' => 'block'
  • Note: Even cached videos can be blocked in this way!

Support

Software Support

Stuff you might like to know about software support:

  1. 100% Free support for life!
    • Ask me a question, and I'll answer it!
    • Working directly on your server is not free.
  2. Regular updates/fixes to the software are Free!
  3. See The FAQ for ways to troubleshoot common issues.
  4. Human support for this script is provided via:

Licenses

Regular License

The Regular License permits the installation of this software on one website.

If you require greater freedom or flexibility, then please purchase an Extended License.

Extended License

If you plan to load this software on multiple websites and/or repackage all or some of the software code in your own application that is redistributed and/or sold for profit, then you MUST buy an extended license.

An extended license costs $449.50 (the cost of 10 individual licenses). There are no exceptions to this rule, and violators will be prosecuted. Please contact me at chump2877@yahoo.com to arrange the purchase of an extended license.


Changelog

Software Changelog

Version 1.42 (11.17.2018)

  • Changed MP4 file formats to MKV in the "Video Streams" sections of video charts and search results, as well as in the "mergedstreams" option of the JSON and Button/Iframe APIs, to:
    • Fix issue that prevented "seeking" (i.e., moving forwards and backwards) during playback of corresponding downloaded videos on many media players and devices
  • Included option in Config file to edit default "MKV" label on download buttons, in JSON API, and at the end of download URLs
  • Added file sizes to download buttons in the "Video Streams" sections of video charts and search results, as well as in the "mergedstreams" option of the JSON and Button/Iframe APIs

Version 1.41 (11.15.2018)

  • Added a "Video Streams" option to each item listed in video charts and search results, and included a "mergedstreams" option with the JSON and Button/Iframe APIs, that:
    • Increases the number of available "composite" video + audio download options and qualities (including HD and Ultra HD) for a given video
    • Merges "DASH" Video-Only and Audio-Only streams via FFmpeg stream copy
    • Addresses YouTube's recent removal of HD "non-DASH" video download links
  • Added ability to show/hide "Videos" and/or "Video Streams" options for each listed item in video charts and search results
  • Added ability to show/hide "videos" and/or "mergedstreams" options on the API instructions page
  • Enabled optional "chunked" download of all available file types (except low-quality "non-DASH" video formats), to increase download speed when/if YouTube throttles their bandwidth
  • Introduced the optional use of high-quality "DASH" audio formats for MP3 conversions
  • Improved the quality of search results when searching some video page URLs
  • Enabled automatic search form submission when a search suggestion is selected
  • Consolidated and reduced the number of requests to YouTube when validating video download URLs
  • Fixed bug that could potentially allow multiple users to simultaneously trigger purging of the "links" or "api" cache folders, resulting in attempts to delete nonexistent (i.e., already deleted) cached files
  • Implemented complex sorting of all available download formats for any given video to end reliance on YouTube's volatile format order
  • Resolved issue that caused an error message to display when cached MP3 files were available but corresponding YouTube download links were otherwise unavailable or nonfunctional
  • Implemented various, minor fixes and refactoring of code

Version 1.4 (04.11.2018)

  • Introduced optional caching of "popular" MP3 files
  • Consolidated and reduced the number of unique YouTube API requests required
  • Enabled automatic caching of YouTube API requests
  • Added mechanism to block the download/conversion of specific videos at the behest of copyright holders
  • Automated installation of FFmpeg and cURL binaries via the software's "config check" utility
  • Enabled further flexibility of website interface and access control depending on JSON/Button API preferences
  • Added multi-language support for additional translations, and added Portuguese language support
  • Fixed bug that halted further processing of additional, available YouTube download URLs if any single download URL was determined to be invalid (i.e., if it returned a HTTP 403 response)
  • Implemented various, minor fixes and refactoring of code

Version 1.33 (02.26.2018)

  • Omitted "Content-Length" HTTP header for MP3 downloads IF the user agent is Firefox (desktop version), resolving intermittent MP3 download failures in Firefox. (Other browsers/platforms are not affected.)

Version 1.32 (02.11.2018)

  • Switched to "non-DASH" video formats for MP3 conversion to avoid slow conversions caused by YouTube-imposed throttling of "DASH" audio downloads
  • Modified all download URLs to use the "redirector.googlevideo.com" subdomain, to generally improve download availability and performance
  • Implemented various, minor fixes and refactoring of code

Version 1.31 (05.05.2017)

  • Fixed bug preventing audio playback in Integrated Music Player

Version 1.3 (04.25.2017)

  • Added JSON REST API and Button/Iframe API, API instructions page, and corresponding documentation
  • Added ability to download all but MP3 formats directly from YouTube, completely bypassing server
  • Added ability to download/convert age-restricted YouTube videos
  • Added search suggestions and auto-complete to front page search form
  • Added "layouts" folder to templates, enabling multiple header/footer files for the same template
  • Added ability to disable regular website interface (e.g., if only API is needed)
  • YouTube API requests are retried upon failure, using a new API key when multiple API keys are present
  • Fixed bug that prevented MP3 downloads when Cloudflare SSL is active
  • Implemented various, minor fixes and refactoring of code

Version 1.2 (02.03.2017)

  • Added dynamic Meta and Open Graph tags for video searches
  • Added dynamic "share images" for video searches
  • Automated generation of robots.txt file
  • Automated generation of XML sitemap index file and associated XML sitemaps
  • Added hreflang values to static pages and sitemap URLs
  • Added multi-language support and translation engine
  • Automated language and country detection for translations and "Top Music Videos", respectively
  • Moved the majority of URL rewriting rules from .htaccess to "app/Core/Router.php"
  • Enabled search URLs with the following formats:
    • http://mysite.com/{Keyword or Keywords}
    • http://mysite.com/{Video Id}
    • http://mysite.com/watch?v={Video Id}
    • http://mysite.com/{YouTube Video URL}
  • Added search URL link to each video title in search results
  • Facilitated search bot crawling of code if JavaScript is "not" enabled
  • Implemented various, minor fixes and refactoring of code

Version 1.11 (01.20.2017)

  • Fixed the mechanism used to detect encrypted YouTube videos

Version 1.1 (09.30.2016)

  • Added support for multiple YouTube API keys, to extend API usage quota limits
  • Added "xeon" template to collection of available template designs
  • Video preview button now opens the corresponding video in a FancyBox modal window instead of a new tab
  • Added protection against content scraping of AJAX URLs
  • Added support for more countries in the Top Videos lists
  • Fixed downloaded/converted file incompatibility issue with third-party video/audio editors
  • Fixed bug that prevented the passing of arguments to "element" files
  • Added ability to pass template-specific variable values to generic "page" and "element" files
  • Added "url rewriting" test and support for testing multiple YouTube API keys in "config check" utility
  • Updated the Server Configuration, Software Installation, FAQ, and Changelog sections of these docs

Version 1.01 (07.16.2016)

  • Fixed Error 404 page styles, in some cases
  • Provided option to forward all http:// requests to https:// via .htaccess
  • Fixed bug affecting the video duration format displayed on thumbnail images
  • Updated the Server Configuration, FAQ, and Changelog sections of these docs
  • Fixed url encoding issue that prevented download of some videos
  • Fixed url encoding issue that adversely affected searching with certain keywords