352 lines
12 KiB
PHP
352 lines
12 KiB
PHP
<?
|
|
define('INDCH', ' ');
|
|
|
|
/**
|
|
* M3uPlaylist class
|
|
*
|
|
* @package Campcaster
|
|
* @subpackage StorageServer
|
|
* @copyright 2010 Sourcefabric O.P.S.
|
|
* @license http://www.gnu.org/licenses/gpl.txt
|
|
*/
|
|
class M3uPlaylist {
|
|
|
|
/**
|
|
* Parse M3U file or string
|
|
*
|
|
* @param string $data
|
|
* local path to M3U file or M3U string
|
|
* @param string $loc
|
|
* location: 'file'|'string'
|
|
* @return array
|
|
* reference, parse result tree (or PEAR::error)
|
|
*/
|
|
function &parse($data='', $loc='file')
|
|
{
|
|
switch ($loc) {
|
|
case "file":
|
|
if (!is_file($data)) {
|
|
return PEAR::raiseError(
|
|
"M3uPlaylist::parse: file not found ($data)"
|
|
);
|
|
}
|
|
if (!is_readable($data)) {
|
|
return PEAR::raiseError(
|
|
"M3uPlaylist::parse: can't read file ($data)"
|
|
);
|
|
}
|
|
$data = file_get_contents($data);
|
|
case "string":
|
|
$arr = preg_split("|\n#EXTINF: |", $data);
|
|
if ($arr[0] != '#EXTM3U') {
|
|
return PEAR::raiseError(
|
|
"M3uPlaylist::parse: invalid M3U header"
|
|
);
|
|
}
|
|
array_shift($arr);
|
|
break;
|
|
default:
|
|
return PEAR::raiseError(
|
|
"M3uPlaylist::parse: unsupported data location ($loc)"
|
|
);
|
|
}
|
|
return $arr;
|
|
}
|
|
|
|
|
|
/**
|
|
* Import M3U file to storage
|
|
*
|
|
* @param GreenBox $gb
|
|
* @param string $aPath
|
|
* absolute path part of imported file (e.g. /home/user/campcaster)
|
|
* @param string $rPath
|
|
* relative path/filename part of imported file
|
|
* (e.g. playlists/playlist_1.smil)
|
|
* @param array $gunids
|
|
* hash relation from filenames to gunids
|
|
* @param string $plid
|
|
* playlist gunid
|
|
* @param int $subjid
|
|
* local subject (user) id (id of user doing the import)
|
|
* @return Playlist
|
|
*/
|
|
function import(&$gb, $aPath, $rPath, &$gunids, $plid, $subjid=NULL)
|
|
{
|
|
$path = realpath("$aPath/$rPath");
|
|
if (FALSE === $path) {
|
|
return PEAR::raiseError(
|
|
"M3uPlaylist::import: file doesn't exist ($aPath/$rPath)"
|
|
);
|
|
}
|
|
$arr = M3uPlaylist::parse($path);
|
|
if (PEAR::isError($arr)) {
|
|
return $arr;
|
|
}
|
|
require_once("Playlist.php");
|
|
$pl =& Playlist::create($gb, $plid, "imported_M3U");
|
|
if (PEAR::isError($pl)) {
|
|
return $pl;
|
|
}
|
|
$r = $pl->lock($gb, $subjid);
|
|
if (PEAR::isError($r)) {
|
|
return $r;
|
|
}
|
|
foreach ($arr as $i => $it) {
|
|
list($md, $uri) = preg_split("|\n|", $it);
|
|
list($length, $title) = preg_split("|, *|", $md);
|
|
// $gunid = StoredFile::CreateGunid();
|
|
$gunid = ( isset($gunids[basename($uri)]) ? $gunids[basename($uri)] : NULL);
|
|
$acId = BasicStor::IdFromGunid($gunid);
|
|
if (PEAR::isError($acId)) {
|
|
return $acId;
|
|
}
|
|
$length = Playlist::secondsToPlaylistTime($length);
|
|
$offset = '???';
|
|
if (preg_match("|\.([a-zA-Z0-9]+)$|", $uri, $va)) {
|
|
switch (strtolower($ext = $va[1])) {
|
|
case "lspl":
|
|
case "xml":
|
|
case "smil":
|
|
case "m3u":
|
|
$acId = $gb->bsImportPlaylistRaw($gunid,
|
|
$aPath, $uri, $ext, $gunids, $subjid);
|
|
if (PEAR::isError($acId)) {
|
|
break;
|
|
}
|
|
//no break!
|
|
default:
|
|
if (is_null($gunid)) {
|
|
return PEAR::raiseError(
|
|
"M3uPlaylist::import: no gunid");
|
|
}
|
|
$r = $pl->addAudioClip($acId);
|
|
if (PEAR::isError($r)) {
|
|
return $r;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$r = $pl->unlock($gb);
|
|
if (PEAR::isError($r)) {
|
|
return $r;
|
|
}
|
|
return $pl;
|
|
}
|
|
|
|
/**
|
|
* Import M3U file to storage
|
|
*
|
|
* @param GreenBox $gb
|
|
* @param string $data
|
|
* local path to M3U file
|
|
* @return string
|
|
* XML playlist in Campcaster playlist format
|
|
*/
|
|
function convert2lspl(&$gb, $data)
|
|
{
|
|
$arr = M3uPlaylist::parse($data);
|
|
if (PEAR::isError($arr)) {
|
|
return $arr;
|
|
}
|
|
$ind = '';
|
|
$ind2 = $ind.INDCH;
|
|
$ind3 = $ind2.INDCH;
|
|
$res = '';
|
|
foreach ($arr as $i => $it) {
|
|
list($md, $uri) = preg_split("|\n|", $it);
|
|
list($length, $title) = preg_split("|, *|", $md);
|
|
$gunid = StoredFile::CreateGunid();
|
|
$gunid2 = StoredFile::CreateGunid();
|
|
$length = Playlist::secondsToPlaylistTime($length);
|
|
$offset = '???';
|
|
$clipStart = '???';
|
|
$clipEnd = '???';
|
|
$clipLength = '???';
|
|
$uri_h = preg_replace("|--|", "d;d;", htmlspecialchars("$uri"));
|
|
if (preg_match("|\.([a-zA-Z0-9]+)$|", $uri, $va)) {
|
|
switch (strtolower($ext = $va[1])) {
|
|
case "lspl":
|
|
case "xml":
|
|
case "smil":
|
|
case "m3u":
|
|
$acOrPl = "$ind3<playlist id=\"$gunid2\" ".
|
|
"playlength=\"$length\" title=\"$title\"/> ".
|
|
"<!-- $uri_h -->\n";
|
|
break;
|
|
default:
|
|
$acOrPl = "$ind3<audioClip id=\"$gunid2\" ".
|
|
"playlength=\"$length\" title=\"$title\"/> ".
|
|
"<!-- $uri_h -->\n";
|
|
break;
|
|
}
|
|
}
|
|
$res .= "$ind2<playlistElement id=\"$gunid\" relativeOffset=\"$offset\" clipStart=\"$clipStart\" clipEnd=\"$clipEnd\" clipLength=\"$clipLength\">\n".
|
|
$acOrPl.
|
|
"$ind2</playlistElement>\n";
|
|
}
|
|
$res = "$ind<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
|
|
"$ind<playlist id=\"$gunid\" playlength=\"$playlength\" title=\"\">\n".
|
|
"$ind2<metadata/>\n".
|
|
"$res".
|
|
"$ind</playlist>\n";
|
|
return $res;
|
|
}
|
|
} // class M3uPlaylist
|
|
|
|
|
|
/**
|
|
* @package Campcaster
|
|
* @subpackage StorageServer
|
|
* @copyright 2010 Sourcefabric O.P.S.
|
|
* @license http://www.gnu.org/licenses/gpl.txt
|
|
*/
|
|
class M3uPlaylistBodyElement {
|
|
function convert2lspl(&$tree, $ind='')
|
|
{
|
|
$ind2 = $ind.INDCH;
|
|
if ($tree->name != 'body') {
|
|
return PEAR::raiseError("M3uPlaylist::parse: body tag expected");
|
|
}
|
|
if (isset($tree->children[1])) {
|
|
return PEAR::raiseError(sprintf(
|
|
"M3uPlaylist::parse: unexpected tag %s in tag body",
|
|
$tree->children[1]->name
|
|
));
|
|
}
|
|
$res = M3uPlaylistParElement::convert2lspl($tree->children[0], $ind2);
|
|
if (PEAR::isError($res)) {
|
|
return $res;
|
|
}
|
|
$gunid = StoredFile::CreateGunid();
|
|
$playlength = '???'; // ***
|
|
$res = "$ind<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
|
|
"$ind<playlist id=\"$gunid\" playlength=\"$playlength\" title=\"\">\n".
|
|
"$ind2<metadata/>\n".
|
|
"$res".
|
|
"$ind</playlist>\n";
|
|
return $res;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @package Campcaster
|
|
* @subpackage StorageServer
|
|
* @copyright 2010 Sourcefabric O.P.S.
|
|
* @license http://www.gnu.org/licenses/gpl.txt
|
|
*/
|
|
class M3uPlaylistParElement {
|
|
function convert2lspl(&$tree, $ind='')
|
|
{
|
|
if ($tree->name != 'par') {
|
|
return PEAR::raiseError("M3uPlaylist::parse: par tag expected");
|
|
}
|
|
$res = '';
|
|
foreach ($tree->children as $i => $ch) {
|
|
$ch =& $tree->children[$i];
|
|
$r = M3uPlaylistAudioElement::convert2lspl($ch, $ind.INDCH);
|
|
if (PEAR::isError($r)) {
|
|
return $r;
|
|
}
|
|
$res .= $r;
|
|
}
|
|
return $res;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @package Campcaster
|
|
* @subpackage StorageServer
|
|
* @copyright 2010 Sourcefabric O.P.S.
|
|
* @license http://www.gnu.org/licenses/gpl.txt
|
|
*/
|
|
class M3uPlaylistAudioElement {
|
|
function convert2lspl(&$tree, $ind='')
|
|
{
|
|
$ind2 = $ind.INDCH;
|
|
if ($tree->name != 'audio') {
|
|
return PEAR::raiseError("M3uPlaylist::parse: audio tag expected");
|
|
}
|
|
if (isset($tree->children[2])) {
|
|
return PEAR::raiseError(sprintf(
|
|
"M3uPlaylist::parse: unexpected tag %s in tag audio",
|
|
$tree->children[2]->name
|
|
));
|
|
}
|
|
$res = ''; $fadeIn = 0; $fadeOut = 0;
|
|
foreach ($tree->children as $i => $ch) {
|
|
$ch =& $tree->children[$i];
|
|
$r = M3uPlaylistAnimateElement::convert2lspl($ch, $ind2);
|
|
if (PEAR::isError($r)) {
|
|
return $r;
|
|
}
|
|
switch ($r['type']) {
|
|
case "fadeIn":
|
|
$fadeIn = $r['val'];
|
|
break;
|
|
case "fadeOut":
|
|
$fadeOut = $r['val'];
|
|
break;
|
|
}
|
|
}
|
|
if ($fadeIn > 0 || $fadeOut > 0) {
|
|
$fadeIn = Playlist::secondsToPlaylistTime($fadeIn);
|
|
$fadeOut = Playlist::secondsToPlaylistTime($fadeOut);
|
|
$fInfo = "$ind2<fadeInfo fadeIn=\"$fadeIn\" fadeOut=\"$fadeOut\"/>\n";
|
|
} else {
|
|
$fInfo = '';
|
|
}
|
|
$plElGunid = StoredFile::CreateGunid();
|
|
$aGunid = StoredFile::CreateGunid();
|
|
$title = basename($tree->attrs['src']->val);
|
|
$offset = Playlist::secondsToPlaylistTime($tree->attrs['begin']->val);
|
|
$playlength = '???'; # ***
|
|
$res = "$ind<playlistElement id=\"$plElGunid\" relativeOffset=\"$offset\">\n".
|
|
"$ind2<audioClip id=\"$aGunid\" playlength=\"$playlength\" title=\"$title\"/>\n".
|
|
$fInfo.
|
|
"$ind</playlistElement>\n";
|
|
return $res;
|
|
}
|
|
} // class M3uPlaylistAudioElement
|
|
|
|
|
|
/**
|
|
* @package Campcaster
|
|
* @subpackage StorageServer
|
|
* @copyright 2010 Sourcefabric O.P.S.
|
|
* @license http://www.gnu.org/licenses/gpl.txt
|
|
*/
|
|
class M3uPlaylistAnimateElement {
|
|
function convert2lspl(&$tree, $ind='') {
|
|
if ($tree->name != 'animate') {
|
|
return PEAR::raiseError("M3uPlaylist::parse: animate tag expected");
|
|
}
|
|
if ($tree->attrs['attributeName']->val == 'soundLevel' &&
|
|
$tree->attrs['from']->val == '0%' &&
|
|
$tree->attrs['to']->val == '100%' &&
|
|
$tree->attrs['calcMode']->val == 'linear' &&
|
|
$tree->attrs['fill']->val == 'freeze' &&
|
|
$tree->attrs['begin']->val == '0s' &&
|
|
preg_match("|^([0-9.]+)s$|", $tree->attrs['end']->val, $va)
|
|
) {
|
|
return array('type'=>'fadeIn', 'val'=>$va[1]);
|
|
}
|
|
if ($tree->attrs['attributeName']->val == 'soundLevel' &&
|
|
$tree->attrs['from']->val == '100%' &&
|
|
$tree->attrs['to']->val == '0%' &&
|
|
$tree->attrs['calcMode']->val == 'linear' &&
|
|
$tree->attrs['fill']->val == 'freeze' &&
|
|
preg_match("|^([0-9.]+)s$|", $tree->attrs['begin']->val, $vaBegin) &&
|
|
preg_match("|^([0-9.]+)s$|", $tree->attrs['end']->val, $vaEnd)
|
|
) {
|
|
return array('type'=>'fadeOut', 'val'=>($vaEnd[1] - $vaBegin[1]));
|
|
}
|
|
return PEAR::raiseError(
|
|
"M3uPlaylistAnimateElement::convert2lspl: animate parameters too general"
|
|
);
|
|
}
|
|
}
|
|
|
|
?>
|