diff options
author | Nathan Kinkade <nath@nkinka.de> | 2013-01-16 17:32:36 +0000 |
---|---|---|
committer | Nathan Kinkade <nath@nkinka.de> | 2013-01-16 17:32:36 +0000 |
commit | 0047af90bf4db08b22838e6ded22a7fa70cee98a (patch) | |
tree | 1c6cb658ffac9ae5d00e32668bed1b1bfbf70b5a /modules | |
parent | 77e2e58aeff49477242f789b367def4b08836a47 (diff) | |
parent | 9d684b7b83f0aa026e9d6f06228294f179a3bcaa (diff) |
Manually resolved conflict after recent pull.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/g2_import/controllers/g2.php | 7 | ||||
-rw-r--r-- | modules/gallery/css/gallery.css | 6 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_installer.php | 10 | ||||
-rw-r--r-- | modules/gallery/helpers/graphics.php | 54 | ||||
-rw-r--r-- | modules/gallery/helpers/item_rest.php | 2 | ||||
-rw-r--r-- | modules/gallery/helpers/movie.php | 34 | ||||
-rw-r--r-- | modules/gallery/models/item.php | 69 | ||||
-rw-r--r-- | modules/gallery/module.info | 2 | ||||
-rw-r--r-- | modules/gallery/views/movieplayer.html.php | 61 | ||||
-rw-r--r-- | modules/tag/controllers/tag_name.php | 33 | ||||
-rw-r--r-- | modules/tag/models/tag.php | 16 | ||||
-rw-r--r-- | modules/user/controllers/users.php | 2 |
12 files changed, 228 insertions, 68 deletions
diff --git a/modules/g2_import/controllers/g2.php b/modules/g2_import/controllers/g2.php index 6c960893..98eb57f1 100644 --- a/modules/g2_import/controllers/g2.php +++ b/modules/g2_import/controllers/g2.php @@ -34,6 +34,11 @@ class G2_Controller extends Controller { $path = $input->get("path"); $id = $input->get("g2_itemId"); + /* Tags are handled specially, since there's no mapping for them */ + if (($path && 0 === strpos($path, "tag/"))) { + url::redirect("tag_name/" . substr($path, 4)); + } + if (($path && $path != 'index.php' && $path != 'main.php') || $id) { if ($id) { // Requests by id are either core.DownloadItem or core.ShowItem requests. Later versions of @@ -94,4 +99,4 @@ class G2_Controller extends Controller { throw new Kohana_404_Exception(); } } -}
\ No newline at end of file +} diff --git a/modules/gallery/css/gallery.css b/modules/gallery/css/gallery.css index 9d773699..7e711156 100644 --- a/modules/gallery/css/gallery.css +++ b/modules/gallery/css/gallery.css @@ -143,6 +143,12 @@ width: 1%; } +/* Unsupported movie download link ~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +.g-movie-download-link { + text-align: center; +} + /** ******************************************************************* * 2) Admin **********************************************************************/ diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index 1f190800..597771f3 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -313,8 +313,9 @@ class gallery_installer { module::set_var("gallery", "extra_binary_paths", "/usr/local/bin:/opt/local/bin:/opt/bin"); module::set_var("gallery", "timezone", null); module::set_var("gallery", "lock_timeout", 1); + module::set_var("gallery", "movie_extract_frame_time", 3); - module::set_version("gallery", 52); + module::set_version("gallery", 53); } static function upgrade($version) { @@ -735,6 +736,13 @@ class gallery_installer { ->execute(); module::set_version("gallery", $version = 52); } + + if ($version == 52) { + // In v53, we added the ability to change the default time used when extracting frames from + // movies. Previously we hard-coded this at 3 seconds, so we use that as the default. + module::set_var("gallery", "movie_extract_frame_time", 3); + module::set_version("gallery", $version = 53); + } } static function uninstall() { diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index c19fbe6d..e7c5da68 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -155,13 +155,27 @@ class graphics_Core { try { foreach ($ops as $target => $output_file) { if ($input_item->is_movie()) { - // Convert the movie to a JPG first + // Convert the movie filename to a JPG first, delete anything that might already be there $output_file = legal_file::change_extension($output_file, "jpg"); - try { - movie::extract_frame($input_file, $output_file); - } catch (Exception $e) { - // Assuming this is MISSING_FFMPEG for now - copy(MODPATH . "gallery/images/missing_movie.jpg", $output_file); + unlink($output_file); + // Run movie_extract_frame events, which can either: + // - generate an output file, bypassing the ffmpeg-based movie::extract_frame + // - add to the options sent to movie::extract_frame (e.g. change frame extract time, + // add de-interlacing arguments to ffmpeg... see movie helper for more info) + // Note that the args are similar to those of the events in gallery_graphics + $movie_options_wrapper = new stdClass(); + $movie_options_wrapper->movie_options = array(); + module::event("movie_extract_frame", $input_file, $output_file, + $movie_options_wrapper, $input_item); + // If no output_file generated by events, run movie::extract_frame with movie_options + clearstatcache(); + if (@filesize($output_file) == 0) { + try { + movie::extract_frame($input_file, $output_file, $movie_options_wrapper->movie_options); + } catch (Exception $e) { + // Didn't work, likely because of MISSING_FFMPEG - copy missing_movie instead + copy(MODPATH . "gallery/images/missing_movie.jpg", $output_file); + } } $working_file = $output_file; } else { @@ -201,7 +215,7 @@ class graphics_Core { // Something went wrong rebuilding the image. Leave it dirty and move on. // @todo we should handle this better. Kohana_Log::add("error", "Caught exception rebuilding image: {$item->title}\n" . - $e->getMessage() . "\n" . $e->getTraceAsString()); + $e->getMessage() . "\n" . $e->getTraceAsString()); throw $e; } } @@ -260,13 +274,13 @@ class graphics_Core { $count = graphics::find_dirty_images_query()->count_records(); if ($count) { site_status::warning( - t2("One of your photos is out of date. <a %attrs>Click here to fix it</a>", - "%count of your photos are out of date. <a %attrs>Click here to fix them</a>", - $count, - array("attrs" => html::mark_clean(sprintf( - 'href="%s" class="g-dialog-link"', - url::site("admin/maintenance/start/gallery_task::rebuild_dirty_images?csrf=__CSRF__"))))), - "graphics_dirty"); + t2("One of your photos is out of date. <a %attrs>Click here to fix it</a>", + "%count of your photos are out of date. <a %attrs>Click here to fix them</a>", + $count, + array("attrs" => html::mark_clean(sprintf( + 'href="%s" class="g-dialog-link"', + url::site("admin/maintenance/start/gallery_task::rebuild_dirty_images?csrf=__CSRF__"))))), + "graphics_dirty"); } } @@ -320,12 +334,12 @@ class graphics_Core { } else { // ImageMagick & GraphicsMagick $magick_kits = array( - "imagemagick" => array( - "name" => "ImageMagick", "binary" => "convert", "version_arg" => "-v", - "version_regex" => "/Version: \S+ (\S+)/"), - "graphicsmagick" => array( - "name" => "GraphicsMagick", "binary" => "gm", "version_arg" => "version", - "version_regex" => "/\S+ (\S+)/")); + "imagemagick" => array( + "name" => "ImageMagick", "binary" => "convert", "version_arg" => "-version", + "version_regex" => "/Version: \S+ (\S+)/"), + "graphicsmagick" => array( + "name" => "GraphicsMagick", "binary" => "gm", "version_arg" => "version", + "version_regex" => "/\S+ (\S+)/")); // Loop through the kits foreach ($magick_kits as $index => $settings) { $path = system::find_binary( diff --git a/modules/gallery/helpers/item_rest.php b/modules/gallery/helpers/item_rest.php index 14580cd9..43fec3ab 100644 --- a/modules/gallery/helpers/item_rest.php +++ b/modules/gallery/helpers/item_rest.php @@ -150,7 +150,7 @@ class item_rest_Core { static function post($request) { $parent = rest::resolve($request->url); - access::required("edit", $parent); + access::required("add", $parent); $entity = $request->params->entity; $item = ORM::factory("item"); diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index ddc513ea..6d70ab2d 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -57,7 +57,16 @@ class movie_Core { return $form; } - static function extract_frame($input_file, $output_file) { + /** + * Extract a frame from a movie file. Valid movie_options are start_time (in seconds), + * input_args (extra ffmpeg input args) and output_args (extra ffmpeg output args). Extra args + * are added at the end of the list, so they can override any prior args. + * + * @param string $input_file + * @param string $output_file + * @param array $movie_options (optional) + */ + static function extract_frame($input_file, $output_file, $movie_options=NULL) { $ffmpeg = movie::find_ffmpeg(); if (empty($ffmpeg)) { throw new Exception("@todo MISSING_FFMPEG"); @@ -65,23 +74,32 @@ class movie_Core { list($width, $height, $mime_type, $extension, $duration) = movie::get_file_metadata($input_file); - // extract frame at 0:03, unless movie is shorter than 4 sec. - $start_time_arg = ($duration > 4) ? " -ss 00:00:03" : ""; - - $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($input_file) . + if (is_numeric($movie_options["start_time"])) { + $start_time = max(0, $movie_options["start_time"]); // ensure it's non-negative + } else { + $start_time = module::get_var("gallery", "movie_extract_frame_time", 3); // use default + } + // extract frame at start_time, unless movie is too short + $start_time_arg = ($duration >= $start_time + 0.1) ? + "-ss " . date("H:i:s", mktime(0,0,$start_time,0,0,0,0)) : ""; + + $input_args = $movie_options["input_args"] ? $movie_options["input_args"] : ""; + $output_args = $movie_options["output_args"] ? $movie_options["output_args"] : ""; + + $cmd = escapeshellcmd($ffmpeg) . " $input_args -i " . escapeshellarg($input_file) . " -an $start_time_arg -an -r 1 -vframes 1" . " -s {$width}x{$height}" . - " -y -f mjpeg " . escapeshellarg($output_file) . " 2>&1"; + " -y -f mjpeg $output_args " . escapeshellarg($output_file) . " 2>&1"; exec($cmd, $exec_output, $exec_return); clearstatcache(); // use $filename parameter when PHP_version is 5.3+ if (filesize($output_file) == 0 || $exec_return) { // Maybe the movie needs the "-threads 1" argument added // (see http://sourceforge.net/apps/trac/gallery/ticket/1924) - $cmd = escapeshellcmd($ffmpeg) . " -threads 1 -i " . escapeshellarg($input_file) . + $cmd = escapeshellcmd($ffmpeg) . " -threads 1 $input_args -i " . escapeshellarg($input_file) . " -an $start_time_arg -an -r 1 -vframes 1" . " -s {$width}x{$height}" . - " -y -f mjpeg " . escapeshellarg($output_file) . " 2>&1"; + " -y -f mjpeg $output_args " . escapeshellarg($output_file) . " 2>&1"; exec($cmd, $exec_output, $exec_return); clearstatcache(); diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 931da382..8f127532 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -663,31 +663,70 @@ class Item_Model_Core extends ORM_MPTT { } /** - * Return a flowplayer <script> tag for movies + * Return a view for movies. By default this is a Flowplayer v3 <script> tag, but + * movie_img events can override this and provide their own player/view. If no player/view + * is found and the movie is unsupported by Flowplayer v3, this returns a simple download link. * @param array $extra_attrs * @return string */ public function movie_img($extra_attrs) { - $v = new View("movieplayer.html"); $max_size = module::get_var("gallery", "resize_size", 640); $width = $this->width; $height = $this->height; - if ($width > $max_size || $height > $max_size) { - if ($width > $height) { - $height = (int)($height * $max_size / $width); - $width = $max_size; + if ($width == 0 || $height == 0) { + // Not set correctly, likely because ffmpeg isn't available. Making the window 0x0 causes the + // video to be effectively unviewable. So, let's guess: set width to max_size and guess a + // height (using 4:3 aspect ratio). Once the video metadata is loaded, js in + // movieplayer.html.php will correct these values. + $width = $max_size; + $height = ceil($width * 3/4); + } + $attrs = array_merge(array("id" => "g-item-id-{$this->id}"), $extra_attrs, + array("class" => "g-movie")); + + // Run movie_img events, which can either: + // - generate a view, which is used in place of the standard Flowplayer v3 player + // (use view variable) + // - alter the arguments sent to the standard player + // (use fp_params and fp_config variables) + $movie_img = new stdClass(); + $movie_img->max_size = $max_size; + $movie_img->width = $width; + $movie_img->height = $height; + $movie_img->attrs = $attrs; + $movie_img->url = $this->file_url(true); + $movie_img->fp_params = array(); // additional Flowplayer params values (will be json encoded) + $movie_img->fp_config = array(); // additional Flowplayer config values (will be json encoded) + $movie_img->view = array(); + module::event("movie_img", $movie_img, $this); + + if (count($movie_img->view) > 0) { + // View generated - use it + $view = implode("\n", $movie_img->view); + } else { + // View NOT generated - see if filetype supported by Flowplayer v3 + // Note that the extension list below is hard-coded and doesn't use the legal_file helper + // since anything else will not work in Flowplayer v3. + if (in_array(strtolower(pathinfo($this->name, PATHINFO_EXTENSION)), + array("flv", "mp4", "m4v", "mov", "f4v"))) { + // Filetype supported by Flowplayer v3 - use it (default) + $view = new View("movieplayer.html"); + $view->max_size = $movie_img->max_size; + $view->width = $movie_img->width; + $view->height = $movie_img->height; + $view->attrs = $movie_img->attrs; + $view->url = $movie_img->url; + $view->fp_params = $movie_img->fp_params; + $view->fp_config = $movie_img->fp_config; } else { - $width = (int)($width * $max_size / $height); - $height = $max_size; + // Filetype NOT supported by Flowplayer v3 - display download link + $attrs = array_merge($attrs, array("style" => "width: {$max_size}px;", + "download" => $this->name, // forces download (HTML5 only) + "class" => "g-movie g-movie-download-link")); + $view = html::anchor($this->file_url(true), t("Click here to download item."), $attrs); } } - - $v->attrs = array_merge($extra_attrs, array("style" => "width:{$width}px;height:{$height}px", - "class" => "g-movie")); - if (empty($v->attrs["id"])) { - $v->attrs["id"] = "g-item-id-{$this->id}"; - } - return $v; + return $view; } /** diff --git a/modules/gallery/module.info b/modules/gallery/module.info index faefd663..64cad0a7 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,6 +1,6 @@ name = "Gallery 3" description = "Gallery core application" -version = 52 +version = 53 author_name = "Gallery Team" author_url = "http://codex.gallery2.org/Gallery:Team" info_url = "http://codex.gallery2.org/Gallery3:Modules:gallery" diff --git a/modules/gallery/views/movieplayer.html.php b/modules/gallery/views/movieplayer.html.php index 343eafe8..25cb9f58 100644 --- a/modules/gallery/views/movieplayer.html.php +++ b/modules/gallery/views/movieplayer.html.php @@ -1,26 +1,49 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> -<?= html::anchor($item->file_url(true), "", $attrs) ?> +<?= html::anchor($url, "", $attrs) ?> <script type="text/javascript"> - flowplayer( - "<?= $attrs["id"] ?>", - { - src: "<?= url::abs_file("lib/flowplayer.swf") ?>", - wmode: "transparent", - provider: "pseudostreaming" - }, - { - clip: { - scaling: 'fit' - }, - plugins: { - pseudostreaming: { - url: "<?= url::abs_file("lib/flowplayer.pseudostreaming-byterange.swf") ?>" + var id = "<?= $attrs["id"] ?>"; + var max_size = <?= $max_size ?>; + // set the size of the movie html anchor, taking into account max_size and height of control bar + function set_movie_size(width, height) { + if((width > max_size) || (height > max_size)) { + if (width > height) { + height = Math.ceil(height * max_size / width); + width = max_size; + } else { + width = Math.ceil(width * max_size / height); + height = max_size; + } + } + height += flowplayer(id).getConfig().plugins.controls.height; + $("#" + id).css({width: width, height: height}); + }; + // setup flowplayer + flowplayer(id, + $.extend(true, { + "src": "<?= url::abs_file("lib/flowplayer.swf") ?>", + "wmode": "transparent", + "provider": "pseudostreaming" + }, <?= json_encode($fp_params) ?>), + $.extend(true, { + "plugins": { + "pseudostreaming": { + "url": "<?= url::abs_file("lib/flowplayer.pseudostreaming-byterange.swf") ?>" }, - controls: { - autoHide: 'always', - hideDelay: 2000 + "controls": { + "autoHide": "always", + "hideDelay": 2000, + "height": 24 + } + }, + "clip": { + "scaling": "fit", + "onMetaData": function(clip) { + // set movie size a second time using actual size from metadata + set_movie_size(parseInt(clip.metaData.width), parseInt(clip.metaData.height)); } } - } + }, <?= json_encode($fp_config) ?>) ).ipad(); + // set movie size using width and height passed from movie_img function + $("document").ready(set_movie_size(<?= $width ?>, <?= $height ?>)); </script> diff --git a/modules/tag/controllers/tag_name.php b/modules/tag/controllers/tag_name.php new file mode 100644 index 00000000..1a1179fe --- /dev/null +++ b/modules/tag/controllers/tag_name.php @@ -0,0 +1,33 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2012 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Tag_Name_Controller extends Controller { + public function __call($function, $args) { + $tag_name = $function; + $tag = ORM::factory("tag")->where("name", "=", $tag_name)->find(); + if (!$tag->loaded()) { + // No matching tag was found. If this was an imported tag, this is probably a bug. + // If the user typed the URL manually, it might just be wrong + throw new Kohana_404_Exception(); + } + + url::redirect($tag->abs_url()); + } + +} diff --git a/modules/tag/models/tag.php b/modules/tag/models/tag.php index 37d1aa68..213ea0df 100644 --- a/modules/tag/models/tag.php +++ b/modules/tag/models/tag.php @@ -141,7 +141,7 @@ class Tag_Model_Core extends ORM { /** * Return the server-relative url to this item, eg: - * /gallery3/index.php/tags/35 + * /gallery3/index.php/tags/35/Bob * * @param string $query the query string (eg "page=3") */ @@ -152,4 +152,18 @@ class Tag_Model_Core extends ORM { } return $url; } + + /** + * Return the full url to this item, eg: + * http://example.com/gallery3/index.php/tags/35/Bob + * + * @param string $query the query string (eg "page=3") + */ + public function abs_url($query=null) { + $url = url::abs_site("tag/{$this->id}/" . urlencode($this->name)); + if ($query) { + $url .= "?$query"; + } + return $url; + } } diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index 0f880fa9..bfa9d720 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -198,7 +198,7 @@ class Users_Controller extends Controller { ->error_messages("length", t("Your email address is too long")) ->error_messages("required", t("You must enter a valid email address")); - module::event("user_change_password_form", $user, $form); + module::event("user_change_email_form", $user, $form); $group->submit("")->value(t("Save")); return $form; } |