From 5aa4bf11c7d7559151b04d64771423341c90d819 Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Sat, 14 Aug 2010 12:19:50 +0100 Subject: [PATCH] Various UI improvements --- HandBrakeCluster/Exceptions.class.php | 5 +- HandBrakeCluster/Job.class.php | 42 ++++++++++- HandBrakeCluster/Main.class.php | 31 +++++++- HandBrakeCluster/RequestParser.class.php | 6 +- HandBrakeCluster/Rips/Source.class.php | 24 ++++++- images/caution.png | Bin 0 -> 2554 bytes images/redo.png | Bin 0 -> 9725 bytes images/trash.png | Bin 0 -> 10375 bytes pages/jobs.php | 88 ++++++++++++++++++++++- pages/rips/setup-rip.php | 1 + styles/normal.css | 4 +- templates/jobs.tpl | 56 ++++++++++++++- templates/rips/setup-rip.tpl | 17 +++-- 13 files changed, 255 insertions(+), 19 deletions(-) create mode 100644 images/caution.png create mode 100644 images/redo.png create mode 100644 images/trash.png diff --git a/HandBrakeCluster/Exceptions.class.php b/HandBrakeCluster/Exceptions.class.php index 09fc7fc..3841070 100644 --- a/HandBrakeCluster/Exceptions.class.php +++ b/HandBrakeCluster/Exceptions.class.php @@ -24,4 +24,7 @@ class HandBrakeCluster_Exception_CacheException extends HandBrakeCluster class HandBrakeCluster_Exception_InvalidCacheDir extends HandBrakeCluster_Exception_CacheException {}; class HandBrakeCluster_Exception_CacheObjectNotFound extends HandBrakeCluster_Exception_CacheException {}; -?> \ No newline at end of file +class HandBrakeCluster_Exception_LogicException extends HandBrakeCluster_Exception {}; +class HandBrakeCluster_Exception_JobNotRunning extends HandBrakeCluster_Exception_LogicException {}; + +?> diff --git a/HandBrakeCluster/Job.class.php b/HandBrakeCluster/Job.class.php index 5aca165..940bf0f 100644 --- a/HandBrakeCluster/Job.class.php +++ b/HandBrakeCluster/Job.class.php @@ -44,6 +44,12 @@ class HandBrakeCluster_Job { $this->subtitle_tracks = $subtitle_tracks; } + public function __clone() { + $this->id = null; + + $this->create(); + } + public static function fromDatabaseRow($row) { return new HandBrakeCluster_Job( HandBrakeCluster_Rips_Source::load($rips['source']), @@ -124,12 +130,14 @@ class HandBrakeCluster_Job { $jobs = array(); foreach ($titles as $title => $details) { if (HandBrakeCluster_Main::issetelse($details['queue'])) { + HandBrakeCluster_Main::issetelse($details['output_filename'], HandBrakeCluster_Exception_InvalidParameters); + $job = new HandBrakeCluster_Job( $source, null, HandBrakeCluster_Main::issetelse($details['name'], 'unnamed job'), $source->filename(), - HandBrakeCluster_Main::issetelse($details['output_filename'], HandBrakeCluster_Exception_InvalidParameters), + $global_options['output-directory'] . DIRECTORY_SEPARATOR . $details['output_filename'], $title, $global_options['format'], $global_options['video-codec'], @@ -179,6 +187,18 @@ class HandBrakeCluster_Job { $status = HandBrakeCluster_JobStatus::updateStatusForJob($this, HandBrakeCluster_JobStatus::CREATED); } + public function delete() { + $database = HandBrakeCluster_Main::instance()->database(); + $database->update( + 'DELETE FROM jobs WHERE id=:job_id LIMIT 1', + array( + array(name => 'job_id', value => $this->id, type => PDO::PARAM_INT), + ) + ); + + $this->id = null; + } + public function queue($gearman) { $main = HandBrakeCluster_Main::instance(); $config = $main->config(); @@ -188,8 +208,8 @@ class HandBrakeCluster_Job { // Construct the rip options $rip_options = array( 'nice' => $config->get('rips.nice', 15), - 'input_filename' => dirname($this->source_filename) . DIRECTORY_SEPARATOR . basename($this->source_filename), - 'output_filename' => dirname($this->destination_filename) . DIRECTORY_SEPARATOR . basename($this->destination_filename), + 'input_filename' => $this->source_filename, + 'output_filename' => $this->destination_filename, 'title' => $this->title, 'format' => $this->format, 'video_codec' => $this->video_codec, @@ -233,6 +253,22 @@ class HandBrakeCluster_Job { return HandBrakeCluster_JobStatus::updateStatusForJob($this, $new_status, $rip_progress); } + public function calculateETA() { + $current_status = $this->currentStatus(); + if ($current_status->status() != HandBrakeCluster_JobStatus::RUNNING) { + throw new HandBrakeCluster_Exception_JobNotRunning(); + } + + $running_time = $current_status->mtime() - $current_status->ctime(); + $progress = $current_status->ripProgress(); + + if ($progress > 0) { + $remaining_time = round((100 - $progress) * ($running_time / $progress)); + } + + return $remaining_time; + } + public function id() { return $this->id; } diff --git a/HandBrakeCluster/Main.class.php b/HandBrakeCluster/Main.class.php index 32f4101..b68e018 100644 --- a/HandBrakeCluster/Main.class.php +++ b/HandBrakeCluster/Main.class.php @@ -32,6 +32,8 @@ class HandBrakeCluster_Main { $this->smarty->cache_dir = './tmp/cache'; $this->smarty->config_fir = './config'; + $this->smarty->register_modifier('formatDuration', array('HandBrakeCluster_Main', 'formatDuration')); + $this->smarty->assign('version', '0.1'); $this->base_uri = dirname($_SERVER['SCRIPT_NAME']) . '/'; @@ -160,12 +162,39 @@ class HandBrakeCluster_Main { return $var; } - if (preg_match('/^HandBrakeCluster_Exception/', $default) && class_exists($default) && is_subclass_of($default, HandBrakeCluster_Exception)) { + if (is_string($default) && preg_match('/^HandBrakeCluster_Exception/', $default) && class_exists($default) && is_subclass_of($default, HandBrakeCluster_Exception)) { throw new $default(); } return $default; } + + public static function formatDuration($time) { + if (is_null($time)) { + return 'unknown'; + } + + $labels = array('seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years'); + $limits = array(60, 3600, 86400, 604800, 2592000, 31556926, PHP_INT_MAX); + + $working_time = $time; + + $result = ""; + $ptr = count($labels) - 1; + + while ($ptr >= 0 && $working_time < $limits[$ptr]) { + --$ptr; + } + + while ($ptr >= 0) { + $unit_time = floor($working_time / $limits[$ptr]); + $working_time -= $unit_time * $limits[$ptr]; + $result = $result . ' ' . $unit_time . ' ' . $labels[$ptr]; + --$ptr; + } + + return $result; + } } diff --git a/HandBrakeCluster/RequestParser.class.php b/HandBrakeCluster/RequestParser.class.php index 7ccb2c7..802b585 100644 --- a/HandBrakeCluster/RequestParser.class.php +++ b/HandBrakeCluster/RequestParser.class.php @@ -72,12 +72,16 @@ class HandBrakeCluster_RequestParser { return join('/', $this->page); } + public function exists($key) { + return isset($this->vars[$key]); + } + public function get($key, $default = null) { if (isset($this->vars[$key])) { return $this->vars[$key]; } - if (is_subclass_of($default, HandBrakeCluster_Exception)) { + if (is_string($default) && preg_match('/^HandBrakeCluster_Exception/', $default) && class_exists($default) && is_subclass_of($default, HandBrakeCluster_Exception)) { throw new $default(); } diff --git a/HandBrakeCluster/Rips/Source.class.php b/HandBrakeCluster/Rips/Source.class.php index 024ae59..a39f6dd 100644 --- a/HandBrakeCluster/Rips/Source.class.php +++ b/HandBrakeCluster/Rips/Source.class.php @@ -131,7 +131,7 @@ class HandBrakeCluster_Rips_Source { $title->addChapter($matches['id'], $matches['duration']); } break; - case $title && $mode == self::PM_AUDIO && preg_match('/^ \+ (?P\d+), (?P.+) \((?P.+)\) \((?P.+) ch\) \((?P.+)\), (?P\d+)Hz, (?P\d+)bps$/', $line, $matches): { + case $title && $mode == self::PM_AUDIO && preg_match('/^ \+ (?P\d+), (?P.+) \((?P.+)\) \((?P(.+ ch|Dolby Surround))\) \((?P.+)\), (?P\d+)Hz, (?P\d+)bps$/', $line, $matches): { $title->addAudioTrack( new HandBrakeCluster_Rips_SourceAudioTrack( $matches['id'], $matches['name'], $matches['format'], $matches['channels'], @@ -196,7 +196,27 @@ class HandBrakeCluster_Rips_Source { } return $longest_title; - } + } + + public function longestTitleIndex() { + $longest_index = null; + $maximmum_duration = 0; + + if ( ! $this->titles) { + return null; + } + + for ($i = 0, $l = count($this->titles); $i < $l; ++$i) { + $title = $this->titles[$i]; + $duration = $title->durationInSeconds(); + if ($duration > $maximum_duration) { + $longest_index = $i; + $maximum_duration = $duration; + } + } + + return $longest_index; + } public function filename() { return $this->source; diff --git a/images/caution.png b/images/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..cb9d5ea0df3fb7abe744d6ef885847c13b786d4d GIT binary patch literal 2554 zcmVPx#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU*cu7P-R9Hvtm}yW|M;eAj!AUtmOHnh%%)~HLR9PcMG?rWGpb{ZL z1dJ<)aY5WLh(<8#m>6XjB8vnG6Gtt^g$P(~C1Elw7eQq4vUp{aMG-;Va6jFLao%$q z`?iK}j1`E{ZCeEszMz2Dc}$LQtDmwn!<2S9Jt)90@E=k+Oa z-Ep}&d+X{MB2!36NH3Ur1{5D3->+XkKI>fDkEL5Fv@(KL?4xC&a?K$h_rHlud-v|` zDN_%C4j(=&(#-#SoYe3ut%#uI`{c4vdM%i00_gR)uUAYFnZm-tdc@RSAo!+l-@bgN zg%0BhXeuM+a;-L68u{uTTDpr?#cW<2GbE0HNOGO{~NT>wQ#N54+<2{I*DMky{X52ZCR zxvGDN*@+LDL)Ba8l})tpE20V7uvpg%5NH4X{arG31{4tyA=0c|I8~ux+LVXMWx=#6 zO7&Z`2$UVagsQzsp%*DwPx9B0Qor>JM~gaPg`G2X2!z#$GkLg7qqkFOWt3bI4i{@{ zDv(x&p?`=pYnNDqrcE2r zl!YiX8b5l?PjlrUA8G!oJiR_e;79K z+|M4Mk)h31Kdm;P(P~q)g{n7GZG{*7x`mCupSFbLx{*uFH(y9upn*2_QU+)~C27-B z!p4{lY%?63T3A@vb;>XzFffoWV${gNmlHQAE{1PP;Tvf44K4DaYV_ibpdm`X@mOSQ zZtd=I=Snu2=>X%W>5j-0v>~swxfE;lrQL8&gR22L%k$^YB}oDkfb^IQ z05N2YyK&>j=+U~Zalkvq{|fqy7HYLo`i(ouT@K$grMnG$SGfu^ZjKd1*>+7wobjOv7z~^NuE2o z3>x%eS5)|=pKX5HKDObU9Wupg3cjiRWulLZF7G%v;Mk9V&CSgZ9z5VodOCFogmEuk zym&~I&Xm^I3MH1T?RE}B~bDBy19v||z@MF`aO{Jx!Z~~a% zXfQo`^a#0wNTQiu1LE>v1oVWekoVrbd)3v|)22=1(Qzk>**2-}>|Bz)h-A-~F0u-r zEoFQrrOzU1GwObs80Bp)9Krjzy1J@Vs)B+7lnbKWx^?UB-Ma|>$p60M~S&>&NjQh%@%X)G-*j~qF2;=~Dj3pjiB?1c*#GBPsq^76{d%Mlaq<_Z~3 z8M-(tc%+PZsHLR^>p<_Wsi{E}h=dKu#l=Nr@^Jj1I$;VbJlTKr2s7RH5OZ_$*w|QH zy>X}GK)o;D9Q45wEij#FNG3;fIhe zZmwJ>FkwL~eTazW1XltJlffD2F%ScFgl!xTI3NiO2isv7S`Nme!NN3bBhzcp;*qH9 zyS-?0D9ofnTxNFGHnDol4XZ*4P~uPg6JoG!3#E!zuox_f?epTE+Vugg{jpLneTay- zhz>Z^E!$q0YuM`p*66M1w=;4e(;I; z#wi{%^iGLAOBow2GKohN%*P)#C9mQ3uXMuET~q4`W^j(q|JmjD7rg=h19t5(ulxW^ Q2LJ#707*qoM6N<$f-6kHbN~PV literal 0 HcmV?d00001 diff --git a/images/redo.png b/images/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..882dafb4f96b5aa12f7b2e605e2396c15bbe038a GIT binary patch literal 9725 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 literal 0 HcmV?d00001 diff --git a/images/trash.png b/images/trash.png new file mode 100644 index 0000000000000000000000000000000000000000..531d42f095008b9962a09bcd1ca7ac7f24b24e7d GIT binary patch literal 10375 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 ziE#4?atre7@bfsmarty->assign('jobs', $jobs); +$main = HandBrakeCluster_Main::instance(); +$req = $main->request(); +$config = $main->config(); + +if ($req->get('submit')) { + $action = HandBrakeCluster_Main::issetelse($_POST['action'], HandBrakeCluster_Exception_InvalidParameters); + + # If a bulk action was selected, the action will be a single term, otherwise it will also contain + # the id of the single item to act upon. Work out which was used now. + $matches = $job_ids = array(); + if (preg_match('/^(.*)\[(\d+)\]$/', $action, $matches)) { + $action = $matches[1]; + $job_ids = array($matches[2]); + } + else { + $job_ids = $_POST['include']; + } + + $jobs = array(); + foreach ($job_ids as $job_id) { + $job = HandBrakeCluster_Job::fromId($job_id); + if (!$job) { + throw new HandBrakeCluster_Exception_InvalidParameters('job_id'); + } + $jobs[] = $job; + } + + switch ($action) { + case 'mark-failed': { + foreach ($jobs as $job) { + $job->updateStatus(HandBrakeCluster_JobStatus::FAILED); + } + } break; + + case 'retry': { + # Clone each of the selected jobs + foreach ($jobs as $job) { + $new_job = clone $job; + } + + # Dispatch all the jobs in one run + HandBrakeCluster_Job::runAllJobs(); + + # Redirect to the job queued page to show the jobs were successfully dispatched + HandBrakeCluster_Page::redirect('rips/setup-rip/queued'); + } break; + + case 'delete': { + foreach ($jobs as $job) { + $job->delete(); + } + } break; + + default: { + throw new HandBrakeCluster_Exception_InvalidParameters('action'); + } + } + + HandBrakeCluster_Page::redirect('jobs'); + +} else { + + if (isset($_POST['view'])) { + $statusName = urlencode($_POST['view']); + HandBrakeCluster_Page::redirect("jobs/view/{$statusName}"); + } + + $statusName = $req->get('view', 'any'); + switch ($statusName) { + case 'any': $status = null; break; + case 'queued': $status = HandBrakeCluster_JobStatus::QUEUED; break; + case 'running': $status = HandBrakeCluster_JobStatus::RUNNING; break; + case 'complete': $status = HandBrakeCluster_JobStatus::COMPLETE; break; + case 'failed': $status = HandBrakeCluster_JobStatus::FAILED; break; + default: throw new HandBrakeCluster_Exception_InvalidParameters('view'); + } + + $jobs = array(); + if ($status) { + $jobs = HandBrakeCluster_Job::allWithStatus($status); + } else { + $jobs = HandBrakeCluster_Job::all(); + } + + $this->smarty->assign('jobs', $jobs); +} ?> diff --git a/pages/rips/setup-rip.php b/pages/rips/setup-rip.php index 99511af..80b4da2 100644 --- a/pages/rips/setup-rip.php +++ b/pages/rips/setup-rip.php @@ -29,6 +29,7 @@ if ($req->get('submit')) { $this->smarty->assign('source', $source); $this->smarty->assign('titles', $source->titles()); $this->smarty->assign('longest_title', $source->longestTitle()); + $this->smarty->assign('default_output_directory', $config->get('rips.default.output_directory')); } ?> diff --git a/styles/normal.css b/styles/normal.css index 86d8927..89dafec 100644 --- a/styles/normal.css +++ b/styles/normal.css @@ -104,8 +104,8 @@ label { width: 16px; } -table#setup-rips input,select { - +form#setup-rips input[type="text"] { + width: 30em; } #quantizer-slider { diff --git a/templates/jobs.tpl b/templates/jobs.tpl index b312e36..7dd1eb2 100644 --- a/templates/jobs.tpl +++ b/templates/jobs.tpl @@ -1,6 +1,32 @@

Jobs

{if $jobs} + +
+
+ View + + + + + +
+
+ +
+
+ Bulk Actions + + + + +
@@ -8,20 +34,46 @@ + {foreach from=$jobs item=job} {assign var=current_status value=$job->currentStatus()} - + - + + {/foreach}
Destination Title StatusActions
{$job->name()}{$job->name()} {$job->destinationFilename()} {$job->title()}{$current_status->statusName()}{if $current_status->hasProgressInfo()} ({$current_status->ripProgress()}%, last updated {$current_status->mtime()|date_format:"%D %T"}){/if} + {$current_status->statusName()} + {if $current_status->hasProgressInfo()} +
+ Progress: {$current_status->ripProgress()}%
+ At: {$current_status->mtime()|date_format:"%D %T"}
+ ETA: {$job->calculateETA()|formatDuration} + {/if} +
+
+ + + + +
+
+
+ Bulk Actions + + + + +
+
{else} There are no jobs {/if} + diff --git a/templates/rips/setup-rip.tpl b/templates/rips/setup-rip.tpl index f585cae..f97ea3f 100644 --- a/templates/rips/setup-rip.tpl +++ b/templates/rips/setup-rip.tpl @@ -8,15 +8,17 @@ to see a list of running jobs, or the logs page for more detailed progress information.

{else} +

{$source->filename()|htmlspecialchars}

+
Configure global rip options - +
- +
@@ -58,7 +60,7 @@
{foreach from=$titles item=title} -

Title {$title->id()} (Duration: {$title->duration()}, Chapters: {$title->chapterCount()})

+

Title {$title->id()} (Duration: {$title->duration()}, Chapters: {$title->chapterCount()})

Configure title rip options @@ -68,11 +70,16 @@
+
+ + +
+
@@ -142,7 +149,7 @@ {literal}