/backend/class-node.php
PHP | 1744 lines | 1186 code | 156 blank | 402 comment | 437 complexity | b73a24c1d3c98448504b8431b89d0679 MD5 | raw file
- <?php if (!defined(JZ_SECURE_ACCESS)) die ('Security breach detected.');
- /**
- * - JINZORA | Web-based Media Streamer -
- *
- * Jinzora is a Web-based media streamer, primarily desgined to stream MP3s
- * (but can be used for any media file that can stream from HTTP).
- * Jinzora can be integrated into a CMS site, run as a standalone application,
- * or integrated into any PHP website. It is released under the GNU GPL.
- *
- * - Resources -
- * - Jinzora Author: Ross Carlson <ross@jasbone.com>
- * - Web: http://www.jinzora.org
- * - Documentation: http://www.jinzora.org/docs
- * - Support: http://www.jinzora.org/forum
- * - Downloads: http://www.jinzora.org/downloads
- * - License: GNU GPL <http://www.gnu.org/copyleft/gpl.html>
- *
- * - Contributors -
- * Please see http://www.jinzora.org/modules.php?op=modload&name=jz_whois&file=index
- *
- * - Code Purpose -
- * These are the classes extended by the backend adaptors.
- *
- * @since 05.10.04
- * @author Ben Dodson <bdodson@seas.upenn.edu>
- */
-
- class jzMediaNodeClass extends jzMediaElement {
- var $natural_depth; // if the level before us is 'hidden'
-
- /**
- * Constructor for a jzMediaNodeClass
- *
- * @author Ben Dodson
- * @version 5/14/04
- * @since 5/14/04
- */
- function jzMediaNodeClass($par = array(),$mode = "path") {
- $this->_constructor($par,$mode);
- }
- function _constructor($par = array(),$mode) {
- $this->natural_depth = 1;
- parent::_constructor($par,$mode);
- }
- /**
- * Returns the type of the node.
- *
- * @author Ben Dodson
- * @version 10/31/04
- * @since 10/31/04
- */
- function getType() {
- return "jzMediaNode";
- }
-
- /**
- * Gets the 'natural depth' of this node.
- * This has no real purpose outside of the class.
- *
- * @author Ben Dodson
- * @version 5/21/04
- * @since 5/21/04
- */
- function getNaturalDepth() {
- return $this->natural_depth;
- }
-
- /**
- * Sets the natural depth (for searching, counting etc.) of this node.
- * Useful if the node is preceded by a hidden level.
- *
- * @author Ben Dodson
- * @version 5/14/04
- * @since 5/14/04
- */
- function setNaturalDepth($n) {
- $this->natural_depth = $n;
- }
- /**
- * Counts the number of subnodes $distance steps down of type $type.
- * $distance = -1 means do it recursively.
- *
- * @author Ben Dodson
- * @version 5/14/04
- * @since 5/14/04
- */
- function getSubNodeCount($type='both', $distance = false) {
-
- if ($distance === false) {
- $distance = $this->getNaturalDepth();
- }
- // alias:
- if ($type == "tracks") {
- $type = "leaves";
- }
- // EASY METHOD:
- return sizeof($this->getSubNodes($type,$distance,true,0)); // $random = true is faster than sorting.
- // POSSIBLE TODO 1) make another cache for counting.
- // POSSIBLE TODO 2) don't return the array; just count as you go.
- }
- /**
- * Returns the subnodes as an array. A $distance of -1 means do it recursively.
- *
- * @author Ben Dodson
- * @version 6/4/04
- * @since 6/4/04
- */
- function getSubNodes($type='nodes',$distance=false, $random=false, $limit=0, $hasArt = false, $offset=false) {
-
- if ($distance === false) {
- $distance = $this->getNaturalDepth();
- }
-
- // alias:
- if ($type == "tracks") {
- $type = "leaves";
- }
-
- // 2 cases:
- $search = array();
- $vals = array();
-
- // 1) recursive
- if ($distance <= 0) {
- $node = $this;
- $search[] = $node;
- while ($search != array()) {
- $node = array_pop($search);
- $cache = $node->readCache("nodes");
- if ($nodearray = $cache[7]) {
- foreach ($nodearray as $name) {
- $search[] = &new jzMediaNode($node->getPath("String") . "/" . $name);
-
- if ($type == "nodes" || $type == "both") {
- $me = new jzMediaNode($node->getPath("String") . "/" . $name);
- if ($hasArt) {
- if ($me->getMainArt() != "-" && $me->getMainArt() !== false)
- $vals[] = $me;
- } else {
- $vals[] = $me;
- }
- }
- }
- }
- if ($type == "leaves" || $type == "both") {
- if ($trackarray = $cache[8]) {
- foreach ($trackarray as $track) {
- $vals[] = &new jzMediaTrack($node->getPath("String") . "/" . $track);
- }
- }
- }
- }
- }
- // 2: not.
- else {
- $i = 1;
- $node = $this;
- $search[] = $node;
- while ($distance != $i) {
- $i++;
- $temp = array();
- while ($search != array()) {
- $node = array_pop($search);
- $cache = $node->readCache("nodes");
- if ($nodearray = $cache[7]) {
- foreach ($nodearray as $name) {
- $temp[] = &new jzMediaNode($node->getPath("String") . "/" . $name);
- }
- }
- }
- $search = $temp;
- }
- foreach ($search as $node) {
- $cache = $node->readCache("nodes");
- if ($type == "both" || $type == "nodes") {
- if ($nodearray = $cache[7]) {
- foreach ($nodearray as $name) {
- $me = new jzMediaNode($node->getPath("String") . "/" . $name);
- if ($hasArt) {
- if ($me->getMainArt() != "-" && $me->getMainArt() !== false) {
- $vals[] = $me;
- }
- } else {
- $vals[] = $me;
- }
- }
- }
- }
- if ($type == "both" || $type == "leaves") {
- if ($trackarray = $cache[8]) {
- foreach ($trackarray as $track) {
- $vals[] = &new jzMediaTrack($node->getPath("String") . "/" . $track);
- }
- }
- }
- }
-
- }
- if ($random === true) {
- srand((float)microtime() * 1000000);
- shuffle($vals);
- }
- else if ($random === false) {
- usort($vals, "compareNodes");
- }
- else {
- // do nothing.
- }
- if ($limit > 0 && $limit < sizeof($vals)) {
- $final = array();
- for ($i = 0; $i < $limit; $i++) {
- $final[] = $vals[$i];
- }
- return $final;
- }
- else {
- return $vals;
- }
- }
-
- /**
- * Returns the 'top' subnodes. $distance = -1 is recursive.
- *
- * $top_type is one of:
- * most-played, best-rated
- *
- * @author
- * @version
- * @since
- */
- function getTopSubNodes($type='nodes',$top_type='most-played', $distance=false, $limit=0) {
- if ($distance === false) {
- $distance = $this->getNaturalDepth();
- }
- // alias:
- if ($type == "tracks") {
- $type = "leaves";
- }
- }
-
- /**
- * Returns the subnode named $name.
- *
- * @author Ben Dodson
- * @version 5/16/04
- * @since 5/16/04
- */
- function getSubNode($name) {
- $p = $this->path;
- $p[] = $name;
- // TODO: check for jzMediaTrack or jzMediaNode?
- // I'm not sure how needed this function is anyways...
- return jzMediaElement($p);
-
- }
- /**
- * Completely handles a power search
- *
- * @author Ben Dodson
- * @since 4/6/05
- * @version 4/6/05
- *
- **/
- function powerSearch() {
- $roots = array();
- $roots[] = $this;
- // Exploit our hierarchical design.
- // A relational database should handle this search differently.
- if (isset($_POST['genre']) && $_POST['genre'] != "") {
- $roots = $this->search($_POST['genre'],"nodes",distanceTo("genre",$this));
- }
- if (isset($_POST['artist']) && $_POST['artist'] != "") {
- $new_roots = array();
- foreach ($roots as $r) {
- $new_roots = $new_roots + $r->search($_POST['artist'],"nodes",distanceTo("artist",$r));
- }
- $roots = $new_roots;
- }
- if (isset($_POST['album']) && $_POST['album'] != "") {
- $new_roots = array();
- foreach ($roots as $r) {
- $new_roots = $new_roots + $r->search($_POST['album'],"nodes",distanceTo("album",$r));
- }
- $roots = $new_roots;
- }
- // If nothing in their query is track-specifc, we are done.
- if (powerSearchType() != "tracks") {
- return $roots;
- }
- $results = array();
- $metasearch = getSearchMeta();
- foreach ($roots as $r) {
- $results = $results + $r->search($_POST['song_title'],"tracks",-1,0,$_POST['operator'],$metasearch);
- }
-
- return $results;
- }
- /**
- * Searches a specified level for elements.
- * The level is -1 for any level.
- * These parameters may change before the coding gets done.
- * The 'op' is one of: and|or|exact
- * If it is 'exact', the search term should be a string.
- *
- * @author Ben Dodson
- * @version 9/21/04
- * @since 9/20/04
- */
- function search($searchArray2, $type='both', $depth = -1, $limit = 0, $op = "and", $metasearch = array(), $exclude = array()) {
- // for now, no search by id:
- if ($type == "id") {
- return array();
- }
- // alias:
- if ($type == "tracks") {
- $type = "leaves";
- }
-
- if ($depth === false) {
- $depth = $this->getNaturalDepth();
- }
-
- // allow strings as well as arrays for searching:
- if (is_string($searchArray2) && $op != "exact") {
- if (stristr($searchArray2,"\"") === false) {
- if ($searchArray2 == "")
- $searchArray = array();
- else {
- $searchArray = explode(" ",$searchArray2);
- }
- }
- else { // gets nasty..
- $open_quote = false;
- $searchArray = array();
- $word = "";
- for ($i = 0; $i < strlen($searchArray2); $i++) {
- if ($searchArray2[$i] == ' ' && $open_quote == false) {
- $searchArray[] = $word;
- $word = "";
- }
- else if ($searchArray2[$i] == '"') {
- $open_quote = !$open_quote;
- }
- else {
- $word .= $searchArray2[$i];
- }
- }
- if ($word != "") {
- $searchArray[] = $word;
- }
- }
- } else {
- $searchArray = $searchArray2;
- }
- // Exclude array, too:
- if (is_string($exclude)) {
- if ($exclude == "") {
- $excludeArray = array();
- }
- else if (stristr($exclude,"\"") === false) {
- if ($exclude == "") {
- $excludeArray = array();
- } else {
- $excludeArray = explode(" ",$exclude);
- }
- }
- else { // gets nasty..
- $open_quote = false;
- $excludeArray = array();
- $word = "";
- for ($i = 0; $i < strlen($exclude); $i++) {
- if ($exclude[$i] == ' ' && $open_quote == false) {
- $excludeArray[] = $word;
- $word = "";
- }
- else if ($exclude[$i] == '"') {
- $open_quote = !$open_quote;
- }
- else {
- $word .= $exclude[$i];
- }
- }
- if ($word != "") {
- $excludeArray[] = $word;
- }
- }
- } else {
- $excludeArray = $exclude;
- }
-
- // Clean up:
- $tmp = array();
- if (is_array($searchArray)) {
- foreach ($searchArray as $term) {
- if (!($term == "" || $term == " ")) {
- $tmp[] = $term;
- }
- }
- $searchArray = $tmp;
- }
- $tmp = array();
- foreach ($excludeArray as $term) {
- if (!($term == "" || $term == " ")) {
- $tmp[] = $term;
- }
- }
- $excludeArray = $tmp;
-
- // LYRICS SEARCHING: different kind of search.
- if ($type == "lyrics") {
- $matches = array();
- $kids = $this->getSubNodes("tracks",$depth,"leave",0);
- foreach ($kids as $kid) {
- $meta = $kid->getMeta();
- $path = $kid->getPath("String");
- if ($op == "exact") {
- if (stristr($meta['lyrics'], $searchArray2) !== false) {
- $matches[] = $kid;
- }
- } else if ($op == "or") {
- $valid = true;
- if ($excludeArray != array()) {
- foreach($excludeArray as $word) {
- if (stristr($meta['lyrics'],$word) !== false) {
- $valid = false;
- }
- }
- }
- if ($valid) {
- if (sizeof($searchArray) == 0) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- else {
- foreach($searchArray as $word) {
- if (stristr($meta['lyrics'],$word) !== false) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- }
- }
- }
- } else { // $op == "and"
- $possible_match = false;
- $all_words = true;
- $valid = true;
- if ($excludeArray != array()) {
- foreach($excludeArray as $word) {
- if (stristr($meta['lyrics'],$word) !== false) {
- $valid = false;
- }
- }
- }
- if ($valid) {
- if (sizeof($searchArray) == 0) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- else {
- foreach($searchArray as $word) {
- if (stristr($meta['lyrics'],$word) !== false) {
- $possible_match = true;
- }
- else if (stristr($path,$word) === false) {
- $all_words = false;
- }
- }
- }
- if ($possible_match && $all_words) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- }
- }
- }
- return $matches;
- }
- $kids = $this->getSubNodes($type,$depth,"leave",0);
- // don't sort our nodes, because it takes time.
- // but don't randomize either.
- $matches = array();
- foreach ($kids as $kid) {
- $path = $kid->getPath("String");
- $pathArray = $kid->getPath();
- // NOTE: The 'name' of the child is taken from the filename,
- // NOT from the ID3 or any other metadata method.
- // This is currently (9/21/04) DIFFERENT than what $this->getName() returns
- // ..and it is MUCH faster!!
- $name = $pathArray[sizeof($pathArray)-1];
- // op == 'exact'
- if ($op == "exact") {
- if ($name == $searchArray2) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- // op == 'or'
- } else if ($op == "or") {
- $valid = true;
- if ($excludeArray != array()) {
- foreach($excludeArray as $word) {
- if (stristr($name,$word) !== false) {
- $valid = false;
- }
- }
- }
- if ($valid) {
- if (sizeof($searchArray) == 0) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- else {
- foreach($searchArray as $word) {
- if (stristr($name,$word) !== false) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- }
- }
- }
- }
- else { // "and"
- $possible_match = false;
- $all_words = true;
- $valid = true;
- if ($excludeArray != array()) {
- foreach($excludeArray as $word) {
- if (stristr($name,$word) !== false) {
- $valid = false;
- }
- }
- }
- if ($valid) {
- if (sizeof($searchArray) == 0) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- else {
- foreach($searchArray as $word) {
- if (stristr($name,$word) !== false) {
- $possible_match = true;
- }
- else if (stristr($path,$word) === false) {
- $all_words = false;
- }
- }
- }
- if ($possible_match && $all_words) {
- $matches[] = $kid;
- if ($limit > 0 && sizeof($matches) >= $limit) {
- return $matches;
- }
- }
- }
- }
- }
- if ($metasearch != array() && $type == "leaves") {
- $matches = filterSearchResults($matches,$metasearch);
- }
- return $matches;
- }
-
-
- /**
- * Updates the cache using this node as a base.
- *
- * @author Ben Dodson
- * @version 6/7/04
- * @since 5/17/04
- */
- function updateCache($recursive = true, $root = false, $showStatus = false, $readID3 = true) {
- /* Serialized array:
- * nodes/path---to---node:
- * (root is called jzroot)
- * See backend.php.
- */
- $this->updateCacheHelper($recursive, $this->getNaturalDepth()-1, $root, $showStatus, $readID3);
- $be = &new jzBackend();
- $be->setUpdated();
- }
-
- function updateCacheHelper($recursive, $levelsLeft, $root, $showStatus, $readID3) {
- global $audio_types, $video_types, $ext_graphic, $default_art, $backend,
- $track_num_seperator, $hierarchy, $protocols;
- if ($root !== false)
- $mediapath = $root;
- else
- $mediapath = $this->getFilePath();
- if ($mediapath == "-") { // let's find it..
- $parent = $this->getParent();
- $mediapath = $parent->getFilePath() . "/" . $this->getName();
- }
- $nodepath = $this->getPath("String");
-
- /* Echo out our current status, if they want it: */
- if ($showStatus === true) {
- showStatus($mediapath);
- } else if ($showStatus == "cli") {
- echo word("Scanning: ") . $mediapath . "\n";
- }
-
- // First add $this.
- // Was I already cached?
- $cache = $this->readCache();
-
- if ($cache[0] == "-") { $cache[0] = $nodepath; }
- if ($cache[13] == "-") { $cache[13] = $mediapath; }
- if ($cache[6] == "-") { $cache[6] = jz_filemtime($mediapath); }
- if ($cache[15] == "-") {
- $ptype = findPType($this);
- $cache[15] = $ptype;
- }
- $blankfilecache = blankCache("track");
- // Recurse and add $this's media files.
- if (!($handle = opendir($mediapath)))
- die("Could not access directory $mediapath");
-
- // scan for info while going through directory:
- $trackcount = 0;
- $new_nodes = $cache[7];
- $new_tracks = $cache[8];
- $bestImage = "";
- $bestDescription = "";
- while ($file = readdir($handle)) {
- $childpath = ($nodepath == "") ? $file : $nodepath . "/" . $file;
- $fullchildpath = $mediapath . "/" . $file;
- if ($file == "." || $file == "..") {
- continue;
- }
- else if (is_dir($fullchildpath)) {
- if ($recursive) {
- $next = &new jzMediaNode($childpath);
- $next->updateCacheHelper(true,$levelsLeft, $fullchildpath,$showStatus,$readID3);
- } else {
- if ($levelsLeft === false && $this->getNaturalDepth() > 1) {
- $next = &new jzMediaNode($childpath);
- $next->updateCacheHelper(false,$this->getNaturalDepth()-2,$fullchildpath,$showStatus,$readID3);
- } else if ($levelsLeft > 0) {
- $next = &new jzMediaNode($childpath);
- $next->updateCacheHelper(false,$levelsLeft-1,$fullchildpath,$showStatus,$readID3);
- }
- }
- if ($new_nodes != array()) {
- $key = array_search($file,$new_nodes);
- if (false === $key) {
- $new_nodes[] = $file;
- $next = &new jzMediaNode($childpath);
- }
- } else {
- $new_nodes[] = $file;
- $next = &new jzMediaNode($childpath);
- }
-
- }
- else {
- if (preg_match("/\.(txt)$/i", $file)) {
- // TODO: GET THE CORRECT DESCRIPTION IN $bestDescription
- // $bestDescription = $fullchildpath;
-
- }
- else if (preg_match("/\.($ext_graphic)$/i", $file) && !stristr($file,".thumb.")) {
- // An image
- if (@preg_match("/($default_art)/i",$file)) {
- $bestImage = $fullchildpath;
- }
- else if ($bestImage == "") {
- $bestImage = $fullchildpath;
- }
- }
- else if (preg_match("/\.($audio_types)$/i", $file)
- || preg_match("/\.($video_types)$/i", $file)) {
- //* * * A track * * * *//
- // Add it to the track list.
- if ($new_tracks != array()) {
- $key = array_search($file,$new_tracks);
- if (false === $key) {
- $new_tracks[] = $file;
- }
- } else {
- $new_tracks[] = $file;
- }
-
- // And at it's details..
- $childnode = &new jzMediaTrack($childpath);
- if (($cache[2] == "-" || $cache[2] < date("U",jz_filemtime($fullchildpath))) || !$childnode->readCache()) {
- // Add as a new/updated track.
-
- $filecache[$trackcount] = $childnode->readCache();
- if ($filecache[$trackcount][0] == "-") {
- $filecache[$trackcount][0] = $fullchildpath;
- $filecache[$trackcount][6] = jz_filemtime($fullchildpath);
- $filecache[$trackcount][2] = $file;
- }
- //////////
- // META //
- //////////
-
- $track = &new jzMediaTrack($childpath);
- $track->playpath = $fullchildpath;
- if ($readID3 === true) {
- $meta = $track->getMeta("file"); // read meta info from the file;
- } else {
- $meta = array();
- }
-
-
- $filecache[$trackcount][7] = $meta['title'];
- $filecache[$trackcount][8] = $meta['frequency'];
- $filecache[$trackcount][9] = $meta['comment'];
- $filecache[$trackcount][11] = $meta['year'];
- $filecache[$trackcount][13] = $meta['size'];
- $filecache[$trackcount][14] = $meta['length'];
- $filecache[$trackcount][15] = $meta['genre'];
- $filecache[$trackcount][16] = $meta['artist'];
- $filecache[$trackcount][17] = $meta['album'];
- $filecache[$trackcount][18] = $meta['type'];
- $filecache[$trackcount][19] = $meta['lyrics'];
- $filecache[$trackcount][20] = $meta['bitrate'];
- $filecache[$trackcount][21] = $meta['number'];
-
- // Now let's see if there is a description file...
- $desc_file = str_replace(".". $meta['type'],"",$fullchildpath). ".txt";
- $long_description = "";
- if (is_file($desc_file) and filesize($desc_file) <> 0){
- // Ok, let's read the description file
- $handle2 = fopen($desc_file, "rb");
- $filecache[$trackcount][10] = fread($handle2, filesize($desc_file));
- fclose($handle2);
- } else {
- $filecache[$trackcount][10] = "";
- }
- // Now let's see if there is a thumbnail for this track
- $filecache[$trackcount][1] = searchThumbnail($fullchildpath);
- } else {
- // slow but necessary..
- //$filecache[$trackcount] = $childnode->readCache();
- }
- $trackcount++;
-
- // Let's track this
- writeLogData('importer',"Importing track: ". $fullchildpath);
- $_SESSION['jz_import_full_progress']++;
- }
- }
- }
- if ($new_nodes != array()) {
- foreach ($new_nodes as $i => $my_path) {
- $me = &new jzMediaNode($nodepath . "/" . $my_path);
- if ($me->getFilePath() == "-") {
- $arr = explode("/",$my_path);
- $mfp = $this->getFilePath() . "/" . $arr[sizeof($arr)-1];
- } else {
- $mfp = $me->getFilePath();
- }
- if (!is_dir($mfp)) {
- // TODO: The commented out part should check to see if there are 'permanent' subnodes.
- // It is possible a directory was created to house links (and does not have
- // any data on the filesystem)
- $remove_me = true;
- $list = $me->getSubNodes("tracks",-1);
- foreach ($list as $el) {
- if (stristr($el->getFilePath(),"://")) {
- $remove_me = false;
- break;
- }
- }
- if ($remove_me) {
- $me->deleteCache();
- unset($new_nodes[$i]);
- }
- }
- }
- }
- if ($new_tracks != array()) {
- foreach ($new_nodes as $i => $my_path) {
- $me = &new jzMediaTrack($nodepath . "/" . $my_path);
- if (!is_file($fpath = $me->getFilePath())) {
- $valid = false;
- $parr = explode("|",$protocols);
- if (strlen($fpath) > 2) {
- foreach ($parr as $p) {
- if (stristr($fpath,$p) !== false) {
- $valid = true;
- }
- }
- }
- if (!$valid) {
- $me->deleteCache();
- unset($new_tracks[$i]);
- }
- }
- }
- }
-
-
- // Update $this
- if ($bestImage != "") {
- $cache[1] = $bestImage;
- }
- if ($bestDescription != "") {
- $cache[10] = file_get_contents($bestDescription);
- }
- $cache[2] = date("U");
- natcasesort($new_nodes);
- $cache[7] = array_values($new_nodes);
- natcasesort($new_tracks);
- $cache[8] = array_values($new_tracks);
- // * * * * * * * *
- // Write the cache.
- $this->writeCache($cache,"nodes");
- if ($filecache != array()) {
- $this->writeCache($filecache,"tracks");
- }
- }
- /**
- * Returns whether or not this is a leaf (which it isn't)
- *
- * @author Laurent Perrin
- * @version 5/10/04
- * @since 5/10/04
- */
- function isLeaf() { return false; }
- /**
- * Returns the nodes starting with the specified letter.
- * if $letter is "#" it returns nodes that don't start with a-z.
- * if $letter is "*" it returns all nodes.
- *
- * @author Ben Dodson <bdodson@seas.upenn.edu>
- * @version 6/4/04
- * @since 5/11/04
- */
- function getAlphabetical($letter, $type = "nodes", $depth = false) {
- if ($depth === false) {
- $depth = $this->getNaturalDepth();
- }
- if ($depth == 0) {
- $first = strtolower(substr($this->getName(),0,1));
- $letter = strtolower($letter);
- if ($letter == "#") {
- if (!('a' <= $first && $first <= 'z')) {
- return array($this);
- }
- } else if ($letter == "*") {
- return array($this);
- }
- else { // standard case
- if ($letter == $first) {
- return array($this);
- }
- }
- }
- else {
- $array = array();
- foreach ($this->getSubNodes() as $subnode) {
- if (!$subnode->isLeaf()) {
- if (($arr = $subnode->getAlphabetical($letter, $type,$depth - 1)) != array()) {
- foreach ($arr as $item) {
- $array[] = $item;
- }
- }
- }
- }
- usort($array,"compareNodes");
- return $array;
- }
- }
-
- /**
- * Marks this node as 'featured.'
- *
- * @author Ben Dodson
- * @version 6/8/04
- * @since 6/8/04
- */
- function addFeatured() {
- // Just 1 cache: from the root node.
- $root = &new jzMediaNode();
- $cache = $root->readCache("featured");
- $cache[] = $this->getPath("String");
- $root->writeCache($cache, "featured");
- }
-
- /**
- * Checks to see if this node is featured
- *
- * @author Ben Dodson
- * @version 6/8/04
- * @since 6/8/04
- */
- function isFeatured() {
- $root = &new jzMediaNode();
- $path = $this->getPath("String");
- $cache = $root->readCache("featured");
- for ($i = 0; $i < sizeof($cache); $i++) {
- if ($cache[$i] == $path) {
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Removes this node from the featured list.
- *
- * @author Ben Dodson
- * @version 6/8/04
- * @since 6/8/04
- */
- function removeFeatured() {
- $root = &new jzMediaNode();
- $path = $this->getPath("String");
- $cache = $root->readCache("featured");
- for ($i = 0; $i < sizeof($cache); $i++) {
- if ($cache[$i] == $path) {
- $cache[$i] = $cache[sizeof($cache)-1];
- unset($cache[sizeof($cache)-1]);
- $root->writeCache($cache, "featured");
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns featured nodes. Limit 0 means get them all.
- * Order is random.
- *
- * @author Ben Dodson
- * @version 6/8/04
- * @since 6/8/04
- */
- function getFeatured($distance = -1, $limit = 1) {
- $root = &new jzMediaNode();
- $cache = $root->readCache("featured");
- $path = $this->getPath("String");
- $level = $this->getLevel();
- $vals = array();
- $i = 0;
-
- if ($distance === false) {
- $distance = $this->getNaturalDepth();
- }
-
- if (sizeof($cache) == 0) { return false; }
-
- srand((float) microtime() * 10000000);
- $keys = array_rand($cache,sizeof($cache));
-
- if (!is_array($keys)) {
- // only 1 key:
- $keys = array($keys);
- }
-
- foreach ($keys as $key) {
- $temp = $cache[$key];
- if ($path == "" || (strpos($temp, $path) == 0 && strpos($temp, $path) !== false && $temp != $path)) {
- $temp2 = &new jzMediaNode($temp);
- if ($distance <= 0 || $temp2->getLevel() - $level == $distance) {
- $vals[$i] = $temp2;
- $i++;
- if ($i >= $limit) {
- return $vals;
- }
- }
- }
- }
- return $vals;
-
- }
-
-
- /**
- * Adds a request. $type is either 'request' or 'broken.'
- *
- *
- * @author Ben Dodson
- * @version 9/1/04
- * @since 9/1/04
- */
- function addRequest($entry, $comment, $user, $type = "request") {
- // Just 1 cache: from the root node.
- $root = &new jzMediaNode();
- $cache = $root->readCache("request");
-
- $new = array();
- $new['entry'] = $entry;
- $new['comment'] = $comment;
- $new['user'] = $user;
- $new['type'] = strtolower($type);
- $new['id'] = md5($entry . $comment . $user . $type);
- $new['path'] = $this->getPath("String");
-
- $cache[] = $new;
- $root->writeCache($cache, "request");
- }
-
-
- /**
- * Gets requests. Default is to do so recursively and return all types.
- * Returns results as an array with the following fields:
- * entry,comment,user,type,id,path
- *
- * Path is the parent path for the request.
- * Type is the type of the request, currently 'broken' or 'request'
- *
- * @author Ben Dodson
- * @version 9/1/04
- * @since 9/1/04
- */
- function getRequests($distance = -1, $type = "all") {
- $root = &new jzMediaNode();
- $cache = $root->readCache("request");
- $path = $this->getPath("String");
- $level = $this->getLevel();
- $results = array();
-
- if (sizeof($cache) == 0) { return false; }
-
- for ($i = 0; $i < sizeof($cache); $i++) {
-
- if (strtolower($type) == "all" || strtolower($type) == $cache[$i]['type']) {
- $temp = $cache[$i]['path'];
- $tnode = &new jzMediaNode($temp);
- if ($path == "" || (strpos($temp, $path) == 0 && strpos($temp, $path) !== false)) {
- if ($distance <= 0) {
- $results[] = $cache[$i];
- }
- else if ($tnode->getLevel() - $level == $distance) {
- $results[] = $cache[$i];
- }
- }
- }
- }
- return $results;
- }
-
-
- /**
- * Removes request with id $id. (from getRequests['id']).
- *
- *
- * @author Ben Dodson
- * @version 9/1/04
- * @since 9/1/04
- */
- function removeRequest($id) {
- $root = &new jzMediaNode();
- $cache = $root->readCache("request");
- for ($i = 0; $i < sizeof($cache); $i++) {
- if ($cache[$i]['id'] == $id) {
- $cache[$i] = $cache[sizeof($cache)-1];
- unset($cache[sizeof($cache)-1]);
- $root->writeCache($cache, "request");
- return true;
- }
- }
- return false;
- }
-
- /**
- * Adds link to the given node.
- *
- *
- * @author Ben Dodson
- * @version 9/18/04
- * @since 9/18/04
- */
- function addLink ($node) {
- $cache = $this->readCache();
- $linkarray = $cache[14];
- $count = sizeof($linkarray);
-
-
- // let's not add it twice.
- $path = $node->getPath("String");
- $type = ($node->isLeaf()) ? 'leaf' : 'node';
- for ($i = 0; $i < $count; $i++) {
- if ($linkarray[$i]['path'] == $path && $linkarray[$i]['type'] == $type) {
- return true;
- }
- }
-
-
- $linkarray[$count]['path'] = $node->getPath("String");
- if ($node->isLeaf()) {
- $linkarray[$count]['type'] = 'leaf';
- }
- else {
- $linkarray[$count]['type'] = 'node';
- }
- $cache[14] = $linkarray;
- $this->writeCache($cache);
- }
-
- /**
- * Removes the link to the given node.
- *
- *
- * @author Ben Dodson
- * @version 9/18/04
- * @since 9/18/04
- */
- function removeLink ($node) {
- $cache = $this->readCache();
- $linkarray = $cache[14];
- $newlinkarray = array();
- $count = sizeof($linkarray);
-
- $path = $node->getPath("String");
- $type = ($node->isLeaf()) ? 'leaf' : 'node';
-
- for ($i = 0; $i < $count; $i++) {
- if (!($linkarray[$i]['path'] == $path && $linkarray[$i]['type'] == $type)) {
- $newlinkarray[] = $linkarray[$i];
- }
- }
- $cache[14] = $newlinkarray;
- $this->writeCache($cache);
- }
-
-
- /**
- * Gets the node's links.
- *
- *
- * @author Ben Dodson
- * @version 9/18/04
- * @since 9/18/04
- */
- function getLinks($type = 'both') {
- $cache = $this->readCache();
- $linkarray = $cache[14];
- $return = array();
- // alias:
- if ($type == "tracks") {
- $type = "leaves";
- }
-
- for ($i = 0; $i < sizeof($linkarray); $i++) {
- if ($linkarray[$i]['type'] == 'node') {
- if ($type == 'both' || $type == 'nodes') {
- $return[] = &new jzMediaNode($linkarray[$i]['path']);
- }
- }
- if ($linkarray[$i]['type'] == 'leaf') {
- if ($type == 'both' || $type == 'leaves') {
- $return[] = &new jzMediaTrack($linkarray[$i]['path']);
- }
- }
- }
-
- return $return;
- }
-
-
- /**
- * Injects a leaf or a node into $this.
- * Updated parameters for Jinzora 3.0.
- *
- * $pathArray can set the following fields:
- * genre, subgenre, artist, album, disk, track
- * If anything is not set, this function will try and pull
- * the information from $this.
- *
- * @author Ben Dodson
- * @since version - Jul 28, 2006
- */
- function inject($pathArray, $filename, $meta = false) {
-
- if (!isset($pathArray['genre']) && false !== ($info = getInformation($this, "genre"))) {
- $pathArray['genre'] = $info;
- }
- if (!isset($pathArray['subgenre']) && false !== ($info = getInformation($this, "subgenre"))) {
- $pathArray['subgenre'] = $info;
- }
- if (!isset($pathArray['artist']) && false !== ($info = getInformation($this, "artist"))) {
- $pathArray['artist'] = $info;
- }
- if (!isset($pathArray['album']) && false !== ($info = getInformation($this, "album"))) {
- $pathArray['album'] = $info;
- }
- if (!isset($pathArray['disk']) && false !== ($info = getInformation($this, "disk"))) {
- $pathArray['disk'] = $info;
- }
- $mpath = buildPath($pathArray);
- $root = new jzMediaNode();
- $res = $root->oldInject($mpath, $filename);
- if (is_object($res) and $res->isLeaf()) {
- $be = new jzBackend();
- $be->registerFile($filename, $mpath);
- if (is_array($meta) && sizeof($meta) > 0) {
- $res->setMeta($meta,"cache");
- $res->playpath = $filename;
- }
- }
- else if (is_array($meta) && sizeof($meta) > 0) {
- // Update the meta data even if file is already in cache
- $track = &new jzMediaTrack($mpath);
- $track->playpath = $filename;
- $track->setMeta($meta,"cache");
- }
- return $res;
- }
-
- /*
- * Adds tracks in bulk to Jinzora.
- *
- * @author Ben Dodson
- * @since 9/5/04
- */
- function bulkInject($paths,$filenames,$metas) {
- $results = array();
- for ($i = 0; $i < sizeof($paths); $i++) {
- $results[] = $this->inject($paths[$i],$filenames[$i],$metas[$i]);
- }
- return $results;
- }
-
- /**
- * Injects a leaf or a node into $this.
- * If sizeof($path) > 1, does so 'recursively'
- * If the element path is found, do nothing and return false.
- *
- * @author Ben Dodson
- * @version 10/14/04
- * @since 10/14/04
- */
- function oldInject($path, $filepath, $type = "leaf") {
- global $hierarchy;
- if (is_string($path)) {
- // todo: be more flexible (be carefully of '://')
- return false;
- }
- if ($type == "track") {
- $type = "leaf";
- }
- // Handle $path[0].
- if ($path == array()) {
- return false;
- }
- else {
- $rawhead = array_shift($path);
- $head = pathize($rawhead);
- $nextpath = $this->getPath();
- $nextpath[] = $head;
- $nexttrack = &new jzMediaTrack($nextpath);
- $nexttrack->playpath = $filepath;
- $nextnode = &new jzMediaNode($nextpath);
-
- if (file_exists($filepath)) {
- $date = jz_filemtime($filepath);
- } else {
- $date = 0;
- }
- // add $next to cache, add its child, and continue.
-
- $cache = $this->readCache("nodes");
-
- if ($cache[15] == "-") {
- $ptype = findPType($this);
- $cache[15] = $ptype;
- }
-
- if (sizeof($path) == 0 && $type == "leaf") {
- $found = false;
- foreach ($cache[8] as $el) {
- if ($el == $rawhead) {
- return false;
- }
- }
- if (!$found) {
- $cache[8][] = $rawhead;
- }
- natcasesort($cache[8]);
- }
- else {
- $found = false;
- if (!is_array($cache[7])) {
- //print_r($this);
- die();
- }
- foreach ($cache[7] as $el) {
- if (strtolower($el) == strtolower($head)) {
- $found = true;
- }
- }
- if (!$found) {
- $cache[7][] = $head;
- }
- natcasesort($cache[7]);
- }
- $this->writeCache($cache,"nodes");
-
- if (sizeof($path) == 0) { // gets its own cache.
- if ($type == "leaf") {
- $cache = $nexttrack->readCache();
-
- $cache[6] = $date;
- $cache[0] = $filepath;
- $cache[2] = $rawhead;
-
- $nexttrack->playpath = $filepath;
- $nexttrack->writeCache($cache);
- return $nexttrack;
-
- }
- else {
- $cache = $nextnode->readCache();
- $cache[6] = ($cache[6] < $date) ? $date : $cache[6];
-
- // Don't need filepath. Writing to filesystem in id3 mode is stupid-
- // everything will go in the data_dir.
- $nextnode->writeCache($cache);
- return $nextnode;
- }
- }
- else {
- return $nextnode->oldInject($path,$filepath,$type);
- }
- }
- }
-
-
- /**
- * Gets the ptype for this node.
- *
- * @author Ben Dodson
- * @version 10/31/04
- * @since 10/31/04
- */
- function getPType() {
- if ($this->getLevel() == 0) return "root";
- $cache = $this->readCache();
- return $cache[15];
- }
-
-
- /**
- * Sets the ptype for this node.
-
- * @author Ben Dodson
- * @version 10/31/04
- * @since 10/31/04
- */
- function setPType($type) {
- $cache = $this->readCache();
- $cache[15] = $type;
- $this->writeCache($cache);
- }
- /**
- * Adds meta data to all subnodes
- *
- * @author Ben Dodson
- * @version 1/21/05
- * @since 1/21/05
- *
- **/
- function bulkMetaUpdate($meta,$mode = false, $displayOutput = false) {
- $tracks = $this->getSubNodes("tracks",-1);
- foreach ($tracks as $track) {
- $track->setMeta($meta,$mode,$displayOutput);
- }
- $display = new jzDisplay();
- $display->purgeCachedPage($this);
- }
-
- /**
- * Imports media in the specified format.
-
- * @author Ben Dodson
- * @version 10/31/04
- * @since 10/31/04
- */
- function mediaImport($type, $file) {
- switch ($type) {
- case "jzLibrary":
- echo "Importing media...<br>";
- ob_flush();
- if ($file == "URL") {
- $contents = "";
- $url = $_GET['query'];
- $fp = fopen($url,'r');
- while (!feof($fp)) {
- $contents .= fread($fp, 2048);
- }
- $arr = unserialize($contents);
- } else {
- $arr = unserialize($file);
- }
- for ($i = 0; $i < sizeof($arr); $i++) {
- $mpath = explode("/",$arr[$i]['path']);
- if (sizeof($mpath) > 0) {
- if ($child = $this->oldInject($mpath,$arr[$i]['filepath'])) {
- $child->setMeta($arr[$i]['meta'],"cache");
- }
- }
- }
- echo "Import complete.";
- break;
- }
- }
-
- /**
- * Gathers all of our statistics as an array with
- * the following keys:
- *
- * avg_bitrate
- * avg_length (seconds)
- * avg_length_str (string version)
- * total_length (seconds)
- * total_length_str (string version)
- * avg_size (megs)
- * total_size (megs)
- * total_size_str (string version)
- * total_genres
- * total_artists
- * total_albums
- * total_disks
- * total_tracks
- * avg_year
- *
- * @author Ben Dodson
- * @version 11/16/04
- * @since 11/16/04
- */
- function getStats($return = false) {
- if (!$return){
- $this->generateStats($return);
- return $this->stats;
- } else {
- $data = $this->generateStats($return);
- return $data[$return];
- }
- }
-
- /**
- * Creates all of our statistics.
- *
- * @author Ben Dodson
- * @version 11/16/04
- * @since 11/16/04
- * @param $string specifically what to return, defaults to everything
- */
- function generateStats($return = false) {
- $stats = array();
-
- // have to do it...
- $elements = $this->getSubNodes("tracks",-1);
-
- $length = $size = $bitrate = $year = $yearc = $lengthc = $brc = $sizec = $tracks = 0;
- foreach ($elements as $track) {
- $tracks++;
- $meta = $track->getMeta();
- if ($meta['length'] != '-' && $meta['length'] > 0) {
- $length += $meta['length'];
- $lengthc++;
- }
-
- if ($meta['size'] != '-' && $meta['size'] > 0) {
- $size += $meta['size'];
- $sizec++;
- }
-
- if ($meta['year'] != '-' && $meta['year'] > 1000) {
- $year += $meta['year'];
- $yearc++;
- }
-
- if ($meta['bitrate'] != '-' && $meta['bitrate'] > 0) {
- $bitrate += $meta['bitrate'];
- $brc++;
- }
- }
- if ($tracks == 0) return false;
-
- $stats['total_size'] = $size;
- $stats['total_length'] = $length;
- $stats['total_tracks'] = $tracks;
- $stats['avg_bitrate'] = @round($bitrate / $brc,2);
- $stats['avg_length'] = @round($length / $lengthc,0);
- $stats['avg_size'] = @round($size / $sizec,2);
- $stats['avg_year'] = @round($year / $yearc,2);
-
- $str = "";
- // stringize stuff:
- $stats['avg_length_str'] = stringize_time($stats['avg_length']);
- $stats['total_length_str'] = stringize_time($stats['total_length']);
- $stats['total_size_str'] = stringize_size($stats['total_size']);
-
- // Now did we want to return something specific
- if ($return){
- return $stats[$return];
- }
-
- if (($d = distanceTo('genre',$this)) !== false)
- $stats['total_genres'] = $this->getSubNodeCount('nodes',$d);
- else
- $stats['total_genres'] = 0;
-
- if (($d = distanceTo('artist',$this)) !== false)
- $stats['total_artists'] = $this->getSubNodeCount('nodes',$d);
- else
- $stats['total_artists'] = 0;
-
- if (($d = distanceTo('album',$this)) !== false)
- $stats['total_albums'] = $this->getSubNodeCount('nodes',$d);
- else
- $stats['total_albums'] = 0;
-
- // nodes at track level are disks.
- if (($d = distanceTo('track',$this)) !== false)
- $stats['total_disks'] = $this->getSubNodeCount('nodes',$d);
- else
- $stats['total_disks'] = 0;
-
- $this->stats = $stats;
- }
- /**
- * Removes media from the cache.
- *
- * @author Ben Dodson
- * @version 11/16/04
- * @since 11/16/04
- */
- function removeMedia($element) {
- $parent = $element->getParent();
-
- if ($element->isLeaf()) {
- // Delete parent references to $element:
- $nodecache = $parent->readCache("nodes");
- $tracklist = $nodecache[8];
- $name = $element->getPath();
- $name = $name[sizeof($name)-1];
- removeFromArray($tracklist,$name);
- $nodecache[8] = $tracklist;
- $parent->writeCache($nodecache,"nodes");
- $trackcache = $parent->readCache("tracks");
- foreach ($trackcache as $id=>$arr) {
- if ($arr[2] == $name) {
- unset($trackcache[$id]);
- }
- }
- $trackcache = array_values($trackcache);
- $parent->writeCache($trackcache,"tracks");
- } else {
- // First wipe out the children:
- $children = $element->getSubNodes("nodes",-1);
- foreach ($children as $child) {
- $this->removeMedia($child);
- }
- // Now clear $element from its parent:
- $nodecache = $parent->readCache("nodes");
- $nodelist = $nodecache[7];
- $name = $element->getName();
- removeFromArray($nodelist,$name);
- $nodecache[7] = $nodelist;
- $parent->writeCache($nodecache,"nodes");
- // Now kill $element's caches:
- $element->deleteCache();
- }
- // Now see if the parent should be removed:
- $count = $parent->getSubNodeCount("both",1);
- if ($count == 0 && $parent->getLevel() > 0) {
- $this->removeMedia($parent);
- }
- }
- /* Moves media from one location to another
- * This function calls other backend functions
- * to make it work for all backends.
- * It is not meant to be the most efficient implementation.
- *
- * @author Ben Dodson
- * @since 8/10/05
- * @version 8/11/05
- **/
- function moveMedia($element, $newpath) {
- $root = new jzMediaNode();
- $be = new jzBackend();
- $playpath = $element->getFilePath();
- $type = ($element->isLeaf()) ? "leaf" : "node";
- if (is_string($newpath)) {
- $path = explode("/",$newpath);
- } else if (is_array($newpath)) {
- $path = $newpath;
- } else {
- return false;
- }
-
- if ($type == "node") { return false; }
-
-
- $pc = $element->getPlayCount();
- $dc = $element->getDownloadCount();
- $vc = $element->getViewCount();
- $desc = $element->getDescription();
- $sdesc = $element->getShortDescription();
- $art = $element->getMainArt();
- $discussion = $element->getDiscussion();
- $rating = $element->getRating();
- $rating_count = $element->getRatingCount();
- if ($be->hasFeature('setID')) {
- $mid = $element->getID();
- }
- // TODO:
- // This does not work correctly with nodes yet.
- // You should pull the above data, then recursively move children,
- // then remove me, and finally set the data as below.
- // I did not do this yet (8/11/05) because I would not have been
- // able to test it. (for things like collisions,
- // and also how to handle the filesystem)
- // If the backend has a lookup file, update it.
- if ($element->isLeaf()) {
- $media_path = getMediaDir($element);
- $be = new jzBackend();
- $rl_name = 'reverse_lookup-' . str_replace(':','',str_replace('\\','-',str_replace('/','-',$media_path)));
- $LOOKUP = $be->loadData($rl_name);
- if (is_array($LOOKUP)) {
- if (isset($LOOKUP[$element->getFilename("host")])) {
- $LOOKUP[$element->getFilename("host")] = implode('/',$path);
- $be->storeData($rl_name,$LOOKUP);
- }
- }
- }
- $this->removeMedia($element);
- if (false !== ($new = $root->inject($path,$playpath))) {
- $new->setPlayCount($pc);
- $new->setDownloadCount($dc);
- $new->setViewCount($vc);
- $new->addRating($rating,$rating_count);
- if ($be->hasFeature('setID')) {
- $new->setID($mid);
- }
- if (!isNothing($desc)) {
- $new->addDescription($desc);
- }
- if (!isNothing($sdesc)) {
- $new->addShortDescription($sdesc);
- }
- if (!isNothing($art)) {
- $new->addMainArt($art);
- }
- if ($discussion != array() && !isNothing($discussion)) {
- $new->addFullDiscussion($discussion);
- }
- return $new;
- }
- }
-
- function getMostDownloaded($type = "nodes", $distance = false, $limit = 10) {
- return array();
- }
-
- function getMostPlayed($type = "nodes", $distance = false, $limit = 10) {
- return array();
- }
-
- function getMostViewed($type = "nodes", $distance = false, $limit = 10) {
- return array();
- }
-
- function getRecentlyAdded($type = "nodes", $distance = false, $limit = 10) {
- return array();
- }
-
- function getRecentlyPlayed($type = "nodes", $distance = false, $limit = 10) {
- return array();
- }
-
- function getTopRated($type = "nodes", $distance = false, $limit = 10) {
- return array();
- }
-
- }
-
-
- ?>