One feature is missing in Cakebox compared to the legacy version. The possibility to move easily to the next/previous video file in the same folder.

My developement enviroment is Mac OSX, MAMP Pro, Apache 2, PHP 5.5.26, NodeJS 2.11.3, PHPStorm 9.0.2.

I wrote a post about how to setup Cakebox to the latest (developement) version 2.0.0.

Backend

In order to browse server file, we will use the great Finder component from SensioLabs.

Dependency

We edit our dependencies,

back/composer.json

{
  "name": "cakebox",
  "type": "project",
  "description": "",
  "require": {
    "php": ">=5.4.0",
    "silex/silex": "~1.3",
    "symfony/finder": "~2.7"
  },
  "autoload": {
    "psr-0": {"Cakebox": "src/"}
  }
}

Controller

The file controller back/src/Cakebox/Controller/FileController.php must be edited to fetch next and previous readable video file in the same folder.


 <?php
 
 namespace Cakebox\Controller;
 
 use Silex\Application;
 use SPLFileInfo;
 use Symfony\Component\Finder\Finder;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 
 /**
  * FileController
  */
 class FileController {
 
     /**
      * Get file informations (size, name ...)
      *
      * @param Application $app     Silex Application
      * @param Request     $request Request parameters
      *
      * @return JsonResponse Object containing file informations
      */
     public function get(Application $app, Request $request) {
 
         if ($app["rights.canPlayMedia"] == false) {
             $app->abort(403, "This user doesn't have the rights to retrieve file informations");
         }
 
         $filepath = $app['service.main']->checkPath($app['cakebox.root'], $request->get('path'));
 
         if (!isset($filepath)) {
             $app->abort(400, "Missing parameters");
         }
 
         $file = new SPLFileInfo("{$app['cakebox.root']}/{$filepath}");
 
         $fileinfo             = [];
         $fileinfo["name"]     = $file->getBasename("." . $file->getExtension());
         $fileinfo["fullname"] = $file->getFilename();
         $fileinfo["mimetype"] = mime_content_type($file->getPathName());
         $fileinfo["access"]   =
             str_replace('%2F', '/', rawurlencode("{$app['cakebox.access']}/{$filepath}"));
         $fileinfo["size"]     = $file->getSize();
 
         $arrDirectory = $this->getCurrentDirectoryFiles($file, $app);
 
         if (count($arrDirectory) > 1) {
             $fileinfo['previousFile'] =
                 $this->arrayKeyRelative($arrDirectory, $file->getRealPath(), -1);
 
             if ($fileinfo['previousFile']) {
                 $fileinfo['previousFile'] =
                     str_replace($app['cakebox.root'], '', $fileinfo['previousFile']);
             }
 
             $fileinfo['nextFile'] = $this->arrayKeyRelative($arrDirectory, $file->getRealPath(), 1);
 
             if ($fileinfo['nextFile']) {
                 $fileinfo['nextFile'] =
                     str_replace($app['cakebox.root'], '', $fileinfo['nextFile']);
             }
         }
 
         return $app->json($fileinfo, 200);
     }
 
     /**
      * Get files in the current $file directory
      *
      * @param SPLFileInfo $file
      * @param Application $app
      *
      * @return array
      */
     private function getCurrentDirectoryFiles(SPLFileInfo $file, Application $app) {
         $finder = new Finder();
         $finder->files()->in($file->getPath())->depth('== 0')->ignoreVCS(true)
                ->ignoreDotFiles($app['directory.ignoreDotFiles'])->notName($app["directory.ignore"])
                ->filter(function ($curFile) use ($app) {
                    /**
                     * @var SPLFileInfo $curFile
                     */
                    if ($curFile->isReadable()
                        && in_array(strtolower($curFile->getExtension()), $app['extension.video'])
                    ) {
                        return true;
                    }
 
                    return false;
                })->sortByType();
 
         return iterator_to_array($finder->getIterator());
     }
 
     /**
      * Get desired offset in an array
      *
      * @param array      $array
      * @param int|string $current_key
      * @param int        $offset
      * @param bool       $strict
      *
      * @return mixed     return desired offset, if in array, or false if not
      */
     private function arrayKeyRelative($array, $current_key, $offset = 1, $strict = true) {
 
         $keys = array_keys($array);
 
         $current_key_index = array_search($current_key, $keys, $strict);
 
         if (isset($keys[$current_key_index + $offset])) {
             return $keys[$current_key_index + $offset];
         }
 
         return false;
     }
 }

Model

Fetch and convert file path to url in the Angular controller.

front/src/app/play/play.controller.js

$scope.fileinfo = File.get({'path': $routeParams.path}, function(data) {
    if ($scope.bsConfig.apikey) {
        $scope.betaseries = Betaseries.get({'filename': data.name});
    }

    if (data.previousFile) {
        $scope.prevplay = '#/play' + data.previousFile;
    }
    if (data.nextFile) {
        $scope.nextplay = '#/play' + data.nextFile;
    }
});

Display

Display them in the view.

front/src/app/play/play.html

<div class="row">
    <div class="col-sm-6">
        <a ng-href="{{ prevplay }}" ng-show="prevplay" translate>PLAY_PAGE.PREV</a>
    </div>
    <div class="col-sm-6">
        <a ng-href="{{ nextplay }}" ng-show="nextplay" translate>PLAY_PAGE.NEXT</a>
    </div>
</div>

And finally create translation.

front/src/assets/languages/locale-*.json

{
    
    "PREV": "Previous video",
    "NEXT": "Next video"
}

Commit and pull request

https://github.com/Cakebox/cakebox/pull/178