nystudio107 / craft-transcoder

Transcode video & audio files to various formats, and provide video thumbnails
https://nystudio107.com/plugins/transcoder
Other
43 stars 12 forks source link

Add possibility to check for encoded videos via CURL/HTTP instead of local paths #66

Open arifje opened 1 year ago

arifje commented 1 year ago

Currently all functions that are checking if an encoded version of the video/gif/audio exists, are looking for a local path, like "/content/video/encoded/video.mp4". While that might work fine when your data is on the same server, this is not te case when your content is hosted on a remote server or CDN.

In our case that path is pointing to a NFS share and NFS shares are a risk due to connection issues. Also, we have multiple backends (web) and we need to create a NFS share on each of these clients to keep this plugin working and detecting the encoded files. When the NFS server doesn't respond, all webservers freeze.

A better approach to my opinion would be to do this check with a simple CURL/HTTP request. I dirty hacked our version to test it, and it seem to work fine;

   public function getVideoUrl(string|Asset $filePath, array $videoOptions, bool $generate = true, array $encodingOptions = []): string
    {
        $result = '';
        $settings = Transcoder::$plugin->getSettings();
        $subfolder = '';
        $devMode = Craft::$app->config->getGeneral()->devMode;

        // Sub folder check
        if (is_object($filePath) && ($filePath instanceof Asset) && $settings['createSubfolders']) {          
            $subfolder = $filePath->folderPath;
        } else {        
            // Grab segment from URL
            $segments = explode("/", $filePath);
            $subfolder = $segments[count($segments)-2] . '/';
        }

        // Video options
        $videoOptions = $this->coalesceOptions('defaultVideoOptions', $videoOptions);

        // Get the video encoder presets to use
        $videoEncoders = $settings['videoEncoders'];
        $thisEncoder = $videoEncoders[$videoOptions['videoEncoder']];
        $videoOptions['fileSuffix'] = $thisEncoder['fileSuffix'];

        // Destination video file
        $destVideoFile = $this->getFilename($filePath, $videoOptions);

        // Generate video 
        if($generate) {

            // Encoded video URL
            $url = $settings['transcoderUrls']['video'] . $subfolder ?? $settings['transcoderUrls']['default'];
            $encodedUrl = Craft::parseEnv($url) . $destVideoFile;                    

            // Remote url is passed, check if it exists
            if (!is_object($filePath) && filter_var($filePath, FILTER_VALIDATE_URL)) {

                // curl request
                $ch = curl_init($encodedUrl);
                curl_setopt($ch, CURLOPT_NOBODY, true);
                curl_exec($ch);
                $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);

                if($retcode=="200") {
                    return $encodedUrl;                      
                }         
            } 

         ....

        // Don't generate the video, check for existing encoded video, show original if there's not an encoded video            
        } else {

            // Encoded video URL
            $url = $settings['transcoderUrls']['video'] . $subfolder ?? $settings['transcoderUrls']['default'];
            $encodedUrl = Craft::parseEnv($url) . $destVideoFile;

            // Validator  
            $validator = new UrlValidator();
            $error = '';

            if ($validator->validate($encodedUrl, $error)) {

                // curl request
                $ch = curl_init($encodedUrl);
                curl_setopt($ch, CURLOPT_NOBODY, true);
                curl_exec($ch);
                $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);

                if($retcode=="200") {

                    $result = $encodedUrl;

                } else {

                    if($devMode) {
                        echo "<div class='uk-alert'>";
                        echo "<div class='uk-padding-small'>Can't find remote encoded URL:<br><br>$encodedUrl <br><br>Showing original video asset</div>";
                        echo "</div>";                        
                    }

                    $result = "";
                }
            }
        }

Would be awesome if this could be integrated as an option/setting preference.