Implemented HBC parser to read all useful info about titles

Titles, chapters, audio and subtitle streams and metadata are now parsed from the handbrakecli output into title objects.
Source-details page now renders this info
This commit is contained in:
2010-03-21 16:12:21 +00:00
parent 0477d7363f
commit 50283e9a9b
7 changed files with 371 additions and 13 deletions

2
.gitignore vendored
View File

@@ -3,5 +3,5 @@
.project
.settings
.htaccess
dbconfig.conf
/dbconfig.conf
tmp/*

View File

@@ -2,8 +2,14 @@
class HandBrakeCluster_Rips_Source {
const PM_TITLE = 0;
const PM_CHAPTER = 1;
const PM_AUDIO = 2;
const PM_SUBTITLE = 3;
protected $source;
protected $output;
protected $titles = array();
public function __construct($source) {
$this->source = $source;
@@ -29,19 +35,111 @@ class HandBrakeCluster_Rips_Source {
// Process the output
$lines = explode("\n", $handbrake_output);
$title = null;
$mode = self::PM_TITLE;
foreach ($lines as $line) {
// Skip any line that doesn't begin with a + (with optional leading whitespace)
if ( ! preg_match('/\s*\+/', $line)) {
continue;
}
$matches = array();
switch (true) {
case preg_match('/^\+ title (?P<id>\d+):$/', $line, $matches): {
if ($title) {
$this->addTitle($title);
}
$mode = self::PM_TITLE;
$title = new HandBrakeCluster_Rips_SourceTitle($matches['id']);
} break;
case $title && preg_match('/^ \+ chapters:$/', $line): {
$mode = self::PM_CHAPTER;
} break;
case $title && preg_match('/^ \+ audio tracks:$/', $line): {
$mode = self::PM_AUDIO;
} break;
case $title && preg_match('/^ \+ subtitle tracks:$/', $line): {
$mode = self::PM_SUBTITLE;
} break;
case $title && $mode == self::PM_TITLE && preg_match('/^ \+ duration: (?P<duration>\d+:\d+:\d+)$/', $line, $matches): {
$title->setDuration($matches['duration']);
} break;
case $title && $mode == self::PM_TITLE && preg_match('/^ \+ angle\(s\) (?P<angles>\d+)$/', $line, $matches): {
$title->setAngles($matches['angles']);
} break;
//" + size: 720x576, pixel aspect: 64/45, display aspect: 1.78, 25.000 fps"
case $title && $mode == self::PM_TITLE && preg_match('/^ \+ size: (?P<width>\d+)x(?P<height>\d+), pixel aspect: (?P<pixel_aspect>\d+\/\d+), display aspect: (?P<display_aspect>[\d\.]+), (?<framerate>[\d\.]+) fps$/', $line, $matches): {
$title->setDisplayInfo(
$matches['width'], $matches['height'], $matches['pixel_aspect'],
$matches['display_aspect'], $matches['framerate']
);
} break;
case $title && $mode == self::PM_TITLE && preg_match('/^ \+ autocrop: (?P<autocrop>(?:\d+\/?){4})$/', $line, $matches): {
$title->setAutocrop($matches['autocrop']);
} break;
case $title && $mode == self::PM_CHAPTER && preg_match('/^ \+ (?P<id>\d+): cells \d+->\d+, \d+ blocks, duration (?P<duration>\d+:\d+:\d+)$/', $line, $matches): {
$title->addChapter($matches['id'], $matches['duration']);
} break;
case $title && $mode == self::PM_AUDIO && preg_match('/^ \+ (?P<id>\d+), (?P<name>.+) \((?P<format>.+)\) \((?P<channels>.+) ch\) \((?P<language>.+)\), (?P<samplerate>\d+)Hz, (?P<bitrate>\d+)bps$/', $line, $matches): {
$title->addAudioTrack(
new HandBrakeCluster_Rips_SourceAudioTrack(
$matches['id'], $matches['name'], $matches['format'], $matches['channels'],
$matches['language'], $matches['samplerate'], $matches['bitrate']
)
);
} break;
case $title && $mode == self::PM_SUBTITLE && preg_match('/^ \+ (?P<id>\d+), (?P<name>.+) \((?P<language>.+)\) \((?P<format>.+)\)$/', $line, $matches): {
$title->addSubtitleTrack(
new HandBrakeCluster_Rips_SourceSubtitleTrack(
$matches['id'], $matches['name'], $matches['language'], $matches['format']
)
);
} break;
default: {
// Ignore this unmatched line
} break;
}
$this->output .= $line . "\n";
}
// Handle the last title found as a special case
if ($title) {
$this->addTitle($title);
}
}
public function addTitle(HandBrakeCluster_Rips_SourceTitle $title) {
$this->titles[] = $title;
}
public function output() {
return $this->output;
}
public function titleCount() {
return count($this->titles);
}
public function titles() {
return $this->titles;
}
};
?>

View File

@@ -0,0 +1,53 @@
<?php
class HandBrakeCluster_Rips_SourceAudioTrack {
protected $id;
protected $name;
protected $format;
protected $channels;
protected $language;
protected $samplerate;
protected $bitrate;
public function __construct($id, $name, $format, $channels, $language, $samplerate, $bitrate) {
$this->id = $id;
$this->name = $name;
$this->format = $format;
$this->channels = $channels;
$this->language = $language;
$this->samplerate = $samplerate;
$this->bitrate = $bitrate;
}
public function id() {
return $this->id;
}
public function name() {
return $name;
}
public function format() {
return $this->format;
}
public function channels() {
return $this->channels;
}
public function language() {
return $this->language;
}
public function samplerate() {
return $this->samplerate;
}
public function bitrate() {
return $this->bitrate;
}
};
?>

View File

@@ -0,0 +1,35 @@
<?php
class HandBrakeCluster_Rips_SourceSubtitleTrack {
protected $id;
protected $name;
protected $language;
protected $format;
public function __construct($id, $name, $language, $format) {
$this->id = $id;
$this->name = $name;
$this->language = $language;
$this->format = $format;
}
public function id() {
return $this->id;
}
public function name() {
return $this->name;
}
public function language() {
return $this->language;
}
public function format() {
return $this->format;
}
};
?>

View File

@@ -0,0 +1,122 @@
<?php
class HandBrakeCluster_Rips_SourceTitle {
protected $id;
//protected $vts;
//protected $ttn;
//protected $cell_count;
//protected $blocks;
protected $angles;
protected $duration;
protected $width;
protected $height;
protected $pixel_aspect;
protected $display_aspect;
protected $framerate;
protected $autocrop;
protected $chapters = array();
protected $audio = array();
protected $subtitles = array();
public function __construct($id) {
$this->id = $id;
}
public function id() {
return $this->id;
}
public function angles() {
return $this->angles;
}
public function setAngles($angles) {
$this->angles = $angles;
}
public function duration() {
return $this->duration;
}
public function setDuration($duration) {
$this->duration = $duration;
}
public function width() {
return $this->width;
}
public function height() {
return $this->height;
}
public function displayAspect() {
return $this->display_aspect;
}
public function pixelAspect() {
return $this->pixel_aspect;
}
public function framerate() {
return $this->framerate;
}
public function setDisplayInfo($width, $height, $display_aspect, $pixel_aspect, $framerate) {
$this->width = $width;
$this->height = $height;
$this->pixel_aspect = $pixel_aspect;
$this->display_aspect = $display_aspect;
$this->framerate = $framerate;
}
public function autocrop() {
return $this->autocrop;
}
public function setAutocrop($autocrop) {
$this->autocrop = $autocrop;
}
public function chapterCount() {
return count($this->chapters);
}
public function chapters() {
return $this->chapters;
}
public function addChapter($chapter_id, $duration) {
$this->chapters[$chapter_id] = $duration;
}
public function audioTrackCount() {
return count($this->audio);
}
public function audioTracks() {
return $this->audio;
}
public function addAudioTrack(HandBrakeCluster_Rips_SourceAudioTrack $audio_track) {
$this->audio[] = $audio_track;
}
public function subtitleTrackCount() {
return count($this->subtitles);
}
public function subtitleTracks() {
return $this->subtitles;
}
public function addSubtitleTrack(HandBrakeCluster_Rips_SourceSubtitleTrack $subtitle_track) {
$this->subtitles[] = $subtitle_track;
}
};
?>

View File

@@ -23,5 +23,6 @@ $source = new HandBrakeCluster_Rips_Source($source_path);
$this->smarty->assign('source_path', $source_path);
$this->smarty->assign('source', $source);
$this->smarty->assign('output', $source->output());
$this->smarty->assign('titles', $source->titles());
?>

View File

@@ -14,10 +14,59 @@
<th>Source</th>
<td>{$source_path|escape:"html"}</td>
</tr>
{if $titles}
<tr>
<th>Output</th>
<td><pre>{$output|escape:"html"}</pre></td>
<th>Titles</th>
<td>
<table class="titles">
<colgroup class="title-number">
<col />
</colgroup>
<colgroup class="title-header">
<col />
</colgroup>
<colgroup>
<col />
</colgroup>
<tbody>
{foreach from=$titles item=title}
<tr>
<th rowspan="5">{$title->id()}</th>
<td>Duration</td>
<td>{$title->duration()}</td>
</tr>
<tr>
<td>Display</td>
<td>
<ul>
<li>Size: {$title->width()}x{$title->height()}</li>
<li>Pixel aspect ratio: {$title->pixelAspect()}</li>
<li>Display aspect ratio: {$title->displayAspect()}</li>
<li>Framerate: {$title->framerate()}</li>
<li>Autocrop: {$title->autocrop()}</li>
</ul>
</td>
</tr>
<tr>
<td>Chapters</td>
<td>{$title->chapterCount()}</td>
</tr>
<tr>
<td>Audio Tracks</td>
<td>{$title->audioTrackCount()}</td>
</tr>
<tr>
<td>Subtitle Tracks</td>
<td>{$title->subtitleTrackCount()}</td>
</tr>
{/foreach}
</tbody>
</table>
</td>
</tr>
{/if}
</tbody>
</table>
{else}