From: <neb...@us...> - 2009-03-17 00:07:22
|
Revision: 1652 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1652&view=rev Author: nebelschwade Date: 2009-03-17 00:07:12 +0000 (Tue, 17 Mar 2009) Log Message: ----------- SparqlQueries over DL-Learner are now working (try testJamendo.php) Modified Paths: -------------- trunk/src/moosique.net/js/player.js Added Paths: ----------- trunk/src/moosique.net/php/DllearnerConnection.php trunk/src/moosique.net/php/SparqlQueryBuilder.php trunk/src/moosique.net/php/Utilities.php trunk/src/moosique.net/php/config.ini trunk/src/moosique.net/php/config.php trunk/src/moosique.net/php/requestHandler.php trunk/src/moosique.net/php/test.php trunk/src/moosique.net/php/testJamendo.php Property Changed: ---------------- trunk/src/moosique.net/ trunk/src/moosique.net/php/ Property changes on: trunk/src/moosique.net ___________________________________________________________________ Added: svn:ignore + .git Modified: trunk/src/moosique.net/js/player.js =================================================================== --- trunk/src/moosique.net/js/player.js 2009-03-16 10:23:18 UTC (rev 1651) +++ trunk/src/moosique.net/js/player.js 2009-03-17 00:07:12 UTC (rev 1652) @@ -39,6 +39,7 @@ 'html': 'X', 'events': { 'click': function() { + console.log('Deleted Song from PLaylist'); this.getParent().destroy(); // and refresh the playlist if clicked y.addTracks($('playlist'), '', true); @@ -164,86 +165,95 @@ * adding functionality for the player-GUI and the play, next etc. buttons */ addEventsToButtons: function() { + + var that = this; // the Play-Pause Button - this.playPause.addEvent('click', function() { + that.playPause.addEvent('click', function() { + console.log('Clicked Play/Pause'); // STOPPED: 0, PAUSED: 1, PLAYING: 2,BUFFERING: 5, ENDED: 7 - if (this.y.getPlayerState() == 0 || - this.y.getPlayerState() == 1 || - this.y.getPlayerState() == 7) { - this.y.play(); + if (that.y.getPlayerState() == 0 || + that.y.getPlayerState() == 1 || + that.y.getPlayerState() == 7) { + that.y.play(); } else { - this.y.pause(); + that.y.pause(); } - }.bind(this)); + }); // the previous-Track Button - this.prev.addEvent('click', function() { - this.y.previous(); - }.bind(this)); + that.prev.addEvent('click', function() { + console.log('Clicked Prev Button'); + that.y.previous(); + }); // the next-Track Button - this.next.addEvent('click', function() { - this.y.next(); - }.bind(this)); + that.next.addEvent('click', function() { + console.log('Clicked Next Button'); + that.y.next(); + }); // the Stop-Playing Button - this.stop.addEvent('click', function() { - this.playPause.setStyle('background-image', 'url(img/play.png)'); - this.nowPlayingHeader.set('text', 'Player stopped'); - this.nowPlayingTrack.set('text', '...'); - this.nowPlayingTime.set('text', '0:00 / 0:00'); - this.y.stop(); - }.bind(this)); + that.stop.addEvent('click', function() { + console.log('Clicked Stop Button'); + that.playPause.setStyle('background-image', 'url(img/play.png)'); + that.nowPlayingHeader.set('text', 'Player stopped'); + that.nowPlayingTrack.set('text', '...'); + that.nowPlayingTime.set('text', '0:00 / 0:00'); + that.y.stop(); + }); // Mute-Toggle-Switch - this.toggleMute.addEvent('click', function() { - if (this.y.getVolume() > 0) { - this.y.setVolume(0); - this.toggleMute.setStyle('text-decoration', 'line-through'); + that.toggleMute.addEvent('click', function() { + console.log('Clicked Mute Switch'); + if (that.y.getVolume() > 0) { + that.y.setVolume(0); + that.toggleMute.setStyle('text-decoration', 'line-through'); } else { - this.y.setVolume(1); - this.toggleMute.setStyle('text-decoration', 'none'); + that.y.setVolume(1); + that.toggleMute.setStyle('text-decoration', 'none'); } - }.bind(this)); + }); }, /** * Playlist related functions */ initPlaylist: function() { - this.togglePlaylist.addEvent('click', function() { - if (this.playlistContainer.getStyle('display') == 'none') { - this.playlistContainer.setStyle('display', 'block'); - this.togglePlaylist.setStyle('text-decoration', 'line-through'); + var that = this; + + that.togglePlaylist.addEvent('click', function() { + if (that.playlistContainer.getStyle('display') == 'none') { + that.playlistContainer.setStyle('display', 'block'); + that.togglePlaylist.setStyle('text-decoration', 'line-through'); } else { - this.playlistContainer.setStyle('display', 'none'); - this.togglePlaylist.setStyle('text-decoration', 'none'); + that.playlistContainer.setStyle('display', 'none'); + that.togglePlaylist.setStyle('text-decoration', 'none'); } - }.bind(this)); + }); // same for the closePlaylist-Button - this.closePlaylist.addEvent('click', function() { - this.playlistContainer.setStyle('display', 'none'); - this.togglePlaylist.setStyle('text-decoration', 'none'); - }.bind(this)); + that.closePlaylist.addEvent('click', function() { + that.playlistContainer.setStyle('display', 'none'); + that.togglePlaylist.setStyle('text-decoration', 'none'); + }); // nifty UI-Stuff, draggable and resizable - this.playlistContainer.makeDraggable({ + that.playlistContainer.makeDraggable({ handle: $('playlistHeader') }); - this.playlistContainer.makeResizable({ + that.playlistContainer.makeResizable({ handle: $('playlistFooter'), limit: {x: [300, 600], y: [150, 1000]} }); // opacity and intial hide - this.playlistContainer.setStyle('opacity', 0.9); // easier than css hacks + that.playlistContainer.setStyle('opacity', 0.9); // easier than css hacks // this.playlistContainer.setStyle('display', 'none'); // Make the playlist, samples and recommendations sortable - this.makeSortableLists($$('#playlist, #samples, #recommendations')); + that.makeSortableLists($$('#playlist, #samples, #recommendations')); // make links unclickable for recommendations and samples - this.makeLinksUnclickable($$('#recommendations li a, #samples li a')); + that.makeLinksUnclickable($$('#recommendations li a, #samples li a')); }, @@ -267,6 +277,9 @@ * @param {Object} lists An Element-Collection of lists (ol, ul) */ makeSortableLists: function(lists) { + + var that = this; + new Sortables(lists, { // indicate moving state by adding styles onStart: function(li) { @@ -280,9 +293,10 @@ if (li.getParent().get('id') == 'playlist') { li.getFirst('a').set('class', 'htrack'); // reload playlist - this.y.addTracks(this.playlist, '', true); + that.y.addTracks(that.playlist, '', true); + console.log('Updated Playlist'); } - }.bind(this) + } }); } Property changes on: trunk/src/moosique.net/php ___________________________________________________________________ Added: svn:ignore + def0.xsd def1.xsd main.wsdl Added: trunk/src/moosique.net/php/DllearnerConnection.php =================================================================== --- trunk/src/moosique.net/php/DllearnerConnection.php (rev 0) +++ trunk/src/moosique.net/php/DllearnerConnection.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,42 @@ +<?php + +/** + * + */ +class dllearnerConnection { + + private $conf; + private $client; + private $endpoint; + + function __construct($conf) { + $this->conf = $conf; + // we use jamendo as the default sparql-endpoint + $this->setEndpoint($this->conf->getUrl('jamendo')); + $this->connect(); + } + + private function connect() { + // connect to DL-Learner-Web-Service + $this->client = new SoapClient( + $this->conf->getUrl('wsdlLocal') + ); + } + + public function setEndpoint($endpoint) { + $this->endpoint = $endpoint; + } + + public function getEndpoint() { + return $this->endpoint; + } + + public function sparqlQuery($query) { + $id = $this->client->generateID(); + $knowledgeSourceId = $this->client->addKnowledgeSource($id, 'sparql', $this->endpoint); + $result = $this->client->sparqlQuery($id, $knowledgeSourceId, $query); + return $result; + } + +} +?> \ No newline at end of file Added: trunk/src/moosique.net/php/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/php/SparqlQueryBuilder.php (rev 0) +++ trunk/src/moosique.net/php/SparqlQueryBuilder.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,109 @@ +<?php + +/** + * TODO, create a universal SparqlQueryBuilder for the different requests + * that can be made by a user or are made by the system for additional data + * like geodates, images, stuff... + */ +class SparqlQueryBuilder { + + private $config; + private $queryString; + + function __construct($config, $search, $typeOfSearch, $results) { + $this->config = $config; + $this->buildQuery($search, $typeOfSearch, $results); + } + + function getQuery() { + return $this->queryString; + } + + private function buildQuery($search, $typeOfSearch, $results) { + $this->queryString = ''; + $this->queryString .= $this->sparqlPrefixes(); + $this->queryString .= $this->selectStatement($typeOfSearch); + $this->queryString .= $this->whereStatement($search, $typeOfSearch, $results); + } + + + private function sparqlPrefixes() { + $prefixes = ''; + foreach($this->config->getPrefixes() as $prefix => $resource) { + $prefixes .= 'PREFIX ' . $prefix . ': ' . $resource . "\n"; + } + return $prefixes; + } + + private function selectStatement($typoOfSearch) { + $select = 'SELECT '; + switch($typoOfSearch) { + + case 'artist' : + $select .= '?artist ?album'; + break; + + case 'song': + $select .= '?artist ?album'; + break; + + case 'tag': + $select .= '?artist ?album'; + break; + } + return $select; + } + + private function whereStatement($search, $typeOfSearch, $wantedResults) { + $where = 'WHERE { ' . "\n"; + + switch($typeOfSearch) { + + case 'artist' : + $where .= ' + ?artist a mo:MusicArtist . + ?artist foaf:name "' . $search . '" . + ?artist foaf:homepage ?homepage . + ?record foaf:maker ?artist . + ?record dc:title ?title . + ?record mo:image ?image . + '; + break; + + case 'song' : + $where .= ' + ?track a mo:Track . + ?track dc:title "' . $search . '" . + ?track foaf:maker ?artist . + ?artist foaf:name ?name . + ?track dc:title ?tracksname . + ?record mo:track ?track . + ?record dc:title ?recordname . + '; + break; + + case 'tag' : + + break; + + // default case is artist + default : + $where .= ' + ?artist a mo:MusicArtist . + ?artist foaf:name "' . $search . '" . + ?artist foaf:homepage ?homepage . + ?record foaf:maker ?artist . + ?record dc:title ?title . + ?record mo:image ?image . + '; + break; + + } + $where .= ' }'; + return $where; + } + +} + + +?> \ No newline at end of file Added: trunk/src/moosique.net/php/Utilities.php =================================================================== --- trunk/src/moosique.net/php/Utilities.php (rev 0) +++ trunk/src/moosique.net/php/Utilities.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,167 @@ +<?php +/** + * Copyright (C) 2007-2008, Jens Lehmann + * + * This file is part of DL-Learner. + * + * DL-Learner 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 3 of the License, or + * (at your option) any later version. + * + * DL-Learner 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, see <http://www.gnu.org/licenses/>. + * + */ + +// Pear HTTP_Request class required +include ('HTTP/Request.php'); + +/** + * Collection of static utility functions. + * + * @author Jens Lehmann + * @author Sebastian Hellmann + */ + +class Utilities { + + /** + * Loads WSDL and imported XSD files from web service and stores them + * locally. + */ + public static function loadWSDLfiles($wsdluri) { + $main = self :: getRequest($wsdluri); + $other = self :: getXSDImports($main); + $newMain = self :: changeXSDImports($main); + self :: writeToFile("main.wsdl", $newMain); + $x = 0; + foreach ($other as $o) { + self :: writeToFile("def" . ($x++) . ".xsd", self :: getRequest($o)); + } + } + + /** + * Change XSD imports in WSDL file to point to local imports. + */ + public static function changeXSDImports($wsdlFileContent) { + $before = "<xsd:import schemaLocation=\""; + $after = "\" namespace=\""; + $newWSDL = ""; + $desca = "def"; + $descb = ".xsd"; + $x = 0; + while ($posstart = strpos($wsdlFileContent, $before)) { + $posstart += strlen($before); + $newWSDL .= substr($wsdlFileContent, 0, $posstart); + $wsdlFileContent = substr($wsdlFileContent, $posstart); + $newWSDL .= $desca . ($x++) . $descb; + $posend = strpos($wsdlFileContent, $after); + $wsdlFileContent = substr($wsdlFileContent, $posend); + } + return $newWSDL . $wsdlFileContent; + } + + /** + * Extracts XSD imports from WSDL file. + */ + public static function getXSDImports($wsdlFileContent) { + $before = "<xsd:import schemaLocation=\""; + $after = "\" namespace=\""; + $ret = array (); + while ($posstart = strpos($wsdlFileContent, $before)) { + $posstart += strlen($before); + $wsdlFileContent = substr($wsdlFileContent, $posstart); + $posend = strpos($wsdlFileContent, $after); + $tmp = substr($wsdlFileContent, 0, $posend); + $ret[] = $tmp; + $wsdlFileContent = substr($wsdlFileContent, $posend +strlen($after)); + } + return $ret; + } + + /** + * Peforms a GET request and returns body of result. + */ + public static function getRequest($uri) { + $req = & new HTTP_Request($uri); + $req->setMethod(HTTP_REQUEST_METHOD_GET); + $req->sendRequest(); + $ret = $req->getResponseBody(); + return $ret; + } + + /** + * Writes $content to file $filename. + */ + public static function writeToFile($filename, $content) { + $fp = fopen($filename, "w"); + fwrite($fp, $content); + fclose($fp); + } + + /** + * Prints a list of all Web Service components and their configuration options. + */ + public static function printWebserviceComponents($client) { + echo '<h1>Web Service Information</h1>'; + + echo '<h2>Knowledge Sources</h2>'; + Utilities :: printComponentsInfo($client, $client->getKnowledgeSources()->item); + + echo '<h2>Reasoners</h2>'; + Utilities :: printComponentsInfo($client, $client->getReasoners()->item); + + echo '<h2>Learning Problems</h2>'; + Utilities :: printComponentsInfo($client, $client->getLearningProblems()->item); + + echo '<h2>Learning Algorithms</h2>'; + Utilities :: printComponentsInfo($client, $client->getLearningAlgorithms()->item); + } + + /** + * Print information about all given components. + */ + public static function printComponentsInfo($client, $components) { + foreach ($components as $component) + Utilities :: printComponentInfo($client, $component); + } + + /** + * Print information about a component. + */ + public static function printComponentInfo($client, $component) { + echo '<h3>component: ' . $component . '</h3>'; + + $options = $client->getConfigOptions($component, true)->item; + if (!is_array($options)) + $options = array ( + $options + ); + + foreach ($options as $option) + Utilities :: printOption($option); + } + + /** + * Prints information about an option. + * + * @param String Option as returned by the DL-Learner web service + * getConfigOption() method. + */ + public static function printOption($option) { + $parts = split('#', $option); + echo 'option name: <b>' . $parts[0] . '</b><br />'; + echo 'option description: ' . $parts[1] . '<br />'; + echo 'option class: ' . $parts[2] . '<br />'; + if ($parts[3] != 'null') + echo 'option name: ' . $parts[3] . '<br />'; + echo '<br />'; + } +} +?> Added: trunk/src/moosique.net/php/config.ini =================================================================== --- trunk/src/moosique.net/php/config.ini (rev 0) +++ trunk/src/moosique.net/php/config.ini 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,32 @@ +; Config file for moosique.net +; Define Prefixes and global URLs here + +[general] +path = "./" + +[url] +wsdl = "http://localhost:8181/services?wsdl" +wsdlLocal = "main.wsdl" +musicbrainz = "http://dbtune.org/musicbrainz/sparql/" +jamendo = "http://dbtune.org/jamendo/sparql/" + +[prefix] +; map = "<file:/home/moustaki/work/motools/musicbrainz/d2r-server-0.4/mbz_mapping_raw.n3#>" +rdfs = "<http://www.w3.org/2000/01/rdf-schema#>" +owl = "<http://www.w3.org/2002/07/owl#>" +event = "<http://purl.org/NET/c4dm/event.owl#>" +rel = "<http://purl.org/vocab/relationship/>" +lingvoj = "<http://www.lingvoj.org/ontology#>" +foaf = "<http://xmlns.com/foaf/0.1/>" +rdf = "<http://www.w3.org/1999/02/22-rdf-syntax-ns#>" +tags = "<http://www.holygoat.co.uk/owl/redwood/0.1/tags/>" +db = "<http://dbtune.org/musicbrainz/resource/>" +dc = "<http://purl.org/dc/elements/1.1/>" +geo = "<http://www.geonames.org/ontology#>" +bio = "<http://purl.org/vocab/bio/0.1/>" +mo = "<http://purl.org/ontology/mo/>" +vocab = "<http://dbtune.org/musicbrainz/resource/vocab/>" +xsd = "<http://www.w3.org/2001/XMLSchema#>" +mbz = "<http://purl.org/ontology/mbz#>" +; +; \ No newline at end of file Added: trunk/src/moosique.net/php/config.php =================================================================== --- trunk/src/moosique.net/php/config.php (rev 0) +++ trunk/src/moosique.net/php/config.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,53 @@ +<?php + +/** + * + */ +class config { + + private $config; + + /** + * On Class initialization, read the ini file to get + * the config values and hand them to $this->config + */ + function __construct() { + $this->config = parse_ini_file('config.ini', true); + + // load WSDL files (has to be done due to a Java web service bug) + include('Utilities.php'); + ini_set('soap.wsdl_cache_enabled', '0'); + Utilities::loadWSDLfiles($this->getUrl('wsdl')); + } + + /** + * + * @return + * @param String $value + */ + function getGeneral($value) { + return $this->config['general'][$value]; + } + + /** + * + * @return + * @param object $value + */ + function getUrl($value) { + return $this->config['url'][$value]; + } + + /** + * + * @return + */ + function getPrefixes() { + return $this->config['prefix']; + } +} + +// instantiate the config class +$conf = new config; + +?> \ No newline at end of file Added: trunk/src/moosique.net/php/requestHandler.php =================================================================== --- trunk/src/moosique.net/php/requestHandler.php (rev 0) +++ trunk/src/moosique.net/php/requestHandler.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,17 @@ +<?php + +class RequestHandler { + + function handle() { + + } + + function schalala() { + + } + + + +} + +?> \ No newline at end of file Added: trunk/src/moosique.net/php/test.php =================================================================== --- trunk/src/moosique.net/php/test.php (rev 0) +++ trunk/src/moosique.net/php/test.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,25 @@ +<?php + +include('config.php'); +include('SparqlQueryBuilder.php'); +include('DllearnerConnection.php'); + + +$connection = new DllearnerConnection($conf); +$connection->setEndpoint('http://arc.semsol.org/community/irc/sparql'); + +$query = ' +SELECT ?s ?p ?o WHERE { + ?s ?p ?o . +} LIMIT 10'; + + +$json = $connection->sparqlQuery($query); +$result = json_decode($json); +$bindings = $result->results->bindings; + +echo '<pre>'; +print_r($bindings); +echo '</pre>'; + +?> \ No newline at end of file Added: trunk/src/moosique.net/php/testJamendo.php =================================================================== --- trunk/src/moosique.net/php/testJamendo.php (rev 0) +++ trunk/src/moosique.net/php/testJamendo.php 2009-03-17 00:07:12 UTC (rev 1652) @@ -0,0 +1,33 @@ +<?php + +include('config.php'); +// include('SparqlQueryBuilder.php'); +include('DllearnerConnection.php'); + +$connection = new DllearnerConnection($conf); + +$query = ' +SELECT ?artist ?album +WHERE +{ ?a + a mo:MusicArtist; + foaf:name ?artist; + foaf:made ?album. + ?album tags:taggedWithTag <http://dbtune.org/jamendo/tag/stonerrock>. + } +'; + +/* TODO +$spargel = new SparqlQueryBuilder($conf, 'Low Earth Orbit', 'artist', array('artist', 'title', 'image')); +$query = $spargel->getQuery(); +*/ + +$json = $connection->sparqlQuery($query); +$result = json_decode($json); +$bindings = $result->results->bindings; + +echo '<pre>'; +print_r($bindings); +echo '</pre>'; + +?> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <neb...@us...> - 2009-04-07 21:25:51
|
Revision: 1686 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1686&view=rev Author: nebelschwade Date: 2009-04-07 21:25:36 +0000 (Tue, 07 Apr 2009) Log Message: ----------- Changed GUI of moosique.net * added Search, Recommendations and Information Tabs * CSS-Tweaks, CSS-Sprites, bandwidth reduction SPARQL problems: see testJamendo.php Modified Paths: -------------- trunk/src/moosique.net/css/default.css trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/ajax.js trunk/src/moosique.net/js/player.js trunk/src/moosique.net/php/DllearnerConnection.php trunk/src/moosique.net/php/SparqlQueryBuilder.php trunk/src/moosique.net/php/ajaxer.php trunk/src/moosique.net/php/config.ini trunk/src/moosique.net/php/config.php trunk/src/moosique.net/php/testJamendo.php Added Paths: ----------- trunk/src/moosique.net/img/controls.png trunk/src/moosique.net/js/interface.js trunk/src/moosique.net/php/LastFM.php Property Changed: ---------------- trunk/src/moosique.net/ Property changes on: trunk/src/moosique.net ___________________________________________________________________ Modified: svn:ignore - .git + .git moosique.net.esproj Modified: trunk/src/moosique.net/css/default.css =================================================================== --- trunk/src/moosique.net/css/default.css 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/css/default.css 2009-04-07 21:25:36 UTC (rev 1686) @@ -1,33 +1,44 @@ @charset 'utf-8'; -@media all { - -/* based loosely on CSS-Reset Style from Eric Meyer and Stefan Nietzsche */ +@media all { /* Yes we want to reset this for print-Styles too */ +/* Based on various Reset-Styles, included own stuff and added mediabox-Style */ +/* Reset all elements except form stuff */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td - { margin: 0; padding: 0; border: 0; outline: 0; vertical-align: baseline; } -:focus { outline: 0; } +small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; vertical-align: baseline; +} + html { height: 100%; } -body { height: 101%; line-height: 1; background: #fff; } +body { height: 101%; background-color: #fff; color: #000; line-height: 1; } ol, ul { list-style: none; } table { border-collapse: collapse; border-spacing: 0; } caption, th, td { text-align: left; font-weight: normal; } blockquote:before, blockquote:after, q:before, q:after { content: ""; } blockquote, q { quotes: "" ""; } +strong, b { font-weight: bold; } +em, i { font-style: italic; } label, input[type=button], input[type=submit], button { cursor: pointer; } -q:lang(de) { quotes: '„' '“' '‚' '‘'; } -q:lang(en) { quotes: '“' '”' "‘" "’"; } abbr[title] { border-bottom: 1px dotted #888 !important; cursor: help; } a abbr { cursor: pointer !important; } + +/* General purpose-Classes */ +.hidden { position: absolute; left: -9999999em; top: -9999999em;} + +/* Clearfix hack */ .clearfix:after { clear: both; content: "."; display: block; height: 0; visibility: hidden; } .clearfix { display: inline-block; } -.hidden { position: absolute; left: -9999em; top: -9999em; } +* html .clearfix { height: 1%; } +.clearfix { display: block; } -/* =================================================================== */ +/* Special Stuff */ +:focus { outline: 0; } +a { text-decoration: none; } +a:hover { text-decoration: underline; } +a:active { position: relative; top: 1px; } +input:focus, textarea:focus, select:focus { background: #eee; } fieldset { border: 1px solid #333; padding: 9px; } fieldset legend { padding: 0 9px; } -h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal;} +h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal; } - } /* End @media all */ \ No newline at end of file Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/css/style.css 2009-04-07 21:25:36 UTC (rev 1686) @@ -3,16 +3,12 @@ /* moosique.net * - * Overall width: 955px -- golden ratio: 590px & 365px - * * Semiblack: #131313 * Dark Grey: #383838 * Light Grey: #545454 * White: #fff * Yellowish: #ffbc00 - * Border: #272727 * - * */ @media screen { @@ -27,15 +23,10 @@ } body { - background: url(../img/bg_body.png) top left repeat-x #383838; + background: #333; } -a { - text-decoration: none; -} - a:hover { - text-decoration: underline; color: #ffbc00; } @@ -46,39 +37,30 @@ /* Default Container Positioning */ /* =================================================================== */ - #container, #header, #mainContainer, #content { position: relative; } -#container { - width: 955px; - margin: 0 auto; +#headerContainer { + height: 140px; + background: #131313; + border-top: 1px solid #999; + border-bottom: 10px solid #ffbc00; } #header { - height: 132px; + width: 960px; + margin: 0 auto; } -#content { - /* width: 590px; */ - top: 4px; - width: 557px; - padding: 30px 30px 30px 0; - border-right: 3px solid #272727; - min-height: 300px; - height: auto !important; - height: 300px; +#container { + border-top: 1px solid #1a1a1a; } -#sidebar { - /* width: 365px; */ - width: 335px; - position: absolute; - right: 0; - top: 4px; - padding: 30px 0 30px 30px; - +#mainContainer { + width: 960px; + margin: 0 auto; + padding: 30px 0; } #footer { @@ -86,19 +68,18 @@ text-align: center; } - -/* Header Area */ +/* header Area */ /* =================================================================== */ #header h1 a { font-size: 36px; - line-height: 120px; + line-height: 90px; font-family: Georgia, "Times New Roman", Times, serif; text-decoration: none; } #now { position: absolute; - top: 30px; + top: 20px; left: 280px; width: 410px; height: 37px; @@ -131,7 +112,7 @@ #status { position: absolute; - top: 93px; + top: 83px; left: 300px; width: 410px; font-size: 11px; @@ -141,7 +122,7 @@ position: absolute; width: 116px; height: 37px; - top: 30px; + top: 20px; right: 0; padding: 10px 20px; background: #545454; @@ -159,6 +140,10 @@ margin-right: 10px; } +#playPause { + width: 26px; +} + #next { margin-right: 0; } @@ -170,26 +155,16 @@ } #prev { - + background: url(../img/controls.png) 0px -160px no-repeat; } - -#playPause { - width: 26px; -} - -/* TODO Sprites */ -#prev { - background: url(../img/prev.png) center center no-repeat; -} #next { - background: url(../img/next.png) center center no-repeat; + background: url(../img/controls.png) 0px -120px no-repeat; } -/* Will be changed by JavaScript onclick */ #playPause { - background: url(../img/play.png) center center no-repeat; + background: url(../img/controls.png) 0px 0px no-repeat; } #stop { - background: url(../img/stop.png) center center no-repeat; + background: url(../img/controls.png) 0px -80px no-repeat; } #toggles { @@ -211,20 +186,19 @@ } - /* Playlist Area */ /* =================================================================== */ #playlistContainer { position: absolute; width: 368px; - /* top: 132px; */ - top: 450px; + top: 30px; right: 0; background: #000; -moz-border-radius: 10px; -webkit-border-radius: 10px; z-index: 100; + display: none; } #playlistHeader { @@ -253,12 +227,12 @@ #closePlaylist { position: absolute; - width: 20px; + width: 100px; height: 20px; top: 5px; right: 10px; text-align: right; - font-weight: bold; + font-size: 10px; } #playlist { @@ -287,28 +261,53 @@ width: 14px; height: 14px; line-height: 14px; - color: #131313; - background: #fff; - font-weight: bold; - text-align: center; margin-right: -19px; z-index: 1000; + text-indent: -99999999px; + background: url(../img/controls.png) 0px -200px no-repeat; } -/* Samples */ -#samples li { - cursor: move; - padding: 3px; +/* mainMenu */ +/* =================================================================== */ + +#mainMenu ul { + position: absolute; + top: -46px; + left: 0; } +#mainMenu ul li { + float: left; + -moz-border-radius-topleft: 10px; + -moz-border-radius-topright: 10px; + -webkit-border-top-left-radius: 10px; + -webkit-border-top-right-radius: 10px; + padding: 0 15px; + background: #545454; + margin: 5px 5px 0 0; + height: 30px; + line-height: 30px; +} -/* Content Area */ -/* =================================================================== */ -#searchContainer * { +#mainMenu ul li a { color: #131313; } +#mainMenu ul li.active { + height: 35px; + line-height: 35px; + margin-top: 0; + background: #ffbc00; +} +#mainMenu ul li.active a { + font-weight: bold; +} + + +/* Content Area Default Styles */ +/* =================================================================== */ + #mainContainer h2 { font-size: 20px; line-height: 28px; @@ -321,32 +320,57 @@ font-family: "Courier New", Courier, monospace; } -/* Recommendations and Samples */ -#content ol { + +/* search */ +/* =================================================================== */ +#searchForm * { + color: #131313; +} + + +/* Recommendations */ +/* =================================================================== */ +#recommendations { + display: none; /* Initial Hide */ +} + +#recommendations ol { list-style: decimal; margin-left: 24px; + width: 50%; } -#content ol li a { +#recommendations ol li a { cursor: move; text-decoration: none; } -#content ol li a:hover { +#recommendations ol li a:hover { text-decoration: none; color: #fff; } +#recommendations li:hover { + border: 1px solid #ffbc00; +} + /* Draggable li-Items */ -#playlist li.moving, #samples li.moving, #recommendations li.moving { +#playlist li.moving, #recommendations li.moving { background: #666; border: 3px solid #ffbc00; color: #000; font-weight: bold; } +/* information */ +/* =================================================================== */ +#information { + display: none; /* Initial Hide */ +} + + /* Sidebar Area */ /* =================================================================== */ @@ -359,22 +383,4 @@ } - - -/* =================================================================== */ -/* ======================== IE 7 Styles ============================== */ -/* =================================================================== */ -.ie7 .class { - -} - - -/* =================================================================== */ -/* ================= IE 6 (and below) Styles ======================== */ -/* =================================================================== */ -.ie6 .class { - -} - - } /* end @media screen \ No newline at end of file Added: trunk/src/moosique.net/img/controls.png =================================================================== (Binary files differ) Property changes on: trunk/src/moosique.net/img/controls.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/index.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -13,8 +13,7 @@ <!--[if lte IE 6]><body class="ie6"><![endif]--> <!--[if !IE]><!--><body><!-- <![endif]--> - <div id="container"> - + <div id="headerContainer"> <div id="header"> <h1><a href="index.php">moosique.net</a></h1> <div id="now"> @@ -38,22 +37,28 @@ <a href="#" id="togglePlaylist" title="Show/Hide Playlist">Playlist</a> </div> </div> + </div> - - <div id="playlistContainer"> - <div id="playlistHeader"> - Playlist - <a href="#" id="closePlaylist" title="Close Playlist Window">X</a> - </div> - <ol id="playlist"> - <li><a href="mp3/moosique.mp3" class="htrack">Welcome to moosique</a></li> - </ol> - <div id="playlistFooter"> </div> - </div> + <div id="container"> <div id="mainContainer"> + <div id="mainMenu"> + <ul class="clearfix"> + <li class="active"><a href="#" class="search">Search</a></li> + <li><a href="#" class="recommendations">Recommendations</a></li> + <li><a href="#" class="information">Information</a></li> + </ul> + </div> <div id="content"> - <div id="searchContainer"> + + + <div id="search"> + <h2>Welcome to moosique.net!</h2> + <p> + Want to listen to some good free music? Just enter an artist or song + name, search for tags or enter your last.fm username and let the moogic + happen... + </p> <form id="searchForm" method="post" action="php/ajaxer.php"> <div> <select name="typeOfSearch" id="typeOfSearch"> @@ -62,66 +67,71 @@ <option value="tag">Tag</option> <option value="lastfm">Last.fm-User</option> </select> - <input id="search" name="search" type="text" /> + <input id="searchValue" name="searchValue" type="text" /> <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> </div> </form> + <div id="results"> + + </div> </div> - <div id="info"> - <h2>Welcome to moosique.net!</h2> - <p> - Want to listen to some good free music? Just enter an artist or song - name, search for tags or enter your last.fm username and let the moogic - happen... - </p> - <p> - Or fill your Playlist with these Samples...<br /> - (Drag them to the Playlist) - </p> - <ol id="samples"> + <div id="recommendations"> + <h2>Try dragging these samples to the playlist</h2> + <ol> <li><a href="http://stream6-3.jamendo.com/8654/mp31/01%20-%20Low%20Earth%20Orbit%20-%20My%20Mistakes.mp3">Low Earth Orbit - My Mistakes</a></li> <li><a href="http://stream6-3.jamendo.com/8654/mp31/02%20-%20Low%20Earth%20Orbit%20-%20Like%20Mud.mp3">Low Earth Orbit - Like Mud</a></li> <li><a href="http://stream6-3.jamendo.com/8654/mp31/03%20-%20Low%20Earth%20Orbit%20-%20Defend.mp3">Low Earth Orbit - Defend</a></li> <li><a href="http://stream6-3.jamendo.com/8654/mp31/04%20-%20Low%20Earth%20Orbit%20-%20What%20Can%20I%20Say.mp3">Low Earth Orbit - What Can I Say</a></li> </ol> + </div> - </div> - - - <div id="sidebar"> - <div id="moreInfo"> - <h2>About the Artist</h2> - <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> - <p> - Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat - duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil - imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis - dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus - qui nobis videntur parum. - </p> + <div id="information"> + <div id="sidebar"> + <div id="moreInfo"> + <h2>About the Artist</h2> + <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> + <p> + Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat + duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil + imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis + dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus + qui nobis videntur parum. + </p> + </div> + </div> </div> </div> + + <div id="playlistContainer"> + <div id="playlistHeader"> + Playlist + <a href="#" id="closePlaylist" title="Close Playlist Window">Close Window</a> + </div> + <ol id="playlist"> + <li><a href="mp3/moosique.mp3" class="htrack">Welcome to moosique</a></li> + </ol> + <div id="playlistFooter"> </div> + </div> <div id="footer"> <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | <a href="http://aksw.org/Projects/DLLearner">Powered by DL-Learner</a> </div> - - </div> - </div> + + <!-- JS at the bottom, faster loading pages --> <script type="text/javascript" src="js/mootools-core.js"></script> <script type="text/javascript" src="js/mootools-more.js"></script> <script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> <script type="text/javascript" src="js/player.js"></script> + <script type="text/javascript" src="js/interface.js"></script> <script type="text/javascript" src="js/ajax.js"></script> - <!--[if lte IE 6]><script type="text/javascript" src="js/ie6fixes.js"></script><![endif]--> </body> </html> \ No newline at end of file Modified: trunk/src/moosique.net/js/ajax.js =================================================================== --- trunk/src/moosique.net/js/ajax.js 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/js/ajax.js 2009-04-07 21:25:36 UTC (rev 1686) @@ -5,7 +5,7 @@ // handle search requests $('searchForm').addEvent('submit', function(e) { - var info = $('info'); + var results = $('results'); var submit = $('searchSubmit'); e.stop(); // prevent form submitting the non-ajax way @@ -13,18 +13,18 @@ onRequest: function(response) { submit.set('disabled', 'disabled'); // disable submit button until request complete - info.set('html', '<h2>Processing your search request...</h2>'); + results.set('html', '<h2>Processing your search request...</h2>'); }, onFailure: function(response) { - info.set('html', '<h2>Unable to process your search. Try again.</h2>'); + results.set('html', '<h2>Unable to process your search. Try again.</h2>'); }, onSuccess: function(response) { submit.erase('disabled'); // reenable submitbutton responseObject = JSON.decode(response); // info.set('text', response); - info.set('html', '<h2>Done.</h2>'); + results.set('html', '<h2>Done.</h2>'); // Firebug needed console.log(responseObject); Added: trunk/src/moosique.net/js/interface.js =================================================================== --- trunk/src/moosique.net/js/interface.js (rev 0) +++ trunk/src/moosique.net/js/interface.js 2009-04-07 21:25:36 UTC (rev 1686) @@ -0,0 +1,17 @@ +window.addEvent('domready', function() { + +// switching between search, recommendation and information + +$$('#mainMenu ul li a').each(function(a) { + a.addEvent('click', function(e) { + e.stop(); // dont follow link + $$('#mainMenu ul li').removeClass('active'); + a.getParent().toggleClass('active'); + console.log(a.get('class')); + $('content').getChildren().setStyle('display', 'none') + $(a.get('class')).setStyle('display', 'block'); + }); + +}); + +}); \ No newline at end of file Modified: trunk/src/moosique.net/js/player.js =================================================================== --- trunk/src/moosique.net/js/player.js 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/js/player.js 2009-04-07 21:25:36 UTC (rev 1686) @@ -66,7 +66,7 @@ */ var trackPause = function() { $$('#now h2').set('text', 'Player Paused'); - $('playPause').setStyle('background-image', 'url(img/play.png)'); + $('playPause').setStyle('background-position', '0px 0px'); } /** @@ -76,14 +76,14 @@ var trackStart = function() { $$('#now h2').set('text', 'You are listening to:'); $$('#now h3').set('text', y.getMetaData().title); - $('playPause').setStyle('background-image', 'url(img/pause.png)'); + $('playPause').setStyle('background-position', '0px -40px'); } /** * trackComplete: we change the Pause-Button to a Play-Button */ var trackComplete = function() { - $('playPause').setStyle('background-image', 'url(img/play.png)'); + $('playPause').setStyle('background-position', '0px 0px'); /* TODO * Nice, someone listened a track until the end, this is a good thing, * we can assume our recommendation was not that bad... @@ -196,7 +196,7 @@ // the Stop-Playing Button that.stop.addEvent('click', function() { console.log('Clicked Stop Button'); - that.playPause.setStyle('background-image', 'url(img/play.png)'); + that.playPause.setStyle('background-position', '0px 0px'); that.nowPlayingHeader.set('text', 'Player stopped'); that.nowPlayingTrack.set('text', '...'); that.nowPlayingTime.set('text', '0:00 / 0:00'); @@ -251,9 +251,9 @@ // this.playlistContainer.setStyle('display', 'none'); // Make the playlist, samples and recommendations sortable - that.makeSortableLists($$('#playlist, #samples, #recommendations')); + that.makeSortableLists($$('#playlist, #recommendations ol')); // make links unclickable for recommendations and samples - that.makeLinksUnclickable($$('#recommendations li a, #samples li a')); + that.makeLinksUnclickable($$('#recommendations li a')); }, Modified: trunk/src/moosique.net/php/DllearnerConnection.php =================================================================== --- trunk/src/moosique.net/php/DllearnerConnection.php 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/php/DllearnerConnection.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -5,28 +5,41 @@ */ class dllearnerConnection { - private $conf; + private $config; private $client; private $endpoint; - function __construct($conf) { - $this->conf = $conf; + /** + * + * @return + * @param object $config + */ + function __construct($config) { + $this->config = $config; // we use jamendo as the default sparql-endpoint - $this->setEndpoint($this->conf->getUrl('jamendo')); + $this->setEndpoint($this->config->getUrl('jamendo')); $this->connect(); } + /** + * + * @return + */ private function connect() { // connect to DL-Learner-Web-Service - $this->client = new SoapClient( - $this->conf->getUrl('wsdlLocal') - ); + $this->client = new SoapClient($this->config->getUrl('wsdlLocal')); } + /** + * + * @return + * @param object $endpoint + */ public function setEndpoint($endpoint) { $this->endpoint = $endpoint; } + public function getEndpoint() { return $this->endpoint; } Added: trunk/src/moosique.net/php/LastFM.php =================================================================== --- trunk/src/moosique.net/php/LastFM.php (rev 0) +++ trunk/src/moosique.net/php/LastFM.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -0,0 +1,82 @@ +<?php + +/** + * TODO: UGLY! Use Sparql-Querys instead?! + * + * Later. + */ +class LastFM { + + private $data; + private $config; + private $username; + + function __construct($config, $username) { + $this->config = $config; + $this->username = $username; + $this->getData(); + } + + function getData() { + include_once('arc/ARC2.php'); + $rdfParser = ARC2::getRDFParser(); + $lastfmResource = $this->config->getUrl('lastfm') . urlencode($this->username); + $rdfParser->parse($lastfmResource); + // parse, non simple array + $index = $rdfParser->getSimpleIndex(0); + $this->data = $index; + } + + function getRecentTracks() { + $playedTracks = array(); + $trackNodes = array(); + + echo '<pre>'; + // print_r($this->data); + + if (is_array($this->data) && !empty($this->data)) { + foreach($this->data as $rootItem => $rootValue) { + // only process further if the rootitem ist no uri + if (!preg_match('/http:\/\//i', $rootItem)) { + foreach($rootValue as $childItem => $childValue) { + // if there is a childitem :track_played, we can use the information + if ($childItem == $this->config->getPrefix('played')) { + $trackNodes[] = $childValue[0]['value']; + } + } + } + } + } else { + echo 'Data-Array empty.'; + } + + if (!empty($trackNodes)) { + foreach($trackNodes as $trackNode) { + $track = $this->data[$trackNode][$this->config->getPrefix('title')][0]['value']; + $artistNode = $this->data[$trackNode][$this->config->getPrefix('maker')][0]['value']; + $artist = $this->data[$artistNode][$this->config->getPrefix('name')][0]['value']; + $artistZitgist = $this->data[$artistNode][$this->config->getPrefix('same')][0]['value']; + $album = ''; + $albumZitgist = ''; + + $playedTracks[] = array($artist, $track, $album, $artistZitgist, $albumZitgist); + + } + } else { + echo "No recently played tracks avaiable from last.fm."; + } + + print_r($trackNodes); + print_r($playedTracks); + echo '</pre>'; + } + + +} + +include('config.php'); + +$lastfm = new LastFM($conf, 'nebelschwade'); +$lastfm->getRecentTracks(); + +?> \ No newline at end of file Modified: trunk/src/moosique.net/php/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/php/SparqlQueryBuilder.php 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/php/SparqlQueryBuilder.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -29,8 +29,8 @@ private function sparqlPrefixes() { $prefixes = ''; - foreach($this->config->getPrefixes() as $prefix => $resource) { - $prefixes .= 'PREFIX ' . $prefix . ': ' . $resource . "\n"; + foreach($this->config->getAllPrefixes() as $prefix => $resource) { + $prefixes .= 'PREFIX ' . $prefix . ': <' . $resource . '>' . "\n"; } return $prefixes; } Modified: trunk/src/moosique.net/php/ajaxer.php =================================================================== --- trunk/src/moosique.net/php/ajaxer.php 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/php/ajaxer.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -6,11 +6,11 @@ include_once('arc/ARC2.php'); $rdfParser = ARC2::getRDFParser(); - if (isset($_POST['search']) && !empty($_POST['search'])) { + if (isset($_POST['searchValue']) && !empty($_POST['searchValue'])) { if ($_POST['typeOfSearch'] === 'lastfm') { $lastfmContent = ''; - $lastfmResource = 'http://dbtune.org/last-fm/' . urlencode($_POST['search']); + $lastfmResource = 'http://dbtune.org/last-fm/' . urlencode($_POST['searchValue']); $rdfParser->parse($lastfmResource); Modified: trunk/src/moosique.net/php/config.ini =================================================================== --- trunk/src/moosique.net/php/config.ini 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/php/config.ini 2009-04-07 21:25:36 UTC (rev 1686) @@ -1,32 +1,38 @@ ; Config file for moosique.net ; Define Prefixes and global URLs here -[general] -path = "./" - [url] -wsdl = "http://localhost:8181/services?wsdl" -wsdlLocal = "main.wsdl" +jamendo = "http://dbtune.org/jamendo/sparql/" +lastfm = "http://dbtune.org/last-fm/" +local = "http://127.0.0.1/" musicbrainz = "http://dbtune.org/musicbrainz/sparql/" -jamendo = "http://dbtune.org/jamendo/sparql/" +wsdl = "http://localhost:8181/services?wsdl" +wsdlLocal = "main.wsdl" [prefix] -; map = "<file:/home/moustaki/work/motools/musicbrainz/d2r-server-0.4/mbz_mapping_raw.n3#>" -rdfs = "<http://www.w3.org/2000/01/rdf-schema#>" -owl = "<http://www.w3.org/2002/07/owl#>" -event = "<http://purl.org/NET/c4dm/event.owl#>" -rel = "<http://purl.org/vocab/relationship/>" -lingvoj = "<http://www.lingvoj.org/ontology#>" -foaf = "<http://xmlns.com/foaf/0.1/>" -rdf = "<http://www.w3.org/1999/02/22-rdf-syntax-ns#>" -tags = "<http://www.holygoat.co.uk/owl/redwood/0.1/tags/>" -db = "<http://dbtune.org/musicbrainz/resource/>" -dc = "<http://purl.org/dc/elements/1.1/>" -geo = "<http://www.geonames.org/ontology#>" -bio = "<http://purl.org/vocab/bio/0.1/>" -mo = "<http://purl.org/ontology/mo/>" -vocab = "<http://dbtune.org/musicbrainz/resource/vocab/>" -xsd = "<http://www.w3.org/2001/XMLSchema#>" -mbz = "<http://purl.org/ontology/mbz#>" +bio = "http://purl.org/vocab/bio/0.1/" +db = "http://dbtune.org/musicbrainz/resource/" +dc = "http://purl.org/dc/elements/1.1/" +event = "http://purl.org/NET/c4dm/event.owl#" +foaf = "http://xmlns.com/foaf/0.1/" +geo = "http://www.geonames.org/ontology#" +lingvoj = "http://www.lingvoj.org/ontology#" +mbz = "http://purl.org/ontology/mbz#" +mo = "http://purl.org/ontology/mo/" +owl = "http://www.w3.org/2002/07/owl#" +rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" +rdfs = "http://www.w3.org/2000/01/rdf-schema#" +rel = "http://purl.org/vocab/relationship/" +tags = "http://www.holygoat.co.uk/owl/redwood/0.1/tags/" +vocab = "http://dbtune.org/musicbrainz/resource/vocab/" +xsd = "http://www.w3.org/2001/XMLSchema#" ; -; \ No newline at end of file +; Last.fm-related Stuff +; +account = "http://xmlns.com/foaf/0.1/accountName" +maker = "http://xmlns.com/foaf/0.1/maker" +name = "http://xmlns.com/foaf/0.1/name" +played = "http://purl.org/ontology/last-fm/track_played" +title = "http://purl.org/dc/elements/1.1/title" +track = "http://purl.org/ontology/mo/track" +same = "http://www.w3.org/2002/07/owl#sameAs" \ No newline at end of file Modified: trunk/src/moosique.net/php/config.php =================================================================== --- trunk/src/moosique.net/php/config.php 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/php/config.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -12,37 +12,42 @@ * the config values and hand them to $this->config */ function __construct() { + $this->createConfig(); + } + + /** + * + * @return + */ + private function createConfig() { $this->config = parse_ini_file('config.ini', true); // load WSDL files (has to be done due to a Java web service bug) include('Utilities.php'); ini_set('soap.wsdl_cache_enabled', '0'); - Utilities::loadWSDLfiles($this->getUrl('wsdl')); + Utilities::loadWSDLfiles($this->getUrl('wsdl')); } /** * - * @return - * @param String $value */ - function getGeneral($value) { - return $this->config['general'][$value]; + public function getUrl($value) { + return $this->config['url'][$value]; } - + /** * * @return * @param object $value */ - function getUrl($value) { - return $this->config['url'][$value]; + public function getPrefix($value) { + return $this->config['prefix'][$value]; } - /** * * @return */ - function getPrefixes() { + public function getAllPrefixes() { return $this->config['prefix']; } } Modified: trunk/src/moosique.net/php/testJamendo.php =================================================================== --- trunk/src/moosique.net/php/testJamendo.php 2009-04-07 18:47:26 UTC (rev 1685) +++ trunk/src/moosique.net/php/testJamendo.php 2009-04-07 21:25:36 UTC (rev 1686) @@ -6,23 +6,37 @@ $connection = new DllearnerConnection($conf); -$query = ' -SELECT ?artist ?album -WHERE -{ ?a - a mo:MusicArtist; - foaf:name ?artist; - foaf:made ?album. - ?album tags:taggedWithTag <http://dbtune.org/jamendo/tag/stonerrock>. - } +$queryWorking = ' +select ?artist ?album where { + +?artistLink rdf:type mo:MusicArtist ; + foaf:name ?artist ; + foaf:made ?album ; + +} LIMIT 10 '; + +$queryNOTworking = ' +select ?artist ?album where { + +?artistLink rdf:type mo:MusicArtist ; + foaf:name ?artist ; + foaf:made ?album ; + +FILTER (regex(str(?artist), "vin", "i")) . + +} LIMIT 10 +'; + + /* TODO $spargel = new SparqlQueryBuilder($conf, 'Low Earth Orbit', 'artist', array('artist', 'title', 'image')); $query = $spargel->getQuery(); */ -$json = $connection->sparqlQuery($query); +$json = $connection->sparqlQuery($queryWorking); +// $json = $connection->sparqlQuery($queryNOTworking); $result = json_decode($json); $bindings = $result->results->bindings; @@ -30,4 +44,5 @@ print_r($bindings); echo '</pre>'; -?> \ No newline at end of file +?> + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <neb...@us...> - 2009-05-27 21:49:18
|
Revision: 1775 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1775&view=rev Author: nebelschwade Date: 2009-05-27 21:49:13 +0000 (Wed, 27 May 2009) Log Message: ----------- + Frontend changed for better usability + Frontend Performancefixes, JavaScript & Sprites + The Search now allows for searching Artist and Tags and actually returns sth. + Full Albums found in the search can now be played -> xspf-Playlistfile + FirePHP-Debugger + View-Class Changed general Filestructure and removed unused ARC-Framework Modified Paths: -------------- trunk/src/moosique.net/css/default.css trunk/src/moosique.net/css/style.css trunk/src/moosique.net/img/controls.png trunk/src/moosique.net/img/loading.gif trunk/src/moosique.net/index.php trunk/src/moosique.net/js/ajax.js trunk/src/moosique.net/js/interface.js trunk/src/moosique.net/js/mootools-core.js trunk/src/moosique.net/js/mootools-more.js trunk/src/moosique.net/js/player.js Added Paths: ----------- trunk/src/moosique.net/img/noArtistImage.png trunk/src/moosique.net/moosique/ trunk/src/moosique.net/moosique/classes/ trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/Debugger.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/FirePHP.php trunk/src/moosique.net/moosique/classes/LastFM.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/Utilities.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/def0.xsd trunk/src/moosique.net/moosique/def1.xsd trunk/src/moosique.net/moosique/index.php trunk/src/moosique.net/moosique/main.wsdl trunk/src/moosique.net/moosique/xml2json/ trunk/src/moosique.net/moosique/xml2json/json.php trunk/src/moosique.net/moosique/xml2json/xml2json.php Removed Paths: ------------- trunk/src/moosique.net/img/bg_body.png trunk/src/moosique.net/img/del.png trunk/src/moosique.net/img/next.png trunk/src/moosique.net/img/pause.png trunk/src/moosique.net/img/play.png trunk/src/moosique.net/img/prev.png trunk/src/moosique.net/img/stop.png trunk/src/moosique.net/js/ie6fixes.js trunk/src/moosique.net/js/slimbox.js trunk/src/moosique.net/mp3/ trunk/src/moosique.net/php/ Modified: trunk/src/moosique.net/css/default.css =================================================================== --- trunk/src/moosique.net/css/default.css 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/css/default.css 2009-05-27 21:49:13 UTC (rev 1775) @@ -1,44 +1,44 @@ -@charset 'utf-8'; -@media all { /* Yes we want to reset this for print-Styles too */ -/* Based on various Reset-Styles, included own stuff and added mediabox-Style */ -/* Reset all elements except form stuff */ -html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; vertical-align: baseline; -} - -html { height: 100%; } -body { height: 101%; background-color: #fff; color: #000; line-height: 1; } -ol, ul { list-style: none; } -table { border-collapse: collapse; border-spacing: 0; } -caption, th, td { text-align: left; font-weight: normal; } -blockquote:before, blockquote:after, q:before, q:after { content: ""; } -blockquote, q { quotes: "" ""; } -strong, b { font-weight: bold; } -em, i { font-style: italic; } -label, input[type=button], input[type=submit], button { cursor: pointer; } -abbr[title] { border-bottom: 1px dotted #888 !important; cursor: help; } -a abbr { cursor: pointer !important; } - -/* General purpose-Classes */ -.hidden { position: absolute; left: -9999999em; top: -9999999em;} - -/* Clearfix hack */ -.clearfix:after { clear: both; content: "."; display: block; height: 0; visibility: hidden; } -.clearfix { display: inline-block; } -* html .clearfix { height: 1%; } -.clearfix { display: block; } - -/* Special Stuff */ -:focus { outline: 0; } -a { text-decoration: none; } -a:hover { text-decoration: underline; } -a:active { position: relative; top: 1px; } -input:focus, textarea:focus, select:focus { background: #eee; } -fieldset { border: 1px solid #333; padding: 9px; } -fieldset legend { padding: 0 9px; } -h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal; } - -} /* End @media all */ \ No newline at end of file +@media all { /* Yes we want to reset this for print-Styles too */ +/* Based on various Reset-Styles, included own stuff and added mediabox-Style */ +/* Reset all elements except form stuff */ +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; vertical-align: baseline; +} + +html { height: 100%; } +body { height: 101%; background-color: #fff; color: #000; line-height: 1; } +ol, ul { list-style: none; } +table { border-collapse: collapse; border-spacing: 0; } +caption, th, td { text-align: left; font-weight: normal; } +blockquote:before, blockquote:after, q:before, q:after { content: ""; } +blockquote, q { quotes: "" ""; } +strong, b { font-weight: bold; } +em, i { font-style: italic; } +label, input[type=button], input[type=submit], button { cursor: pointer; } +abbr[title] { border-bottom: 1px dotted #888 !important; cursor: help; } +a abbr { cursor: pointer !important; } + +/* General purpose-Classes */ +.hidden { position: absolute; left: -9999999em; top: -9999999em;} + +/* Clearfix hack */ +.clearfix:after { clear: both; content: "."; display: block; height: 0; visibility: hidden; } +.clearfix { display: inline-block; } +* html .clearfix { height: 1%; } +.clearfix { display: block; } + +/* Special Stuff */ +:focus { outline: 0; } +a { text-decoration: none; } +a:hover { text-decoration: underline; } +a:active { position: relative; top: 1px; } +.ie6 a:active, .ie7 a:active { position: static; top: auto; } +input:focus, textarea:focus, select:focus { background: #eee; } +fieldset { border: 1px solid #333; padding: 9px; } +fieldset legend { padding: 0 9px; } +h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal; } + +} /* End @media all */ Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/css/style.css 2009-05-27 21:49:13 UTC (rev 1775) @@ -1,12 +1,8 @@ -@charset 'utf-8'; -@import url(default.css); - /* moosique.net * * Semiblack: #131313 - * Dark Grey: #383838 * Light Grey: #545454 - * White: #fff + * White: #f8faf7 * Yellowish: #ffbc00 * */ @@ -16,14 +12,14 @@ /* Default Element Styling --- Start Editing below this line */ /* =================================================================== */ * { - font-family: Verdana, Arial, "Lucida Grande", Helvetica, sans-serif; - font-size: 14px; - line-height: 18px; - color: #fff; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + line-height: 16px; + color: #131313; } body { - background: #333; + background: #f8faf7; } a:hover { @@ -32,7 +28,7 @@ /* Abstand Zeilenhoehe nach unten bei manchen Elementen */ p, h1, h2, h3, h4, h5, h6, table, ul, ol, blockquote, pre, form { - margin-bottom: 18px; + margin-bottom: 16px; } /* Default Container Positioning */ @@ -42,25 +38,27 @@ } #headerContainer { - height: 140px; - background: #131313; - border-top: 1px solid #999; - border-bottom: 10px solid #ffbc00; + height: 95px; + background: #333; + border-bottom: 5px solid #ffbc00; + padding: 20px 0 0 0; } #header { - width: 960px; + width: 760px; margin: 0 auto; } #container { - border-top: 1px solid #1a1a1a; + border-top: 1px solid #ccc; } #mainContainer { - width: 960px; + width: 700px; margin: 0 auto; - padding: 30px 0; + padding: 30px; + border: 1px solid #ccc; + border-top: none; } #footer { @@ -71,316 +69,304 @@ /* header Area */ /* =================================================================== */ #header h1 a { - font-size: 36px; - line-height: 90px; - font-family: Georgia, "Times New Roman", Times, serif; + font-size: 32px; + line-height: 32px; + font-family: Georgia, Times, "Times New Roman", serif; text-decoration: none; + color: #f8faf7; } -#now { +#status, #header .currentlyPlaying { position: absolute; - top: 20px; - left: 280px; - width: 410px; - height: 37px; - padding: 10px 20px; - background: #545454; + top: 0; + right: 0; + width: 380px; + background: #545454; + padding: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } -#now h2, #now h3, now p { - margin: 0; +#status { + background: #545454; + color: #f8faf7; + z-index: 1000000; + height: 32px; + line-height: 32px; + text-align: center; } -#now h2, #now p { - font-size: 11px; - line-height: 11px; +.currentlyPlaying h2, .currentlyPlaying h3, .currentlyPlaying h4 { + margin-bottom: 0; } -#now h3 { - font-size: 18px; - line-height: 24px; +#header .currentlyPlaying h2 { + font-size: 10px; } -#now p { +#header .currentlyPlaying h4 { position: absolute; - top: 10px; + bottom: 10px; right: 10px; - text-align: right; + font-size: 10px; } -#status { - position: absolute; - top: 83px; - left: 300px; - width: 410px; - font-size: 11px; +#searchForm input#searchValue { + margin: 0 5px; + width: 100px; } -#playerControls { +#loadingImg { + display: none; +} + +/* mainMenu & status */ +/* =================================================================== */ + +#mainMenu ul { position: absolute; - width: 116px; - height: 37px; - top: 20px; - right: 0; - padding: 10px 20px; - background: #545454; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; + top: 70px; + right: 0; } -#prev, #next, #stop, #playPause { - display: block; - width: 20px; - height: 37px; - text-decoration: none; - text-indent: -1000000px; +#mainMenu ul li { float: left; - margin-right: 10px; + -moz-border-radius-topleft: 10px; + -moz-border-radius-topright: 10px; + -webkit-border-top-left-radius: 10px; + -webkit-border-top-right-radius: 10px; + padding: 0 15px; + background: #545454; + margin: 5px 0 0 5px; + height: 20px; + line-height: 20px; } -#playPause { - width: 26px; +#mainMenu ul li a { + color: #131313; } -#next { - margin-right: 0; +#mainMenu ul li.active { + height: 25px; + line-height: 25px; + margin-top: 0; + background: #ffbc00; } -/* clicky feel */ -#prev:active, #next:active, #stop:active, #playPause:active { - position: relative; - top: 2px; +#mainMenu ul li.active a { + font-weight: bold; } -#prev { - background: url(../img/controls.png) 0px -160px no-repeat; +#mainMenu ul li a:hover { + text-decoration: none; } -#next { - background: url(../img/controls.png) 0px -120px no-repeat; + + +/* Content Area Default Styles */ +/* =================================================================== */ +#content h2, #content h3 { + font-size: 16px; + line-height: 24px; + font-weight: bold; } -#playPause { - background: url(../img/controls.png) 0px 0px no-repeat; -} -#stop { - background: url(../img/controls.png) 0px -80px no-repeat; -} -#toggles { - position: absolute; - width: 156px; - height: 18px; - top: 93px; - right: 0; - text-align: center; +/* for debugging */ +#content pre { + font-family: "Courier New", Courier, monospace; + font-size: 10px; } -#toggleMute, #togglePlaylist { - font-size: 11px; - text-decoration: none; +/* Initial hiding */ +#recommendations, #player, #information, #help { + display: none; /* Initial Hide */ } -#toggleMute { - padding-right: 10px; +#footer * { + font-size: 10px; } -/* Playlist Area */ +/* home -- search results */ /* =================================================================== */ - -#playlistContainer { - position: absolute; - width: 368px; - top: 30px; - right: 0; - background: #000; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; - z-index: 100; - display: none; +#results h3 em { + font-size: 16px; } -#playlistHeader { - position: relative; - -moz-border-radius-topleft: 10px; - -moz-border-radius-topright: 10px; - -webkit-border-top-left-radius: 10px; - -webkit-border-top-right-radius: 10px; - background: #111; - padding: 5px 10px; - cursor: move; +#results ul li h3 a { + font-weight: normal; } -#playlistFooter { - position: absolute; - width: 100%; - bottom: 0; - -moz-border-radius-bottomleft: 10px; - -moz-border-radius-bottomright: 10px; - -webkit-border-bottom-left-radius: 10px; - -webkit-border-bottom-right-radius: 10px; - background: #111; - padding: 5px 0; - cursor: se-resize; +#results ul li img { + border: 2px solid #545454; + margin-bottom: 16px; } -#closePlaylist { - position: absolute; - width: 100px; - height: 20px; - top: 5px; - right: 10px; - text-align: right; - font-size: 10px; +#results ul li { + display: block; + border: 1px dotted #545454; + padding: 16px; + margin: 0 16px 16px 0; + float: left; + width: 300px; } -#playlist { - padding: 20px; - margin: 0 0 20px 0; +#results .artistSearch ul li { + height: 450px; } -#playlist li { - position: relative; /* Delete Buttons */ - list-style: decimal; - list-style-position: inside; - cursor: move; - padding: 3px; +#results ul ul { + list-style: square; } -#playlist li a.ymp-btn-page-pause { - font-weight: bold; +#results ul li ul li, +#results .artistSearch ul li ul li, +#results .tagSearch ul li ul li { + border: none; + display: list-item; + padding: 0; + margin: 0 0 0 32px; + width: auto; + height: auto; + float: none; } -/* Delete buttons */ -#playlist li a.del { - position: absolute; - display: block; - top: 5px; - right: 10px; - width: 14px; - height: 14px; - line-height: 14px; - margin-right: -19px; - z-index: 1000; - text-indent: -99999999px; - background: url(../img/controls.png) 0px -200px no-repeat; +#results .tagSearch ul li ul { + clear: both; } + -/* mainMenu */ -/* =================================================================== */ -#mainMenu ul { - position: absolute; - top: -46px; - left: 0; +#results .artistSearch ul li div.artistImage { + text-align: center; } -#mainMenu ul li { +#results .tagSearch ul li div.cover { + margin-right: 16px; + width: 110px; float: left; - -moz-border-radius-topleft: 10px; - -moz-border-radius-topright: 10px; - -webkit-border-top-left-radius: 10px; - -webkit-border-top-right-radius: 10px; - padding: 0 15px; - background: #545454; - margin: 5px 5px 0 0; - height: 30px; - line-height: 30px; } -#mainMenu ul li a { - color: #131313; +#results .tagSearch ul li h4 { + display: inline; + font-weight: bold; } -#mainMenu ul li.active { - height: 35px; - line-height: 35px; - margin-top: 0; - background: #ffbc00; + + + + +/* Recommendations */ +/* =================================================================== */ +#recommended { + list-style: decimal; + margin-left: 24px; } -#mainMenu ul li.active a { +#recommended li { + line-height: 24px; +} + +#recommended a:hover { + cursor: pointer; + text-decoration: none; font-weight: bold; + color: #131313; } -/* Content Area Default Styles */ + +/* information */ /* =================================================================== */ -#mainContainer h2 { - font-size: 20px; - line-height: 28px; - font-weight: bold; -} -/* for debugging */ -#mainContainer pre { - font-size: 12px; - font-family: "Courier New", Courier, monospace; -} -/* search */ +/* player */ /* =================================================================== */ -#searchForm * { - color: #131313; + +#playerControls { + position: absolute; + width: 149px; + height: 37px; + top: 0; + right: 0; + padding: 10px 20px; + background: #545454; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; } +#prev, #next, #stop, #playPause, #mute { + display: block; + width: 20px; + height: 37px; + text-decoration: none; + text-indent: -1000000px; + float: left; + margin-right: 10px; +} -/* Recommendations */ -/* =================================================================== */ -#recommendations { - display: none; /* Initial Hide */ +/* clicky feel */ +#prev:active, #next:active, #stop:active, +#playPause:active, #mute:active { + position: relative; + top: 2px; } -#recommendations ol { - list-style: decimal; - margin-left: 24px; - width: 50%; +/* Sprites */ +#prev { background: url(../img/controls.png) 0px -160px no-repeat; } +#next { background: url(../img/controls.png) 0px -120px no-repeat; } +#stop { background: url(../img/controls.png) 0px -80px no-repeat; } + +#playPause { + background: url(../img/controls.png) 0px 0px no-repeat; + width: 26px; } -#recommendations ol li a { +#mute { + background: url(../img/controls.png) 0px -280px no-repeat; + margin-right: 0; + width: 23px; +} +/* End Sprites */ + +#playlist li { + position: relative; /* Delete Buttons */ + list-style: decimal; + list-style-position: inside; cursor: move; - text-decoration: none; + padding: 3px; } -#recommendations ol li a:hover { - text-decoration: none; - color: #fff; +#playlist li a.ymp-btn-page-pause { + font-weight: bold; } -#recommendations li:hover { - border: 1px solid #ffbc00; +/* Delete buttons */ +#playlist li a.del { + position: absolute; + display: block; + top: 5px; + right: 20px; + width: 14px; + height: 14px; + line-height: 14px; + margin-right: -19px; + z-index: 1000; + text-indent: -99999999px; + background: url(../img/controls.png) 0px -200px no-repeat; } - /* Draggable li-Items */ -#playlist li.moving, #recommendations li.moving { +#playlist li.moving { background: #666; border: 3px solid #ffbc00; - color: #000; font-weight: bold; } -/* information */ -/* =================================================================== */ -#information { - display: none; /* Initial Hide */ -} -/* Sidebar Area */ -/* =================================================================== */ - -/* Footer Area */ -/* =================================================================== */ -#footer a { - font-size: 11px; -} - - -} /* end @media screen \ No newline at end of file +} /* end @media screen */ \ No newline at end of file Deleted: trunk/src/moosique.net/img/bg_body.png =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/img/controls.png =================================================================== (Binary files differ) Deleted: trunk/src/moosique.net/img/del.png =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/img/loading.gif =================================================================== (Binary files differ) Deleted: trunk/src/moosique.net/img/next.png =================================================================== (Binary files differ) Added: trunk/src/moosique.net/img/noArtistImage.png =================================================================== (Binary files differ) Property changes on: trunk/src/moosique.net/img/noArtistImage.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Deleted: trunk/src/moosique.net/img/pause.png =================================================================== (Binary files differ) Deleted: trunk/src/moosique.net/img/play.png =================================================================== (Binary files differ) Deleted: trunk/src/moosique.net/img/prev.png =================================================================== (Binary files differ) Deleted: trunk/src/moosique.net/img/stop.png =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/index.php 2009-05-27 21:49:13 UTC (rev 1775) @@ -1,10 +1,11 @@ -<!DOCTYPE html +<?php session_start(); ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>moosique.net</title> + <link href="css/default.css" rel="stylesheet" type="text/css" /> <link href="css/style.css" rel="stylesheet" type="text/css" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> </head> @@ -16,120 +17,135 @@ <div id="headerContainer"> <div id="header"> <h1><a href="index.php">moosique.net</a></h1> - <div id="now"> - <h2>Player stopped</h2> - <h3>...</h3> - <p>0:00 / 0:00</p> - </div> - <div id="status"> + <div id="mainMenu"> + <ul class="clearfix"> + <li class="active"><a href="#" class="home">Home</a></li> + <li><a href="#" class="player">Player</a></li> + <li><a href="#" class="recommendations">Recommendations</a></li> + <li><a href="#" class="information">Information</a></li> + <li><a href="#" class="help">Help</a></li> + </ul> </div> - <div id="playerControls"> - <a href="#" id="prev" title="Play previous Track in Playlist">Previous Tack</a> - <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> - <a href="#" id="stop" title="Stop playing">Stop</a> - <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> + <form id="searchForm" method="get" action="moosique/"> + <div class="clearfix"> + <select name="typeOfSearch" id="typeOfSearch"> + <option value="artistSearch">Artist</option> + <option value="tagSearch">Tag</option> + <?php /* + <option value="songSearch">Song</option> + <option value="lastfm">Last.fm-User</option> + */ ?> + </select> + <input id="searchValue" name="searchValue" type="text" /> + <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" disabled="disabled" /> + <img id="loadingImg" src="img/loading.gif" alt="Loading..." /> + </div> + </form> + + <div id="status"> </div> + + <div class="currentlyPlaying"> + <h2>Player stopped</h2> + <h3>...</h3> + <h4>0:00 / 0:00</h4> </div> - <div id="toggles"> - <a href="#" id="toggleMute" title="Sound on/off">Mute</a> - <a href="#" id="togglePlaylist" title="Show/Hide Playlist">Playlist</a> - </div> </div> </div> <div id="container"> - <div id="mainContainer"> - <div id="mainMenu"> - <ul class="clearfix"> - <li class="active"><a href="#" class="search">Search</a></li> - <li><a href="#" class="recommendations">Recommendations</a></li> - <li><a href="#" class="information">Information</a></li> - </ul> - </div> - <div id="content"> + <div id="content" class="clearfix"> - - <div id="search"> - <h2>Welcome to moosique.net!</h2> - <p> - Want to listen to some good free music? Just enter an artist or song - name, search for tags or enter your last.fm username and let the moogic - happen... - </p> - <form id="searchForm" method="post" action="php/ajaxer.php"> - <div> - <select name="typeOfSearch" id="typeOfSearch"> - <option value="artist">Artist</option> - <option value="song">Songtitle</option> - <option value="tag">Tag</option> - <option value="lastfm">Last.fm-User</option> - </select> - <input id="searchValue" name="searchValue" type="text" /> - <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> - </div> - </form> + <div id="home"> + <div id="welcome"> + <h2>Welcome to moosique.net!</h2> + <p> + Want to listen to some good free music? Just enter an artist or song + name or search for music using tags <!-- or enter your last.fm username --> and let the moogic + happen. By listening to songs you like, the system will automatically learn about + your musical taste and generate recommendations. You can find them in the tab »Recommendations«. + </p> + <p> + You can find information about the song currently playing in the tab »Information« and view + your Playlist and control the Player in the Tab »Player«. + </p> + <p> + Now get started and add something to the Playlist! + </p> + </div> <div id="results"> </div> </div> <div id="recommendations"> - <h2>Try dragging these samples to the playlist</h2> - <ol> - <li><a href="http://stream6-3.jamendo.com/8654/mp31/01%20-%20Low%20Earth%20Orbit%20-%20My%20Mistakes.mp3">Low Earth Orbit - My Mistakes</a></li> - <li><a href="http://stream6-3.jamendo.com/8654/mp31/02%20-%20Low%20Earth%20Orbit%20-%20Like%20Mud.mp3">Low Earth Orbit - Like Mud</a></li> - <li><a href="http://stream6-3.jamendo.com/8654/mp31/03%20-%20Low%20Earth%20Orbit%20-%20Defend.mp3">Low Earth Orbit - Defend</a></li> - <li><a href="http://stream6-3.jamendo.com/8654/mp31/04%20-%20Low%20Earth%20Orbit%20-%20What%20Can%20I%20Say.mp3">Low Earth Orbit - What Can I Say</a></li> + <h2>Recommended Songs</h2> + <p>Click a song to add it to your playlist.</p> + <ol id="recommended"> + <li></li> </ol> </div> <div id="information"> - <div id="sidebar"> - <div id="moreInfo"> - <h2>About the Artist</h2> - <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> - <p> - Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat - duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil - imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis - dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus - qui nobis videntur parum. - </p> - </div> + <div id="moreInfo"> + <h2>About the Artist</h2> + <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> + <p> + Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat + duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil + imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis + dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus + qui nobis videntur parum. + </p> </div> </div> + + <div id="player"> + <h3>Playlist</h3> + <p> + You can delete entries from the playlist by clicking the small x on the left. <br /> + You also can move the playlist-entries around to change their order. + </p> - </div> + <ol id="playlist"> + <li></li> + </ol> - <div id="playlistContainer"> - <div id="playlistHeader"> - Playlist - <a href="#" id="closePlaylist" title="Close Playlist Window">Close Window</a> + <div id="playerControls"> + <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> + <a href="#" id="stop" title="Stop playing">Stop</a> + <a href="#" id="prev" title="Play previous Track in Playlist">Previous Tack</a> + <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> + <a href="#" id="mute" title="Sound on/off">Mute</a> + </div> + </div> - <ol id="playlist"> - <li><a href="mp3/moosique.mp3" class="htrack">Welcome to moosique</a></li> - </ol> - <div id="playlistFooter"> </div> - </div> - - <div id="footer"> - <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | - <a href="http://aksw.org/Projects/DLLearner">Powered by DL-Learner</a> - </div> + + <div id="help"> + + </div> + + </div> <!-- end content --> + </div> <!-- end mainContainer --> + <div id="footer"> + <a href="http://jamendo.com">Jamendo</a> | + <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | + <a href="http://aksw.org/Projects/DLLearner">Powered by DL-Learner</a> </div> - </div> + </div> <!-- end container --> <!-- JS at the bottom, faster loading pages --> + <script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> + <script type="text/javascript" src="js/mootools-core.js"></script> <script type="text/javascript" src="js/mootools-more.js"></script> - <script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> - + <script type="text/javascript" src="js/player.js"></script> <script type="text/javascript" src="js/interface.js"></script> <script type="text/javascript" src="js/ajax.js"></script> Modified: trunk/src/moosique.net/js/ajax.js =================================================================== --- trunk/src/moosique.net/js/ajax.js 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/js/ajax.js 2009-05-27 21:49:13 UTC (rev 1775) @@ -1,55 +1,93 @@ window.addEvent('domready', function() { -var responseObject = ''; - // handle search requests $('searchForm').addEvent('submit', function(e) { var results = $('results'); var submit = $('searchSubmit'); + var loading = $('loadingImg'); e.stop(); // prevent form submitting the non-ajax way this.set('send', { - onRequest: function(response) { + onRequest: function() { submit.set('disabled', 'disabled'); // disable submit button until request complete - results.set('html', '<h2>Processing your search request...</h2>'); + // show homescreen for resultdisplaying + showTab('home'); + submit.setStyle('display', 'none'); + loading.setStyle('display', 'inline'); + results.set('html', '<h2>Searching...</h2>'); }, - onFailure: function(response) { + onFailure: function() { results.set('html', '<h2>Unable to process your search. Try again.</h2>'); }, onSuccess: function(response) { submit.erase('disabled'); // reenable submitbutton - responseObject = JSON.decode(response); - // info.set('text', response); - results.set('html', '<h2>Done.</h2>'); - // Firebug needed - console.log(responseObject); - - - - /* - var newPlaylistItem = new Element('a', { - 'href': responseObject.playlist.trackList.track.location, - 'html': responseObject.playlist.trackList.track.creator + ' - ' + responseObject.playlist.trackList.track.title - }); + submit.setStyle('display', 'inline'); + loading.setStyle('display', 'none'); - newPlaylistItem.inject(info); - */ + // if the welcome-text ist present, cut it to help + if ($('welcome')) { + if ($('welcome').get('html').length > 100) { + $('help').set('html', $('welcome').get('html')); + $('welcome').destroy(); + } + } + + // display results + results.set('html', response); + + // addEvents to result-links + makeAddable(); } - - - }); - this.send(); + // only send form if value is at least 3 + if ($('searchValue').get('value').length > 2) { + this.send(); + } - }); +makeAddable(); +}); -}); \ No newline at end of file + +/** + * For Recommendations and Search-Results + */ +function makeAddable() { + $$('a.addToPlaylist').each(function(a) { + a.addEvent('click', function(e) { + e.stop(); // dont follow link + // remove the class from preventing adding again + + a.removeClass('addToPlaylist'); + + // TODO, now using xspfs, later we only will use mp3-links + a.set('type', 'application/xspf+xml'); + + // if the Playlist is empty, remove entries + if ($('playlist').getFirst()) { + if ($('playlist').getFirst().get('text') == '') { + $('playlist').empty(); + } + } + + + a.getParent().inject($('playlist')); + if (a.get('title')) { + a.set('text', a.get('title')); + } + + // + mooPlayer.refreshPlaylist(); + showTab('player'); + + }); + }); +} \ No newline at end of file Deleted: trunk/src/moosique.net/js/ie6fixes.js =================================================================== --- trunk/src/moosique.net/js/ie6fixes.js 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/js/ie6fixes.js 2009-05-27 21:49:13 UTC (rev 1775) @@ -1,48 +0,0 @@ -window.addEvent('domready', function() { - if (Browser.Engine.trident4) { - - // PNG-Support for IE6 for all img-Tags - $$('img').each(function(i) { - // additional styles - iStyle = "display: inline-block; "; - if (i.getParent().get('href') !== "") { - iStyle += "cursor: pointer; " - } - // if the img-src is a .png - var iName = i.get('src').toLowerCase(); - if (iName.substring(iName.length - 3, iName.length) == "png") { - var strNewHTML = '<span id="' + i.get('id') + - '" class="'+ i.get('class') + - '" style="' + iStyle + - 'width: ' + i.getSize().x + - 'px; height: ' + i.getSize().y + - 'px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader' + - "(src=\'" + i.getProperty('src') + "\', sizingMethod='scale');\"></span>"; - i.outerHTML = strNewHTML; - } - }); - - // PNG-Background-Image-Support for chosen tags (edit for performance) - $$('div', 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'form').each(function(el) { - var bgImg = el.getStyle('background-image'); - if (bgImg.contains('.png')) { - var expression = /url\("(.*\.png)"\)/; // IE-only, other browsers dont "" - var result = expression.exec(bgImg); - var imgUrl = result[1]; - - var method = 'crop'; - // if repeat-x or y scale the image, does not work for patterns - if ( el.getStyle('background-repeat') == 'repeat-x' || - el.getStyle('background-repeat') == 'repeat-y') { - method = 'scale'; - } - if (imgUrl.length > 4) { - el.setStyles({ - 'background-image': 'none', - 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imgUrl + "', sizingMethod='" + method + "');" - }); - } - } - }); - } -}); \ No newline at end of file Modified: trunk/src/moosique.net/js/interface.js =================================================================== --- trunk/src/moosique.net/js/interface.js 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/js/interface.js 2009-05-27 21:49:13 UTC (rev 1775) @@ -5,13 +5,32 @@ $$('#mainMenu ul li a').each(function(a) { a.addEvent('click', function(e) { e.stop(); // dont follow link - $$('#mainMenu ul li').removeClass('active'); - a.getParent().toggleClass('active'); - console.log(a.get('class')); - $('content').getChildren().setStyle('display', 'none') - $(a.get('class')).setStyle('display', 'block'); + showTab(a.get('class').toString()); }); }); -}); \ No newline at end of file +$('searchValue').addEvent('keyup', function() { + if (this.get('value').length > 2) { + $('searchSubmit').erase('disabled'); + } else { + $('searchSubmit').set('disabled', 'disabled'); + } +}); + + +}); + +/** + * + * @param {String} tabID ID of the Tab to show + */ +function showTab(tabID) { + $$('#mainMenu ul li').removeClass('active'); + $$('#mainMenu ul li a.' + tabID).getParent().toggleClass('active'); + $('content').getChildren().setStyle('display', 'none') + $(tabID).setStyle('display', 'block'); + +} + + Modified: trunk/src/moosique.net/js/mootools-core.js =================================================================== --- trunk/src/moosique.net/js/mootools-core.js 2009-05-27 10:51:47 UTC (rev 1774) +++ trunk/src/moosique.net/js/mootools-core.js 2009-05-27 21:49:13 UTC (rev 1775) @@ -1,129 +1,352 @@ -//MooTools, <http://mootools.net>, My Object Oriented (JavaScript) Tools. Copyright (c) 2006-2008 Valerio Proietti, <http://mad4milk.net>, MIT Style License. +//MooTools, <http://mootools.net>, My Object Oriented (JavaScript) Tools. Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net>, MIT Style License. -var MooTools={'version':'1.2.1','build':'0d4845aab3d9a4fdee2f0d4a6dd59210e4b697cf'};var Native=function(options){options=options||{};var name=options.name;var legacy=options.legacy;var protect=options.protect;var methods=options.implement;var generics=options.generics;var initialize=options.initialize;var afterImplement=options.afterImplement||function(){};var object=initialize||legacy;generics=generics!==false;object.constructor=Native;object.$family={name:'native'};if(legacy&&initialize)object.prototype=legacy.prototype;object.prototype.constructor=object;if(name){var family=name.toLowerCase();object.prototype.$family={name:family};Native.typize(object,family);} -var add=function(obj,name,method,force){if(!protect||force||!obj.prototype[name])obj.prototype[name]=method;if(generics)Native.genericize(obj,name,protect);afterImplement.call(obj,name,method);return obj;};object.alias=function(a1,a2,a3){if(typeof a1=='string'){if((a1=this.prototype[a1]))return add(this,a2,a1,a3);} -for(var a in a1)this.alias(a,a1[a],a2);return this;};object.implement=function(a1,a2,a3){if(typeof a1=='string')return add(this,a1,a2,a3);for(var p in a1)add(this,p,a1[p],a2);return this;};if(methods)object.implement(methods);return object;};Native.genericize=function(object,property,check){if((!check||!object[property])&&typeof object.prototype[property]=='function')object[property]=function(){var args=Array.prototype.slice.call(arguments);return object.prototype[property].apply(args.shift(),args);};};Native.implement=function(objects,properties){for(var i=0,l=objects.length;i<l;i++)objects[i].implement(properties);};Native.typize=function(object,family){if(!object.type)object.type=function(item){return($type(item)===family);};};(function(){var natives={'Array':Array,'Date':Date,'Function':Function,'Number':Number,'RegExp':RegExp,'String':String};for(var n in natives)new Native({name:n,initialize:natives[n],protect:true});var types={'boolean':Boolean,'native':Native,'object':Object};for(var t in types)Native.typize(types[t],t);var generics={'Array':["concat","indexOf","join","lastIndexOf","pop","push","reverse","shift","slice","sort","splice","toString","unshift","valueOf"],'String':["charAt","charCodeAt","concat","indexOf","lastIndexOf","match","replace","search","slice","split","substr","substring","toLowerCase","toUpperCase","valueOf"]};for(var g in generics){for(var i=generics[g].length;i--;)Native.genericize(window[g],generics[g][i],true);};})();var Hash=new Native({name:'Hash',initialize:function(object){if($type(object)=='hash')object=$unlink(object.getClean());for(var key in object)this[key]=object[key];return this;}});Hash.implement({forEach:function(fn,bind){for(var key in this){if(this.hasOwnProperty(key))fn.call(bind,this[key],key,this);}},getClean:function(){var clean={};for(var key in this){if(this.hasOwnProperty(key))clean[key]=this[key];} -return clean;},getLength:function(){var length=0;for(var key in this){if(this.hasOwnProperty(key))length++;} -return length;}});Hash.alias('forEach','each');Array.implement({forEach:function(fn,bind){for(var i=0,l=this.length;i<l;i++)fn.call(bind,this[i],i,this);}});Array.alias('forEach','each');function $A(iterable){if(iterable.item){var array=[];for(var i=0,l=iterable.length;i<l;i++)array[i]=iterable[i];return array;} -return Array.prototype.slice.call(iterable);};function $arguments(i){return function(){return arguments[i];};};function $chk(obj){return!!(obj||obj===0);};function $clear(timer){clearTimeout(timer);clearInterval(timer);return null;};function $defined(obj){return(obj!=undefined);};function $each(iterable,fn,bind){var type=$type(iterable);((type=='arguments'||type=='collection'||type=='array')?Array:Hash).each(iterable,fn,bind);};function $empty(){};function $extend(original,extended){for(var key in(extended||{}))original[key]=extended[key];return original;};function $H(object){return new Hash(object);};function $lambda(value){return(typeof value=='function')?value:function(){return value;};};function $merge(){var mix={};for(var i=0,l=arguments.length;i<l;i++){var object=arguments[i];if($type(object)!='object')continue;for(var key in object){var op=object[key],mp=mix[key];mix[key]=(mp&&$type(op)=='object'&&$type(mp)=='object')?$merge(mp,op):$unlink(op);}} -return mix;};function $pick(){for(var i=0,l=arguments.length;i<l;i++){if(arguments[i]!=undefined)return arguments[i];} -return null;};function $random(min,max){return Math.floor(Math.random()*(max-min+1)+min);};function $splat(obj){var type=$type(obj);return(type)?((type!='array'&&type!='arguments')?[obj]:obj):[];};var $time=Date.now||function(){return+new Date;};function $try(){for(var i=0,l=arguments.length;i<l;i++){try{return arguments[i]();}catch(e){}} -return null;};function $type(obj){if(obj==undefined)return false;if(obj.$family)return(obj.$family.name=='number'&&!isFinite(obj))?false:obj.$family.name;if(obj.nodeName){switch(obj.nodeType){case 1:return'element';case 3:return(/\S/).test(obj.nodeValue)?'textnode':'whitespace';}}else if(typeof obj.length=='number'){if(obj.callee)return'arguments';else if(obj.item)return'collection';} -return typeof obj;};function $unlink(object){var unlinked;switch($type(object)){case'object':unlinked={};for(var p in object)unlinked[p]=$unlink(object[p]);break;case'hash':unlinked=new Hash(object);break;case'array':unlinked=[];for(var i=0,l=object.length;i<l;i++)unlinked[i]=$unlink(object[i]);break;default:return object;} -return unlinked;};var Browser=$merge({Engine:{name:'unknown',version:0},Platform:{name:(window.orientation!=undefined)?'ipod':(navigator.platform.match(/mac|win|linux/i)||['other'])[0].toLowerCase()},Features:{xpath:!!(document.evaluate),air:!!(window.runtime),query:!!(document.querySelector)},Plugins:{},Engines:{presto:function(){return(!window.opera)?false:((arguments.callee.caller)?960:((document.getElementsByClassName)?950:925));},trident:function(){return(!window.ActiveXObject)?false:((window.XMLHttpRequest)?5:4);},webkit:function(){return(navigator.taintEnabled)?false:((Browser.Features.xpath)?((Browser.Features.query)?525:420):419);},gecko:function(){return(document.getBoxObjectFor==undefined)?false:((document.getElementsByClassName)?19:18);}}},Browser||{});Browser.Platform[Browser.Platform.name]=true;Browser.detect=function(){for(var engine in this.Engines){var version=this.Engines[engine]();if(version){this.Engine={name:engine,version:version};this.Engine[engine]=this.Engine[engine+version]=true;break;}} -return{name:engine,version:version};};Browser.detect();Browser.Request=function(){return $try(function(){return new XMLHttpRequest();},function(){return new ActiveXObject('MSXML2.XMLHTTP');});};Browser.Features.xhr=!!(Browser.Request());Browser.Plugins.Flash=(function(){var version=($try(function(){return navigator.plugins['Shockwave Flash'].description;},function(){return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');})||'0 r0').match(/\d+/g);return{version:parseInt(version[0]||0+'.'+version[1]||0),build:parseInt(version[2]||0)};})();function $exec(text){if(!text)return text;if(window.execScript){window.execScript(text);}else{var script=document.createElement('script');script.setAttribute('type','text/javascript');script[(Browser.Engine.webkit&&Browser.Engine.version<420)?'innerText':'text']=text;document.head.appendChild(script);document.head.removeChild(script);} -return text;};Native.UID=1;var $uid=(Browser.Engine.trident)?function(item){return(item.uid||(item.uid=[Native.UID++]))[0];}:function(item){return item.uid||(item.uid=Native.UID++);};var Window=new Native({name:'Window',legacy:(Browser.Engine.trident)?null:window.Window,initialize:function(win){$uid(win);if(!win.Element){win.Element=$empty;if(Browser.Engine.webkit)win.document.createElement("iframe");win.Element.prototype=(Browser.Engine.webkit)?window["[[DOMElement.prototype]]"]:{};} -win.document.window=win;return $extend(win,Window.Prototype);},afterImplement:function(property,value){window[property]=Window.Prototype[property]=value;}});Window.Prototype={$family:{name:'window'}};new Window(window);var Document=new Native({name:'Document',legacy:(Browser.Engine.trident)?null:window.Document,initialize:function(doc){$uid(doc);doc.head=doc.getElementsByTagName('head')[0];doc.html=doc.getElementsByTagName('html')[0];if(Browser.Engine.trident&&Browser.Engine.version<=4)$try(function(){doc.execCommand("BackgroundImageCache",false,true);});if(Browser.Engine.trident)doc.window.attachEvent('onunload',function(){doc.window.detachEvent('onunload',arguments.callee);doc.head=doc.html=doc.window=null;});return $extend(doc,Document.Prototype);},afterImplement:function(property,value){document[property]=Document.Prototype[property]=value;}});Document.Prototype={$family:{name:'document'}};new Document(document);Array.implement({every:function(fn,bind){for(var i=0,l=this.length;i<l;i++){if(!fn.call(bind,this[i],i,this))return false;} -return true;},filter:function(fn,bind){var results=[];for(var i=0,l=this.length;i<l;i++){if(fn.call(bind,this[i],i,this))results.push(this[i]);} -return results;},clean:function(){return this.filter($defined);},indexOf:function(item,from){var len=this.length;for(var i=(from<0)?Math.max(0,len+from):from||0;i<len;i++){if(this[i]===item)return i;} -return-1;},map:function(fn,bind){var results=[];for(var i=0,l=this.length;i<l;i++)results[i]=fn.call(bind,this[i],i,this);return results;},some:function(fn,bind){for(var i=0,l=this.length;i<l;i++){if(fn.call(bind,this[i],i,this))return true;} -return false;},associate:function(keys){var obj={},length=Math.min(this.length,keys.length);for(var i=0;i<length;i++)obj[keys[i]]=this[i];return obj;},link:function(object){var result={};for(var i=0,l=this.length;i<l;i++){for(var key in object){if(object[key](this[i])){result[key]=this[i];delete object[key];break;}}} -return result;},contains:function(item,from){return this.indexOf(item,from)!=-1;},extend:function(array){for(var i=0,j=array.length;i<j;i++)this.push(array[i]);return this;},getLast:function(){return(this.length)?this[this.length-1]:null;},getRandom:function(){return(this.length)?this[$random(0,this.length-1)]:null;},include:function(item){if(!this.contains(item))this.push(item);return this;},combine:function(array){for(var i=0,l=array.length;i<l;i++)this.include(array[i]);return this;},erase:function(item){for(var i=this.length;i--;i){if(this[i]===item)this.splice(i,1);} -return this;},empty:function(){this.length=0;return this;},flatten:function(){var array=[];for(var i=0,l=this.length;i<l;i++){var type=$type(this[i]);if(!type)continue;array=array.concat((type=='array'||type=='collection'||type=='arguments')?Array.flatten(this[i]):this[i]);} -return array;},hexToRgb:function(array){if(this.length!=3)return null;var rgb=this.map(function(value){if(value.length==1)value+=value;return value.toInt(16);});return(array)?rgb:'rgb('+rgb+')';},rgbToHex:function(array){if(this.length<3)return null;if(this.length==4&&this[3]==0&&!array)return'transparent';var hex=[];for(var i=0;i<3;i++){var bit=(this[i]-0).toString(16);hex.push((bit.length==1)?'0'+bit:bit);} -return(array)?hex:'#'+hex.join('');}});Function.implement({extend:function(properties){for(var property in properties)this[property]=properties[property];return this;},create:function(options){var self=this;options=options||{};return function(event){var args=options.arguments;args=(args!=undefined)?$splat(args):Array.slice(arguments,(options.event)?1:0);if(options.event)args=[event||window.event].extend(args);var returns=function(){return self.apply(options.bind||null,args);};if(options.delay)return setTimeout(returns,options.delay);if(options.periodical)return setInterval(returns,options.periodical);if(options.attempt)return $try(returns);return returns();};},run:function(args,bind){return this.apply(bind,$splat(args));},pass:function(args,bind){return this.create({bind:bind,arguments:args});},bind:function(bind,args){return this.create({bind:bind,arguments:args});},bindWithEvent:function(bind,args){return this.create({bind:bind,arguments:args,event:true});},attempt:function(args,bind){return this.create({bind:bind,arguments:args,attempt:true})();},delay:function(delay,bind,args){return this.create({bind:bind,arguments:args,delay:delay})();},periodical:function(periodical,bind,args){return this.create({bind:bind,arguments:args,periodical:periodical})();}});Number.implement({limit:function(min,max){return Math.min(max,Math.max(min,this));},round:function(precision){precision=Math.pow(10,precision||0);return Math.round(this*precision)/precision;},times:function(fn,bind){for(var i=0;i<this;i++)fn.call(bind,i,this);},toFloat:function(){return parseFloat(this);},toInt:function(base){return parseInt(this,base||10);}});Number.alias('times','each');(function(math){var methods={};math.each(function(name){if(!Number[name])methods[name]=function(){return Math[name].apply(null,[this].concat($A(arguments)));};});Number.implement(methods);})(['abs','acos','asin','atan','atan2','ceil','cos','exp','floor','log','max','min','pow','sin','sqrt','tan']);String.implement({test:function(regex,params){return((typeof regex=='string')?new RegExp(regex,params):regex).test(this);},contains:function(string,separator){return(separator)?(separator+this+separator).indexOf(separator+string+separator)>-1:this.indexOf(string)>-1;},trim:function(){return this.replace(/^\s+|\s+$/g,'');},clean:function(){return this.replace(/\s+/g,' ').trim();},camelCase:function(){return this.replace(/-\D/g,function(match){return match.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/[A-Z]/g,function(match){return('-'+match.charAt(0).toLowerCase());});},capitalize:function(){return this.replace(/\b[a-z]/g,function(match){return match.toUpperCase();});},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,'\\$1');},toInt:function(base){return parseInt(this,base||10);},toFloat:function(){return parseFloat(this);},hexToRgb:function(array){var hex=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);return(hex)?hex.slice(1).hexToRgb(array):null;},rgbToHex:function(array){var rgb=this.match(/\d{1,3}/g);return(rgb)?rgb.rgbToHex(array):null;},stripScripts:function(option){var scripts='';var text=this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi,function(){scripts+=arguments[1]+'\n';return'';});if(option===true)$exec(scripts);else if($type(option)=='function')option(scripts,text);return text;},substitute:function(object,regexp){return this.replace(regexp||(/\\?\{([^{}]+)\}/g),function(match,name){if(match.charAt(0)=='\\')return match.slice(1);return(object[name]!=undefined)?object[name]:'';});}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(value){for(var key in this){if(this.hasOwnProperty(key)&&this[key]===value)return key;} -return null;},hasValue:function(value){return(Hash.keyOf(this,value)!==null);},extend:function(properties){Hash.each(properties,function(value,key){Hash.set(this,key,value);},this);return this;},combine:function(properties){Hash.each(properties,function(value,key){Hash.include(this,key,value);},this);return this;},erase:function(key){if(this.hasOwnProperty(key))delete this[key];return this;},get:function(key){return(this.hasOwnProperty(key))?this[key]:null;},set:function(key,value){if(!this[key]||this.hasOwnProperty(key))this[key]=value;return this;},empty:function(){Hash.each(this,function(value,key){delete this[key];},this);return this;},include:function(key,value){var k=this[key];if(k==undefined)this[key]=value;return this;},map:function(fn,bind){var results=new Hash;Hash.each(this,function(value,key){results.set(key,fn.call(bind,value,key,this));},this);return results;},filter:function(fn,bind){var results=new Hash;Hash.each(this,function(value,key){if(fn.call(bind,value,key,this))results.set(key,value);},this);return results;},every:function(fn,bind){for(var key in this){if(this.hasOwnProperty(key)&&!fn.call(bind,this[key],key))return false;} -return true;},some:function(fn,bind){for(var key in this){if(this.hasOwnProperty(key)&&fn.call(bind,this[key],key))return true;} -return false;},getKeys:function(){var keys=[];Hash.each(this,function(value,key){keys.push(key);});return keys;},getValues:function(){var values=[];Hash.each(this,function(value){values.push(value);});return values;},toQueryString:function(base){var queryString=[];Hash.each(this,function(value,key){if(base)key=base+'['+key+']';var result;switch($type(value)){case'object':result=Hash.toQueryString(value,key);break;case'array':var qs={};value.each(function(val,i){qs[i]=val;});result=Hash.toQueryString(qs,key);break;default:result=key+'='+encodeURIComponent(value);} -if(value!=undefined)queryString.push(result);});return queryString.join('&');}});Hash.alias({keyOf:'indexOf',hasValue:'contains'});var Event=new Native({name:'Event',initialize:function(event,win){win=win||window;var doc=win.document;event=event||win.event;if(event.$extended)return event;this.$extended=true;var type=event.type;var target=event.target||event.srcElement;while(target&&target.nodeType==3)target=target.parentNode;if(type.test(/key/)){var code=event.which||event.keyCode;var key=Event.Keys.keyOf(code);if(type=='keydown'){var fKey=code-111;if(fKey>0&&fKey<13)key='f'+fKey;} -key=key||String.fromCharCode(code).toLowerCase();}else if(type.match(/(click|mouse|menu)/i)){doc=(!doc.compatMode||doc.compatMode=='CSS1Compat')?doc.html:doc.body;var page={x:event.pageX||event.clientX+doc.scrollLeft,y:event.pageY||event.clientY+doc.scrollTop};var client={x:(event.pageX)?event.pageX-win.pageXOffset:event.clientX,y:(event.pageY)?event.pageY-win.pageYOffset:event.clientY};if(type.match(/DOMMouseScroll|mousewheel/)){var wheel=(event.wheelDelta)?event.wheelDelta/120:-(event.detail||0)/3;} -var rightClick=(event.which==3)||(event.button==2);var related=null;if(type.match(/over|out/)){switch(type){case'mouseover':related=event.relatedTarget||event.fromElement;break;case'mouseout':related=event.relatedTarget||event.toElement;} -if(!(function(){while(related&&related.nodeType==3)related=related.parentNode;return true;}).create({attempt:Browser.Engine.gecko})())related=false;}} -return $extend(this,{event:event,type:type,page:page,client:client,rightClick:rightClick,wheel:wheel,relatedTarget:related,target:target,code:code,key:key,shift:event.shiftKey,control:event.ctrlKey,alt:event.altKey,meta:event.metaKey});}});Event.Keys=new Hash({'enter':13,'up':38,'down':40,'left':37,'right':39,'esc':27,'space':32,'backspace':8,'tab':9,'delete':46});Event.implement({stop:function(){return this.stopPropagation().preventDefault();},stopPropagation:function(){if(this.event.stopPropagation)this.event.stopPropagation();else this.event.cancelBubble=true;return this;},preventDefault:function(){if(this.event.preventDefault)this.event.preventDefault();else this.event.returnValue=false;return this;}});var Class=new Native({name:'Class',initialize:function(properties){properties=properties||{};var klass=function(){for(var key in this){if($type(this[key])!='function')this[key]=$unlink(this[key]);} -this.constructor=klass;if(Class.prototyping)return this;var instance=(this.initialize)?this.initialize.apply(this,arguments):this;if(this.options&&this.options.initialize)this.options.initialize.call(this);return instance;};for(var mutator in Class.Mutators){if(!properties[mutator])continue;properties=Class.Mutators[mutator](properties,properties[mutator]);delete properties[mutator];} -$extend(klass,this);klass.constructor=Class;klass.prototype=properties;return klass;}});Class.Mutators={Extends:function(self,klass){Class.prototyping=klass.prototype;var subclass=new klass;delete subclass.parent;subclass=Class.inherit(subclass,self);delete Class.prototyping;return subclass;},Implements:function(self,klasses){$splat(klasses).each(function(klass){Class.prototying=klass;$extend(self,($type(klass)=='class')?new klass:klass);delete Class.prototyping;});return self;}};Class.extend({inherit:function(object,properties){var caller=arguments.callee.caller;for(var key in properties){var override=properties[key];var previous=object[key];var type=$type(override);if(previous&&type=='function'){if(override!=previous){if(caller){override.__parent=previous;object[key]=override;}else{Class.override(object,key,override);}}}else if(type=='object'){object[key]=$merge(previous,override);}else{object[key]=override;}} -if(caller)object.parent=function(){return arguments.callee.caller.__parent.apply(this,arguments);};return object;},override:function(object,name,method){var parent=Class.prototyping;if(parent&&object[name]!=parent[name])parent=null;var override=function(){var previous=this.parent;this.parent=parent?parent[name]:object[name];var value=method.apply(this,arguments);this.parent=previous;return value;};object[name]=override;}});Class.implement({implement:function(){var proto=this.prototype;$each(arguments,function(properties){Class.inherit(proto,properties);});return this;}});var Chain=new Class({$chain:[],chain:function(){this.$chain.extend(Array.flatten(arguments));return this;},callChain:function(){return(this.$chain.length)?this.$chain.shift().apply(this,arguments):false;},clearChain:function(){this.$chain.empty();return this;}});var Events=new Class({$events:{},addEvent:function(type,fn,internal){type=Events.removeOn(type);if(fn!=$empty){this.$events[type]=this.$events[type]||[];this.$events[type].include(fn);if(internal)fn.internal=true;} -return this;},addEvents:function(events){for(var type in events)this.addEvent(type,events[type]);return this;},fireEvent:function(type,args,delay){type=Events.removeOn(type);if(!this.$events||!this.$events[type])return this;this.$events[type].each(function(fn){fn.create({'bind':this,'delay':delay,'arguments':args})();},this);return this;},removeEvent:function(type,fn){type=Events.removeOn(type);if(!this.$events[type])return this;if(!fn.internal)this.$events[type].erase(fn);return this;},removeEvents:function(events){if($type(events)=='object'){for(var type in events)this.removeEvent(type,events[type]);return this;} -if(events)events=Events.removeOn(events);for(var type in this.$events){if(events&&events!=type)continue;var f... [truncated message content] |
From: <neb...@us...> - 2009-09-01 13:44:11
|
Revision: 1833 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1833&view=rev Author: nebelschwade Date: 2009-09-01 13:44:00 +0000 (Tue, 01 Sep 2009) Log Message: ----------- Changed Layout and Playlist Handling Added new JS-Classes A Simple Examples for testing learn-Case Modified Paths: -------------- trunk/src/moosique.net/css/style.css trunk/src/moosique.net/img/controls.png trunk/src/moosique.net/img/loading.gif trunk/src/moosique.net/index.php trunk/src/moosique.net/js/interface.js trunk/src/moosique.net/js/player.js trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/Debugger.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/index.php trunk/src/moosique.net/moosique/main.wsdl Added Paths: ----------- trunk/src/moosique.net/css/index.php trunk/src/moosique.net/css/reset.css trunk/src/moosique.net/img/bg.png trunk/src/moosique.net/js/index.php trunk/src/moosique.net/js/jsmin-1.1.1.php trunk/src/moosique.net/js/mootools-1.2.3-core-yc.js trunk/src/moosique.net/js/request.js trunk/src/moosique.net/moosique/classes/FirePHP.class.php trunk/src/moosique.net/moosique/data/ trunk/src/moosique.net/moosique/data/allRecords.txt trunk/src/moosique.net/moosique/data/allRecordsWithTags.txt trunk/src/moosique.net/moosique/data/allTags.txt trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt trunk/src/moosique.net/moosique/data/dontUse.txt trunk/src/moosique.net/moosique/data/tagsWeUse.txt trunk/src/moosique.net/moosique/getAllTags.php trunk/src/moosique.net/moosique/jamendo.owl trunk/src/moosique.net/moosique/learnTest.php trunk/src/moosique.net/moosique/stonerTest.owl trunk/src/moosique.net/moosique/tagsToOwl.php Removed Paths: ------------- trunk/src/moosique.net/css/default.css trunk/src/moosique.net/js/ajax.js trunk/src/moosique.net/js/mootools-core.js trunk/src/moosique.net/js/mootools-more.js trunk/src/moosique.net/moosique/classes/FirePHP.php trunk/src/moosique.net/moosique/xml2json/ Deleted: trunk/src/moosique.net/css/default.css =================================================================== --- trunk/src/moosique.net/css/default.css 2009-08-29 14:08:33 UTC (rev 1832) +++ trunk/src/moosique.net/css/default.css 2009-09-01 13:44:00 UTC (rev 1833) @@ -1,44 +0,0 @@ -@media all { /* Yes we want to reset this for print-Styles too */ -/* Based on various Reset-Styles, included own stuff and added mediabox-Style */ -/* Reset all elements except form stuff */ -html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; vertical-align: baseline; -} - -html { height: 100%; } -body { height: 101%; background-color: #fff; color: #000; line-height: 1; } -ol, ul { list-style: none; } -table { border-collapse: collapse; border-spacing: 0; } -caption, th, td { text-align: left; font-weight: normal; } -blockquote:before, blockquote:after, q:before, q:after { content: ""; } -blockquote, q { quotes: "" ""; } -strong, b { font-weight: bold; } -em, i { font-style: italic; } -label, input[type=button], input[type=submit], button { cursor: pointer; } -abbr[title] { border-bottom: 1px dotted #888 !important; cursor: help; } -a abbr { cursor: pointer !important; } - -/* General purpose-Classes */ -.hidden { position: absolute; left: -9999999em; top: -9999999em;} - -/* Clearfix hack */ -.clearfix:after { clear: both; content: "."; display: block; height: 0; visibility: hidden; } -.clearfix { display: inline-block; } -* html .clearfix { height: 1%; } -.clearfix { display: block; } - -/* Special Stuff */ -:focus { outline: 0; } -a { text-decoration: none; } -a:hover { text-decoration: underline; } -a:active { position: relative; top: 1px; } -.ie6 a:active, .ie7 a:active { position: static; top: auto; } -input:focus, textarea:focus, select:focus { background: #eee; } -fieldset { border: 1px solid #333; padding: 9px; } -fieldset legend { padding: 0 9px; } -h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal; } - -} /* End @media all */ Added: trunk/src/moosique.net/css/index.php =================================================================== --- trunk/src/moosique.net/css/index.php (rev 0) +++ trunk/src/moosique.net/css/index.php 2009-09-01 13:44:00 UTC (rev 1833) @@ -0,0 +1,27 @@ +<?php +/* This little Script takes all included css-files and + * compresses them by removing comments, line-breaks and + * useless space-characters + */ +header('Content-type: text/css'); +// set offset to 365 days = 1 year +$offset = 60 * 60 * 24 * 365; +header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $offset) . ' GMT'); + +ob_start('compress'); /* uncomment for deployment, smaller css-files */ +// ob_start(); + +function compress($buffer) { + // remove comments + $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer); + // remove tabs, spaces, newlines, etc. + $buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer); + return $buffer; +} + +/* the css-files to include and compress */ +include('reset.css'); +include('style.css'); + +ob_end_flush(); +?> \ No newline at end of file Added: trunk/src/moosique.net/css/reset.css =================================================================== --- trunk/src/moosique.net/css/reset.css (rev 0) +++ trunk/src/moosique.net/css/reset.css 2009-09-01 13:44:00 UTC (rev 1833) @@ -0,0 +1,25 @@ +/* basic reset */ +/* =================================================================== */ +@media all { +html, body, div, h1, h2, h3, +h4, h5, h6, ul, ol, dl, li, +dt, dd, p, img, blockquote, +pre, form, fieldset, table, +th, td { margin: 0; padding: 0; font: inherit; color: inherit; + text-decoration: none; border: none; outline: none; } +ol, ul { list-style: none; } +table { border-collapse: collapse; border-spacing: 0; } +caption, th, td { text-align: left; font-weight: normal; } +label, input[type=button], +input[type=submit], button { cursor: pointer; } +:focus { outline: 0; } +input, textarea, +select, option { font: inherit; color: inherit; } +a { color: inherit; font: inherit; text-decoration: none; } +a:hover { text-decoration: underline; } +a:active { position: relative; top: 1px; } +.hidden { position: absolute; left: -9999px; top: -9999px; } +.clearfix:after { clear: both; content: ' '; display: block; font-size: 0; line-height: 0; + visibility: hidden; width: 0; height: 0; } +.clearfix { display: inline-block; } +} /* end @media all */ \ No newline at end of file Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-08-29 14:08:33 UTC (rev 1832) +++ trunk/src/moosique.net/css/style.css 2009-09-01 13:44:00 UTC (rev 1833) @@ -1,372 +1,135 @@ -/* moosique.net - * - * Semiblack: #131313 - * Light Grey: #545454 - * White: #f8faf7 - * Yellowish: #ffbc00 - * - */ - +/* moosique.net - a jamendo radio with recommendations! */ @media screen { - -/* Default Element Styling --- Start Editing below this line */ -/* =================================================================== */ -* { - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 12px; - line-height: 16px; - color: #131313; -} +/*=============== Default Styling ===============*/ +body { font: normal 12px/16px Verdana, Arial, sans-serif; color: #f1f7e4; + background: url('../img/bg.png') top left repeat #3a3a3a; border-top: 5px solid #1fd611; } +input, textarea, select { background: #292929; border: 1px solid #5a5a5a; outline: none; padding: 5px; } +input[type=submit] { padding: 5px 10px; } +textarea:focus, input:focus, +select:focus { border: 1px solid #1fd611; } +a:hover { color: #1fd611; } +h1 { font: 32px/32px Georgia, Times, serif; } +h2 { font: 28px/28px Georgia, Times, serif; } +h3 { font: 20px/20px Georgia, Times, serif; } +h4 { font: 16px/16px Georgia, Times, serif; } +h5 { font: 12px/12px Georgia, Times, serif; } +h6 { font: 10px/10px Georgia, Times, serif; } +pre { font: normal 10px/14px Monaco, Courier, monospace; } +p, h1, h2, h3, h4, h5, h6, +table, ul, ol, blockquote, +pre, form { margin-bottom: 16px; } -body { - background: #f8faf7; -} - -a:hover { - color: #ffbc00; -} - -/* Abstand Zeilenhoehe nach unten bei manchen Elementen */ -p, h1, h2, h3, h4, h5, h6, table, ul, ol, blockquote, pre, form { - margin-bottom: 16px; -} - -/* Default Container Positioning */ -/* =================================================================== */ -#container, #header, #mainContainer, #content { - position: relative; -} - -#headerContainer { - height: 95px; - background: #333; - border-bottom: 5px solid #ffbc00; - padding: 20px 0 0 0; -} - -#header { - width: 760px; - margin: 0 auto; -} - -#container { - border-top: 1px solid #ccc; -} - -#mainContainer { - width: 700px; - margin: 0 auto; - padding: 30px; - border: 1px solid #ccc; - border-top: none; -} - -#footer { - padding: 20px; - text-align: center; -} - -/* header Area */ -/* =================================================================== */ -#header h1 a { - font-size: 32px; - line-height: 32px; - font-family: Georgia, Times, "Times New Roman", serif; - text-decoration: none; - color: #f8faf7; -} - -#status, #header .currentlyPlaying { - position: absolute; - top: 0; - right: 0; - width: 380px; - background: #545454; - padding: 10px; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#status { - background: #545454; - color: #f8faf7; - z-index: 1000000; - height: 32px; - line-height: 32px; - text-align: center; -} - -.currentlyPlaying h2, .currentlyPlaying h3, .currentlyPlaying h4 { - margin-bottom: 0; -} - -#header .currentlyPlaying h2 { - font-size: 10px; -} - -#header .currentlyPlaying h4 { - position: absolute; - bottom: 10px; - right: 10px; - font-size: 10px; -} - -#searchForm input#searchValue { - margin: 0 5px; - width: 100px; -} - -#loadingImg { - display: none; -} - -/* mainMenu & status */ -/* =================================================================== */ - -#mainMenu ul { - position: absolute; - top: 70px; - right: 0; -} - -#mainMenu ul li { - float: left; - -moz-border-radius-topleft: 10px; - -moz-border-radius-topright: 10px; - -webkit-border-top-left-radius: 10px; - -webkit-border-top-right-radius: 10px; - padding: 0 15px; - background: #545454; - margin: 5px 0 0 5px; - height: 20px; - line-height: 20px; -} - -#mainMenu ul li a { - color: #131313; -} - -#mainMenu ul li.active { - height: 25px; - line-height: 25px; - margin-top: 0; - background: #ffbc00; -} - -#mainMenu ul li.active a { - font-weight: bold; -} - -#mainMenu ul li a:hover { - text-decoration: none; -} - - -/* Content Area Default Styles */ -/* =================================================================== */ -#content h2, #content h3 { - font-size: 16px; - line-height: 24px; - font-weight: bold; -} - -/* for debugging */ -#content pre { - font-family: "Courier New", Courier, monospace; - font-size: 10px; -} - /* Initial hiding */ -#recommendations, #player, #information, #help { - display: none; /* Initial Hide */ -} +#recommendations, #player, +#information, #help, +#loadingImg, #header h1 { display: none; } -#footer * { - font-size: 10px; -} +/* Rounded Corners */ +input, textarea, select { -moz-border-radius: 5px; -webkit-border-radius: 5px; } +#content, #status, #playing, +#playerControls, #results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; } +#mainMenu a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; + -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; } + +/* button-click-feeling for links, by offsetting top position */ +#prev:active, #next:active, +#stop:active, #mute:active +#playPause:active, { position: relative; top: 2px; } +#playlist .delete:active, +#playlist .moveUp:active, +#playlist .moveDown:active { top: 6px; } -/* home -- search results */ -/* =================================================================== */ -#results h3 em { - font-size: 16px; -} +/*=============== Default Containers ===============*/ +#container, #header, +#headerContainer, +#mainContainer, #content, +#playlist li { position: relative; } +#container { width: 760px; margin: 0 auto; } +#header { height: 150px; padding-top: 20px; } +#content { background: #292929; padding: 20px; } +#footer { font: normal 10px/14px Verdana, Arial, sans-serif; padding: 20px; text-align: center; } -#results ul li h3 a { - font-weight: normal; -} -#results ul li img { - border: 2px solid #545454; - margin-bottom: 16px; -} +/*=============== header Area, Player Controls, Status, Playing and Search Form ===============*/ +#status, #playing { position: absolute; top: 70px; left: 0; width: 490px; height: 60px; + background: #292929; padding: 10px 20px; } +#playerControls { position: absolute; top: 70px; right: 0; width: 170px; height: 60px; + padding: 10px 20px; background: #292929; } +#status { background: #393939; height: 60px; line-height: 60px; text-align: center; + font-weight: bold; border: 1px solid #1fd611; z-index: 1000; } +#playing span { display: block; margin-bottom: 0; font-size: 10px; } +#playing .track { font: bold 12px/32px Verdana, Arial, sans-serif; } +#playing .time { position: absolute; bottom: 10px; right: 20px; } -#results ul li { - display: block; - border: 1px dotted #545454; - padding: 16px; - margin: 0 16px 16px 0; - float: left; - width: 300px; -} +#prev, #next, #stop, +#playPause, #mute { display: block; width: 20px; height: 40px; text-indent: -10000px; + float: left; margin: 10px 0 0 10px; } +/* Sprites */ +#prev { background: url(../img/controls.png) 0px -160px no-repeat; } +#next { background: url(../img/controls.png) 0px -120px no-repeat; } +#stop { background: url(../img/controls.png) 0px -80px no-repeat; } +#mute { background: url(../img/controls.png) 0px -280px no-repeat; margin-right: 0; width: 23px; } +#playPause { background: url(../img/controls.png) 0px 0px no-repeat; width: 26px; } -#results .artistSearch ul li { - height: 450px; -} +/* Search form */ +#searchValue { margin: 0 5px; width: 100px; } +#loadingImg { cursor: wait; } -#results ul ul { - list-style: square; -} -#results ul li ul li, -#results .artistSearch ul li ul li, -#results .tagSearch ul li ul li { - border: none; - display: list-item; - padding: 0; - margin: 0 0 0 32px; - width: auto; - height: auto; - float: none; -} +/*=============== Menu ===============*/ +#mainMenu ul { position: absolute; top: 0; right: 0; } +#mainMenu li { float: left; } +#mainMenu a { display: block; margin-left: 10px; line-height: 30px; height: 30px; + padding: 10px 12px; color: #fafafa; background: #4a4a4a; } +#mainMenu .active a, +#mainMenu .active a:hover { background: #1fd611; } +#mainMenu a:hover { text-decoration: none; background: #5a5a5a; } -#results .tagSearch ul li ul { - clear: both; -} - +/*=============== Search Results ===============*/ +#results li h3 a { font-weight: normal; } +#results li img { border: 2px solid #545454; margin-bottom: 16px; } +#results li { display: block; border: 1px solid #545454; padding: 16px; margin-bottom: 16px; + float: left; width: 318px; } +#results li.odd { margin-right: 16px; clear: both; } +#results ul ul { list-style: disc; } -#results .artistSearch ul li div.artistImage { - text-align: center; -} +/* This is for the list of found albums etc */ +#results li li, +#results .artistSearch li li, +#results .tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 32px; + width: auto; height: auto; float: none; } +#results .tagSearch ul ul { clear: both; } +#results .artistImage { text-align: center; } +#results .cover { margin-right: 16px; width: 110px; float: left; } +#results .tagSearch h4 { display: inline; } -#results .tagSearch ul li div.cover { - margin-right: 16px; - width: 110px; - float: left; -} -#results .tagSearch ul li h4 { - display: inline; - font-weight: bold; -} +/*=============== Recommendations and playlist ===============*/ +#recommended a:hover { cursor: pointer; text-decoration: none; font-weight: bold; color: #131313; } +#playlist, #recommended, +#recently { margin-left: 36px; list-style: decimal; } +#playlist li, #recently li, +#recommended li { line-height: 24px; } +#playlist .ymp-btn-page-pause { font-weight: bold; } +/* Playlist buttons */ +#playlist .delete, +#playlist .moveUp, +#playlist .moveDown { position: absolute; display: block; top: 5px; right: 20px; width: 14px; height: 14px; + line-height: 14px; text-indent: -10000px; + background: url(../img/controls.png) 0px -200px no-repeat;} +#playlist .moveUp { background: url(../img/controls.png) 0px -360px no-repeat; right: 40px; } +#playlist .moveDown { background: url(../img/controls.png) 0px -320px no-repeat; right: 60px; } +/*=============== Information / Help ===============*/ -/* Recommendations */ -/* =================================================================== */ -#recommended { - list-style: decimal; - margin-left: 24px; -} -#recommended li { - line-height: 24px; -} -#recommended a:hover { - cursor: pointer; - text-decoration: none; - font-weight: bold; - color: #131313; -} -/* information */ -/* =================================================================== */ - - - - -/* player */ -/* =================================================================== */ - -#playerControls { - position: absolute; - width: 149px; - height: 37px; - top: 0; - right: 0; - padding: 10px 20px; - background: #545454; - -moz-border-radius: 10px; - -webkit-border-radius: 10px; -} - -#prev, #next, #stop, #playPause, #mute { - display: block; - width: 20px; - height: 37px; - text-decoration: none; - text-indent: -1000000px; - float: left; - margin-right: 10px; -} - -/* clicky feel */ -#prev:active, #next:active, #stop:active, -#playPause:active, #mute:active { - position: relative; - top: 2px; -} - -/* Sprites */ -#prev { background: url(../img/controls.png) 0px -160px no-repeat; } -#next { background: url(../img/controls.png) 0px -120px no-repeat; } -#stop { background: url(../img/controls.png) 0px -80px no-repeat; } - -#playPause { - background: url(../img/controls.png) 0px 0px no-repeat; - width: 26px; -} - -#mute { - background: url(../img/controls.png) 0px -280px no-repeat; - margin-right: 0; - width: 23px; -} -/* End Sprites */ - -#playlist li { - position: relative; /* Delete Buttons */ - list-style: decimal; - list-style-position: inside; - cursor: move; - padding: 3px; -} - -#playlist li a.ymp-btn-page-pause { - font-weight: bold; -} - -/* Delete buttons */ -#playlist li a.del { - position: absolute; - display: block; - top: 5px; - right: 20px; - width: 14px; - height: 14px; - line-height: 14px; - margin-right: -19px; - z-index: 1000; - text-indent: -99999999px; - background: url(../img/controls.png) 0px -200px no-repeat; -} - -/* Draggable li-Items */ -#playlist li.moving { - background: #666; - border: 3px solid #ffbc00; - font-weight: bold; -} - - - - - - } /* end @media screen */ \ No newline at end of file Added: trunk/src/moosique.net/img/bg.png =================================================================== (Binary files differ) Property changes on: trunk/src/moosique.net/img/bg.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/src/moosique.net/img/controls.png =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/img/loading.gif =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-08-29 14:08:33 UTC (rev 1832) +++ trunk/src/moosique.net/index.php 2009-09-01 13:44:00 UTC (rev 1833) @@ -1,153 +1,133 @@ -<?php session_start(); ?><!DOCTYPE html +<?php session_start(); ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> - <head> - <title>moosique.net</title> - <link href="css/default.css" rel="stylesheet" type="text/css" /> - <link href="css/style.css" rel="stylesheet" type="text/css" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <link href="css/" rel="stylesheet" type="text/css" /> + <title>moosique.net</title> </head> - -<!--[if IE 7]><body class="ie7"><![endif]--> -<!--[if lte IE 6]><body class="ie6"><![endif]--> -<!--[if !IE]><!--><body><!-- <![endif]--> - - <div id="headerContainer"> - <div id="header"> - <h1><a href="index.php">moosique.net</a></h1> - - <div id="mainMenu"> - <ul class="clearfix"> - <li class="active"><a href="#" class="home">Home</a></li> - <li><a href="#" class="player">Player</a></li> - <li><a href="#" class="recommendations">Recommendations</a></li> - <li><a href="#" class="information">Information</a></li> - <li><a href="#" class="help">Help</a></li> - </ul> - </div> - - <form id="searchForm" method="get" action="moosique/"> - <div class="clearfix"> - <select name="typeOfSearch" id="typeOfSearch"> +<body> +<div id="container"> + <div id="header"> + <h1>moosique.net</h1> + <div id="mainMenu"> + <ul class="clearfix"> + <li class="active"><a href="#" class="home">Search</a></li> + <li><a href="#" class="player">Playlist</a></li> + <li><a href="#" class="recommendations">Recommendations</a></li> + <li><a href="#" class="information">Info</a></li> + <li><a href="#" class="help">?</a></li> + </ul> + </div> + <form id="searchForm" method="get" action="moosique/"> + <ol> + <li> + <select name="searchType" id="searchType"> + <?php /* <option value="allSearch">Everything</option> */ ?> <option value="artistSearch">Artist</option> <option value="tagSearch">Tag</option> - <?php /* <option value="songSearch">Song</option> - <option value="lastfm">Last.fm-User</option> - */ ?> + <?php /* <option value="lastfm">Last.fm-User</option> */ ?> </select> <input id="searchValue" name="searchValue" type="text" /> - <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" disabled="disabled" /> + <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> <img id="loadingImg" src="img/loading.gif" alt="Loading..." /> - </div> - </form> - - <div id="status"> </div> - - <div class="currentlyPlaying"> - <h2>Player stopped</h2> - <h3>...</h3> - <h4>0:00 / 0:00</h4> - </div> - + </li> + </ol> + </form> + <div id="playerControls"> + <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> + <a href="#" id="stop" title="Stop playing">Stop</a> + <a href="#" id="prev" title="Play previous Track in Playlist">Previous Tack</a> + <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> + <a href="#" id="mute" title="Sound on/off">Mute</a> </div> + <h4 id="status"> </h4> + <div id="playing"> + <span class="info">Player stopped</span> + <span class="track">...</span> + <span class="time">0:00 / 0:00</span> + </div> </div> - <div id="container"> - <div id="mainContainer"> - <div id="content" class="clearfix"> + <div id="content"> + <div id="home"> + <div id="welcome"> + <h2>Welcome to moosique.net!</h2> + <p> + Want to listen to some good free music? Just enter an artist or song + name or search for music using tags <!-- or enter your last.fm username --> and let the moogic + happen. By listening to songs you like, the system will automatically learn about + your musical taste and generate recommendations. You can find them in the tab »Recommendations«. + </p> + <p> + You can find information about the song currently playing in the tab »Information« and view + your Playlist and control the Player in the Tab »Player«. + </p> + <p> + Now get started and add something to the Playlist! + </p> + </div> + <div id="results"> - <div id="home"> - <div id="welcome"> - <h2>Welcome to moosique.net!</h2> - <p> - Want to listen to some good free music? Just enter an artist or song - name or search for music using tags <!-- or enter your last.fm username --> and let the moogic - happen. By listening to songs you like, the system will automatically learn about - your musical taste and generate recommendations. You can find them in the tab »Recommendations«. - </p> - <p> - You can find information about the song currently playing in the tab »Information« and view - your Playlist and control the Player in the Tab »Player«. - </p> - <p> - Now get started and add something to the Playlist! - </p> - </div> - <div id="results"> - - </div> - </div> + </div> + </div> - <div id="recommendations"> - <h2>Recommended Songs</h2> - <p>Click a song to add it to your playlist.</p> - <ol id="recommended"> - <li></li> - </ol> - - </div> + <div id="recommendations"> + <h2>Recommended Songs</h2> + <p>These are the automatically generated recommendations. Click on a song to add it to your playlist.</p> + <ol id="recommended"> + <li></li> + </ol> + <h2>Recently Listened to</h2> + <p>These are the songs you recently listened to. Click on a song to re-enqueue it to your current playlist. (NOT WORKING YET!)</p> + <ol id="recently"> + <li></li> + </ol> + </div> - <div id="information"> - <div id="moreInfo"> - <h2>About the Artist</h2> - <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> - <p> - Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat - duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil - imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis - dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus - qui nobis videntur parum. - </p> - </div> - </div> - - <div id="player"> - <h3>Playlist</h3> - <p> - You can delete entries from the playlist by clicking the small x on the left. <br /> - You also can move the playlist-entries around to change their order. - </p> + <div id="information"> + <div id="moreInfo"> + <h2>About the Artist</h2> + <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> + <p> + Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat + duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil + imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis + dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus + qui nobis videntur parum. + </p> + </div> + </div> + + <div id="player"> + <h3>Playlist</h3> + <p> + You can delete entries from the playlist by clicking the small x on the left and change their order by clicking on the small up- and down-arrows.<br /> + </p> + <ol id="playlist"> + <li></li> + </ol> + + </div> - <ol id="playlist"> - <li></li> - </ol> + <div id="help"> + + </div> - <div id="playerControls"> - <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> - <a href="#" id="stop" title="Stop playing">Stop</a> - <a href="#" id="prev" title="Play previous Track in Playlist">Previous Tack</a> - <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> - <a href="#" id="mute" title="Sound on/off">Mute</a> - </div> - - </div> + </div> <!-- end content --> - <div id="help"> - - </div> - - </div> <!-- end content --> - </div> <!-- end mainContainer --> - <div id="footer"> - <a href="http://jamendo.com">Jamendo</a> | - <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | - <a href="http://aksw.org/Projects/DLLearner">Powered by DL-Learner</a> - </div> - </div> <!-- end container --> + <div id="footer"> + <a href="http://jamendo.com">Jamendo</a> | + <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | + <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> + </div> +</div> <!-- end container --> - - <!-- JS at the bottom, faster loading pages --> - <script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> - - <script type="text/javascript" src="js/mootools-core.js"></script> - <script type="text/javascript" src="js/mootools-more.js"></script> - - <script type="text/javascript" src="js/player.js"></script> - <script type="text/javascript" src="js/interface.js"></script> - <script type="text/javascript" src="js/ajax.js"></script> +<script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> +<script type="text/javascript" src="js/"></script> </body> </html> \ No newline at end of file Deleted: trunk/src/moosique.net/js/ajax.js =================================================================== --- trunk/src/moosique.net/js/ajax.js 2009-08-29 14:08:33 UTC (rev 1832) +++ trunk/src/moosique.net/js/ajax.js 2009-09-01 13:44:00 UTC (rev 1833) @@ -1,93 +0,0 @@ -window.addEvent('domready', function() { - -// handle search requests -$('searchForm').addEvent('submit', function(e) { - - var results = $('results'); - var submit = $('searchSubmit'); - var loading = $('loadingImg'); - - e.stop(); // prevent form submitting the non-ajax way - this.set('send', { - - onRequest: function() { - submit.set('disabled', 'disabled'); // disable submit button until request complete - // show homescreen for resultdisplaying - showTab('home'); - submit.setStyle('display', 'none'); - loading.setStyle('display', 'inline'); - results.set('html', '<h2>Searching...</h2>'); - }, - - onFailure: function() { - results.set('html', '<h2>Unable to process your search. Try again.</h2>'); - }, - - onSuccess: function(response) { - submit.erase('disabled'); // reenable submitbutton - submit.setStyle('display', 'inline'); - loading.setStyle('display', 'none'); - - // if the welcome-text ist present, cut it to help - if ($('welcome')) { - if ($('welcome').get('html').length > 100) { - $('help').set('html', $('welcome').get('html')); - $('welcome').destroy(); - } - } - - // display results - results.set('html', response); - - // addEvents to result-links - makeAddable(); - } - - }); - - // only send form if value is at least 3 - if ($('searchValue').get('value').length > 2) { - this.send(); - } - -}); - -makeAddable(); - -}); - - -/** - * For Recommendations and Search-Results - */ -function makeAddable() { - $$('a.addToPlaylist').each(function(a) { - a.addEvent('click', function(e) { - e.stop(); // dont follow link - // remove the class from preventing adding again - - a.removeClass('addToPlaylist'); - - // TODO, now using xspfs, later we only will use mp3-links - a.set('type', 'application/xspf+xml'); - - // if the Playlist is empty, remove entries - if ($('playlist').getFirst()) { - if ($('playlist').getFirst().get('text') == '') { - $('playlist').empty(); - } - } - - - a.getParent().inject($('playlist')); - if (a.get('title')) { - a.set('text', a.get('title')); - } - - // - mooPlayer.refreshPlaylist(); - showTab('player'); - - }); - }); -} \ No newline at end of file Added: trunk/src/moosique.net/js/index.php =================================================================== --- trunk/src/moosique.net/js/index.php (rev 0) +++ trunk/src/moosique.net/js/index.php 2009-09-01 13:44:00 UTC (rev 1833) @@ -0,0 +1,30 @@ +<?php +/* This little Script takes all included js-files and + * compresses them with the PHP-Variant of js-min + * found here: http://code.google.com/p/jsmin-php/ + */ +header('Content-type: application/javascript'); +// set offset to 365 days = 1 year +$offset = 60 * 60 * 24 * 365; +header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $offset) . ' GMT'); + +ob_start('compress'); + +function compress($buffer) { + include('jsmin-1.1.1.php'); + $buffer = JSMin::minify($buffer); + return $buffer; +} + +/* the javascript-files to include and compress */ +include('mootools-1.2.3-core-yc.js'); +include('player.js'); +include('interface.js'); +include('request.js'); + + +// Since we include the IE6-Fixes with a CC, we don't +// add and compress them here + +ob_end_flush(); +?> \ No newline at end of file Modified: trunk/src/moosique.net/js/interface.js =================================================================== --- trunk/src/moosique.net/js/interface.js 2009-08-29 14:08:33 UTC (rev 1832) +++ trunk/src/moosique.net/js/interface.js 2009-09-01 13:44:00 UTC (rev 1833) @@ -1,22 +1,30 @@ window.addEvent('domready', function() { // switching between search, recommendation and information - -$$('#mainMenu ul li a').each(function(a) { +$$('#mainMenu a').each(function(a) { a.addEvent('click', function(e) { e.stop(); // dont follow link showTab(a.get('class').toString()); }); - }); -$('searchValue').addEvent('keyup', function() { - if (this.get('value').length > 2) { - $('searchSubmit').erase('disabled'); - } else { - $('searchSubmit').set('disabled', 'disabled'); +// update recently listened song if a cookie is set +// update the #recently ol +var rlc = Cookie.read('recentlyListened'); +var rl = JSON.decode(rlc); + +if (rl) { + if (rl.length > 0) { + var count = rl.length; + var recentlyHTML = ''; + for (var i = 0; i < count; i++ ) { + recentlyHTML += '<li>'; + recentlyHTML += rl[i] + '<br />'; + recentlyHTML += '</li>'; + } + document.id('recently').set('html', recentlyHTML); } -}); +} }); @@ -26,10 +34,10 @@ * @param {String} tabID ID of the Tab to show */ function showTab(tabID) { - $$('#mainMenu ul li').removeClass('active'); - $$('#mainMenu ul li a.' + tabID).getParent().toggleClass('active'); - $('content').getChildren().setStyle('display', 'none') - $(tabID).setStyle('display', 'block'); + $$('#mainMenu li').removeClass('active'); + $$('#mainMenu a.' + tabID).getParent().toggleClass('active'); + document.id('content').getChildren().setStyle('display', 'none'); + document.id(tabID).setStyle('display', 'block'); } Added: trunk/src/moosique.net/js/jsmin-1.1.1.php =================================================================== --- trunk/src/moosique.net/js/jsmin-1.1.1.php (rev 0) +++ trunk/src/moosique.net/js/jsmin-1.1.1.php 2009-09-01 13:44:00 UTC (rev 1833) @@ -0,0 +1,291 @@ +<?php +/** + * jsmin.php - PHP implementation of Douglas Crockford's JSMin. + * + * This is pretty much a direct port of jsmin.c to PHP with just a few + * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and + * outputs to stdout, this library accepts a string as input and returns another + * string as output. + * + * PHP 5 or higher is required. + * + * Permission is hereby granted to use this version of the library under the + * same terms as jsmin.c, which has the following license: + * + * -- + * Copyright (c) 2002 Douglas Crockford (www.crockford.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * The Software shall be used for Good, not Evil. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * -- + * + * @package JSMin + * @author Ryan Grove <ry...@wo...> + * @copyright 2002 Douglas Crockford <do...@cr...> (jsmin.c) + * @copyright 2008 Ryan Grove <ry...@wo...> (PHP port) + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 1.1.1 (2008-03-02) + * @link http://code.google.com/p/jsmin-php/ + */ + +class JSMin { + const ORD_LF = 10; + const ORD_SPACE = 32; + + protected $a = ''; + protected $b = ''; + protected $input = ''; + protected $inputIndex = 0; + protected $inputLength = 0; + protected $lookAhead = null; + protected $output = ''; + + // -- Public Static Methods -------------------------------------------------- + + public static function minify($js) { + $jsmin = new JSMin($js); + return $jsmin->min(); + } + + // -- Public Instance Methods ------------------------------------------------ + + public function __construct($input) { + $this->input = str_replace("\r\n", "\n", $input); + $this->inputLength = strlen($this->input); + } + + // -- Protected Instance Methods --------------------------------------------- + + protected function action($d) { + switch($d) { + case 1: + $this->output .= $this->a; + + case 2: + $this->a = $this->b; + + if ($this->a === "'" || $this->a === '"') { + for (;;) { + $this->output .= $this->a; + $this->a = $this->get(); + + if ($this->a === $this->b) { + break; + } + + if (ord($this->a) <= self::ORD_LF) { + throw new JSMinException('Unterminated string literal.'); + } + + if ($this->a === '\\') { + $this->output .= $this->a; + $this->a = $this->get(); + } + } + } + + case 3: + $this->b = $this->next(); + + if ($this->b === '/' && ( + $this->a === '(' || $this->a === ',' || $this->a === '=' || + $this->a === ':' || $this->a === '[' || $this->a === '!' || + $this->a === '&' || $this->a === '|' || $this->a === '?')) { + + $this->output .= $this->a . $this->b; + + for (;;) { + $this->a = $this->get(); + + if ($this->a === '/') { + break; + } elseif ($this->a === '\\') { + $this->output .= $this->a; + $this->a = $this->get(); + } elseif (ord($this->a) <= self::ORD_LF) { + throw new JSMinException('Unterminated regular expression '. + 'literal.'); + } + + $this->output .= $this->a; + } + + $this->b = $this->next(); + } + } + } + + protected function get() { + $c = $this->lookAhead; + $this->lookAhead = null; + + if ($c === null) { + if ($this->inputIndex < $this->inputLength) { + $c = $this->input[$this->inputIndex]; + $this->inputIndex += 1; + } else { + $c = null; + } + } + + if ($c === "\r") { + return "\n"; + } + + if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { + return $c; + } + + return ' '; + } + + protected function isAlphaNum($c) { + return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; + } + + protected function min() { + $this->a = "\n"; + $this->action(3); + + while ($this->a !== null) { + switch ($this->a) { + case ' ': + if ($this->isAlphaNum($this->b)) { + $this->action(1); + } else { + $this->action(2); + } + break; + + case "\n": + switch ($this->b) { + case '{': + case '[': + case '(': + case '+': + case '-': + $this->action(1); + break; + + case ' ': + $this->action(3); + break; + + default: + if ($this->isAlphaNum($this->b)) { + $this->action(1); + } + else { + $this->action(2); + } + } + break; + + default: + switch ($this->b) { + case ' ': + if ($this->isAlphaNum($this->a)) { + $this->action(1); + break; + } + + $this->action(3); + break; + + case "\n": + switch ($this->a) { + case '}': + case ']': + case ')': + case '+': + case '-': + case '"': + case "'": + $this->action(1); + break; + + default: + if ($this->isAlphaNum($this->a)) { + $this->action(1); + } + else { + $this->action(3); + } + } + break; + + default: + $this->action(1); + break; + } + } + } + + return $this->output; + } + + protected function next() { + $c = $this->get(); + + if ($c === '/') { + switch($this->peek()) { + case '/': + for (;;) { + $c = $this->get(); + + if (ord($c) <= self::ORD_LF) { + return $c; + } + } + + case '*': + $this->get(); + + for (;;) { + switch($this->get()) { + case '*': + if ($this->peek() === '/') { + $this->get(); + return ' '; + } + break; + + case null: + throw new JSMinException('Unterminated comment.'); + } + } + + default: + return $c; + } + } + + return $c; + } + + protected function peek() { + $this->lookAhead = $this->get(); + return $this->lookAhead; + } +} + +// -- Exceptions --------------------------------------------------------------- +class JSMinException extends Exception {} +?> \ No newline at end of file Added: trunk/src/moosique.net/js/mootools-1.2.3-core-yc.js =================================================================== --- trunk/src/moosique.net/js/mootools-1.2.3-core-yc.js (rev 0) +++ trunk/src/moosique.net/js/mootools-1.2.3-core-yc.js 2009-09-01 13:44:00 UTC (rev 1833) @@ -0,0 +1,356 @@ +//MooTools, <http://mootools.net>, My Object Oriented (JavaScript) Tools. Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net>, MIT Style License. + +var MooTools={version:"1.2.3",build:"4980aa0fb74d2f6eb80bcd9f5b8e1fd6fbb8f607"};var Native=function(k){k=k||{};var a=k.name;var i=k.legacy;var b=k.protect; +var c=k.implement;var h=k.generics;var f=k.initialize;var g=k.afterImplement||function(){};var d=f||i;h=h!==false;d.constructor=Native;d.$family={name:"native"}; +if(i&&f){d.prototype=i.prototype;}d.prototype.constructor=d;if(a){var e=a.toLowerCase();d.prototype.$family={name:e};Native.typize(d,e);}var j=function(n,l,o,m){if(!b||m||!n.prototype[l]){n.prototype[l]=o; +}if(h){Native.genericize(n,l,b);}g.call(n,l,o);return n;};d.alias=function(n,l,p){if(typeof n=="string"){var o=this.prototype[n];if((n=o)){return j(this,l,n,p); +}}for(var m in n){this.alias(m,n[m],l);}return this;};d.implement=function(m,l,o){if(typeof m=="string"){return j(this,m,l,o);}for(var n in m){j(this,n,m[n],l); +}return this;};if(c){d.implement(c);}return d;};Native.genericize=function(b,c,a){if((!a||!b[c])&&typeof b.prototype[c]=="function"){b[c]=function(){var d=Array.prototype.slice.call(arguments); +return b.prototype[c].apply(d.shift(),d);};}};Native.implement=function(d,c){for(var b=0,a=d.length;b<a;b++){d[b].implement(c);}};Native.typize=function(a,b){if(!a.type){a.type=function(c){return($type(c)===b); +};}};(function(){var a={Array:Array,Date:Date,Function:Function,Number:Number,RegExp:RegExp,String:String};for(var h in a){new Native({name:h,initialize:a[h],protect:true}); +}var d={"boolean":Boolean,"native":Native,object:Object};for(var c in d){Native.typize(d[c],c);}var f={Array:["concat","indexOf","join","lastIndexOf","pop","push","reverse","shift","slice","sort","splice","toString","unshift","valueOf"],String:["charAt","charCodeAt","concat","indexOf","lastIndexOf","match","replace","search","slice","split","substr","substring","toLowerCase","toUpperCase","valueOf"]}; +for(var e in f){for(var b=f[e].length;b--;){Native.genericize(a[e],f[e][b],true);}}})();var Hash=new Native({name:"Hash",initialize:function(a){if($type(a)=="hash"){a=$unlink(a.getClean()); +}for(var b in a){this[b]=a[b];}return this;}});Hash.implement({forEach:function(b,c){for(var a in this){if(this.hasOwnProperty(a)){b.call(c,this[a],a,this); +}}},getClean:function(){var b={};for(var a in this){if(this.hasOwnProperty(a)){b[a]=this[a];}}return b;},getLength:function(){var b=0;for(var a in this){if(this.hasOwnProperty(a)){b++; +}}return b;}});Hash.alias("forEach","each");Array.implement({forEach:function(c,d){for(var b=0,a=this.length;b<a;b++){c.call(d,this[b],b,this);}}});Array.alias("forEach","each"); +function $A(b){if(b.item){var a=b.length,c=new Array(a);while(a--){c[a]=b[a];}return c;}return Array.prototype.slice.call(b);}function $arguments(a){return function(){return arguments[a]; +};}function $chk(a){return !!(a||a===0);}function $clear(a){clearTimeout(a);clearInterval(a);return null;}function $defined(a){return(a!=undefined);}function $each(c,b,d){var a=$type(c); +((a=="arguments"||a=="collection"||a=="array")?Array:Hash).each(c,b,d);}function $empty(){}function $extend(c,a){for(var b in (a||{})){c[b]=a[b];}return c; +}function $H(a){return new Hash(a);}function $lambda(a){return($type(a)=="function")?a:function(){return a;};}function $merge(){var a=Array.slice(arguments); +a.unshift({});return $mixin.apply(null,a);}function $mixin(e){for(var d=1,a=arguments.length;d<a;d++){var b=arguments[d];if($type(b)!="object"){continue; +}for(var c in b){var g=b[c],f=e[c];e[c]=(f&&$type(g)=="object"&&$type(f)=="object")?$mixin(f,g):$unlink(g);}}return e;}function $pick(){for(var b=0,a=arguments.length; +b<a;b++){if(arguments[b]!=undefined){return arguments[b];}}return null;}function $random(b,a){return Math.floor(Math.random()*(a-b+1)+b);}function $splat(b){var a=$type(b); +return(a)?((a!="array"&&a!="arguments")?[b]:b):[];}var $time=Date.now||function(){return +new Date;};function $try(){for(var b=0,a=arguments.length;b<a; +b++){try{return arguments[b]();}catch(c){}}return null;}function $type(a){if(a==undefined){return false;}if(a.$family){return(a.$family.name=="number"&&!isFinite(a))?false:a.$family.name; +}if(a.nodeName){switch(a.nodeType){case 1:return"element";case 3:return(/\S/).test(a.nodeValue)?"textnode":"whitespace";}}else{if(typeof a.length=="number"){if(a.callee){return"arguments"; +}else{if(a.item){return"collection";}}}}return typeof a;}function $unlink(c){var b;switch($type(c)){case"object":b={};for(var e in c){b[e]=$unlink(c[e]); +}break;case"hash":b=new Hash(c);break;case"array":b=[];for(var d=0,a=c.length;d<a;d++){b[d]=$unlink(c[d]);}break;default:return c;}return b;}var Browser=$merge({Engine:{name:"unknown",version:0},Platform:{name:(window.orientation!=undefined)?"ipod":(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase()},Features:{xpath:!!(document.evaluate),air:!!(window.runtime),query:!!(document.querySelector)},Plugins:{},Engines:{presto:function(){return(!window.opera)?false:((arguments.callee.caller)?960:((document.getElementsByClassName)?950:925)); +},trident:function(){return(!window.ActiveXObject)?false:((window.XMLHttpRequest)?5:4);},webkit:function(){return(navigator.taintEnabled)?false:((Browser.Features.xpath)?((Browser.Features.query)?525:420):419); +},gecko:function(){return(document.getBoxObjectFor==undefined)?false:((document.getElementsByClassName)?19:18);}}},Browser||{});Browser.Platform[Browser.Platform.name]=true; +Browser.detect=function(){for(var b in this.Engines){var a=this.Engines[b]();if(a){this.Engine={name:b,version:a};this.Engine[b]=this.Engine[b+a]=true; +break;}}return{name:b,version:a};};Browser.detect();Browser.Request=function(){return $try(function(){return new XMLHttpRequest();},function(){return new ActiveXObject("MSXML2.XMLHTTP"); +});};Browser.Features.xhr=!!(Browser.Request());Browser.Plugins.Flash=(function(){var a=($try(function(){return navigator.plugins["Shockwave Flash"].description; +},function(){return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version");})||"0 r0").match(/\d+/g);return{version:parseInt(a[0]||0+"."+a[1],10)||0,build:parseInt(a[2],10)||0}; +})();function $exec(b){if(!b){return b;}if(window.execScript){window.execScript(b);}else{var a=document.createElement("script");a.setAttribute("type","text/javascript"); +a[(Browser.Engine.webkit&&Browser.Engine.version<420)?"innerText":"text"]=b;document.head.appendChild(a);document.head.removeChild(a);}return b;}Native.UID=1; +var $uid=(Browser.Engine.trident)?function(a){return(a.uid||(a.uid=[Native.UID++]))[0];}:function(a){return a.uid||(a.uid=Native.UID++);};var Window=new Native({name:"Window",legacy:(Browser.Engine.trident)?null:window.Window,initialize:function(a){$uid(a); +if(!a.Element){a.Element=$empty;if(Browser.Engine.webkit){a.document.createElement("iframe");}a.Element.prototype=(Browser.Engine.webkit)?window["[[DOMElement.prototype]]"]:{}; +}a.document.window=a;return $extend(a,Window.Prototype);},afterImplement:function(b,a){window[b]=Window.Prototype[b]=a;}});Window.Prototype={$family:{name:"window"}}; +new Window(window);var Document=new Native({name:"Document",legacy:(Browser.Engine.trident)?null:window.Document,initialize:function(a){$uid(a);a.head=a.getElementsByTagName("head")[0]; +a.html=a.getElementsByTagName("html")[0];if(Browser.Engine.trident&&Browser.Engine.version<=4){$try(function(){a.execCommand("BackgroundImageCache",false,true); +});}if(Browser.Engine.trident){a.window.attachEvent("onunload",function(){a.window.detachEvent("onunload",arguments.callee);a.head=a.html=a.window=null; +});}return $extend(a,Document.Prototype);},afterImplement:function(b,a){document[b]=Document.Prototype[b]=a;}});Document.Prototype={$family:{name:"document"}}; +new Document(document);Array.implement({every:function(c,d){for(var b=0,a=this.length;b<a;b++){if(!c.call(d,this[b],b,this)){return false;}}return true; +},filter:function(d,e){var c=[];for(var b=0,a=this.length;b<a;b++){if(d.call(e,this[b],b,this)){c.push(this[b]);}}return c;},clean:function(){return this.filter($defined); +},indexOf:function(c,d){var a=this.length;for(var b=(d<0)?Math.max(0,a+d):d||0;b<a;b++){if(this[b]===c){return b;}}return -1;},map:function(d,e){var c=[]; +for(var b=0,a=this.length;b<a;b++){c[b]=d.call(e,this[b],b,this);}return c;},some:function(c,d){for(var b=0,a=this.length;b<a;b++){if(c.call(d,this[b],b,this)){return true; +}}return false;},associate:function(c){var d={},b=Math.min(this.length,c.length);for(var a=0;a<b;a++){d[c[a]]=this[a];}return d;},link:function(c){var a={}; +for(var e=0,b=this.length;e<b;e++){for(var d in c){if(c[d](this[e])){a[d]=this[e];delete c[d];break;}}}return a;},contains:function(a,b){return this.indexOf(a,b)!=-1; +},extend:function(c){for(var b=0,a=c.length;b<a;b++){this.push(c[b]);}return this;},getLast:function(){return(this.length)?this[this.length-1]:null;},getRandom:function(){return(this.length)?this[$random(0,this.length-1)]:null; +},include:function(a){if(!this.contains(a)){this.push(a);}return this;},combine:function(c){for(var b=0,a=c.length;b<a;b++){this.include(c[b]);}return this; +},erase:function(b){for(var a=this.length;a--;a){if(this[a]===b){this.splice(a,1);}}return this;},empty:function(){this.length=0;return this;},flatten:function(){var d=[]; +for(var b=0,a=this.length;b<a;b++){var c=$type(this[b]);if(!c){continue;}d=d.concat((c=="array"||c=="collection"||c=="arguments")?Array.flatten(this[b]):this[b]); +}return d;},hexToRgb:function(b){if(this.length!=3){return null;}var a=this.map(function(c){if(c.length==1){c+=c;}return c.toInt(16);});return(b)?a:"rgb("+a+")"; +},rgbToHex:function(d){if(this.length<3){return null;}if(this.length==4&&this[3]==0&&!d){return"transparent";}var b=[];for(var a=0;a<3;a++){var c=(this[a]-0).toString(16); +b.push((c.length==1)?"0"+c:c);}return(d)?b:"#"+b.join("");}});Function.implement({extend:function(a){for(var b in a){this[b]=a[b];}return this;},create:function(b){var a=this; +b=b||{};return function(d){var c=b.arguments;c=(c!=undefined)?$splat(c):Array.slice(arguments,(b.event)?1:0);if(b.event){c=[d||window.event].extend(c); +}var e=function(){return a.apply(b.bind||null,c);};if(b.delay){return setTimeout(e,b.delay);}if(b.periodical){return setInterval(e,b.periodical);}if(b.attempt){return $try(e); +}return e();};},run:function(a,b){return this.apply(b,$splat(a));},pass:function(a,b){return this.create({bind:b,arguments:a});},bind:function(b,a){return this.create({bind:b,arguments:a}); +},bindWithEvent:function(b,a){return this.create({bind:b,arguments:a,event:true});},attempt:function(a,b){return this.create({bind:b,arguments:a,attempt:true})(); +},delay:function(b,c,a){return this.create({bind:c,arguments:a,delay:b})();},periodical:function(c,b,a){return this.create({bind:b,arguments:a,periodical:c})(); +}});Number.implement({limit:function(b,a){return Math.min(a,Math.max(b,this));},round:function(a){a=Math.pow(10,a||0);return Math.round(this*a)/a;},times:function(b,c){for(var a=0; +a<this;a++){b.call(c,a,this);}},toFloat:function(){return parseFloat(this);},toInt:function(a){return parseInt(this,a||10);}});Number.alias("times","each"); +(function(b){var a={};b.each(function(c){if(!Number[c]){a[c]=function(){return Math[c].apply(null,[this].concat($A(arguments)));};}});Number.implement(a); +})(["abs","acos","asin","atan","atan2","ceil","cos","exp","floor","log","max","min","pow","sin","sqrt","tan"]);String.implement({test:function(a,b){return((typeof a=="string")?new RegExp(a,b):a).test(this); +},contains:function(a,b){return(b)?(b+this+b).indexOf(b+a+b)>-1:this.indexOf(a)>-1;},trim:function(){return this.replace(/^\s+|\s+$/g,"");},clean:function(){return this.replace(/\s+/g," ").trim(); +},camelCase:function(){return this.replace(/-\D/g,function(a){return a.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/[A-Z]/g,function(a){return("-"+a.charAt(0).toLowerCase()); +});},capitalize:function(){return this.replace(/\b[a-z]/g,function(a){return a.toUpperCase();});},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1"); +},toInt:function(a){return parseInt(this,a||10);},toFloat:function(){return parseFloat(this);},hexToRgb:function(b){var a=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); +return(a)?a.slice(1).hexToRgb(b):null;},rgbToHex:function(b){var a=this.match(/\d{1,3}/g);return(a)?a.rgbToHex(b):null;},stripScripts:function(b){var a=""; +var c=this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi,function(){a+=arguments[1]+"\n";return"";});if(b===true){$exec(a);}else{if($type(b)=="function"){b(a,c); +}}return c;},substitute:function(a,b){return this.replace(b||(/\\?\{([^{}]+)\}/g),function(d,c){if(d.charAt(0)=="\\"){return d.slice(1);}return(a[c]!=undefined)?a[c]:""; +});}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(b){for(var a in this){if(this.hasOwnProperty(a)&&this[a]===b){return a;}}return null; +},hasValue:function(a){return(Hash.keyOf(this,a)!==null);},extend:function(a){Hash.each(a||{},function(c,b){Hash.set(this,b,c);},this);return this;},combine:function(a){Hash.each(a||{},function(c,b){Hash.include(this,b,c); +},this);return this;},erase:function(a){if(this.hasOwnProperty(a)){delete this[a];}return this;},get:function(a){return(this.hasOwnProperty(a))?this[a]:null; +},set:function(a,b){if(!this[a]||this.hasOwnProperty(a)){this[a]=b;}return this;},empty:function(){Hash.each(this,function(b,a){delete this[a];},this); +return this;},include:function(a,b){if(this[a]==undefi... [truncated message content] |
From: <neb...@us...> - 2009-09-13 15:41:23
|
Revision: 1844 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1844&view=rev Author: nebelschwade Date: 2009-09-13 15:41:13 +0000 (Sun, 13 Sep 2009) Log Message: ----------- Major refactoring of JS-Classes and functions All-Search working Extraction of recentlyListened Songs (posExamples) working Cookie/Session fixes Modified Paths: -------------- trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/index.php trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/jamendo.owl trunk/src/moosique.net/moosique/learnTest.php trunk/src/moosique.net/moosique/main.wsdl Added Paths: ----------- trunk/src/moosique.net/js/debug.js trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/helpers/ trunk/src/moosique.net/moosique/helpers/getAllTags.php trunk/src/moosique.net/moosique/helpers/tagsToOwl.php trunk/src/moosique.net/moosique/jamendo_complete.owl trunk/src/moosique.net/moosique/moosique.conf trunk/src/moosique.net/moosique/newOwl.owl trunk/src/moosique.net/moosique/rocksubset.owl Removed Paths: ------------- trunk/src/moosique.net/js/interface.js trunk/src/moosique.net/js/player.js trunk/src/moosique.net/js/request.js trunk/src/moosique.net/moosique/getAllTags.php trunk/src/moosique.net/moosique/stonerTest.owl trunk/src/moosique.net/moosique/tagsToOwl.php Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-09-12 09:16:36 UTC (rev 1843) +++ trunk/src/moosique.net/css/style.css 2009-09-13 15:41:13 UTC (rev 1844) @@ -32,9 +32,7 @@ -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; } /* button-click-feeling for links, by offsetting top position */ -#prev:active, #next:active, -#stop:active, #mute:active -#playPause:active, { position: relative; top: 2px; } +#playerControls a:active { position: relative; top: 2px; } #playlist .delete:active, #playlist .moveUp:active, #playlist .moveDown:active { top: 6px; } Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-09-12 09:16:36 UTC (rev 1843) +++ trunk/src/moosique.net/index.php 2009-09-13 15:41:13 UTC (rev 1844) @@ -25,11 +25,11 @@ <ol> <li> <select name="searchType" id="searchType"> - <?php /* <option value="allSearch">Everything</option> */ ?> + <option value="allSearch">All</option> <option value="artistSearch">Artist</option> <option value="tagSearch">Tag</option> <option value="songSearch">Song</option> - <?php /* <option value="lastfm">Last.fm-User</option> */ ?> + <?php /* TODO <option value="lastfm">Last.fm-User</option> */ ?> </select> <input id="searchValue" name="searchValue" type="text" /> <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> @@ -58,17 +58,39 @@ <h2>Welcome to moosique.net!</h2> <p> Want to listen to some good free music? Just enter an artist or song - name or search for music using tags <!-- or enter your last.fm username --> and let the moogic + name or search for music using tags and let the moogic happen. By listening to songs you like, the system will automatically learn about your musical taste and generate recommendations. You can find them in the tab »Recommendations«. </p> <p> - You can find information about the song currently playing in the tab »Information« and view - your Playlist and control the Player in the Tab »Player«. + You can find information about the song currently playing in the tab »Info« and edit and view + your current Playlist in the »Playlist«-Tab. </p> <p> Now get started and add something to the Playlist! </p> + + <pre> + <?php + + // recently Heard == posExamples testing + + if (!empty($_COOKIE['moosique'])) { + $recent = json_decode(stripslashes($_COOKIE['moosique']))->recentlyListened; + $posExamples = array(); + foreach($recent as $link) { + preg_match_all('#<a\s*(?:rel=[\'"]([^\'"]+)[\'"])?.*?>((?:(?!</a>).)*)</a>#i', $link, $record); + array_push($posExamples, $record[1][0]); + } + } + + print_r(array_unique($posExamples)); + + ?> + + + </pre> + </div> <div id="results"> @@ -81,11 +103,6 @@ <ol id="recommended"> <li></li> </ol> - <h2>Recently Listened to</h2> - <p>These are the songs you recently listened to. Click on a song to re-enqueue it to your current playlist. (NOT WORKING YET!)</p> - <ol id="recently"> - <li></li> - </ol> </div> <div id="information"> @@ -103,14 +120,19 @@ </div> <div id="player"> - <h3>Playlist</h3> + <h2>Playlist</h2> <p> You can delete entries from the playlist by clicking the small x on the left and change their order by clicking on the small up- and down-arrows.<br /> </p> <ol id="playlist"> <li></li> </ol> - + + <h2>Recently Listened to</h2> + <p>These are the songs you recently listened to. Click on a song to re-enqueue it to your current playlist.</p> + <ol id="recently"> + <li></li> + </ol> </div> <div id="help"> @@ -124,10 +146,22 @@ <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> </div> - </div> <!-- end container --> +<?php + include('moosique/classes/Config.php'); + $c = new Config(); + if ($c->getConfig('debug') == 1) /* debugging active */ { +?> <script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> +<script type="text/javascript" src="js/mootools-1.2.3-core-nc.js"></script> +<script type="text/javascript" src="js/moosique.js"></script> +<script type="text/javascript" src="js/debug.js"></script> +<script type="text/javascript" src="js/start.js"></script> + +<?php } else /* compress for production and dont include debugger */ { ?> +<script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> <script type="text/javascript" src="js/"></script> +<?php } ?> </body> </html> \ No newline at end of file Added: trunk/src/moosique.net/js/debug.js =================================================================== --- trunk/src/moosique.net/js/debug.js (rev 0) +++ trunk/src/moosique.net/js/debug.js 2009-09-13 15:41:13 UTC (rev 1844) @@ -0,0 +1,6 @@ +/* activate debugging */ +if (typeof(console) !== 'undefined') { + debug = console; + debug.log("Firebug-Console for moosique.net activated."); +} + Modified: trunk/src/moosique.net/js/index.php =================================================================== --- trunk/src/moosique.net/js/index.php 2009-09-12 09:16:36 UTC (rev 1843) +++ trunk/src/moosique.net/js/index.php 2009-09-13 15:41:13 UTC (rev 1844) @@ -18,13 +18,9 @@ /* the javascript-files to include and compress */ include('mootools-1.2.3-core-yc.js'); -include('player.js'); -include('interface.js'); -include('request.js'); - - -// Since we include the IE6-Fixes with a CC, we don't -// add and compress them here +include('moosique.js'); +// include('debug.js'); /* no debugging for production */ +include('start.js'); ob_end_flush(); ?> \ No newline at end of file Deleted: trunk/src/moosique.net/js/interface.js =================================================================== --- trunk/src/moosique.net/js/interface.js 2009-09-12 09:16:36 UTC (rev 1843) +++ trunk/src/moosique.net/js/interface.js 2009-09-13 15:41:13 UTC (rev 1844) @@ -1,44 +0,0 @@ -window.addEvent('domready', function() { - -// switching between search, recommendation and information -$$('#mainMenu a').each(function(a) { - a.addEvent('click', function(e) { - e.stop(); // dont follow link - showTab(a.get('class').toString()); - }); -}); - -// update recently listened song if a cookie is set -// update the #recently ol -var rlc = Cookie.read('recentlyListened'); -var rl = JSON.decode(rlc); - -if (rl) { - if (rl.length > 0) { - var count = rl.length; - var recentlyHTML = ''; - for (var i = 0; i < count; i++ ) { - recentlyHTML += '<li>'; - recentlyHTML += rl[i] + '<br />'; - recentlyHTML += '</li>'; - } - document.id('recently').set('html', recentlyHTML); - } -} - - -}); - -/** - * - * @param {String} tabID ID of the Tab to show - */ -function showTab(tabID) { - $$('#mainMenu li').removeClass('active'); - $$('#mainMenu a.' + tabID).getParent().toggleClass('active'); - document.id('content').getChildren().setStyle('display', 'none'); - document.id(tabID).setStyle('display', 'block'); - -} - - Added: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js (rev 0) +++ trunk/src/moosique.net/js/moosique.js 2009-09-13 15:41:13 UTC (rev 1844) @@ -0,0 +1,570 @@ +// initialize an empty debugger, will be activated if firefox/firebug enabled +var debug = {}; +debug.log = function(msg) { + return false; +}; + +/** + * moosique-Player-Class + * + * + * TODO Split out functions and comment it + */ +var Moosique = new Class({ Implements: Options, + + // Some Default Options + options: { + messageFadeTime: 5000, // Time until a Status message fades out + timeToScrobble: 0.5, // factor for calculating max time a user has to listen to a track until its scrobbled + minSearchLength: 3 // minimum number of chars for a search value (tag, artist, song) + }, + + /** + * Initializes the Object and sets some default options + * + * @param {Object} options + */ + initialize: function(options) { + this.setOptions(options); + this.initVars(); + this.applyYahooMediaPlayerConfig(); + this.initInterface(); + this.updateRecently(); + this.activateSearch(); + /* + this.initPlaylist(); + */ + }, + + + initVars: function() { + this.main = document.id('content'); + this.menu = document.id('mainMenu'); + this.playPause = document.id('playPause'); + this.prev = document.id('prev'); + this.next = document.id('next'); + this.stop = document.id('stop'); + this.mute = document.id('mute'); + this.status = document.id('status'); + this.playlist = document.id('playlist'); + this.recently = document.id('recently'); + this.nowPlayingInfo = $$('#playing .info'); + this.nowPlayingTrack = $$('#playing .track'); + this.nowPlayingTime = $$('#playing .time'); + this.searchForm = document.id('searchForm'); + this.searchSubmit = document.id('searchSubmit'); + this.searchValue = document.id('searchValue'); + this.searchType = document.id('searchType'); + this.results = document.id('results'); + this.loading = document.id('loadingImg'); + this.welcome = document.id('welcome'); + this.help = document.id('help'); + + }, + + + applyYahooMediaPlayerConfig: function() { + var that = this; + + var playerConfig = function() { + // display ready-status message + that.displayStatusMessage('Player ready.'); + + /** + * progress: Change the track position and duration displayed every time, as usual in players + * + * every time the song is played for at least half it's + * playtime, we assume that the song is liked, so we add it + * to the list we create the recommendations from + * (much like last.fm scrobbling) and learn from the heard songs + * BIG TODO + */ + var progress = function() { + that.nowPlayingTime.set('text', + that.secondsToMinutesAndSeconds(YAHOO.MediaPlayer.getTrackPosition()) + ' / ' + + that.secondsToMinutesAndSeconds(YAHOO.MediaPlayer.getTrackDuration()) ); + + if (Math.ceil(YAHOO.MediaPlayer.getTrackPosition()) == + Math.ceil(YAHOO.MediaPlayer.getTrackDuration() * that.options.timeToScrobble)) { + /* This is where the main magic happens + + After havin listened to a song for half its time we save this song to the positive examples list + and then send a request to the dllearner who then calulates new recommendations. + + first, we update the cookie with the last played song and then + */ + var lastListenedListItem = YAHOO.MediaPlayer.getMetaData().anchor.getParent().clone(); + var lastListened = lastListenedListItem.getFirst(); + + // remove the buttons and ymp-classes from the child-link + lastListenedListItem.getChildren('.moveUp').destroy(); + lastListenedListItem.getChildren('.moveDown').destroy(); + lastListenedListItem.getChildren('.delete').destroy(); + lastListened.erase('class'); + lastListened.addClass('htrack'); + lastListened.getChildren('em').destroy(); // yahoo buttons + + // this is the final link item we save in the cookie + var last = lastListenedListItem.get('html'); + + // get the current cookie + var recentlyListenedCookie = Cookie.read('moosique'); + var recentlyListened = []; + + if (recentlyListenedCookie) { // does the cookie exist? + recentlyListened = JSON.decode(recentlyListenedCookie).recentlyListened; + + if (recentlyListened) { // if the cookie is not totally empty + // update recently listened and write the cookie, limit to 10 entries, + // due to cookie-max-size of 4KB + // saves the whole link-element with rel to jamendo-album-id and mp3-link + if (recentlyListened.length >= 10) { + recentlyListened.shift(); // remove first item and shift + } + } + } + // add the last played to the array + recentlyListened.push(last); + + // update the cookie + recentlyListenedObject = { 'recentlyListened' : recentlyListened }; + recentlyListenedCookie = Cookie.write( /* save for one year */ + 'moosique', JSON.encode(recentlyListenedObject), { duration: 365 } + ); + + // update the recently played list + that.updateRecently(); + + // TODO + // send ajax request and save the scrobbled song + // and retrieve and update the recommendations + var getRecommendations = new Request({ + method: 'get', + url: 'moosique/index.php', + onSuccess: function(responseText, responseXML) { + mooPlayer.displayStatusMessage('Added this song to your recently listened to songs.'); + } + }).send(YAHOO.MediaPlayer.getMetaData().title); + + + } + }; + + /** + * playlistUpdate: every time the playlist is updated + * we add the events for delete/up/down-buttons to each + * playlistitem and update the status on what happened + */ + var playlistUpdate = function() { + // delete button + $$('#playlist .delete').each(function(del) { + del.removeEvents(); + del.addEvent('click', function(e) { + e.stop(); + this.getParent().destroy(); // deletes the li-element + // and refresh the playlist if clicked + YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + }); + }); + + // up-button + $$('#playlist .moveUp').each(function(up) { + up.removeEvents(); + up.addEvent('click', function(e) { + e.stop(); // don't folow link + var li = up.getParent(); + var before = li.getPrevious(); + if (before) { // it's not the first one + li.inject(before, 'before'); + // and refresh the playlist if clicked + YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + } + }); + }); + + // down button + $$('#playlist .moveDown').each(function(down) { + down.removeEvents(); + down.addEvent('click', function(e) { + e.stop(); // don't folow link + var li = down.getParent(); + var after = li.getNext(); + if (after) { // it's not the first one + li.inject(after, 'after'); + // and refresh the playlist if clicked + YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + } + }); + }); + + that.displayStatusMessage('Playlist updated.'); + // TODO save to current-playlist cookie? + + }; + + /** + * trackPause: we change the Pause-Button to a Play-Button + * and Update the status on #now + */ + var trackPause = function() { + that.nowPlayingInfo.set('text', 'Player paused.'); + that.playPause.setStyle('background-position', '0px 0px'); + }; + + /** + * trackStart: we change the Play-Button to a Pause-Button + * and Update the status on #now and display whats playing + */ + var trackStart = function() { + that.nowPlayingInfo.set('text', 'Currently playing:'); + that.nowPlayingTrack.set('text', YAHOO.MediaPlayer.getMetaData().title); + that.playPause.setStyle('background-position', '0px -40px'); + }; + + /** + * trackComplete: we change the Pause-Button to a Play-Button + */ + var trackComplete = function() { + that.playPause.setStyle('background-position', '0px 0px'); + }; + + // add the configuration to the events by subscribing + YAHOO.MediaPlayer.onProgress.subscribe(progress); + YAHOO.MediaPlayer.onPlaylistUpdate.subscribe(playlistUpdate); + YAHOO.MediaPlayer.onTrackPause.subscribe(trackPause); + YAHOO.MediaPlayer.onTrackStart.subscribe(trackStart); + YAHOO.MediaPlayer.onTrackComplete.subscribe(trackComplete); + }; + + // Initialize YMP if ready and apply the config + YAHOO.MediaPlayer.onAPIReady.subscribe(playerConfig); + + }, + + + + + + updateRecently: function() { + var that = this; + + // Read the Cookie and Update the recently-listened-to list + if (Cookie.read('moosique')) { + var recentSongs = JSON.decode(Cookie.read('moosique')).recentlyListened; + if (recentSongs) { + var count = recentSongs.length; + var recentlyHTML = ''; + for (var i = count-1; i >= 0; i-- ) { + recentlyHTML += '<li>'; + recentlyHTML += recentSongs[i]; + recentlyHTML += '</li>'; + } + that.recently.set('html', recentlyHTML); + that.makeAddable(that.recently.getElements('a')); + } + } + }, + + + + /** + * adding functionality for the player-GUI and the play, next etc. buttons + */ + addEventsToButtons: function() { + var that = this; + + // the previous/next-Track Buttons + that.prev.addEvent('click', function() { YAHOO.MediaPlayer.previous(); }); + that.next.addEvent('click', function() { YAHOO.MediaPlayer.next(); }); + + // the Play-Pause Button + that.playPause.addEvent('click', function() { + // STOPPED: 0, PAUSED: 1, PLAYING: 2,BUFFERING: 5, ENDED: 7 + if (YAHOO.MediaPlayer.getPlayerState() == 0 || + YAHOO.MediaPlayer.getPlayerState() == 1 || + YAHOO.MediaPlayer.getPlayerState() == 7) { + YAHOO.MediaPlayer.play(); + } else { + YAHOO.MediaPlayer.pause(); + } + }); + + // the Stop-Playing Button + that.stop.addEvent('click', function() { + that.playPause.setStyle('background-position', '0px 0px'); + that.nowPlayingInfo.set('text', 'Player stopped.'); + that.nowPlayingTrack.set('text', '...'); + that.nowPlayingTime.set('text', '0:00 / 0:00'); + YAHOO.MediaPlayer.stop(); + // and reload the playlist + that.refreshPlaylist(); + }); + + // Mute-Toggle-Switch + that.mute.addEvent('click', function() { + if (YAHOO.MediaPlayer.getVolume() > 0) { + YAHOO.MediaPlayer.setVolume(0); + that.mute.setStyle('background-position', '0px -240px'); + that.displayStatusMessage('Player muted.'); + } else { + YAHOO.MediaPlayer.setVolume(1); + that.mute.setStyle('background-position', '0px -280px'); + that.displayStatusMessage('Player unmuted.'); + } + }); + }, + + /** + * Playlist related functions + */ + initPlaylist: function() { + var that = this; + + $$('#recommended a').each(function(a) { + a.addEvent('click', function(e) { + // prevent link following + e.stop(); + a.set('class', 'htrack'); + + var liItem = a.getParent(); + // move to the playlist + liItem.inject(that.playlist); + that.refreshPlaylist(); + }); + }); + + that.refreshPlaylist(); + }, + + /** + * Refreshes the playlist by emptying the current one + * and reReading the #playlist-container + */ + refreshPlaylist: function() { + var that = this; + YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + that.displayStatusMessage('Playlist updated.'); + }, + + + /** + * Displays a status message + * + * @param {Object} message + */ + displayStatusMessage: function(message) { + // Update Status and fade out + var that = this; + that.status.set({ + 'text': message, + 'tween': {duration: that.options.messageFadeTime} + }); + that.status.tween('opacity', [1, 0]); + }, + + + /** + * initializes interface-functions, clicking buttons and tabs... + */ + initInterface: function() { + var that = this; + + that.menu.getElements('a').each(function(tab) { + tab.addEvent('click', function(e) { + e.stop(); // dont follow link + that.showTab(tab.get('class').toString()); + }); + }); + + // make buttons functional + this.addEventsToButtons(); + + }, + + + /** + * adds events to the search form for retrieving results etc. + */ + activateSearch: function() { + var that = this; + + that.searchForm.addEvent('submit', function(e) { + e.stop(); // prevent form submitting the non-ajax way + this.set('send', { + + onRequest: function() { + that.searchSubmit.set('disabled', 'disabled'); + that.searchSubmit.setStyle('display', 'none'); + // show homescreen for resultdisplaying + that.showTab('home'); + + that.loading.setStyle('display', 'inline'); + that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take a minute or two...</p>'); + }, + + onFailure: function() { + that.results.set('html', '<h2>Unable to process your search. Try again.</h2>'); + }, + + onSuccess: function(response) { + that.searchSubmit.erase('disabled'); // reenable submitbutton + that.searchSubmit.setStyle('display', 'inline'); + that.loading.setStyle('display', 'none'); + + // if the welcome-text ist present, cut & paste it to help + if (that.welcome) { + if (that.welcome.get('html').length > 100) { + that.help.set('html', that.welcome.get('html')); + that.welcome.destroy(); + } + } + // display results + that.results.set('html', response); + // addEvents to result-links + that.makeAddable($$('a.addToPlaylist')); + } + }); + + // only send form if value is at least 3 chars long + if (that.searchValue.get('value').length > 2) { + this.send(); + } + }); + + + + + + + }, + + + + + + + + /** + * For Recommendations and Search-Results + * This function searches for all links with the class addToPlaylist + * and makes them addable to the playlist, which means clicking on + * them adds them to the playlist and makes them playable. this + * is working for links to whole albums and single tracks also + */ + makeAddable: function (links) { + var that = this; + links.each(function(a) { + a.addEvent('click', function(e) { + e.stop(); // dont follow link + + // remove the class from preventing adding again, if existing + a.removeClass('addToPlaylist'); + // determine if the link is to an album or a single track + var href = a.get('href'); + var rel = a.get('rel'); + + var type = ''; + if (href.match(/jamendo\.com\/get\/track\/id\/album\//gi)) { type = 'albumPlaylist'; } + if (href.match(/jamendo\.com\/get\/track\/id\/track\//gi)) { type = 'trackPlaylist'; } + if (href.match(/\.mp3/)) { type = 'mp3File'; } + + // if the addable item is a playlist, we have to get the playlistitems + if (type == 'albumPlaylist' || type == 'trackPlaylist') { + var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', + onSuccess: function(response) { + that.insertIntoPlaylist(response); + } + }).send('get=' + type + '&playlist=' + href + '&rel=' + rel); + } + if (type == 'mp3File') { + var itemHTML = '<li>' + a.getParent().get('html') + '</li>'; + that.insertIntoPlaylist(itemHTML); + } + }); + }); + }, + + + + + + + + + /** + * appends prepared html code to the playlist, empties the playlist if the first + * element is an empty li and refreshed the playlist and shows the playlist tab + */ + insertIntoPlaylist: function(newItems) { + var that = this; + + // if the first li item of the playlist is empty, kill it + if (that.playlist.getFirst()) { + if (that.playlist.getFirst().get('text') == '') { + that.playlist.empty(); + } + } + // append new html to the playlist + var oldPlaylist = that.playlist.get('html'); + that.playlist.set('html', oldPlaylist + newItems); + + // add the delete, moveUp, moveDown Buttons + that.playlist.getChildren().each(function(li) { + var children = li.getChildren(); + + // only add the buttons if they are not there yet + if (children.length == 1) { + var track = li.getFirst(); + var upButton = new Element('a', { 'href': '#', 'class': 'moveUp', 'title': 'Move up', 'html': '↑' }); + var downButton = new Element('a', { 'href': '#', 'class': 'moveDown', 'title': 'Move down', 'html': '↓' }); + var delButton = new Element('a', { 'href': '#', 'class': 'delete', 'title': 'Delete from Playlist', 'html': 'X' }); + + upButton.inject(track, 'after'); + downButton.inject(upButton, 'after'); + delButton.inject(downButton, 'after'); + } + }); + + // refresh the playlist and show the player-tab + that.refreshPlaylist(); + that.showTab('player'); + }, + + + + + + /** + * + * @param {String} tabID ID of the Tab to show + */ + showTab: function(tabID) { + var that = this; + that.menu.getElements('li').removeClass('active'); + that.menu.getElements('a.' + tabID).getParent().toggleClass('active'); + that.main.getChildren().setStyle('display', 'none'); + document.id(tabID).setStyle('display', 'block'); + + }, + + + + /** + * Converts seconds into a string formatted minutes:seconds + * with leading zeros for seconds + * + * @param {Float} seconds + * @return {String} minsec minutes:seconds + */ + secondsToMinutesAndSeconds: function(seconds) { + var min = Math.floor(seconds / 60); + var sec = Math.floor(seconds % 60); + if (sec < 10) { + sec = '0' + sec; + } + var minsec = min + ":" + sec; + return minsec; + } + + +}); \ No newline at end of file Added: trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js =================================================================== --- trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js (rev 0) +++ trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js 2009-09-13 15:41:13 UTC (rev 1844) @@ -0,0 +1,4036 @@ +/* +Script: Core.js + MooTools - My Object Oriented JavaScript Tools. + +License: + MIT-style license. + +Copyright: + Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). + +Code & Documentation: + [The MooTools production team](http://mootools.net/developers/). + +Inspiration: + - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) + - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) +*/ + +var MooTools = { + 'version': '1.2.3', + 'build': '4980aa0fb74d2f6eb80bcd9f5b8e1fd6fbb8f607' +}; + +var Native = function(options){ + options = options || {}; + var name = options.name; + var legacy = options.legacy; + var protect = options.protect; + var methods = options.implement; + var generics = options.generics; + var initialize = options.initialize; + var afterImplement = options.afterImplement || function(){}; + var object = initialize || legacy; + generics = generics !== false; + + object.constructor = Native; + object.$family = {name: 'native'}; + if (legacy && initialize) object.prototype = legacy.prototype; + object.prototype.constructor = object; + + if (name){ + var family = name.toLowerCase(); + object.prototype.$family = {name: family}; + Native.typize(object, family); + } + + var add = function(obj, name, method, force){ + if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; + if (generics) Native.genericize(obj, name, protect); + afterImplement.call(obj, name, method); + return obj; + }; + + object.alias = function(a1, a2, a3){ + if (typeof a1 == 'string'){ + var pa1 = this.prototype[a1]; + if ((a1 = pa1)) return add(this, a2, a1, a3); + } + for (var a in a1) this.alias(a, a1[a], a2); + return this; + }; + + object.implement = function(a1, a2, a3){ + if (typeof a1 == 'string') return add(this, a1, a2, a3); + for (var p in a1) add(this, p, a1[p], a2); + return this; + }; + + if (methods) object.implement(methods); + + return object; +}; + +Native.genericize = function(object, property, check){ + if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ + var args = Array.prototype.slice.call(arguments); + return object.prototype[property].apply(args.shift(), args); + }; +}; + +Native.implement = function(objects, properties){ + for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); +}; + +Native.typize = function(object, family){ + if (!object.type) object.type = function(item){ + return ($type(item) === family); + }; +}; + +(function(){ + var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; + for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); + + var types = {'boolean': Boolean, 'native': Native, 'object': Object}; + for (var t in types) Native.typize(types[t], t); + + var generics = { + 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], + 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] + }; + for (var g in generics){ + for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true); + } +})(); + +var Hash = new Native({ + + name: 'Hash', + + initialize: function(object){ + if ($type(object) == 'hash') object = $unlink(object.getClean()); + for (var key in object) this[key] = object[key]; + return this; + } + +}); + +Hash.implement({ + + forEach: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); + } + }, + + getClean: function(){ + var clean = {}; + for (var key in this){ + if (this.hasOwnProperty(key)) clean[key] = this[key]; + } + return clean; + }, + + getLength: function(){ + var length = 0; + for (var key in this){ + if (this.hasOwnProperty(key)) length++; + } + return length; + } + +}); + +Hash.alias('forEach', 'each'); + +Array.implement({ + + forEach: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); + } + +}); + +Array.alias('forEach', 'each'); + +function $A(iterable){ + if (iterable.item){ + var l = iterable.length, array = new Array(l); + while (l--) array[l] = iterable[l]; + return array; + } + return Array.prototype.slice.call(iterable); +}; + +function $arguments(i){ + return function(){ + return arguments[i]; + }; +}; + +function $chk(obj){ + return !!(obj || obj === 0); +}; + +function $clear(timer){ + clearTimeout(timer); + clearInterval(timer); + return null; +}; + +function $defined(obj){ + return (obj != undefined); +}; + +function $each(iterable, fn, bind){ + var type = $type(iterable); + ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); +}; + +function $empty(){}; + +function $extend(original, extended){ + for (var key in (extended || {})) original[key] = extended[key]; + return original; +}; + +function $H(object){ + return new Hash(object); +}; + +function $lambda(value){ + return ($type(value) == 'function') ? value : function(){ + return value; + }; +}; + +function $merge(){ + var args = Array.slice(arguments); + args.unshift({}); + return $mixin.apply(null, args); +}; + +function $mixin(mix){ + for (var i = 1, l = arguments.length; i < l; i++){ + var object = arguments[i]; + if ($type(object) != 'object') continue; + for (var key in object){ + var op = object[key], mp = mix[key]; + mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); + } + } + return mix; +}; + +function $pick(){ + for (var i = 0, l = arguments.length; i < l; i++){ + if (arguments[i] != undefined) return arguments[i]; + } + return null; +}; + +function $random(min, max){ + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +function $splat(obj){ + var type = $type(obj); + return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; +}; + +var $time = Date.now || function(){ + return +new Date; +}; + +function $try(){ + for (var i = 0, l = arguments.length; i < l; i++){ + try { + return arguments[i](); + } catch(e){} + } + return null; +}; + +function $type(obj){ + if (obj == undefined) return false; + if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; + if (obj.nodeName){ + switch (obj.nodeType){ + case 1: return 'element'; + case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; + } + } else if (typeof obj.length == 'number'){ + if (obj.callee) return 'arguments'; + else if (obj.item) return 'collection'; + } + return typeof obj; +}; + +function $unlink(object){ + var unlinked; + switch ($type(object)){ + case 'object': + unlinked = {}; + for (var p in object) unlinked[p] = $unlink(object[p]); + break; + case 'hash': + unlinked = new Hash(object); + break; + case 'array': + unlinked = []; + for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); + break; + default: return object; + } + return unlinked; +}; + + +/* +Script: Browser.js + The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. + +License: + MIT-style license. +*/ + +var Browser = $merge({ + + Engine: {name: 'unknown', version: 0}, + + Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, + + Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, + + Plugins: {}, + + Engines: { + + presto: function(){ + return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); + }, + + trident: function(){ + return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4); + }, + + webkit: function(){ + return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); + }, + + gecko: function(){ + return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18); + } + + } + +}, Browser || {}); + +Browser.Platform[Browser.Platform.name] = true; + +Browser.detect = function(){ + + for (var engine in this.Engines){ + var version = this.Engines[engine](); + if (version){ + this.Engine = {name: engine, version: version}; + this.Engine[engine] = this.Engine[engine + version] = true; + break; + } + } + + return {name: engine, version: version}; + +}; + +Browser.detect(); + +Browser.Request = function(){ + return $try(function(){ + return new XMLHttpRequest(); + }, function(){ + return new ActiveXObject('MSXML2.XMLHTTP'); + }); +}; + +Browser.Features.xhr = !!(Browser.Request()); + +Browser.Plugins.Flash = (function(){ + var version = ($try(function(){ + return navigator.plugins['Shockwave Flash'].description; + }, function(){ + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + }) || '0 r0').match(/\d+/g); + return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; +})(); + +function $exec(text){ + if (!text) return text; + if (window.execScript){ + window.execScript(text); + } else { + var script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; + document.head.appendChild(script); + document.head.removeChild(script); + } + return text; +}; + +Native.UID = 1; + +var $uid = (Browser.Engine.trident) ? function(item){ + return (item.uid || (item.uid = [Native.UID++]))[0]; +} : function(item){ + return item.uid || (item.uid = Native.UID++); +}; + +var Window = new Native({ + + name: 'Window', + + legacy: (Browser.Engine.trident) ? null: window.Window, + + initialize: function(win){ + $uid(win); + if (!win.Element){ + win.Element = $empty; + if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 + win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; + } + win.document.window = win; + return $extend(win, Window.Prototype); + }, + + afterImplement: function(property, value){ + window[property] = Window.Prototype[property] = value; + } + +}); + +Window.Prototype = {$family: {name: 'window'}}; + +new Window(window); + +var Document = new Native({ + + name: 'Document', + + legacy: (Browser.Engine.trident) ? null: window.Document, + + initialize: function(doc){ + $uid(doc); + doc.head = doc.getElementsByTagName('head')[0]; + doc.html = doc.getElementsByTagName('html')[0]; + if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ + doc.execCommand("BackgroundImageCache", false, true); + }); + if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() { + doc.window.detachEvent('onunload', arguments.callee); + doc.head = doc.html = doc.window = null; + }); + return $extend(doc, Document.Prototype); + }, + + afterImplement: function(property, value){ + document[property] = Document.Prototype[property] = value; + } + +}); + +Document.Prototype = {$family: {name: 'document'}}; + +new Document(document); + + +/* +Script: Array.js + Contains Array Prototypes like each, contains, and erase. + +License: + MIT-style license. +*/ + +Array.implement({ + + every: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (!fn.call(bind, this[i], i, this)) return false; + } + return true; + }, + + filter: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) results.push(this[i]); + } + return results; + }, + + clean: function() { + return this.filter($defined); + }, + + indexOf: function(item, from){ + var len = this.length; + for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ + if (this[i] === item) return i; + } + return -1; + }, + + map: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); + return results; + }, + + some: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) return true; + } + return false; + }, + + associate: function(keys){ + var obj = {}, length = Math.min(this.length, keys.length); + for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; + return obj; + }, + + link: function(object){ + var result = {}; + for (var i = 0, l = this.length; i < l; i++){ + for (var key in object){ + if (object[key](this[i])){ + result[key] = this[i]; + delete object[key]; + break; + } + } + } + return result; + }, + + contains: function(item, from){ + return this.indexOf(item, from) != -1; + }, + + extend: function(array){ + for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); + return this; + }, + + getLast: function(){ + return (this.length) ? this[this.length - 1] : null; + }, + + getRandom: function(){ + return (this.length) ? this[$random(0, this.length - 1)] : null; + }, + + include: function(item){ + if (!this.contains(item)) this.push(item); + return this; + }, + + combine: function(array){ + for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); + return this; + }, + + erase: function(item){ + for (var i = this.length; i--; i){ + if (this[i] === item) this.splice(i, 1); + } + return this; + }, + + empty: function(){ + this.length = 0; + return this; + }, + + flatten: function(){ + var array = []; + for (var i = 0, l = this.length; i < l; i++){ + var type = $type(this[i]); + if (!type) continue; + array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); + } + return array; + }, + + hexToRgb: function(array){ + if (this.length != 3) return null; + var rgb = this.map(function(value){ + if (value.length == 1) value += value; + return value.toInt(16); + }); + return (array) ? rgb : 'rgb(' + rgb + ')'; + }, + + rgbToHex: function(array){ + if (this.length < 3) return null; + if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (this[i] - 0).toString(16); + hex.push((bit.length == 1) ? '0' + bit : bit); + } + return (array) ? hex : '#' + hex.join(''); + } + +}); + + +/* +Script: Function.js + Contains Function Prototypes like create, bind, pass, and delay. + +License: + MIT-style license. +*/ + +Function.implement({ + + extend: function(properties){ + for (var property in properties) this[property] = properties[property]; + return this; + }, + + create: function(options){ + var self = this; + options = options || {}; + return function(event){ + var args = options.arguments; + args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); + if (options.event) args = [event || window.event].extend(args); + var returns = function(){ + return self.apply(options.bind || null, args); + }; + if (options.delay) return setTimeout(returns, options.delay); + if (options.periodical) return setInterval(returns, options.periodical); + if (options.attempt) return $try(returns); + return returns(); + }; + }, + + run: function(args, bind){ + return this.apply(bind, $splat(args)); + }, + + pass: function(args, bind){ + return this.create({bind: bind, arguments: args}); + }, + + bind: function(bind, args){ + return this.create({bind: bind, arguments: args}); + }, + + bindWithEvent: function(bind, args){ + return this.create({bind: bind, arguments: args, event: true}); + }, + + attempt: function(args, bind){ + return this.create({bind: bind, arguments: args, attempt: true})(); + }, + + delay: function(delay, bind, args){ + return this.create({bind: bind, arguments: args, delay: delay})(); + }, + + periodical: function(periodical, bind, args){ + return this.create({bind: bind, arguments: args, periodical: periodical})(); + } + +}); + + +/* +Script: Number.js + Contains Number Prototypes like limit, round, times, and ceil. + +License: + MIT-style license. +*/ + +Number.implement({ + + limit: function(min, max){ + return Math.min(max, Math.max(min, this)); + }, + + round: function(precision){ + precision = Math.pow(10, precision || 0); + return Math.round(this * precision) / precision; + }, + + times: function(fn, bind){ + for (var i = 0; i < this; i++) fn.call(bind, i, this); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + } + +}); + +Number.alias('times', 'each'); + +(function(math){ + var methods = {}; + math.each(function(name){ + if (!Number[name]) methods[name] = function(){ + return Math[name].apply(null, [this].concat($A(arguments))); + }; + }); + Number.implement(methods); +})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); + + +/* +Script: String.js + Contains String Prototypes like camelCase, capitalize, test, and toInt. + +License: + MIT-style license. +*/ + +String.implement({ + + test: function(regex, params){ + return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); + }, + + contains: function(string, separator){ + return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; + }, + + trim: function(){ + return this.replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return this.replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return this.replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return this.replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return this.replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = this.match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + stripScripts: function(option){ + var scripts = ''; + var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){ + scripts += arguments[1] + '\n'; + return ''; + }); + if (option === true) $exec(scripts); + else if ($type(option) == 'function') option(scripts, text); + return text; + }, + + substitute: function(object, regexp){ + return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + if (match.charAt(0) == '\\') return match.slice(1); + return (object[name] != undefined) ? object[name] : ''; + }); + } + +}); + + +/* +Script: Hash.js + Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. + +License: + MIT-style license. +*/ + +Hash.implement({ + + has: Object.prototype.hasOwnProperty, + + keyOf: function(value){ + for (var key in this){ + if (this.hasOwnProperty(key) && this[key] === value) return key; + } + return null; + }, + + hasValue: function(value){ + return (Hash.keyOf(this, value) !== null); + }, + + extend: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.set(this, key, value); + }, this); + return this; + }, + + combine: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.include(this, key, value); + }, this); + return this; + }, + + erase: function(key){ + if (this.hasOwnProperty(key)) delete this[key]; + return this; + }, + + get: function(key){ + return (this.hasOwnProperty(key)) ? this[key] : null; + }, + + set: function(key, value){ + if (!this[key] || this.hasOwnProperty(key)) this[key] = value; + return this; + }, + + empty: function(){ + Hash.each(this, function(value, key){ + delete this[key]; + }, this); + return this; + }, + + include: function(key, value){ + if (this[key] == undefined) this[key] = value; + return this; + }, + + map: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + results.set(key, fn.call(bind, value, key, this)); + }, this); + return results; + }, + + filter: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + if (fn.call(bind, value, key, this)) results.set(key, value); + }, this); + return results; + }, + + every: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; + } + return true; + }, + + some: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; + } + return false; + }, + + getKeys: function(){ + var keys = []; + Hash.each(this, function(value, key){ + keys.push(key); + }); + return keys; + }, + + getValues: function(){ + var values = []; + Hash.each(this, function(value){ + values.push(value); + }); + return values; + }, + + toQueryString: function(base){ + var queryString = []; + Hash.each(this, function(value, key){ + if (base) key = base + '[' + key + ']'; + var result; + switch ($type(value)){ + case 'object': result = Hash.toQueryString(value, key); break; + case 'array': + var qs = {}; + value.each(function(val, i){ + qs[i] = val; + }); + result = Hash.toQueryString(qs, key); + break; + default: result = key + '=' + encodeURIComponent(value); + } + if (value != undefined) queryString.push(result); + }); + + return queryString.join('&'); + } + +}); + +Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); + + +/* +Script: Event.js + Contains the Event Native, to make the event object completely crossbrowser. + +License: + MIT-style license. +*/ + +var Event = new Native({ + + name: 'Event', + + initialize: function(event, win){ + win = win || window; + var doc = win.document; + event = event || win.event; + if (event.$extended) return event; + this.$extended = true; + var type = event.type; + var target = event.target || event.srcElement; + while (target && target.nodeType == 3) target = target.parentNode; + + if (type.test(/key/)){ + var code = event.which || event.keyCode; + var key = Event.Keys.keyOf(code); + if (type == 'keydown'){ + var fKey = code - 111; + if (fKey > 0 && fKey < 13) key = 'f' + fKey; + } + key = key || String.fromCharCode(code).toLowerCase(); + } else if (type.match(/(click|mouse|menu)/i)){ + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + var page = { + x: event.pageX || event.clientX + doc.scrollLeft, + y: event.pageY || event.clientY + doc.scrollTop + }; + var client = { + x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY + }; + if (type.match(/DOMMouseScroll|mousewheel/)){ + var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + } + var rightClick = (event.which == 3) || (event.button == 2); + var related = null; + if (type.match(/over|out/)){ + switch (type){ + case 'mouseover': related = event.relatedTarget || event.fromElement; break; + case 'mouseout': related = event.relatedTarget || event.toElement; + } + if (!(function(){ + while (related && related.nodeType == 3) related = related.parentNode; + return true; + }).create({attempt: Browser.Engine.gecko})()) related = false; + } + } + + return $extend(this, { + event: event, + type: type, + + page: page, + client: client, + rightClick: rightClick, + + wheel: wheel, + + relatedTarget: related, + target: target, + + code: code, + key: key, + + shift: event.shiftKey, + control: event.ctrlKey, + alt: event.altKey, + meta: event.metaKey + }); + } + +}); + +Event.Keys = new Hash({ + 'enter': 13, + 'up': 38, + 'down': 40, + 'left': 37, + 'right': 39, + 'esc': 27, + 'space': 32, + 'backspace': 8, + 'tab': 9, + 'delete': 46 +}); + +Event.implement({ + + stop: function(){ + return this.stopPropagation().preventDefault(); + }, + + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + return this; + }, + + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + } + +}); + + +/* +Script: Class.js + Contains the Class Function for easily creating, extending, and implementing reusable Classes. + +License: + MIT-style license. +*/ + +function Class(params){ + + if (params instanceof Function) params = {initialize: params}; + + var newClass = function(){ + Object.reset(this); + if (newClass._prototyping) return this; + this._current = $empty; + var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; + delete this._current; delete this.caller; + return value; + }.extend(this); + + newClass.implement(params); + + newClass.constructor = Class; + newClass.prototype.constructor = newClass; + + return newClass; + +}; + +Function.prototype.protect = function(){ + this._protected = true; + return this; +}; + +Object.reset = function(object, key){ + + if (key == null){ + for (var p in object) Object.reset(object, p); + return object; + } + + delete object[key]; + + switch ($type(object[key])){ + case 'object': + var F = function(){}; + F.prototype = object[key]; + var i = new F; + object[key] = Object.reset(i); + break; + case 'array': object[key] = $unlink(object[key]); break; + } + + return object; + +}; + +new Native({name: 'Class', initialize: Class}).extend({ + + instantiate: function(F){ + F._prototyping = true; + var proto = new F; + delete F._prototyping; + return proto; + }, + + wrap: function(self, key, method){ + if (method._origin) method = method._origin; + + return function(){ + if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); + var caller = this.caller, current = this._current; + this.caller = current; this._current = arguments.callee; + var result = method.apply(this, arguments); + this._current = current; this.caller = caller; + return result; + }.extend({_owner: self, _origin: method, _name: key}); + + } + +}); + +Class.implement({ + + implement: function(key, value){ + + if ($type(key) == 'object'){ + for (var p in key) this.implement(p, key[p]); + return this; + } + + var mutator = Class.Mutators[key]; + + if (mutator){ + value = mutator.call(this, value); + if (value == null) return this; + } + + var proto = this.prototype; + + switch ($type(value)){ + + case 'function': + if (value._hidden) return this; + proto[key] = Class.wrap(this, key, value); + break; + + case 'object': + var previous = proto[key]; + if ($type(previous) == 'object') $mixin(previous, value); + else proto[key] = $unlink(value); + break; + + case 'array': + proto[key] = $unlink(value); + break; + + default: proto[key] = value; + + } + + return this; + + } + +}); + +Class.Mutators = { + + Extends: function(parent){ + + this.parent = parent; + this.prototype = Class.instantiate(parent); + + this.implement('parent', function(){ + var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; + if (!previous) throw new Error('The method "' + name + '" has no parent.'); + return previous.apply(this, arguments); + }.protect()); + + }, + + Implements: function(items){ + $splat(items).each(function(item){ + if (item instanceof Function) item = Class.instantiate(item); + this.implement(item); + }, this); + + } + +}; + + +/* +Script: Class.Extras.js + Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. + +License: + MIT-style license. +*/ + +var Chain = new Class({ + + $chain: [], + + chain: function(){ + this.$chain.extend(Array.flatten(arguments)); + return this; + }, + + callChain: function(){ + return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; + }, + + clearChain: function(){ + this.$chain.empty(); + return this; + } + +}); + +var Events = new Class({ + + $events: {}, + + addEvent: function(type, fn, internal){ + type = Events.removeOn(type); + if (fn != $empty){ + this.$events[type] = this.$events[type] || []; + this.$events[type].include(fn); + if (internal) fn.internal = true; + } + return this; + }, + + addEvents: function(events){ + for (var type in events) this.addEvent(type, events[type]); + return this; + }, + + fireEvent: function(type, args, delay){ + type = Events.removeOn(type); + if (!this.$events || !this.$events[type]) return this; + this.$events[type].each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + removeEvent: function(type, fn){ + type = Events.removeOn(type); + if (!this.$events[type]) return this; + if (!fn.internal) this.$events[type].erase(fn); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + if (events) events = Events.removeOn(events); + for (type in this.$events){ + if (events && events != type) continue; + var fns = this.$events[type]; + for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); + } + return this; + } + +}); + +Events.removeOn = function(string){ + return string.replace(/^on([A-Z])/, function(full, first) { + return first.toLowerCase(); + }); +}; + +var Options = new Class({ + + setOptions: function(){ + this.options = $merge.run([this.options].extend(arguments)); + if (!this.addEvent) return this; + for (var option in this.options){ + if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; + this.addEvent(option, this.options[option]); + delete this.options[option]; + } + return this; + } + +}); + + +/* +Script: Element.js + One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, + time-saver methods to let you easily work with HTML Elements. + +License: +... [truncated message content] |
From: <neb...@us...> - 2009-10-07 15:21:57
|
Revision: 1880 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1880&view=rev Author: nebelschwade Date: 2009-10-07 15:21:39 +0000 (Wed, 07 Oct 2009) Log Message: ----------- - Added last.fm-Support - View/RequestHandler Refactoring - Prepared Recommendation-Fetching and display using ajax - Prepared multi-tag searching using a better SPARQL-Query for tags like "stoner doom drone metal" - Enhanced OWL Modified Paths: -------------- trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/debug.js trunk/src/moosique.net/js/index.php trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/LastFM.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt trunk/src/moosique.net/moosique/def0.xsd trunk/src/moosique.net/moosique/def1.xsd trunk/src/moosique.net/moosique/index.php trunk/src/moosique.net/moosique/main.wsdl trunk/src/moosique.net/moosique/testing/learnTest.php trunk/src/moosique.net/moosique/testing/main.wsdl trunk/src/moosique.net/moosique/testing/moreThan80.owl Added Paths: ----------- trunk/src/moosique.net/moosique/testing/nodeExtractionBug.conf Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/css/style.css 2009-10-07 15:21:39 UTC (rev 1880) @@ -1,7 +1,6 @@ -/* moosique.net - a jamendo radio with recommendations! */ @media screen { /*=============== Default Styling ===============*/ -body { font: normal 12px/16px Verdana, Arial, sans-serif; color: #f1f7e4; +body { font: normal 12px/18px Verdana, Arial, sans-serif; color: #f1f7e4; background: url('../img/bg.png') top left repeat #3a3a3a; border-top: 5px solid #1fd611; } input, textarea, select { background: #292929; border: 1px solid #5a5a5a; outline: none; padding: 5px; } input[type=submit] { padding: 5px 10px; } @@ -17,7 +16,7 @@ pre { font: normal 10px/14px Monaco, Courier, monospace; } p, h1, h2, h3, h4, h5, h6, table, ul, ol, blockquote, -pre, form { margin-bottom: 16px; } +pre, form { margin-bottom: 18px; } /* Initial hiding */ #recommendations, #player, @@ -25,11 +24,12 @@ #loadingImg, #header h1 { display: none; } /* Rounded Corners */ -input, textarea, select { -moz-border-radius: 5px; -webkit-border-radius: 5px; } +input, textarea, select { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } #content, #status, #playing, -#playerControls, #results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; } +#playerControls, #results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } #mainMenu a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; - -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; } + -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; border-top-left-radius: 10px; } /* button-click-feeling for links, by offsetting top position */ #playerControls a:active { position: relative; top: 2px; } @@ -75,7 +75,7 @@ #loadingImg { cursor: wait; } -/*=============== Menu ===============*/ +/*=============== Menu & Footer ===============*/ #mainMenu ul { position: absolute; top: 0; right: 0; } #mainMenu li { float: left; } #mainMenu a { display: block; margin-left: 10px; line-height: 30px; height: 30px; @@ -84,23 +84,23 @@ #mainMenu .active a:hover { background: #1fd611; } #mainMenu a:hover { text-decoration: none; background: #5a5a5a; } +#footer a { padding: 0 10px; } /*=============== Search Results ===============*/ #results li h3 a { font-weight: normal; } -#results li img { border: 2px solid #545454; margin-bottom: 16px; } -#results li { display: block; border: 1px solid #545454; padding: 16px; margin-bottom: 16px; - float: left; width: 318px; } -#results li.odd { margin-right: 16px; clear: both; } +#results li img { border: 2px solid #545454; } +#results li { float: left; width: 312px; border: 1px solid #545454; padding: 18px; margin-bottom: 18px; } +#results li.odd { margin-right: 18px; clear: both; } #results ul ul { list-style: disc; } /* This is for the list of found albums etc */ #results li li, #results .artistSearch li li, -#results .tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 32px; +#results .tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; width: auto; height: auto; float: none; } #results .tagSearch ul ul { clear: both; } -#results .artistImage { text-align: center; } -#results .cover { margin-right: 16px; width: 110px; float: left; } +#results .artistImage { text-align: center; margin-bottom: 18px;} +#results .cover { margin: 0 18px 18px 0; width: 104px; height: 104px; float: left; } #results .tagSearch h4 { display: inline; } @@ -128,6 +128,4 @@ - - } /* end @media screen */ \ No newline at end of file Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/index.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -22,20 +22,18 @@ </ul> </div> <form id="searchForm" method="get" action="moosique/"> - <ol> - <li> - <select name="searchType" id="searchType"> - <option value="allSearch">All</option> - <option value="artistSearch">Artist</option> - <option value="tagSearch">Tag</option> - <option value="songSearch">Song</option> - <?php /* TODO <option value="lastfm">Last.fm-User</option> */ ?> - </select> - <input id="searchValue" name="searchValue" type="text" /> - <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> - <img id="loadingImg" src="img/loading.gif" alt="Loading..." /> - </li> - </ol> + <div> + <select name="searchType" id="searchType"> + <option value="allSearch">All</option> + <option value="artistSearch">Artist</option> + <option value="tagSearch">Tag</option> + <option value="songSearch">Song</option> + <option value="lastFM">last.fm</option> + </select> + <input id="searchValue" name="searchValue" type="text" /> + <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> + <img id="loadingImg" src="img/loading.gif" alt="Loading..." /> + </div> </form> <div id="playerControls"> <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> @@ -44,7 +42,7 @@ <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> <a href="#" id="mute" title="Sound on/off">Mute</a> </div> - <h4 id="status"> </h4> + <div id="status"> </div> <div id="playing"> <span class="info">Player stopped</span> <span class="track">...</span> @@ -63,32 +61,16 @@ your musical taste and generate recommendations. You can find them in the tab »Recommendations«. </p> <p> + You can also enter your <a href="http://last.fm">last.fm</a>-username to automatically use your + most-used tags to generate a initial list of recommendations. + </p> + <p> You can find information about the song currently playing in the tab »Info« and edit and view your current Playlist in the »Playlist«-Tab. </p> <p> Now get started and add something to the Playlist! </p> - - <pre> - <?php - - // recently Heard == posExamples testing - /* - if (!empty($_COOKIE['moosique'])) { - $recent = json_decode(stripslashes($_COOKIE['moosique']))->recentlyListened; - $posExamples = array(); - foreach($recent as $link) { - preg_match_all('#<a\s*(?:rel=[\'"]([^\'"]+)[\'"])?.*?>((?:(?!</a>).)*)</a>#i', $link, $record); - array_push($posExamples, $record[1][0]); - } - } - - print_r(array_unique($posExamples)); - */ - ?> - </pre> - </div> <div id="results"> @@ -97,30 +79,32 @@ <div id="recommendations"> <h2>Recommended Songs</h2> - <p>These are the automatically generated recommendations. Click on a song to add it to your playlist.</p> - <ol id="recommended"> - <li></li> - </ol> + <p> + These recommendations are generated every time you listen to a song + for at least half it's length, assuming that you liked it. + </p> + + <div id="recommendationResults"> + + + </div> + <p> + <a href="#" id="generateRecommendations">Nothing showing up here? You can also + generate your list of recommendations by clicking here.</a> + </p> </div> <div id="information"> <div id="moreInfo"> - <h2>About the Artist</h2> - <img src="http://imgjam.com/albums/8654/covers/1.200.jpg" alt="Cover" /> - <p> - Iusto odio dignissim qui blandit praesent. Nisl ut aliquip ex ea commodo, consequat - duis autem vel eum. Nam liber tempor cum soluta nobis eleifend option congue nihil - imperdiet doming id. In hendrerit eu feugiat nulla luptatum zzril delenit augue duis - dolore te feugait. Quod ii legunt saepius claritas est etiam processus dynamicus - qui nobis videntur parum. - </p> + </div> </div> <div id="player"> <h2>Playlist</h2> <p> - You can delete entries from the playlist by clicking the small x on the left and change their order by clicking on the small up- and down-arrows.<br /> + You can delete entries from the playlist by clicking the small x on the right and + change their order by clicking on the small up- and down-arrows.<br /> </p> <ol id="playlist"> <li></li> @@ -131,6 +115,7 @@ <ol id="recently"> <li></li> </ol> + <p><a href="#" id="reset">Click here to reset your »recently listened to«-list.</a></p> </div> <div id="help"> @@ -140,9 +125,9 @@ </div> <!-- end content --> <div id="footer"> + <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> | <a href="http://jamendo.com">Jamendo</a> | - <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> | - <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> + <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> </div> </div> <!-- end container --> Modified: trunk/src/moosique.net/js/debug.js =================================================================== --- trunk/src/moosique.net/js/debug.js 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/js/debug.js 2009-10-07 15:21:39 UTC (rev 1880) @@ -1,4 +1,4 @@ -/* activate debugging */ +/* activate debugging if firebug is avaiable */ if (typeof(console) !== 'undefined') { debug = console; debug.log("Firebug-Console for moosique.net activated."); Modified: trunk/src/moosique.net/js/index.php =================================================================== --- trunk/src/moosique.net/js/index.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/js/index.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -2,10 +2,10 @@ /* This little Script takes all included js-files and * compresses them with the PHP-Variant of js-min * found here: http://code.google.com/p/jsmin-php/ + * This file is only used in non-debugging-mode */ header('Content-type: application/javascript'); -// set offset to 365 days = 1 year -$offset = 60 * 60 * 24 * 365; +$offset = 60 * 60 * 24 * 365; // set offset to 365 days = 1 year header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $offset) . ' GMT'); ob_start('compress'); @@ -19,7 +19,6 @@ /* the javascript-files to include and compress */ include('mootools-1.2.3-core-yc.js'); include('moosique.js'); -// include('debug.js'); /* no debugging for production */ include('start.js'); ob_end_flush(); Modified: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/js/moosique.js 2009-10-07 15:21:39 UTC (rev 1880) @@ -6,13 +6,13 @@ /** * moosique-Player-Class - * - * - * TODO Split out functions and comment it + * + * + * */ var Moosique = new Class({ Implements: Options, - // Some Default Options + // set some default options options: { messageFadeTime: 5000, // Time until a Status message fades out timeToScrobble: 0.5, // factor for calculating max time a user has to listen to a track until its scrobbled @@ -20,8 +20,9 @@ }, /** - * Initializes the Object and sets some default options - * + * Initializes the Object and sets the default options + * activating search functionality and the interface for using the player + * * @param {Object} options */ initialize: function(options) { @@ -31,12 +32,14 @@ this.initInterface(); this.updateRecently(); this.activateSearch(); - /* - this.initPlaylist(); - */ }, + /** + * This function stores references to DOM-Objects in this class + * for easier access in the other methods, if sth. in the DOM is + * changed, just change the references here and everything will work fine. + */ initVars: function() { this.main = document.id('content'); this.menu = document.id('mainMenu'); @@ -59,10 +62,19 @@ this.loading = document.id('loadingImg'); this.welcome = document.id('welcome'); this.help = document.id('help'); - + this.recommendations = document.id('recommendations'); + this.generate = document.id('generateRecommendations'); + this.recResults = document.id('recommendationResults'); + this.reset = document.id('reset'); }, - + /** + * Applies Config-Vars to the Yahoo Media Player as described in http://mediaplayer.yahoo.com/api/ + * for the YMP-Events and initializes the Player. Events are: + * onProgress, onPlaylistUpdate, onTrackPause, onTrackStart, onTrackComplete + * where onProgress is the most important event-handler, because this is where the learning-process is fired + * + */ applyYahooMediaPlayerConfig: function() { var that = this; @@ -73,11 +85,9 @@ /** * progress: Change the track position and duration displayed every time, as usual in players * - * every time the song is played for at least half it's - * playtime, we assume that the song is liked, so we add it - * to the list we create the recommendations from - * (much like last.fm scrobbling) and learn from the heard songs - * BIG TODO + * every time the song is played for a given percent of it's length (set when initializing + * the moosique-Class), we assume that the song is liked (like last.fm-scobling), so we add + * it to the recently listened list AND we create the recommendations and learn */ var progress = function() { that.nowPlayingTime.set('text', @@ -86,13 +96,8 @@ if (Math.ceil(YAHOO.MediaPlayer.getTrackPosition()) == Math.ceil(YAHOO.MediaPlayer.getTrackDuration() * that.options.timeToScrobble)) { - /* This is where the main magic happens - After havin listened to a song for half its time we save this song to the positive examples list - and then send a request to the dllearner who then calulates new recommendations. - - first, we update the cookie with the last played song and then - */ + // first, we update the cookie with the last played song and then var lastListenedListItem = YAHOO.MediaPlayer.getMetaData().anchor.getParent().clone(); var lastListened = lastListenedListItem.getFirst(); @@ -105,6 +110,7 @@ lastListened.getChildren('em').destroy(); // yahoo buttons // this is the final link item we save in the cookie + // stripped of all unneccessary links and buttons, but easy to re-add or learn from var last = lastListenedListItem.get('html'); // get the current cookie @@ -113,7 +119,6 @@ if (recentlyListenedCookie) { // does the cookie exist? recentlyListened = JSON.decode(recentlyListenedCookie).recentlyListened; - if (recentlyListened) { // if the cookie is not totally empty // update recently listened and write the cookie, limit to 10 entries, // due to cookie-max-size of 4KB @@ -134,26 +139,14 @@ // update the recently played list that.updateRecently(); - - // TODO - // send ajax request and save the scrobbled song - // and retrieve and update the recommendations - var getRecommendations = new Request({ - method: 'get', - url: 'moosique/index.php', - onSuccess: function(responseText, responseXML) { - mooPlayer.displayStatusMessage('Added this song to your recently listened to songs.'); - } - }).send(YAHOO.MediaPlayer.getMetaData().title); - - + that.displayStatusMessage('Added this song to your recently listened to songs.'); + that.generateRecommendations(); } }; /** - * playlistUpdate: every time the playlist is updated - * we add the events for delete/up/down-buttons to each - * playlistitem and update the status on what happened + * playlistUpdate: every time the playlist is updated we add the events for + * delete/up/down-buttons to each playlistitem and update the status on what happened */ var playlistUpdate = function() { // delete button @@ -196,10 +189,7 @@ } }); }); - that.displayStatusMessage('Playlist updated.'); - // TODO save to current-playlist cookie? - }; /** @@ -214,6 +204,7 @@ /** * trackStart: we change the Play-Button to a Pause-Button * and Update the status on #now and display whats playing + * TODO: when a track started playing, fetch additional information about artist etc. using musicbrainz */ var trackStart = function() { that.nowPlayingInfo.set('text', 'Currently playing:'); @@ -223,6 +214,7 @@ /** * trackComplete: we change the Pause-Button to a Play-Button + * TODO: if this was the last track, add another track from the recommendations and start playing */ var trackComplete = function() { that.playPause.setStyle('background-position', '0px 0px'); @@ -238,13 +230,37 @@ // Initialize YMP if ready and apply the config YAHOO.MediaPlayer.onAPIReady.subscribe(playerConfig); - }, + /** + * Send an ajax-request to generate the recommendations and passes the + * result to the corresponding html-container + * + */ + generateRecommendations: function() { + var that = this; + + // TODO + // send ajax request and save the scrobbled song + // and retrieve and update the recommendations + var getRecommendations = new Request({ + method: 'get', + url: 'moosique/index.php', + onSuccess: function(response) { + that.recResults.set('html', response); + that.showTab('recommendations'); + that.displayStatusMessage('You have new recommendations!'); + } + }).send('learn=now'); + }, - + /** + * Updates the recently-Listened-To UL-List Element with the contents + * from the recentlyListened-Cookie and makes them re-addable to the playlist + * + */ updateRecently: function() { var that = this; @@ -261,14 +277,17 @@ } that.recently.set('html', recentlyHTML); that.makeAddable(that.recently.getElements('a')); + } else { // cookie is set, but no Songs in recently + that.recently.set('html', '<li></li>'); } + } else { // no Cookie found, emptying recently + that.recently.set('html', '<li></li>'); } }, - - + /** - * adding functionality for the player-GUI and the play, next etc. buttons + * Adds click-events to all player-related buttons, like play, next etc. buttons */ addEventsToButtons: function() { var that = this; @@ -278,8 +297,9 @@ that.next.addEvent('click', function() { YAHOO.MediaPlayer.next(); }); // the Play-Pause Button - that.playPause.addEvent('click', function() { + that.playPause.addEvent('click', function() { // STOPPED: 0, PAUSED: 1, PLAYING: 2,BUFFERING: 5, ENDED: 7 + // see http://mediaplayer.yahoo.com/api/ if (YAHOO.MediaPlayer.getPlayerState() == 0 || YAHOO.MediaPlayer.getPlayerState() == 1 || YAHOO.MediaPlayer.getPlayerState() == 7) { @@ -313,32 +333,11 @@ } }); }, - - /** - * Playlist related functions - */ - initPlaylist: function() { - var that = this; - $$('#recommended a').each(function(a) { - a.addEvent('click', function(e) { - // prevent link following - e.stop(); - a.set('class', 'htrack'); - - var liItem = a.getParent(); - // move to the playlist - liItem.inject(that.playlist); - that.refreshPlaylist(); - }); - }); - - that.refreshPlaylist(); - }, /** - * Refreshes the playlist by emptying the current one - * and reReading the #playlist-container + * Refreshes the YMP-playlist by emptying the current one + * and re-adding all items from the the playlist-container */ refreshPlaylist: function() { var that = this; @@ -350,7 +349,7 @@ /** * Displays a status message * - * @param {Object} message + * @param {String} message */ displayStatusMessage: function(message) { // Update Status and fade out @@ -364,7 +363,9 @@ /** - * initializes interface-functions, clicking buttons and tabs... + * Adds click-Events to the Interface for Tabs and invokes + * addEventsToButtons() + * */ initInterface: function() { var that = this; @@ -376,14 +377,28 @@ }); }); + // generating recommendations clickable + that.generate.addEvent('click', function(e) { + e.stop(); + that.generateRecommendations(); + }); + + that.reset.addEvent('click', function(e) { + e.stop(); + Cookie.dispose('moosique'); + that.updateRecently(); + }); + // make buttons functional this.addEventsToButtons(); - }, /** - * adds events to the search form for retrieving results etc. + * Make the search-Form an ajax-Search form, displaying the results + * on the homepage if successful + * + * TODO: sanitize client-side too using regex and displayStatus */ activateSearch: function() { var that = this; @@ -398,8 +413,15 @@ // show homescreen for resultdisplaying that.showTab('home'); + // if the welcome-text ist present, cut & paste it to help + if (that.welcome) { + if (that.welcome.get('html').length > 100) { + that.help.set('html', that.welcome.get('html')); + that.welcome.destroy(); + } + } that.loading.setStyle('display', 'inline'); - that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take a minute or two...</p>'); + that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take up to a minute...</p>'); }, onFailure: function() { @@ -410,14 +432,6 @@ that.searchSubmit.erase('disabled'); // reenable submitbutton that.searchSubmit.setStyle('display', 'inline'); that.loading.setStyle('display', 'none'); - - // if the welcome-text ist present, cut & paste it to help - if (that.welcome) { - if (that.welcome.get('html').length > 100) { - that.help.set('html', that.welcome.get('html')); - that.welcome.destroy(); - } - } // display results that.results.set('html', response); // addEvents to result-links @@ -428,28 +442,22 @@ // only send form if value is at least 3 chars long if (that.searchValue.get('value').length > 2) { this.send(); - } + } else { + that.displayStatusMessage('Please enter at least 3 chars for searching...'); + } }); - - - - - - }, - - - - /** * For Recommendations and Search-Results * This function searches for all links with the class addToPlaylist * and makes them addable to the playlist, which means clicking on * them adds them to the playlist and makes them playable. this * is working for links to whole albums and single tracks also + * + * @param {Object} links All links to make addable */ makeAddable: function (links) { var that = this; @@ -485,15 +493,11 @@ }, - - - - - - /** * appends prepared html code to the playlist, empties the playlist if the first * element is an empty li and refreshed the playlist and shows the playlist tab + * + * @param {String} HTML-Code with new Items to add to the playlist */ insertIntoPlaylist: function(newItems) { var that = this; @@ -531,11 +535,9 @@ }, - - - /** - * + * Shows the given tab in the menu, and hides all others + * * @param {String} tabID ID of the Tab to show */ showTab: function(tabID) { @@ -544,17 +546,15 @@ that.menu.getElements('a.' + tabID).getParent().toggleClass('active'); that.main.getChildren().setStyle('display', 'none'); document.id(tabID).setStyle('display', 'block'); - }, - /** * Converts seconds into a string formatted minutes:seconds * with leading zeros for seconds * * @param {Float} seconds - * @return {String} minsec minutes:seconds + * @return {String} minsec minutes:seconds */ secondsToMinutesAndSeconds: function(seconds) { var min = Math.floor(seconds / 60); Modified: trunk/src/moosique.net/js/start.js =================================================================== --- trunk/src/moosique.net/js/start.js 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/js/start.js 2009-10-07 15:21:39 UTC (rev 1880) @@ -2,12 +2,12 @@ var YMPParams = { autoplay: false, parse: false, // do not parse initial content - volume: 1.0, - displaystate: 3 // hide the YMP (1 shows) + volume: 1.0, // play it loud! + displaystate: 3 // hide the YMP-default-GUI (1 shows) }; // Create an instance of the moosique.net -// 0.025 for debugging purposes TODO +// TODO 0.025 for debugging purposes var moo = new Moosique({ timeToScrobble: 0.025 }); // default debug Modified: trunk/src/moosique.net/moosique/classes/Config.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Config.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/moosique/classes/Config.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -26,8 +26,10 @@ } } + /** - * + * Returns the value of a general config-entry from config.ini + * * @return String The wanted Configvalue * @param String Value for the wanted Configvalue */ @@ -35,8 +37,21 @@ return $this->config['general'][$value]; } + /** - * + * Returns the value of a last-fm config-entry from config.ini + * + * @return String The wanted Configvalue + * @param String Value for the wanted Configvalue + */ + public function getConfigLastFM($value) { + return $this->config['lastFM'][$value]; + } + + + /** + * Returns the value of an URL defined in config.ini + * * @return String The wanted Url * @param String Value for the wanted Url */ @@ -44,17 +59,45 @@ return $this->config['url'][$value]; } - public function getLearningConfig() { - return $this->config['learning']; + + /** + * This funtion returns one (if specified) or all learning-Config entries from config.ini + * + * @param String Value for a single learning-Configuration + * @return Mixed The wanted value as a string, or - if not specified - complete learingConfig as an array + */ + + public function getConfigLearning($prefix = false) { + if ($prefix !== false) { + if (isset($this->config['learning'][$prefix])) { + return $this->config['learning'][$prefix]; + } else { + return false; + } + } else { + return $this->config['learning']; + } } + /** - * - * @return Array An associative array of all prefixes + * This funtion returns one (if specified) or all prefixes from the config.ini + * + * @param String String-Value for a single prefix + * @return Mixed The wanted prefix as a string, or - if not specified - all Prefixes as an array */ - public function getAllPrefixes() { - return $this->config['prefix']; - } + public function getConfigPrefixes($prefix = false) { + if ($prefix !== false) { + if (isset($this->config['prefix'][$prefix])) { + return $this->config['prefix'][$prefix]; + } else { + return false; + } + } else { + return $this->config['prefix']; + } + } + } Modified: trunk/src/moosique.net/moosique/classes/DllearnerConnection.php =================================================================== --- trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -22,9 +22,9 @@ $this->setEndpoint($this->getConfigUrl('jamendo')); // load WSDL files (has to be done due to a Java web service bug) + ini_set('soap.wsdl_cache_enabled', '0'); include('Utilities.php'); - ini_set('soap.wsdl_cache_enabled', '0'); - // Utilities::loadWSDLfiles($this->getConfigUrl('wsdl')); + Utilities::loadWSDLfiles($this->getConfigUrl('wsdl')); $this->connect(); } @@ -111,23 +111,29 @@ * * */ - public function learn($instances, $positiveExamples, $owlfile) { - $id = $_SESSION['sessionID']; - $conf = $this->getLearningConfig(); + public function learn($instances, $positiveExamples) { + $result = false; + // $id = $_SESSION['sessionID']; - // TODO? use this as knowledgesource ID? - $this->client->addKnowledgeSource($id, 'owlfile', $owlfile); + // TODO for learning we create a new learning-ID and knowledge-Source + $id = $this->client->generateID(); + $kID = $this->client->addKnowledgeSource($id, 'sparql', $this->endpoint); + $conf = $this->getConfigLearning(); + + $this->client->addKnowledgeSource($id, 'owlfile', $this->getConfigUrl('tagOntology')); $this->client->setReasoner($id, $conf['reasoner']); - // set the instances and pos examples - $this->client->applyConfigEntryStringArray($id, $this->knowledgeSourceID, 'instances', $instances); + // set the instances, the learning-Problem and pos examples + // $this->client->applyConfigEntryStringArray($id, $this->knowledgeSourceID, 'instances', $instances); + $this->client->applyConfigEntryStringArray($id, $kID, 'instances', $instances); $this->client->setLearningProblem($id, $conf['problem']); - $this->client->setPositiveExamples($id, $positiveExamples); // recursion-depth and fragment saving - $this->client->applyConfigEntryInt($id, $this->knowledgeSourceID, 'recursionDepth', $conf['recursionDepth']); - $this->client->applyConfigEntryBoolean($id, $this->knowledgeSourceID, 'saveExtractedFragment', $conf['saveExtractedFragment']); + // $this->client->applyConfigEntryInt($id, $this->knowledgeSourceID, 'recursionDepth', $conf['recursionDepth']); + // $this->client->applyConfigEntryBoolean($id, $this->knowledgeSourceID, 'saveExtractedFragment', $conf['saveExtractedFragment']); + $this->client->applyConfigEntryInt($id, $kID, 'recursionDepth', $conf['recursionDepth']); + $this->client->applyConfigEntryBoolean($id, $kID, 'saveExtractedFragment', $conf['saveExtractedFragment']); // algorithm config $learnID = $this->client->setLearningAlgorithm($id, $conf['algorithm']); @@ -135,20 +141,26 @@ $this->client->applyConfigEntryInt($id, $learnID, 'valueFrequencyThreshold', $conf['valueFrequencyThreshold']); $this->client->applyConfigEntryBoolean($id, $learnID, 'useHasValueConstructor', $conf['useHasValueConstructor']); - $this->client->applyConfigEntryStringTupleList($id, $this->knowledgeSourceID, 'replacePredicate', array( - "http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag"), array("http://www.w3.org/1999/02/22-rdf-syntax-ns#type") + // replace prefixes + // $this->client->applyConfigEntryStringTupleList($id, $this->knowledgeSourceID, 'replacePredicate', + $this->client->applyConfigEntryStringTupleList($id, $kID, 'replacePredicate', + array($this->getConfigPrefixes('tags') . 'taggedWithTag'), array($this->getConfigPrefixes('rdf') . 'type') ); $this->client->initAll($id); + $result = $this->client->learnDescriptionsEvaluated($id); + $result = json_decode($result); + return $result; - $concepts = false; - - $concepts = $this->client->learnDescriptionsEvaluated($id); - $concepts = json_decode($concepts); + } + + + public function kbToSqarql($kb) { + return $this->client->SparqlRetrieval($kb, 20); - return $concepts; + } } Modified: trunk/src/moosique.net/moosique/classes/LastFM.php =================================================================== --- trunk/src/moosique.net/moosique/classes/LastFM.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/moosique/classes/LastFM.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -1,83 +1,106 @@ <?php -/** - * TODO: UGLY! Use last.fm-Api instead? - * API-Key: b9877a7391416d0846ad5f240a1838f9 - * - * Later. - */ -class LastFM { +class LastFM extends Config { + + private $topTags; - private $data; - private $config; - private $username; - - function __construct($config, $username) { - $this->config = $config; - $this->username = $username; - $this->getData(); + function __construct($user) { + parent::__construct(); // init config + + $this->getLastFMTags($user); } - function getData() { - include_once('arc/ARC2.php'); - $rdfParser = ARC2::getRDFParser(); - $lastfmResource = $this->config->getUrl('lastfm') . urlencode($this->username); - $rdfParser->parse($lastfmResource); - // parse, non simple array - $index = $rdfParser->getSimpleIndex(0); - $this->data = $index; + /** + * + * + * + */ + private function getLastFMTags($user) { + $allTags = array(); + $requestUrl = $this->getConfigLastFM('topTagsUrl') + . '&user=' . $user + . '&api_key=' . $this->getConfigLastFM('apiKey'); + $lastFMTags = @simplexml_load_file($requestUrl); + + if ($lastFMTags) { // meaning the last.fm-username exists + foreach($lastFMTags->toptags as $tags) { + foreach($tags as $tag) { + $allTags[] = (String)$tag->name; + } + } + // we limit the array to the 10 most used tags + $allTags = array_slice($allTags, 0, 10); + + // if there is a last-fm user, but he has tagged nothing? + // we get the list of top-artists and get the topTags from the artists + if (empty($allTags)) { + $allTags = $this->getTagsFromTopArtists($user); + } + } else { + if ($this->debugger) $this->debugger->log($user, 'The last.fm-User does not exist. Please try again.'); + } + $this->topTags = $allTags; } - function getRecentTracks() { - $playedTracks = array(); - $trackNodes = array(); + /** + * + * + * + */ + private function getTagsFromTopArtists($user) { + $allArtists = array(); + $finalTags = array(); - echo '<pre>'; - // print_r($this->data); - - if (is_array($this->data) && !empty($this->data)) { - foreach($this->data as $rootItem => $rootValue) { - // only process further if the rootitem ist no uri - if (!preg_match('/http:\/\//i', $rootItem)) { - foreach($rootValue as $childItem => $childValue) { - // if there is a childitem :track_played, we can use the information - if ($childItem == $this->config->getPrefix('played')) { - $trackNodes[] = $childValue[0]['value']; - } - } - } + // get the top artists for the user + $requestUrl = $this->getConfigLastFM('topArtistsUrl') + . '&user=' . $user + . '&api_key=' . $this->getConfigLastFM('apiKey'); + + $lastFMArtists = @simplexml_load_file($requestUrl); + + foreach($lastFMArtists->topartists as $artists) { + foreach($artists as $artist) { + $allArtists[] = (String)$artist->name; } - } else { - echo 'Data-Array empty.'; } + // reduce top Artists to TOP 10 + $allArtists = array_slice($allArtists, 0, 10); + + // get the topTags for every artist - if (!empty($trackNodes)) { - foreach($trackNodes as $trackNode) { - $track = $this->data[$trackNode][$this->config->getPrefix('title')][0]['value']; - $artistNode = $this->data[$trackNode][$this->config->getPrefix('maker')][0]['value']; - $artist = $this->data[$artistNode][$this->config->getPrefix('name')][0]['value']; - $artistZitgist = $this->data[$artistNode][$this->config->getPrefix('same')][0]['value']; - $album = ''; - $albumZitgist = ''; - - $playedTracks[] = array($artist, $track, $album, $artistZitgist, $albumZitgist); - + foreach($allArtists as $artistName) { + $requestUrl = $this->getConfigLastFM('artistsTopTagsUrl') + . '&artist=' . urlencode($artistName) + . '&api_key=' . $this->getConfigLastFM('apiKey'); + $artistTags = @simplexml_load_file($requestUrl); + + // take only the first two tags, that should be enough + foreach($artistTags->toptags as $tags) { + $someCounter = 0; + foreach($tags as $tag) { + $finalTags[] = (String)$tag->name; + $someCounter++; + if ($someCounter == 2) break; + } } - } else { - echo "No recently played tracks avaiable from last.fm."; } + // remove double entries and limit the array to the TOP 10 + $finalTags = array_unique($finalTags); + $finalTags = array_slice($finalTags, 0, 10); - print_r($trackNodes); - print_r($playedTracks); - echo '</pre>'; + return $finalTags; } - - + + /** + * + * + * + */ + public function getTopTags() { + return $this->topTags; + } + + } -include('config.php'); - -$lastfm = new LastFM($conf, 'nebelschwade'); -$lastfm->getRecentTracks(); - ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/RequestHandler.php =================================================================== --- trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -20,103 +20,199 @@ if ($this->isAjax() && $this->isGet()) { $this->response = $this->processRequest(); } else { - // TODO + // we do nothing. This application is based on AJAX. } } /** - * Returns the HTML stored in the private $response - * - * @return String HTML-Code generated - */ - public function getResponse() { - return $this->response; - } - - /** * Processes the request made through ajax, handles * the different searches and other related requests * * @return */ private function processRequest() { + $response = ''; - // general search + // general search for all / artist / tags / song + // ====================================================================== if (isset($_GET['searchType']) && isset($_GET['searchValue'])) { - - $search = $this->cleanString($_GET['searchValue']); + // clean up the search value + $search = $this->cleanString($_GET['searchValue'], $_GET['searchType']); + // a search for "everything" causes 3 searches for artist, tags and songs + // concatenating the response from all 3 searches if ($_GET['searchType'] == 'allSearch') { + // artist + $data = $this->getData($search, 'artistSearch'); + $view = new View($data, 'artistSearch'); + $response .= $view->getHTML(); + // tag + $data = $this->getData($search, 'tagSearch'); + $view = new View($data, 'tagSearch'); + $response .= $view->getHTML(); + // song + $data = $this->getData($search, 'songSearch'); + $view = new View($data, 'songSearch'); + $response .= $view->getHTML(); - // TODO doing 3times the same thing is ugly, build function doing this - - // Artists - $sparql = new SparqlQueryBuilder($search, 'artistSearch', 20); - $query = $sparql->getQuery(); - $json = $this->connection->sparqlQuery($query); - $result = json_decode($json); - $artistObject = $result->results->bindings; - $artistView = new View('artistSearch', $artistObject); - $artistResponse = $artistView->getHTML(); - - // Tags - $sparql = new SparqlQueryBuilder($search, 'tagSearch', 20); - $query = $sparql->getQuery(); - $json = $this->connection->sparqlQuery($query); - $result = json_decode($json); - $tagObject = $result->results->bindings; - $tagView = new View('tagSearch', $tagObject); - $tagResponse = $tagView->getHTML(); - - - // Songs - $sparql = new SparqlQueryBuilder($search, 'songSearch', 20); - $query = $sparql->getQuery(); - $json = $this->connection->sparqlQuery($query); - $result = json_decode($json); - $songObject = $result->results->bindings; - $songView = new View('songSearch', $songObject); - $songResponse = $songView->getHTML(); - - // merge results, and return it - return $artistResponse . $tagResponse . $songResponse; - - } else { // normal tag/artist/song-search - - $sparql = new SparqlQueryBuilder($search, $_GET['searchType']); - $query = $sparql->getQuery(); - + } - // sparql-query to dellearner - $json = $this->connection->sparqlQuery($query); - // convert to useable object - $result = json_decode($json); - $resultObject = $result->results->bindings; - - // create and return the response - $view = new View($_GET['searchType'], $resultObject); + if ($_GET['searchType'] == 'artistSearch' || + $_GET['searchType'] == 'tagSearch' || + $_GET['searchType'] == 'songSearch') { + // normal search for artist, tag or song + $data = $this->getData($search, $_GET['searchType']); + $view = new View($data, $_GET['searchType']); $response = $view->getHTML(); + } - return $response; + + if ($_GET['searchType'] == 'lastFM') { + $lastFM = new LastFM($search); + $tags = $lastFM->getTopTags(); + // no we have the topTags, do a search for related albums + foreach($tags as $tag) { + // TODO when using last.fm-Tags for tagSearch, we want exakt results, meaning + // no "darkmetalbeermusic" when the lastfm tag is "metal" + + $tag = $this->cleanString($tag, $_GET['searchType']); + // displaying 10 results per tag (=100 results) should be enough + $data = $this->getData($tag, $_GET['searchType'], 20); + $view = new View($data, $_GET['searchType']); + $response .= $view->getHTML(); + } + } } - // TODO other requuests + // TODO other requests --- artist Information - // a playlist is requested. due to a bug in ymp we don't - // directly deliver the .xspf-file, we return a prepared - // list of <li> including the links to the mp3-files + + + + // A Learning-Request + // ====================================================================== + if (isset($_GET['learn']) && $_GET['learn'] == 'now') { + $posExamples = $this->getPositiveExamples(); + $instances = $this->getInstances($posExamples); + + $this->debugger->log($instances, "INSTANZEN"); + $this->debugger->log($posExamples, "posExamples"); + + $res = $this->connection->learn($instances, $posExamples); + + // TODO (Yes, BIG one) + // build sparql-query based on learning-results + // build html-view build an sparql-results --- misuse tagSearch-Thingie + foreach ($res as $solution) { + $response .= round($solution->scoreValue*100, 2) . '% --- ' . $solution->descriptionKBSyntax . "\n"; + // $response .= $this->connection->kbToSqarql($solution->descriptionKBSyntax) . "\n"; + } + + $response = '<pre>' . $response . '</pre>'; + + } + + + // A Playlist-Request + // ====================================================================== if (isset($_GET['get']) && isset($_GET['playlist'])) { - $view = new View($_GET['get'], - array('playlist' => $_GET['playlist'], 'albumID' => $_GET['rel']) + // Due to a bug in YMP we don't directly deliver the .xspf-file, we return a prepared + // list of <li> including the links to the mp3-files, and this is build in the view of course. + $data = $this->prepareData( + array('playlist' => $_GET['playlist'], 'albumID' => $_GET['rel']), + $_GET['get'] ); - return $view->getHTML(); + $view = new View($data, $_GET['get']); + $response = $view->getHTML(); } + + + + // Finally returning the response + if (!empty($response)) { + return $response; + } else { + if ($_GET['searchType'] == 'lastFM') { + return '<h2>Nothing found for the last.fm-user »' . $_GET['searchValue'] . '«.'; + } + return "<h2>The repsonse from the server was empty.</h2>"; + } } + /** + * + * + * + */ + private function getPositiveExamples() { + $posExamples = array(); + if (!empty($_COOKIE['moosique'])) { + $recent = json_decode(stripslashes($_COOKIE['moosique']))->recentlyListened; + foreach($recent as $link) { + // extract relation from the cookie-link + preg_match_all('#<a\s*(?:rel=[\'"]([^\'"]+)[\'"])?.*?>((?:(?!</a>).)*)</a>#i', $link, $record); + array_push($posExamples, $record[1][0]); + } + } + + $posExamples = array_unique($posExamples); + return $posExamples; + + } + + /** + * + * + * + */ + private function getInstances($posExamples) { + // TODO more testing, what is the optimum posExamples/neutral ratio, 50/50? + // for now we assume 50/50 + // $totalInstances = $this->getConfigLearning('instances'); + $instances = array(); + // and then add some random Records _not_ in this list + $allRecords = file($this->getConfigUrl('allRecords')); + $countPos = count($posExamples); + + for ($i = 0; $i < $countPos; $i++) { + $randomRecord = trim($allRecords[array_rand($allRecords)]); + // no double entries for the $instances-array + if (!in_array($randomRecord, $posExamples)) { + array_push($instances, $randomRecord); + } + } + // merge with posExamples + $instances = array_merge($posExamples, $instances); + shuffle($instances); + + return $instances; + } + + + /** + * + * @param Integer $limit optional Limit for Sparql-Query + */ + private function getData($search, $type, $limit = 0) { + $sparql = new SparqlQueryBuilder($search, $type, $limit); + $query = $sparql->getQuery(); + // sparql-query to dellearner + $json = $this->connection->sparqlQuery($query); + // convert to useable object + $result = json_decode($json); + $resultObject = $result->results->bindings; + + // prepare the data for HTML processing + $data = $this->prepareData($resultObject, $type); + return $data; + } + + + /** * Establishes a new Dl-Learner Connection and saves it in - * private connection for class-wide use. + * private $connection for class-wide use. * * @return */ @@ -125,16 +221,172 @@ } /** - * Removes unwanted chars from a string - * + * Removes unwanted chars from a search-string + * + * TODO - NOT IMPLEMENTED but prepared + * If the search string contains a %20-Space-Char somewhere in the middle + * of the string, it returns an array of search-values, divided by " " + * Doing this we later can perform more searches for values like "stoner doom metal" + * resulting in an array with [0] => stoner [1] => doom [2] => metal */ - private function cleanString($string) { - $remove = array(' ', '/', '?', '-', '_', '+', "=", '$', ',', '.', ':', ';', '\'', "\"", "\\", "\\\\"); + private function cleanString($string, $type) { + // $remove = array('/', '?', '+', "=", '$', ',', '.', ':', ';', '\'', "\"", "\\", "\\\\"); + $remove = array(' ', '/', '?', '+', "=", '$', ',', '.', ':', ';', '\'', "\"", "\\", "\\\\"); + $string = trim($string); $string = str_replace($remove, '', $string); + // and remove double whitespaces + $string = str_replace(array(' ', ' '), ' ', $string); + + // when searching for tags due to the jamendo-tag handling we split + // tags into an array for better filter-results + /* + if ((strpos($string, " ") > 0) && $type = 'tagSearch') { + $string = explode(" ", $string); + $this->debugger->log($string, "MEHR ALS ZWEI"); + } + */ return $string; } + + /** + * Cleans up objects or retrieves them from a XML-File (for playlists) + * and converts them into arrays for use in the view class + * + * @param Mixed $data The Data-Object (from a Sparql-Query or a playlist-array) + * @param String $type To define what kind of data to prepare + * @return Array A multidimensional Array ready for processing for HTML-output + */ + private function prepareData($data, $type) { + $mergedArray = array(); + + switch ($type) { + case 'artistSearch' : + $mergedArray = $this->mergeArray($data, 'artist'); + $mergedArray = $this->arrayUnique($mergedArray); + break; + + case 'tagSearch' : + $mergedArray = $this->mergeArray($data, 'tag'); + break; + + case 'songSearch' : + $mergedArray = $this->mergeArray($data, 'track'); + $mergedArray = $this->arrayUnique($mergedArray); + break; + + case 'lastFM' : + $mergedArray = $this->mergeArray($data, 'tag'); + break; + + case 'albumPlaylist' : + $playlistObject = simplexml_load_file($data['playlist']); + $mergedArray = $this->object2array($playlistObject); + // prepend the album stream-information + $mergedArray['albumID'] = $data['albumID']; + break; + + case 'trackPlaylist' : + $playlistObject = simplexml_load_file($data['playlist']); + $mergedArray = $this->object2array($playlistObject); + $mergedArray['albumID'] = $data['albumID']; + break; + } + + return $mergedArray; + } + + + /** + * TOOD implement nice merging for multi-tag-search + * This function merges the result-Object to a nice array + * we can process easily. The array is created by type, + * returning the data sorted for artist, tag or song + * + * @param Object $data + * @param String $type This can be 'artist', 'tag' or 'song' + * @return Array A Multidimensional array sorted by type for output-use + */ + private function mergeArray($data, $type) { + // convert the $data-response object to an array + $array = $this->object2array($data); + $combinedArray = array(); + + foreach($array as $subArray) { + if (!array_key_exists($subArray[$type]['value'], $combinedArray)) { + $combinedArray[$subArray[$type]['value']] = $subArray; + } else { + // we already have an object with this tag? -> merge! + $combinedArray[$subArray[$type]['value']] = array_merge_recursive( + $combinedArray[$subArray[$type]['value']], $subArray + ); + } + } + + if (!empty($combinedArray)) { + return $combinedArray; + } else return false; + } + + + /** + * Like the php-function array_unique, but for multidimensional arrays, calls itself recursively + * + * + * @return Array (Multidimensional) array without double entries + * @param Array $array The Array to clean up + */ + private function arrayUnique($array) { + $newArray = array(); + if (is_array($array)) { + foreach($array as $key => $val) { + if ($key != 'type' && $key != 'datatype') { + if (is_array($val)) { + $val2 = $this->arrayUnique($val); + } else { + $val2 = $val; + $newArray = array_unique($array); + break; + } + if (!empty($val2)) { + $newArray[$key] = $val2; + } + } + } + } + return $newArray; + } + + + /** + * Converts a simple Object to an array + * + * @return Array the Array created from the Object + * @param object $obj The Object to convert + */ + private function object2array($obj) { + $arr = array(); + $_arr = is_object($obj) ? get_object_vars($obj) : $obj; + foreach ($_arr as $key => $val) { + $val = (is_array($val) || is_object($val)) ? $this->object2array($val) : $val; + $arr[$key] = $val; + } + return $arr; + } + + + /** + * Returns the HTML stored in the private $response + * + * @return String HTML-Code generated + */ + public function getResponse() { + return $this->response; + } + + + /** * Checks if the request made is an AJAX-Request and returns true if so * * @return Boolean @@ -148,6 +400,7 @@ } } + /** * Checks if the request made is a GET-Request and returns true if so * @@ -161,6 +414,7 @@ } } + /** * Checks if the request made is a POST-Request and returns true if so * @@ -173,9 +427,7 @@ return false; } } + } - - - ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-05 11:09:22 UTC (rev 1879) +++ trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-07 15:21:39 UTC (rev 1880) @@ -28,7 +28,6 @@ * Builds the complete Sparql-Query depending on the type of search * and saves it in the private $queryString. * - * @return * @param object $search * @param object $typeOfSearch * @param object $limit @@ -37,7 +36,7 @@ /* Build up the Prefixes */ $prefixes = ''; - foreach($this->getAllPrefixes() as $prefix => $resource) { + foreach($this->getConfigPrefixes() as $prefix => $resource) { $prefixes .= 'PREFIX ' . $prefix . ': <' . $resource . '>' . "\n"; } @@ -62,6 +61,8 @@ case 'artistSearch' : $query = $this->queryArtistSearch($search); break; case 'tagSearch' : $query = $this->queryTagSearch($search); break; case 'songSearch' : $query = $this->querySongSearch($search); break; + case 'lastFM' : $query = $this->queryTagSearch($search); break; + /* TODO build functions for other queries case 'albumInfo' : $query = $this->queryAlbumInfo($search); break; case 'songInfo' : $query = $this->querySongInfo($search); break; @@ -76,6 +77,7 @@ /** * Returns the Sparql-Query part for an artist-search * + * @param Mixed * @return String Sparql-Query part for artist-search */ private function queryArtistSearch($search) { @@ -92,10 +94,9 @@ }'; // we want the xspf-playlist only, the search filters is // flagged with "i" for case-insensitive search - $queryString .= ' - FILTER (regex(str(?playlist), "xspf", "i")) . - FILTER (regex(str(?artistName), "' . $search . '", "i")) . - '; + $queryString .= 'FILTER (regex(str(?playlist), "xspf", "i")) . '; + $queryString .= 'FILTER (regex(str(?artistName), "' . $search . '", "i")) . '; + return $queryString; } @@ -109,25 +110,61 @@ * @return String Sparql-Query part for tag-search */ private function queryTagSearch($search) { + /* TODO multi-tag search -- maybe building an extra function is better for this + $moreThanOneTag = is_array($search); + $searchCount = 0; + + if ($moreThanOneTag === true) { + $searchCount = count($search); + } + */ $queryString = ' { ?artist rdf:type mo:MusicArtist ; foaf:name ?artistName ; foaf:made ?record . ?record rdf:type mo:Record ; - dc:title ?albumTitle ; - tags:taggedWithTag ?tag ; - mo:available_as ?playlist . - + dc:title ?albumTitle ; '; + /* + if ($moreThanOneTag === true) { + for ($i = 0; $i < $searchCount; $i++) { + $queryString .= ' tags:taggedWithTag ?tag' . $i . ' ; '; + } + } else { + */ + $queryString .= ' tags:taggedWithTag ?tag ; '; + /* + } + */ + $queryString .= ' mo:available_as ?playlist . OPTIONAL { ?record mo:image ?cover . FILTER (regex(str(?cover), "1.100.jpg", "i")) . } - }'; - $queryString .= ' - FILTER (regex(str(?playlist), "xspf", "i")) . - FILTER (regex(str(?tag), "' . $search . '", "i")) . - '; - return $queryString; + } '; + // we want the xspf-playlist only, the search filters is + // flagged with "i" for case-insensitive search + $queryString .= ' FILTER (regex(str(?playlist), "xspf", "i")) . '; + + // searching for more than on value? + /* + if (is_array($search)) { + $queryString .= ' FILTER ('; + + // glueing th... [truncated message content] |
From: <neb...@us...> - 2009-10-20 10:23:32
|
Revision: 1891 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1891&view=rev Author: nebelschwade Date: 2009-10-20 10:23:23 +0000 (Tue, 20 Oct 2009) Log Message: ----------- + readme.txt + recommendations are now working + auto-adding recommendations + modified owl + better code in view + minor style fixes Modified Paths: -------------- trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt trunk/src/moosique.net/moosique/index.php trunk/src/moosique.net/moosique/testing/moreThan80.owl Added Paths: ----------- trunk/src/moosique.net/README.txt trunk/src/moosique.net/moosique/classes/Recommendations.php Added: trunk/src/moosique.net/README.txt =================================================================== --- trunk/src/moosique.net/README.txt (rev 0) +++ trunk/src/moosique.net/README.txt 2009-10-20 10:23:23 UTC (rev 1891) @@ -0,0 +1,40 @@ +Installation-Requirements: +========================== + +See /moosique/config.ini + +- PHP 5.2.x + - output_buffering has to be enabled to use debugging features (if enabled in config.ini) + (FirePHP is included in this package) + - installed PEAR-Packages HTTP and HTTP_Request (used by Utilities.php from DL-Learner) + - + +- A running DL-Learner Webservice Instance + - Set paths in config.ini + + +Notes: +====== +- This is a modern piece of websoftware, use a modern browser! + - Tested and working in: + - Firefox 3.5.x + - Safari 4.x and Webkit nightly build r49764 + - Google Chrome 4.0.x + - Opera 10.x + - Untested: + - Internet Explorer and other platform-unindependent browsers + +- JavaScript has to be enabled, this is an AJAX-Application and uses the + Yahoo Media Player-Script! + +- + +- Debugging makes use of Firebug/FirePHP, thus only working in Firefox + +- + + +Known Bugs: +=========== + +- \ No newline at end of file Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/css/style.css 2009-10-20 10:23:23 UTC (rev 1891) @@ -24,9 +24,10 @@ #loadingImg, #header h1 { display: none; } /* Rounded Corners */ -input, textarea, select { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } +input, textarea, select, +a.button { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } #content, #status, #playing, -#playerControls, #results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } +#playerControls, .results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } #mainMenu a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; border-top-left-radius: 10px; } @@ -73,13 +74,15 @@ /* Search form */ #searchValue { margin: 0 5px; width: 100px; } #loadingImg { cursor: wait; } +a.button { background: #4a4a4a; color: #f1f7e4; padding: 5px 10px; text-decoration: none; } +a.button:hover { border: 1px solid #1fd611; padding: 4px 9px; } +#addRandom { text-decoration: underline; } - /*=============== Menu & Footer ===============*/ #mainMenu ul { position: absolute; top: 0; right: 0; } #mainMenu li { float: left; } #mainMenu a { display: block; margin-left: 10px; line-height: 30px; height: 30px; - padding: 10px 12px; color: #fafafa; background: #4a4a4a; } + padding: 10px 12px; color: #f1f7e4; background: #4a4a4a; } #mainMenu .active a, #mainMenu .active a:hover { background: #1fd611; } #mainMenu a:hover { text-decoration: none; background: #5a5a5a; } @@ -87,24 +90,27 @@ #footer a { padding: 0 10px; } /*=============== Search Results ===============*/ -#results li h3 a { font-weight: normal; } -#results li img { border: 2px solid #545454; } -#results li { float: left; width: 312px; border: 1px solid #545454; padding: 18px; margin-bottom: 18px; } -#results li.odd { margin-right: 18px; clear: both; } -#results ul ul { list-style: disc; } +.results li h3 a { font-weight: normal; } +.results li img { border: 2px solid #545454; } +.results li { float: left; width: 312px; border: 1px solid #545454; padding: 18px; margin-bottom: 18px; } +.results li.odd { margin-right: 18px; clear: both; } +.results ul ul { list-style: disc; } /* This is for the list of found albums etc */ -#results li li, -#results .artistSearch li li, -#results .tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; +.results li li, +.artistSearch li li, +.tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; width: auto; height: auto; float: none; } -#results .tagSearch ul ul { clear: both; } -#results .artistImage { text-align: center; margin-bottom: 18px;} -#results .cover { margin: 0 18px 18px 0; width: 104px; height: 104px; float: left; } -#results .tagSearch h4 { display: inline; } +#recommendationResults ul ul, +.tagSearch ul ul { clear: both; } +.results .artistImage { text-align: center; margin-bottom: 18px;} +.results .cover { margin: 0 18px 18px 0; width: 104px; height: 104px; float: left; } +#recommendationResults h4, +.tagSearch h4 { display: inline; } /*=============== Recommendations and playlist ===============*/ +#autoAdd { float: right; } #recommended a:hover { cursor: pointer; text-decoration: none; font-weight: bold; color: #131313; } #playlist, #recommended, #recently { margin-left: 36px; list-style: decimal; } @@ -121,7 +127,6 @@ #playlist .moveUp { background: url(../img/controls.png) 0px -360px no-repeat; right: 40px; } #playlist .moveDown { background: url(../img/controls.png) 0px -320px no-repeat; right: 60px; } - /*=============== Information / Help ===============*/ Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/index.php 2009-10-20 10:23:23 UTC (rev 1891) @@ -72,29 +72,37 @@ Now get started and add something to the Playlist! </p> </div> - <div id="results"> + <div id="results" class="results"> </div> </div> <div id="recommendations"> - <h2>Recommended Songs</h2> + <form id="autoAdd" method="get" action=""> + <div> + <label for="autoAddCheckbox" title="Check this to automatically add a random song from your recommendations to your playlist everytime your recommendations are updated.">Autoadd recommendations</label> + <input type="checkbox" id="autoAddCheckbox" checked="checked" /> + </div> + </form> + <h2>Recommendations</h2> <p> These recommendations are generated every time you listen to a song - for at least half it's length, assuming that you liked it. + for at least half it's length, assuming that you liked it. You click on a + recommended album to add it to the playlist, or you can <a href="#" id="addRandom">click + here to just add a random song from your recommendations</a>.<br /> + </p> + <div id="recommendationResults" class="results"> - <div id="recommendationResults"> - </div> <p> - <a href="#" id="generateRecommendations">Nothing showing up here? You can also - generate your list of recommendations by clicking here.</a> + <a href="#" id="generateRecommendations" class="button" title="If there is nothing showing up here, you can generate your list of recommendations by clicking here.">Reload recommendations</a> </p> </div> <div id="information"> + <h2>About the artist...</h2> <div id="moreInfo"> </div> @@ -109,13 +117,14 @@ <ol id="playlist"> <li></li> </ol> + <p><a href="#" id="resetPlaylist" class="button" title="Click here to delete all tracks from your playlist.">Delete all</a></p> <h2>Recently Listened to</h2> <p>These are the songs you recently listened to. Click on a song to re-enqueue it to your current playlist.</p> <ol id="recently"> <li></li> </ol> - <p><a href="#" id="reset">Click here to reset your »recently listened to«-list.</a></p> + <p><a href="#" id="resetRecently" class="button" title="Click here to reset your »recently listened to«-list.">Reset</a></p> </div> <div id="help"> @@ -129,6 +138,9 @@ <a href="http://jamendo.com">Jamendo</a> | <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> </div> + <div id="temp" class="hidden"> + + </div> </div> <!-- end container --> <?php Modified: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/js/moosique.js 2009-10-20 10:23:23 UTC (rev 1891) @@ -65,7 +65,12 @@ this.recommendations = document.id('recommendations'); this.generate = document.id('generateRecommendations'); this.recResults = document.id('recommendationResults'); - this.reset = document.id('reset'); + this.resetPlaylist = document.id('resetPlaylist'); + this.resetRecently = document.id('resetRecently'); + this.moreInfo = document.id('moreInfo'); + this.temp = document.id('temp'); + this.autoAddCheckbox = document.id('autoAddCheckbox'); + this.addRandom = document.id('addRandom'); }, /** @@ -154,9 +159,11 @@ del.removeEvents(); del.addEvent('click', function(e) { e.stop(); + // TODO: if playlist empty or deleted currently playing track: STOP! this.getParent().destroy(); // deletes the li-element // and refresh the playlist if clicked YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + // TODO: if playlist empty or deleted currently playing track: STOP! }); }); @@ -210,14 +217,26 @@ that.nowPlayingInfo.set('text', 'Currently playing:'); that.nowPlayingTrack.set('text', YAHOO.MediaPlayer.getMetaData().title); that.playPause.setStyle('background-position', '0px -40px'); + + // send a request to gather additional artist-information + var nowPlayingAlbum = YAHOO.MediaPlayer.getMetaData().anchor.get('rel'); + var getInfo = new Request({ + method: 'get', + url: 'moosique/index.php', + onSuccess: function(response) { + that.moreInfo.set('html', response); + } + }).send('info=' + nowPlayingAlbum); + }; /** * trackComplete: we change the Pause-Button to a Play-Button - * TODO: if this was the last track, add another track from the recommendations and start playing + * and execute the autoAdd-Function for adding recommendations */ var trackComplete = function() { that.playPause.setStyle('background-position', '0px 0px'); + that.autoAddToPlaylist(); }; // add the configuration to the events by subscribing @@ -240,19 +259,39 @@ */ generateRecommendations: function() { var that = this; - - // TODO // send ajax request and save the scrobbled song // and retrieve and update the recommendations var getRecommendations = new Request({ method: 'get', url: 'moosique/index.php', + onRequest: function() { + that.recResults.set('html', '<h2>Generating new recommendations...</h2><p>Please be patient, this may take up to a minute...</p>'); + }, + + onFailure: function() { + that.recResults.set('html', '<h2>Unable to get recommendations. Please reset and try again.</h2>'); + }, onSuccess: function(response) { - that.recResults.set('html', response); - that.showTab('recommendations'); - that.displayStatusMessage('You have new recommendations!'); + response = response.trim(); + if (response != '') { + that.recResults.set('html', response); + that.makeAddable($$('a.addToPlaylist')); + that.showTab('recommendations'); + that.displayStatusMessage('You have new recommendations!'); + + if (that.autoAddCheckbox.checked) { + that.addRandomToPlaylist(); + } else { + debug.log('Autoadding songs from recommendations is disabled.'); + } + } else { + debug.log('Response from server empty.'); + that.recResults.set('html', '<h2>There is nothing in your recently list.</h2><p>You have to listen to some music first, before you can get any recommendations.</p>'); + } + + } - }).send('learn=now'); + }).send('get=recommendations'); }, @@ -311,13 +350,7 @@ // the Stop-Playing Button that.stop.addEvent('click', function() { - that.playPause.setStyle('background-position', '0px 0px'); - that.nowPlayingInfo.set('text', 'Player stopped.'); - that.nowPlayingTrack.set('text', '...'); - that.nowPlayingTime.set('text', '0:00 / 0:00'); - YAHOO.MediaPlayer.stop(); - // and reload the playlist - that.refreshPlaylist(); + that.stopPlaying(); }); // Mute-Toggle-Switch @@ -347,6 +380,23 @@ /** + * + * + * + */ + stopPlaying: function() { + var that = this; + that.playPause.setStyle('background-position', '0px 0px'); + that.nowPlayingInfo.set('text', 'Player stopped.'); + that.nowPlayingTrack.set('text', '...'); + that.nowPlayingTime.set('text', '0:00 / 0:00'); + YAHOO.MediaPlayer.stop(); + // and reload the playlist + that.refreshPlaylist(); + }, + + + /** * Displays a status message * * @param {String} message @@ -383,12 +433,23 @@ that.generateRecommendations(); }); - that.reset.addEvent('click', function(e) { + that.resetRecently.addEvent('click', function(e) { e.stop(); Cookie.dispose('moosique'); that.updateRecently(); }); + + that.resetPlaylist.addEvent('click', function(e) { + e.stop(); + that.playlist.empty(); + that.stopPlaying(); + }); + that.addRandom.addEvent('click', function(e) { + e.stop(); + that.addRandomToPlaylist(); + }); + // make buttons functional this.addEventsToButtons(); }, @@ -472,21 +533,22 @@ var rel = a.get('rel'); var type = ''; - if (href.match(/jamendo\.com\/get\/track\/id\/album\//gi)) { type = 'albumPlaylist'; } - if (href.match(/jamendo\.com\/get\/track\/id\/track\//gi)) { type = 'trackPlaylist'; } + if (href.match(/jamendo\.com\/get\/track\/id\//gi)) { type = 'playlist'; } if (href.match(/\.mp3/)) { type = 'mp3File'; } // if the addable item is a playlist, we have to get the playlistitems - if (type == 'albumPlaylist' || type == 'trackPlaylist') { + if (type == 'playlist') { var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', onSuccess: function(response) { that.insertIntoPlaylist(response); + that.showTab('player'); } }).send('get=' + type + '&playlist=' + href + '&rel=' + rel); } if (type == 'mp3File') { var itemHTML = '<li>' + a.getParent().get('html') + '</li>'; that.insertIntoPlaylist(itemHTML); + that.showTab('player'); } }); }); @@ -531,11 +593,49 @@ // refresh the playlist and show the player-tab that.refreshPlaylist(); - that.showTab('player'); }, /** + * + * + * + */ + addRandomToPlaylist: function() { + var that = this; + var addableAlbums = that.recResults.getElements('.addToPlaylist'); + // pick a random album + var randomAlbum = addableAlbums.getRandom(); + + if (randomAlbum) { + var href = randomAlbum.get('href'); + var rel = randomAlbum.get('rel'); + + if (href.match(/jamendo\.com\/get\/track\/id\//gi)) { type = 'playlist'; } + if (href.match(/\.mp3/)) { type = 'mp3File'; } + + // if the addable item is a playlist, we have to get the playlistitems + var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', + onSuccess: function(response) { + // yay, we have the playlist, choose a random song and add it + // therefore save it as Element in temp and extract a random song + // TODO a better way would be to just get on <li> from the response + // with a regexp and just use this, without creating new dom nodes etc. + that.temp.set('html', '<ul>' + response + '</ul>'); + var songs = that.temp.getElements('li'); + var randomSong = songs.getRandom(); + that.insertIntoPlaylist('<li>' + randomSong.get('html') + '</li>'); + that.temp.empty(); + } + }).send('get=playlist&playlist=' + href + '&rel=' + rel); + } else { + debug.log('You currently have no recommendations, adding a random one will not work.'); + } + + }, + + + /** * Shows the given tab in the menu, and hides all others * * @param {String} tabID ID of the Tab to show Modified: trunk/src/moosique.net/moosique/classes/DllearnerConnection.php =================================================================== --- trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-10-20 10:23:23 UTC (rev 1891) @@ -38,7 +38,7 @@ try { $this->client = new SoapClient($this->getConfigUrl('wsdlLocal')); } catch (Exception $e) { - $this->debugger->log($e, "Error connecting to the DL-Learner Webservice."); + if ($this->debugger) $this->debugger->log($e, "Error connecting to the DL-Learner Webservice."); echo '<h2>Could not connect to the DL-Learner Webservice.</h2>'; exit; } @@ -99,13 +99,12 @@ * @return String A JSON-Object with the containing result-set * @param String $query The SPARQL-Querystring to send */ - public function sparqlQuery($query) { - $result = $this->client->sparqlQuery($_SESSION['sessionID'], $this->knowledgeSourceID, $query); - return $result; - } + public function sparqlQuery($query) { + $result = $this->client->sparqlQuery($_SESSION['sessionID'], $this->knowledgeSourceID, $query); + return $result; + } + - - /** * * @@ -146,21 +145,21 @@ $this->client->applyConfigEntryStringTupleList($id, $kID, 'replacePredicate', array($this->getConfigPrefixes('tags') . 'taggedWithTag'), array($this->getConfigPrefixes('rdf') . 'type') ); - + + // after we have set all conf-values, we initialize the learning process $this->client->initAll($id); $result = $this->client->learnDescriptionsEvaluated($id); - $result = json_decode($result); return $result; } - + /** + * Converts a natural Description in a SPARQL-Query for recommendation retrieval + * + */ public function kbToSqarql($kb) { - return $this->client->SparqlRetrieval($kb, 20); - - - + return $this->client->SparqlRetrieval($kb, $this->getConfig('maxResults')); } } Added: trunk/src/moosique.net/moosique/classes/Recommendations.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Recommendations.php (rev 0) +++ trunk/src/moosique.net/moosique/classes/Recommendations.php 2009-10-20 10:23:23 UTC (rev 1891) @@ -0,0 +1,173 @@ +<?php + +class Recommendations extends Config { + + private $posExamples; + private $instances; + + function __construct() { + parent::__construct(); // init config + } + + /** + * Returns an array of prepared serach-statements to feed the sparql= + * query-bulider with, converted from the natural description of the results + * + * + */ + public function getQueries($connection) { + $queries = array(); + $scores = array(); + $kbSyntaxes = array(); + + // some posExamples and instances set? ready to go... + if (!empty($this->posExamples) && !empty($this->instances)) { + // learn sth! + $res = $connection->learn($this->instances, $this->posExamples); + $solutions = json_decode($res); + + // do we have some solutions? + if ($solutions->solution1) { + foreach ($solutions as $solution) { + // precentage-value, can also be used for display, nicely formatted + $score = round($solution->scoreValue*100, 2); + // scores below threshold are not used for recommendations + if ($score > $this->getConfig('threshold')) { + // check for everything that is quoted + $match = true; + $kbSyntax = $solution->descriptionKBSyntax; + + // everything in quotes is a potential tag + preg_match_all('/\"(\\.|[^\"])*\"/', $kbSyntax, $quoted); + foreach($quoted[0] as $url) { + if (preg_match('/^\"http:\/\//', $url)) { // if a URL, check if URL to Tag + // if only one of the URLS used is not a tag, we don't use it + if (!preg_match('/^\"http:\/\/dbtune\.org\/jamendo\/tag\//', $url)) { + $match = false; + } + } + } + + if ($match) { + $sparql = $connection->kbToSqarql($solution->descriptionKBSyntax); + // extract the subtring we use for the final sparql-query + $sparql = str_replace("SELECT ?subject \nWHERE", '', $sparql); + $sparql = str_replace('LIMIT ' . $this->getConfig('maxResults'), '', $sparql); + $sparql = str_replace('subject a', 'record tags:taggedWithTag', $sparql); + // push it to the queries-array and + $queries[] = $sparql; + $scores[] = $score; + $kbSyntaxes[] = $solution->descriptionKBSyntax; + + } + } + } + } else { + $error = 'There was an error creating recommendations. Please try resetting + your recently-listened-to list, and try again.'; + } + } else { + $error = 'You have to listen to some songs first to fill up your recently-listened-to-list.'; + } + + if (isset($error)) { + return $error; + } else { + // return scores, description and queries + $recommendations = array('scores' => $scores, 'kbSyntaxes' => $kbSyntaxes, 'queries' => $queries); + return $recommendations; + } + } + + + + /** + * + * + * + */ + public function setPosExamples($posExamples = false) { + if ($posExamples === false) { + $posExamples = array(); + if (!empty($_COOKIE['moosique'])) { + $recent = json_decode(stripslashes($_COOKIE['moosique']))->recentlyListened; + foreach($recent as $link) { + // extract relation from the cookie-link + preg_match_all('#<a\s*(?:rel=[\'"]([^\'"]+)[\'"])?.*?>((?:(?!</a>).)*)</a>#i', $link, $record); + $posExamples[] = $record[1][0]; + $posExamples = array_unique($posExamples); + $this->posExamples = $posExamples; + + } + } + + } else { + if (is_array($posExamples)) { + $this->posExamples = $posExamples; + } else { + return false; + } + } + } + + /** + * + * + * + */ + public function setInstances($instances = false) { + + // TODO more testing, what is the optimum posExamples/neutral ratio, 50/50? + // for now we assume 50/50 + // $totalInstances = $this->getConfigLearning('instances'); + + if ($instances === false) { + $instances = array(); + // and then add some random Records _not_ in this list + $allRecords = file($this->getConfigUrl('allRecords')); + $countPos = count($this->posExamples); + + for ($i = 0; $i < $countPos; $i++) { + $randomRecord = trim($allRecords[array_rand($allRecords)]); + // no double entries for the $instances-array + if (!in_array($randomRecord, $posExamples)) { + $instances[] = $randomRecord; + } + } + // merge with posExamples + $instances = array_merge($this->posExamples, $instances); + $this->instances = $instances; + } else { + if (is_array($instances)) { + $this->instances = $instances; + } + } + + + } + + /** + * + * + * + */ + public function getPosExamples() { + return $this->posExamples; + } + + + /** + * + * + * + */ + public function getInstances() { + return $this->instances; + } + + +} + +?> + + Modified: trunk/src/moosique.net/moosique/classes/RequestHandler.php =================================================================== --- trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-20 10:23:23 UTC (rev 1891) @@ -19,8 +19,24 @@ // we only accept ajax-get requests if ($this->isAjax() && $this->isGet()) { $this->response = $this->processRequest(); + + if (!empty($this->response)) { + return $this->response; + } else { + if (isset($_GET['searchType'])) { + return "<h2>Sorry, nothing found.</h2>"; + if ($_GET['searchType'] == 'lastFM') { + return '<h2>Nothing found for the last.fm-user »' . $_GET['searchValue'] . '«.'; + } + } + return "<h2>The repsonse from the server was empty.</h2>"; + } + + + } else { - // we do nothing. This application is based on AJAX. + // we do nothing. This application is based on AJAX - back to home + header('Location: ' . $this->getConfigUrl('base')); } } @@ -58,10 +74,10 @@ } + // normal search for artist, tag or song if ($_GET['searchType'] == 'artistSearch' || $_GET['searchType'] == 'tagSearch' || $_GET['searchType'] == 'songSearch') { - // normal search for artist, tag or song $data = $this->getData($search, $_GET['searchType']); $view = new View($data, $_GET['searchType']); $response = $view->getHTML(); @@ -72,45 +88,56 @@ $lastFM = new LastFM($search); $tags = $lastFM->getTopTags(); // no we have the topTags, do a search for related albums - foreach($tags as $tag) { - // TODO when using last.fm-Tags for tagSearch, we want exakt results, meaning - // no "darkmetalbeermusic" when the lastfm tag is "metal" - - $tag = $this->cleanString($tag, $_GET['searchType']); - // displaying 10 results per tag (=100 results) should be enough - $data = $this->getData($tag, $_GET['searchType'], 20); - $view = new View($data, $_GET['searchType']); + + if (!empty($tags)) { + foreach($tags as $tag) { + // FIXME when using last.fm-Tags for tagSearch, we want exakt results, meaning + // no "darkmetalbeermusic" as result when the lastfm tag is "metal" + + $tag = $this->cleanString($tag, $_GET['searchType']); + // displaying 10 results per tag (=100 results) should be enough + $data = $this->getData($tag, $_GET['searchType'], 20); + $view = new View($data, $_GET['searchType']); + $response .= $view->getHTML(); + } + } else { // let the view handle it, displays error + $view = new View($tags, $_GET['searchType']); $response .= $view->getHTML(); } } } // TODO other requests --- artist Information + // ====================================================================== + if (isset($_GET['info']) && !(empty($_GET['info']))) { + $currentAlbum = $_GET['info']; + $response .= '<p>Artist Information coming soon...</p>'; + } - - - // A Learning-Request // ====================================================================== - if (isset($_GET['learn']) && $_GET['learn'] == 'now') { - $posExamples = $this->getPositiveExamples(); - $instances = $this->getInstances($posExamples); - - $this->debugger->log($instances, "INSTANZEN"); - $this->debugger->log($posExamples, "posExamples"); + if (isset($_GET['get']) && $_GET['get'] == 'recommendations') { + $r = new Recommendations(); + $r->setPosExamples(); + $r->setInstances($r->getPosExamples()); + $recommendations = $r->getQueries($this->connection); - $res = $this->connection->learn($instances, $posExamples); - - // TODO (Yes, BIG one) - // build sparql-query based on learning-results - // build html-view build an sparql-results --- misuse tagSearch-Thingie - foreach ($res as $solution) { - $response .= round($solution->scoreValue*100, 2) . '% --- ' . $solution->descriptionKBSyntax . "\n"; - // $response .= $this->connection->kbToSqarql($solution->descriptionKBSyntax) . "\n"; + $results = array(); + if (is_array($recommendations) && !empty($recommendations)) { + if (!empty($recommendations['queries'])) { + foreach($recommendations['queries'] as $query) { + $data = $this->getData($query, 'recommendations', $this->getConfig('maxResults')); + $results[] = $data; + } + } + $recommendations['results'] = $results; + $view = new View($recommendations, 'recommendations'); + $response .= $view->getHTML(); + + } else { // an error occured during recommendation-retrieval + // give the error message to the view + $view = new View($recommendations, 'recommendations'); } - - $response = '<pre>' . $response . '</pre>'; - } @@ -119,111 +146,21 @@ if (isset($_GET['get']) && isset($_GET['playlist'])) { // Due to a bug in YMP we don't directly deliver the .xspf-file, we return a prepared // list of <li> including the links to the mp3-files, and this is build in the view of course. - $data = $this->prepareData( - array('playlist' => $_GET['playlist'], 'albumID' => $_GET['rel']), - $_GET['get'] - ); + $data = $this->prepareData(array('playlist' => $_GET['playlist'], 'albumID' => $_GET['rel']), $_GET['get']); $view = new View($data, $_GET['get']); $response = $view->getHTML(); } - - // Finally returning the response - if (!empty($response)) { - return $response; - } else { - if ($_GET['searchType'] == 'lastFM') { - return '<h2>Nothing found for the last.fm-user »' . $_GET['searchValue'] . '«.'; - } - return "<h2>The repsonse from the server was empty.</h2>"; - } + return $response; } /** - * - * - * - */ - private function getPositiveExamples() { - $posExamples = array(); - if (!empty($_COOKIE['moosique'])) { - $recent = json_decode(stripslashes($_COOKIE['moosique']))->recentlyListened; - foreach($recent as $link) { - // extract relation from the cookie-link - preg_match_all('#<a\s*(?:rel=[\'"]([^\'"]+)[\'"])?.*?>((?:(?!</a>).)*)</a>#i', $link, $record); - array_push($posExamples, $record[1][0]); - } - } - - $posExamples = array_unique($posExamples); - return $posExamples; - - } - - /** - * - * - * - */ - private function getInstances($posExamples) { - // TODO more testing, what is the optimum posExamples/neutral ratio, 50/50? - // for now we assume 50/50 - // $totalInstances = $this->getConfigLearning('instances'); - $instances = array(); - // and then add some random Records _not_ in this list - $allRecords = file($this->getConfigUrl('allRecords')); - $countPos = count($posExamples); - - for ($i = 0; $i < $countPos; $i++) { - $randomRecord = trim($allRecords[array_rand($allRecords)]); - // no double entries for the $instances-array - if (!in_array($randomRecord, $posExamples)) { - array_push($instances, $randomRecord); - } - } - // merge with posExamples - $instances = array_merge($posExamples, $instances); - shuffle($instances); - - return $instances; - } - - - /** - * - * @param Integer $limit optional Limit for Sparql-Query - */ - private function getData($search, $type, $limit = 0) { - $sparql = new SparqlQueryBuilder($search, $type, $limit); - $query = $sparql->getQuery(); - // sparql-query to dellearner - $json = $this->connection->sparqlQuery($query); - // convert to useable object - $result = json_decode($json); - $resultObject = $result->results->bindings; - - // prepare the data for HTML processing - $data = $this->prepareData($resultObject, $type); - return $data; - } - - - /** - * Establishes a new Dl-Learner Connection and saves it in - * private $connection for class-wide use. - * - * @return - */ - private function establishConnection() { - $this->connection = new DllearnerConnection(); - } - - /** * Removes unwanted chars from a search-string * - * TODO - NOT IMPLEMENTED but prepared + * FIXME - NOT IMPLEMENTED but prepared --- USE AND / OR and stuff and make this an extra function + * * If the search string contains a %20-Space-Char somewhere in the middle * of the string, it returns an array of search-values, divided by " " * Doing this we later can perform more searches for values like "stoner doom metal" @@ -260,46 +197,56 @@ */ private function prepareData($data, $type) { $mergedArray = array(); - switch ($type) { case 'artistSearch' : $mergedArray = $this->mergeArray($data, 'artist'); $mergedArray = $this->arrayUnique($mergedArray); break; - case 'tagSearch' : $mergedArray = $this->mergeArray($data, 'tag'); break; - case 'songSearch' : $mergedArray = $this->mergeArray($data, 'track'); $mergedArray = $this->arrayUnique($mergedArray); break; - case 'lastFM' : $mergedArray = $this->mergeArray($data, 'tag'); break; - - case 'albumPlaylist' : + case 'recommendations' : + $mergedArray = $this->mergeArray($data, 'record'); + $mergedArray = $this->arrayUnique($mergedArray); + break; + case 'playlist' : $playlistObject = simplexml_load_file($data['playlist']); $mergedArray = $this->object2array($playlistObject); // prepend the album stream-information $mergedArray['albumID'] = $data['albumID']; break; - - case 'trackPlaylist' : - $playlistObject = simplexml_load_file($data['playlist']); - $mergedArray = $this->object2array($playlistObject); - $mergedArray['albumID'] = $data['albumID']; - break; } - return $mergedArray; } - - + + /** - * TOOD implement nice merging for multi-tag-search + * + * @param Integer $limit optional Limit for Sparql-Query + */ + private function getData($search, $type, $limit = 0) { + $sparql = new SparqlQueryBuilder($search, $type, $limit); + $query = $sparql->getQuery(); + // sparql-query to dellearner + $json = $this->connection->sparqlQuery($query); + // convert to useable object + $result = json_decode($json); + $resultObject = $result->results->bindings; + + // prepare the data for HTML processing + $data = $this->prepareData($resultObject, $type); + return $data; + } + + + /** * This function merges the result-Object to a nice array * we can process easily. The array is created by type, * returning the data sorted for artist, tag or song @@ -333,7 +280,6 @@ /** * Like the php-function array_unique, but for multidimensional arrays, calls itself recursively * - * * @return Array (Multidimensional) array without double entries * @param Array $array The Array to clean up */ @@ -385,7 +331,17 @@ return $this->response; } + /** + * Establishes a new Dl-Learner Connection and saves it in + * private $connection for class-wide use. + * + * @return + */ + private function establishConnection() { + $this->connection = new DllearnerConnection(); + } + /** * Checks if the request made is an AJAX-Request and returns true if so * Modified: trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-20 10:23:23 UTC (rev 1891) @@ -1,9 +1,9 @@ <?php /** - * TODO, create a universal SparqlQueryBuilder for the different requests - * that can be made by a user or are made by the system for additional data - * like geodates, images, stuff... + * + * + * */ class SparqlQueryBuilder extends Config { @@ -50,25 +50,41 @@ } } + /** + * since there is no ORDER BY RAND() in Sparql and we are limiting + * the number of results for performance, we have to do sth. to + * at least randomize the results a bit..., the idea is to ORDER BY + * the different variables ASC/DESC randomly always used variables are + *?artist, ?artistName, ?record and ?playlist (record or track) + */ + $orderBy = ''; + /* BUG: Nice idea, but the jamendo-sparql-endpoint just ignores limit + when using order-by, thus useless approach */ + /* + $randomVariables = array('?artist', '?artistName', '?record', '?playlist'); + $randomOrder = array('ASC', 'DESC'); + if ($searchType != 'currentInfo') { + $orderBy = ' ORDER BY ' . $randomOrder[array_rand($randomOrder)] + . '(' . $randomVariables[array_rand($randomVariables)] . ')' . "\n"; + } + */ + // we need all information we can get, everytime, thus * - $beginStatement = 'SELECT * WHERE { ' . "\n"; - $endStatement = ' }' . $limit; - + $beginStatement = 'SELECT DISTINCT * WHERE { ' . "\n"; + $endStatement = ' }' . $orderBy . $limit; + $query = ''; - - switch($searchType) { - case 'artistSearch' : $query = $this->queryArtistSearch($search); break; - case 'tagSearch' : $query = $this->queryTagSearch($search); break; - case 'songSearch' : $query = $this->querySongSearch($search); break; - case 'lastFM' : $query = $this->queryTagSearch($search); break; + case 'artistSearch' : $query = $this->queryArtistSearch($search); break; + case 'tagSearch' : $query = $this->queryTagSearch($search); break; + case 'songSearch' : $query = $this->querySongSearch($search); break; + case 'lastFM' : $query = $this->queryTagSearch($search); break; + case 'recommendations' : $query = $this->queryRecommendations($search); break; /* TODO build functions for other queries - case 'albumInfo' : $query = $this->queryAlbumInfo($search); break; - case 'songInfo' : $query = $this->querySongInfo($search); break; + case 'currentInfo' : $query = $this->queryCurrentInfo($search); break; */ } - // save the query $this->queryString = $prefixes . $beginStatement . $query . $endStatement; } @@ -102,9 +118,8 @@ /** - * For a Tag-Search we display the playable records - * Therefore we need record and artist information too. - * AlbumCover is optional + * For a Tag-Search we display the playable records, therefore we need record and + * artist information too, AlbumCover is optional * Returns the Sparql-Query part for tag-search * * @return String Sparql-Query part for tag-search @@ -167,6 +182,9 @@ return $queryString; } + + + /** * Returns the Sparql-Query part for tag-search * @@ -193,7 +211,49 @@ return $queryString; } + + + + + /** + * + * + * + * + */ + private function queryRecommendations($search) { + $queryString = ' { + ?artist rdf:type mo:MusicArtist ; + foaf:name ?artistName ; + foaf:made ?record . + ?record mo:available_as ?playlist ; + dc:title ?albumTitle . + + OPTIONAL { ?artist foaf:img ?artistImage . } + OPTIONAL { ?artist foaf:homepage ?artistHomepage . } + OPTIONAL { + ?record mo:image ?cover . + FILTER (regex(str(?cover), "1.100.jpg", "i")) . + } + } '; + + /* ?record tags:taggedWithTag ?tag + makes the queries blow up high */ + + $queryString .= 'FILTER (regex(str(?playlist), "xspf", "i")) . '; + // and finally we append the sparql-string from kb-Description + $queryString .= $search; + + return $queryString; + } + + + + + + + /** * Returns the build Query-String * * @return String Complete SPARQL-Query stored in SparqlQueryBuilder Modified: trunk/src/moosique.net/moosique/classes/View.php =================================================================== --- trunk/src/moosique.net/moosique/classes/View.php 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/moosique/classes/View.php 2009-10-20 10:23:23 UTC (rev 1891) @@ -6,7 +6,6 @@ * */ class View extends Config { - private $html = '<h2>Nothing found.</h2>'; // view modes are debug or both, default is html view @@ -15,16 +14,18 @@ $this->createOutput($data, $type); } + /** * */ private function createOutput($data, $type) { - if (empty($data)) { + if (!is_array($data) || empty($data)) { switch($type) { case 'artistSearch' : $this->html = '<h2>No Artists found for »' . $_GET['searchValue'] . '«</h2>'; break; case 'tagSearch' : $this->html = '<h2>No Tags found for »' . $_GET['searchValue'] . '«</h2>'; break; case 'songSearch' : $this->html = '<h2>No Songs found for »' . $_GET['searchValue'] . '«.</h2>'; break; - case 'lastFM' : $this->html = ''; break; + case 'lastFM' : $this->html = '<h2>The last.fm-user »' . $_GET['searchValue'] . '« does not exist.</h2>'; break; + case 'recommendations' : $this->html = '<h2>' . $data . '</h2>'; break; } } else { // finally we are producing html, depending on the type of request @@ -45,9 +46,12 @@ case 'lastFM' : $this->html .= $this->tagSearchHTML($data); break; - - case 'albumPlaylist' : $this->html = $this->albumPlaylistHTML($data); break; - case 'trackPlaylist' : $this->html = $this->trackPlaylistHTML($data); break; + case 'recommendations' : + $this->html .= $this->recommendationsHTML($data); + break; + case 'playlist' : + $this->html = $this->playlistHTML($data); + break; } } } @@ -62,8 +66,6 @@ $output = '<div class="artistSearch"><ul class="clearfix">'; $i = 0; // counter variable for alternating li-elements foreach($data as $artist) { - // TODO Template-Usage - // alternating classes for li-elements if (($i % 2) == 0) { $class = 'odd'; } else { $class = ''; } @@ -115,17 +117,17 @@ if (!empty($artist['artistHomepage'])) { $homepage = '<a href="' . $this->getValue($artist['artistHomepage']) . '">(Homepage)</a>'; } - // tags if avaiable + $tags = ''; - if (!empty($artist['tag'])) { - if (is_array($this->getValue($artist['tag']))) { - $tags = implode(', ', $this->getValue($artist['tag'])); - } else { - $tags = $this->getValue($artist['tag']); - } - // remove the uri, we only want to have the tag-name - $tags = str_replace('http://dbtune.org/jamendo/tag/', '', $tags); + $tempTag = $this->getValue($artist['tag']); + if (is_array($tempTag)) { + $tags = implode(', ', $tempTag); + } else { + $tags = $tempTag; } + // remove the uri, we only want to have the tag-name + $tags = str_replace('http://dbtune.org/jamendo/tag/', '', $tags); + $output .= sprintf($template, $class, $this->getValue($artist['artistName']), $homepage, $image, $tags, $records ); @@ -171,25 +173,11 @@ '; // we have to do the if/else because if there is only one // result, the returned response wont contain a subarray - $records = $this->getValue($tag['record']); - if (is_array($records)) { $record = $records[$i]; } - else { $record = $records; } + $record = $this->getSingleValue($this->getValue($tag['record']), $i); + $artistName = $this->getSingleValue($this->getValue($tag['artistName']), $i); + $albumTitle = $this->getSingleValue($this->getValue($tag['albumTitle']), $i); + $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getSingleValue($this->getValue($tag['playlist']), $i)); - $artistNames = $this->getValue($tag['artistName']); - if (is_array($artistNames)) { $artistName = $artistNames[$i]; } - else { $artistName = $artistNames; } - - $albumTitles = $this->getValue($tag['albumTitle']); - if (is_array($albumTitles)) { $albumTitle = $albumTitles[$i]; } - else { $albumTitle = $albumTitles; } - - $playlists = $this->getValue($tag['playlist']); - if (is_array($playlists)) { - $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $playlists[$i]); - } else { - $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $playlists); - } - $addToPlaylist = '<li><a class="addToPlaylist" href="' . $playlist . '" ' . 'title="' . $artistName . ' - ' . $albumTitle . '" ' . 'rel="' . $record . '">Click here to add this album to your playlist.</a></li>'; @@ -197,20 +185,11 @@ /* The album cover is optional, so it could be empty */ $image = '<img src="img/noimage.png" alt="No image found..." />'; if (!empty($tag['cover'])) { - $covers = $this->getValue($tag['cover']); - if (is_array($covers)) { - $image = '<img src="' . $covers[$i] . '" alt="' . $artistName. ' - ' . $albumTitle. '" />'; - } else { - $image = '<img src="' . $covers . '" alt="' . $artistName. ' - ' . $albumTitle. '" />'; - } + $image = '<img src="' . $this->getSingleValue($this->getValue($tag['cover']), $i) . '" alt="' . $artistName. ' - ' . $albumTitle. '" />'; } $output .= sprintf($template, - $class, - $image, - $artistName, - $albumTitle, - $addToPlaylist + $class, $image, $artistName, $albumTitle, $addToPlaylist ); } $output .= '</ul>'; @@ -219,6 +198,7 @@ return $output; } + /** * * @@ -241,55 +221,31 @@ <ul>%s</ul> </li> '; - // we have to do the if/else because if there is only one - // result, the returned response wont contain a subarray - $tracks = $this->getValue($song['track']); - if (is_array($tracks)) { $track = $tracks[$i]; } - else { $track = $tracks; } - - $records = $this->getValue($song['record']); - if (is_array($records)) { $record = $records[$i]; } - else { $record = $records; } + + $track = $this->getSingleValue($this->getValue($song['track']), $i); + $record = $this->getSingleValue($this->getValue($song['record']), $i); + $songTitle = $this->getSingleValue($this->getValue($song['songTitle']), $i); + $artistName = $this->getSingleValue($this->getValue($song['artistName']), $i); + $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getSingleValue($this->getValue($song['playlist']), $i)); - $songTitles = $this->getValue($song['songTitle']); - if (is_array($songTitles)) { $songTitle = $songTitles[$i]; } - else { $songTitle = $songTitles; } - - $artistNames = $this->getValue($song['artistName']); - if (is_array($artistNames)) { $artistName = $artistNames[$i]; } - else { $artistName = $artistNames; } - - $playlists = $this->getValue($song['playlist']); - if (is_array($playlists)) { - $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $playlists[$i]); - } else { - $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $playlists); - } - $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' . $artistName . ' - ' . $songTitle . '">Click here to add this song to your playlist</a></li>'; // Artist-Image is optional $image = '<img src="img/noimage.png" alt="No image found..." />'; if (!empty($song['artistImage'])) { - $images = $this->getValue($song['artistImage']); - if (is_array($images)) { - $image = '<img src="' . $images[$i] . '" alt="' . $artistName. '" />'; - } else { - $image = '<img src="' . $images . '" alt="' . $artistName. '" />'; - } + $image = '<img src="' . $this->getSingleValue($this->getValue($song['artistImage']), $i) + . '" alt="' . $artistName. '" />'; } $tags = ''; - if (!empty($song['tag'])) { - if (is_array($this->getValue($song['tag']))) { - $tags = implode(', ', $this->getValue($song['tag'])); - } else { - $tags = $this->getValue($song['tag']); - } - // remove the uri, we only want to have the tag-name - $tags = str_replace('http://dbtune.org/jamendo/tag/', '', $tags); - } + $tempTag = $this->getValue($song['tag']); + if (is_array($tempTag)) { + $tags = implode(', ', $tempTag); + } else { + $tags = $tempTag; + } + $tags = str_replace('http://dbtune.org/jamendo/tag/', '', $tags); $output .= sprintf($template, $class, $artistName . ' - ' . $songTitle, $image, $tags, $addToPlaylist @@ -301,37 +257,105 @@ /** - * - * - * + * + * + * + * + * + * */ - private function albumPlaylistHTML($data) { - $albumID = $data['albumID']; + private function recommendationsHTML($data) { $output = ''; - foreach($data['trackList'] as $tracks) { - foreach($tracks as $track) { - $output .= '<li><a rel="' . $albumID . '" href="' . $track['location'] - . '" class="htrack">' - . $track['creator'] . ' - ' . $track['title'] - . '</a></li>'; + $count = count($data['scores']); // doesnt matter if scores or results... + + if ($count > 0) { // we have at least one usable result + $scores = $data['scores']; + $syntaxes = $data['kbSyntaxes']; + $results = $data['results']; + + for ($i = 0; $i < $count; $i++) { + $syntax = str_replace('http://dbtune.org/jamendo/tag/', '', $syntaxes[$i]); + $syntax = str_replace('"', '', $syntax); + $output .= '<h3>»' . $syntax . '« (accuracy: ' . $scores[$i] . '%)</h3>'; + $output .= '<ul class="clearfix">'; + + $j = 0; + // cycle through all albums and fill the list + foreach ($results[$i] as $record => $result) { + // alternating classes for li-elements + if (($j % 2) == 0) { $class = 'odd'; } + else { $class = ''; } + $j++; + + $template = ' + <li class="clearfix %s"> + <div class="cover">%s</div> + <h4>%s - %s</h4> + <ul>%s</ul> + </li> + '; + $artistName = $this->getSingleValue($this->getValue($result['artistName'])); + $albumTitle = $this->getSingleValue($this->getValue($result['albumTitle'])); + $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getSingleValue($this->getValue($result['playlist']))); + $addToPlaylist = '<li><a class="addToPlaylist" href="' . $playlist . '" ' + . 'title="' . $artistName . ' - ' . $albumTitle . '" ' + . 'rel="' . $record . '">Click here to add this album to your playlist.</a></li>'; + /* The album cover is optional, so it could be empty */ + $image = '<img src="img/noimage.png" alt="No image found..." />'; + if (!empty($result['cover'])) { + $image = '<img src="' . $this->getSingleValue($this->getValue($result['cover'])) + . '" alt="' . $artistName. ' - ' . $albumTitle. '" />'; + } + + $output .= sprintf($template, + $class, $image, $artistName, $albumTitle, $addToPlaylist + ); + } + $output .= '</ul>'; } + } else { + $output = '<h2>Could not create any recommendations...</h2>'; + $output .= '<p>Listen to some more music or reset your recently listened to list.</p>'; } return $output; } - + + + + + + + + + + + + + /** * * * */ - private function trackPlaylistHTML($data) { + private function playlistHTML($data) { $albumID = $data['albumID']; $output = ''; - foreach($data['trackList'] as $track) { - $output .= '<li><a rel="' . $albumID . '" href="' . $track['location'] - . '" class="htrack">' - . $track['creator'] . ' - ' . $track['title'] - . '</a></li>'; + foreach($data['trackList'] as $tracks) { + // if the tracks-list contains only one song, there are no sub-arrays + if (isset($tracks[0]) && is_array($tracks[0])) { + foreach($tracks as $track) { + $output .= '<li><a rel="' . $albumID . '" href="' . $track['location'] + . '" class="htrack">' + . $track['creator'] . ' - ' . $track['title'] + . '</a></li>'; + } + } else { // only one track, no sub-array, no foreach, same data + $track = $tracks; + $output .= '<li><a rel="' . $albumID . '" href="' . $track['location'] + . '" class="htrack">' + . $track['creator'] . ' - ' . $track['title'] + . '</a></li>'; + } } return $output; } @@ -362,7 +386,22 @@ } } + /** + * + * + * + * + * + */ + private function getSingleValue($data, $index = 0) { + if (is_array($data)) { + return $data[$index]; + } else { + return $data; + } + } + /** * Returns the HTML * Modified: trunk/src/moosique.net/moosique/config.ini =================================================================== --- trunk/src/moosique.net/moosique/config.ini 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/moosique/config.ini 2009-10-20 10:23:23 UTC (rev 1891) @@ -1,36 +1,35 @@ ; Config file for moosique.net + [general] ; Activates global debugging, using FirePHP and Firebug debug = 1 -; If globalLimit = 1 maxResults is used for -; a global SPARQL-Query LIMIT, set to 0 maxResults -; will only be used for viewing results -maxResults = 20 -globalLimit = 0 +; If globalLimit = 1 maxResults is used for a global SPARQL-Query LIMIT, +; set to 0 maxResults will only be used for viewing results +maxResults = 10 +globalLimit = 1 +; %-score a recommendation needs to have to be recommended +threshold = 80 [url] +base = "http://localhost/moosique.net/" local = "http://127.0.0.1/" wsdl = "http://localhost:8181/services?wsdl" wsdlLocal = "http://localhost/moosique.net/moosique/main.wsdl" -; The Default-Jamendo-Endpoint jamendo = "http://dbtune.org/jamendo/sparql/" -; musicbrainz-Endpoint musicbrainz = "http://dbtune.org/musicbrainz/sparql/" -; Last-Fm-Api -; lastfm = "http://dbtune.org/last-fm/" +zitgistdata = "http://dataviewer.zitgist.com/?uri=" tagOntology = "file:/Users/nebelschwade/Sites/moosique.net/moosique/testing/moreThan80.owl" allTags = "http://localhost/moosique.net/moosique/data/allTagsByPopularity.txt" allRecords = "http://localhost/moosique.net/moosique/data/allRecordsWithTags.txt" [lastFM] -; user-top-tags api-url +; change the api-key if you have your own +apiKey = "b9877a7391416d0846ad5f240a1838f9" topTagsUrl = "http://ws.audioscrobbler.com/2.0/?method=user.gettoptags" topArtistsUrl = "http://ws.audioscrobbler.com/2.0/?method=user.gettopartists" artistsTopTagsUrl = "http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags" -; change the api-key if you have your own -apiKey = "b9877a7391416d0846ad5f240a1838f9" ; you don't have to change [learning]-config-vars in most cases @@ -39,7 +38,7 @@ ; set the start class to the correct type (Record in this case) - not supported yet ; celoe.startClass = "http://purl.org/ontology/mo/Record"; ; let it run for a short amount of time (we only want simple expressions) -maxExecutionTimeInSeconds = 2 +maxExecutionTimeInSeconds = 4 ; use owl:hasValue if appropriate ; see: http://www.w3.org/TR/2008/WD-owl2-syntax-20081202/#Individual_Value_Restriction ; not sure whether this greatly influences the results Modified: trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt =================================================================== --- trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt 2009-10-14 14:24:30 UTC (rev 1890) +++ trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt 2009-10-20 10:23:23 UTC (rev 1891) @@ -1,3 +1,7 @@ +Used tags are commented with # +Unused tags are indented (8 spcs) and commented with # +"Not yet in the owl"-tags are neither commented or indented + #http://dbtune.org/jamendo/tag/electro : 2102 #http://dbtune.org/jamendo/tag/rock : 1703 #http://dbtune.org/jamendo/tag/ambient : 1007 @@ -5,22 +9,22 @@ #http://dbtune.org/jamendo/tag/experimental : 810 #http://dbtune.org/jamendo/tag/instrumental : 701 #http://dbtune.org/jamendo/tag/techno : 682 -http://dbtune.org/jamendo/tag/guitare : 583 +# http://dbtune.org/jamendo/tag/guitare : 583 #http://dbtune.org/jamendo/tag/chanson : 442 #http://dbtune.org/jamendo/tag/jazz : 421 #http://dbtune.org/jamendo/tag/poprock : 414 #http://dbtune.org/jamendo/tag/metal : 397 #http://dbtune.org/jamendo/tag/acoustique : 396 #http://dbtune.org/jamendo/tag/alternatif : 389 -http://dbtune.org/jamendo/tag/melodique : 387 +#... [truncated message content] |
From: <neb...@us...> - 2009-10-27 23:03:09
|
Revision: 1895 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1895&view=rev Author: nebelschwade Date: 2009-10-27 23:02:54 +0000 (Tue, 27 Oct 2009) Log Message: ----------- Tag and LastFM-Search now use "exakt search" when searching for more than one word - better results, this is used for the recommendations too implemented albumSearch Random/Limit for results working mootools upgrade, usage of mootools log/spinner/Elements.From, better js new DataHelper class (cleaner RequestHandler) refactored view and sparqlBuilder compressed images css-updates deleted unused data/testing Modified Paths: -------------- trunk/src/moosique.net/css/reset.css trunk/src/moosique.net/css/style.css trunk/src/moosique.net/img/bg.png trunk/src/moosique.net/img/controls.png trunk/src/moosique.net/img/noimage.png trunk/src/moosique.net/index.php trunk/src/moosique.net/js/debug.js trunk/src/moosique.net/js/index.php trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/LastFM.php trunk/src/moosique.net/moosique/classes/Recommendations.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/index.php trunk/src/moosique.net/moosique/testing/learnTest.php Added Paths: ----------- trunk/src/moosique.net/img/spinner.gif trunk/src/moosique.net/js/mootools-1.2.4-core-nc.js trunk/src/moosique.net/js/mootools-1.2.4-core-yc.js trunk/src/moosique.net/js/mootools-1.2.4.2-more-nc.js trunk/src/moosique.net/js/mootools-1.2.4.2-more-yc.js trunk/src/moosique.net/moosique/classes/DataHelper.php trunk/src/moosique.net/moosique/data/moosique.owl trunk/src/moosique.net/moosique/testing/nodeExtractionBug_2.conf Removed Paths: ------------- trunk/src/moosique.net/img/loading.gif trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js trunk/src/moosique.net/js/mootools-1.2.3-core-yc.js trunk/src/moosique.net/moosique/data/allRecords.txt trunk/src/moosique.net/moosique/data/allTags.txt trunk/src/moosique.net/moosique/data/dontUse.txt trunk/src/moosique.net/moosique/data/tagsWeUse.txt Modified: trunk/src/moosique.net/css/reset.css =================================================================== --- trunk/src/moosique.net/css/reset.css 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/css/reset.css 2009-10-27 23:02:54 UTC (rev 1895) @@ -1,4 +1,4 @@ -/* basic reset */ +/* default minimal basic css reset */ /* =================================================================== */ @media all { html, body, div, h1, h2, h3, @@ -17,7 +17,6 @@ select, option { font: inherit; color: inherit; } a { color: inherit; font: inherit; text-decoration: none; } a:hover { text-decoration: underline; } -a:active { position: relative; top: 1px; } .hidden { position: absolute; left: -9999px; top: -9999px; } .clearfix:after { clear: both; content: ' '; display: block; font-size: 0; line-height: 0; visibility: hidden; width: 0; height: 0; } Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/css/style.css 2009-10-27 23:02:54 UTC (rev 1895) @@ -2,11 +2,12 @@ /*=============== Default Styling ===============*/ body { font: normal 12px/18px Verdana, Arial, sans-serif; color: #f1f7e4; background: url('../img/bg.png') top left repeat #3a3a3a; border-top: 5px solid #1fd611; } -input, textarea, select { background: #292929; border: 1px solid #5a5a5a; outline: none; padding: 5px; } +input, select { background: #292929; border: 1px solid #5a5a5a; outline: none; padding: 5px; } input[type=submit] { padding: 5px 10px; } -textarea:focus, input:focus, -select:focus { border: 1px solid #1fd611; } +input:focus, select:focus { border: 1px solid #1fd611; } a:hover { color: #1fd611; } +a.button { background: #4a4a4a; color: #f1f7e4; padding: 5px 10px; text-decoration: none; } +a.button:hover { border: 1px solid #1fd611; padding: 4px 9px; } h1 { font: 32px/32px Georgia, Times, serif; } h2 { font: 28px/28px Georgia, Times, serif; } h3 { font: 20px/20px Georgia, Times, serif; } @@ -15,110 +16,93 @@ h6 { font: 10px/10px Georgia, Times, serif; } pre { font: normal 10px/14px Monaco, Courier, monospace; } p, h1, h2, h3, h4, h5, h6, -table, ul, ol, blockquote, -pre, form { margin-bottom: 18px; } +ul, ol, pre, form { margin-bottom: 18px; } /* Initial hiding */ -#recommendations, #player, -#information, #help, -#loadingImg, #header h1 { display: none; } +#recommendations, #information, +#header h1, #player, #help { display: none; } /* Rounded Corners */ -input, textarea, select, -a.button { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } +input, select, a.button { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } #content, #status, #playing, #playerControls, .results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } -#mainMenu a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; +#nav a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; border-top-left-radius: 10px; } -/* button-click-feeling for links, by offsetting top position */ -#playerControls a:active { position: relative; top: 2px; } -#playlist .delete:active, -#playlist .moveUp:active, -#playlist .moveDown:active { top: 6px; } - - /*=============== Default Containers ===============*/ #container, #header, -#headerContainer, -#mainContainer, #content, -#playlist li { position: relative; } +#content, #playlist li { position: relative; } #container { width: 760px; margin: 0 auto; } #header { height: 150px; padding-top: 20px; } #content { background: #292929; padding: 20px; } #footer { font: normal 10px/14px Verdana, Arial, sans-serif; padding: 20px; text-align: center; } -/*=============== header Area, Player Controls, Status, Playing and Search Form ===============*/ +/*=============== Player Controls, Status, Playing ===============*/ #status, #playing { position: absolute; top: 70px; left: 0; width: 490px; height: 60px; background: #292929; padding: 10px 20px; } #playerControls { position: absolute; top: 70px; right: 0; width: 170px; height: 60px; padding: 10px 20px; background: #292929; } +#playerControls a:active { position: relative; top: 2px; } #status { background: #393939; height: 60px; line-height: 60px; text-align: center; font-weight: bold; border: 1px solid #1fd611; z-index: 1000; } #playing span { display: block; margin-bottom: 0; font-size: 10px; } #playing .track { font: bold 12px/32px Verdana, Arial, sans-serif; } #playing .time { position: absolute; bottom: 10px; right: 20px; } - #prev, #next, #stop, #playPause, #mute { display: block; width: 20px; height: 40px; text-indent: -10000px; float: left; margin: 10px 0 0 10px; } -/* Sprites */ #prev { background: url(../img/controls.png) 0px -160px no-repeat; } #next { background: url(../img/controls.png) 0px -120px no-repeat; } #stop { background: url(../img/controls.png) 0px -80px no-repeat; } #mute { background: url(../img/controls.png) 0px -280px no-repeat; margin-right: 0; width: 23px; } #playPause { background: url(../img/controls.png) 0px 0px no-repeat; width: 26px; } -/* Search form */ + +/*=============== Search Form ===============*/ #searchValue { margin: 0 5px; width: 100px; } -#loadingImg { cursor: wait; } -a.button { background: #4a4a4a; color: #f1f7e4; padding: 5px 10px; text-decoration: none; } -a.button:hover { border: 1px solid #1fd611; padding: 4px 9px; } +.spinner { position: absolute; z-index: 10; background: url('../img/bg.png') top left repeat #3a3a3a; } +.spinner-img { background: url('../img/spinner.gif') top left no-repeat; width: 24px; height: 24px; margin: 0 auto; } + + +/*=============== Content & General ===============*/ #addRandom { text-decoration: underline; } +#footer a { padding: 0 10px; } -/*=============== Menu & Footer ===============*/ -#mainMenu ul { position: absolute; top: 0; right: 0; } -#mainMenu li { float: left; } -#mainMenu a { display: block; margin-left: 10px; line-height: 30px; height: 30px; + +/*=============== Menu ===============*/ +#nav ul { position: absolute; top: 0; right: 0; } +#nav li { float: left; } +#nav a { display: block; margin-left: 10px; line-height: 30px; height: 30px; padding: 10px 12px; color: #f1f7e4; background: #4a4a4a; } -#mainMenu .active a, -#mainMenu .active a:hover { background: #1fd611; } -#mainMenu a:hover { text-decoration: none; background: #5a5a5a; } +#nav .active a, +#nav .active a:hover { background: #1fd611; } +#nav a:hover { text-decoration: none; background: #5a5a5a; } -#footer a { padding: 0 10px; } -/*=============== Search Results ===============*/ -.results li h3 a { font-weight: normal; } -.results li img { border: 2px solid #545454; } +/*=============== Search Results, Recommendations & Playlist ===============*/ +.results h3 a { font-weight: normal; } +.results img { border: 2px solid #545454; max-width: 308px; max-height: 308px; } .results li { float: left; width: 312px; border: 1px solid #545454; padding: 18px; margin-bottom: 18px; } .results li.odd { margin-right: 18px; clear: both; } .results ul ul { list-style: disc; } - -/* This is for the list of found albums etc */ .results li li, .artistSearch li li, .tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; width: auto; height: auto; float: none; } + +.results h4 { display: inline; } #recommendationResults ul ul, .tagSearch ul ul { clear: both; } -.results .artistImage { text-align: center; margin-bottom: 18px;} -.results .cover { margin: 0 18px 18px 0; width: 104px; height: 104px; float: left; } -#recommendationResults h4, -.tagSearch h4 { display: inline; } - - -/*=============== Recommendations and playlist ===============*/ +.results .image { text-align: center; margin-bottom: 18px; } +#recommendationResults.results .image, +.results .tagSearch .image { margin: 0 18px 18px 0; width: 104px; height: 104px; float: left; } #autoAdd { float: right; } -#recommended a:hover { cursor: pointer; text-decoration: none; font-weight: bold; color: #131313; } -#playlist, #recommended, -#recently { margin-left: 36px; list-style: decimal; } -#playlist li, #recently li, -#recommended li { line-height: 24px; } -#playlist .ymp-btn-page-pause { font-weight: bold; } -/* Playlist buttons */ +#playlist, #recently { margin-left: 36px; list-style: decimal; } +#playlist li, #recently li { line-height: 24px; } +#playlist .ymp-btn-page-pause { font-weight: bold; } #playlist .delete, #playlist .moveUp, #playlist .moveDown { position: absolute; display: block; top: 5px; right: 20px; width: 14px; height: 14px; @@ -126,11 +110,13 @@ background: url(../img/controls.png) 0px -200px no-repeat;} #playlist .moveUp { background: url(../img/controls.png) 0px -360px no-repeat; right: 40px; } #playlist .moveDown { background: url(../img/controls.png) 0px -320px no-repeat; right: 60px; } +#playlist .delete:active, +#playlist .moveUp:active, +#playlist .moveDown:active { top: 6px; } -/*=============== Information / Help ===============*/ +/*=============== Information & Help ===============*/ - } /* end @media screen */ \ No newline at end of file Modified: trunk/src/moosique.net/img/bg.png =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/img/controls.png =================================================================== (Binary files differ) Deleted: trunk/src/moosique.net/img/loading.gif =================================================================== (Binary files differ) Modified: trunk/src/moosique.net/img/noimage.png =================================================================== (Binary files differ) Added: trunk/src/moosique.net/img/spinner.gif =================================================================== (Binary files differ) Property changes on: trunk/src/moosique.net/img/spinner.gif ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/index.php 2009-10-27 23:02:54 UTC (rev 1895) @@ -1,18 +1,17 @@ <?php session_start(); ?> -<!DOCTYPE html - PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<!DOCTYPE html> +<html lang="en"> <head> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <link href="css/" rel="stylesheet" type="text/css" /> + <meta charset="utf-8" /> + <link rel="stylesheet" href="css/" /> <title>moosique.net</title> </head> <body> <div id="container"> <div id="header"> <h1>moosique.net</h1> - <div id="mainMenu"> + + <div id="nav"> <ul class="clearfix"> <li class="active"><a href="#" class="home">Search</a></li> <li><a href="#" class="player">Playlist</a></li> @@ -21,20 +20,22 @@ <li><a href="#" class="help">?</a></li> </ul> </div> + <form id="searchForm" method="get" action="moosique/"> <div> <select name="searchType" id="searchType"> <option value="allSearch">All</option> <option value="artistSearch">Artist</option> <option value="tagSearch">Tag</option> + <option value="albumSearch">Album</option> <option value="songSearch">Song</option> <option value="lastFM">last.fm</option> </select> <input id="searchValue" name="searchValue" type="text" /> <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> - <img id="loadingImg" src="img/loading.gif" alt="Loading..." /> </div> </form> + <div id="playerControls"> <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> <a href="#" id="stop" title="Stop playing">Stop</a> @@ -42,6 +43,7 @@ <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> <a href="#" id="mute" title="Sound on/off">Mute</a> </div> + <div id="status"> </div> <div id="playing"> <span class="info">Player stopped</span> @@ -87,18 +89,18 @@ <h2>Recommendations</h2> <p> These recommendations are generated every time you listen to a song - for at least half it's length, assuming that you liked it. You click on a + for at least half it's length, assuming that you liked it. You can click on a recommended album to add it to the playlist, or you can <a href="#" id="addRandom">click here to just add a random song from your recommendations</a>.<br /> </p> + <p> + <a href="#" id="generateRecommendations" class="button" title="If there is nothing showing up here, you can generate your list of recommendations by clicking here.">Reload recommendations</a> + </p> <div id="recommendationResults" class="results"> </div> - <p> - <a href="#" id="generateRecommendations" class="button" title="If there is nothing showing up here, you can generate your list of recommendations by clicking here.">Reload recommendations</a> - </p> </div> <div id="information"> @@ -138,9 +140,7 @@ <a href="http://jamendo.com">Jamendo</a> | <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> </div> - <div id="temp" class="hidden"> - - </div> + </div> <!-- end container --> <?php @@ -148,15 +148,15 @@ $c = new Config(); if ($c->getConfig('debug') == 1) /* debugging active */ { ?> -<script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> -<script type="text/javascript" src="js/mootools-1.2.3-core-nc.js"></script> -<script type="text/javascript" src="js/moosique.js"></script> -<script type="text/javascript" src="js/debug.js"></script> -<script type="text/javascript" src="js/start.js"></script> - +<script src="http://mediaplayer.yahoo.com/js"></script> +<script src="js/mootools-1.2.4-core-nc.js"></script> +<script src="js/mootools-1.2.4.2-more-nc.js"></script> +<script src="js/moosique.js"></script> +<script src="js/debug.js"></script> +<script src="js/start.js"></script> <?php } else /* compress for production and dont include debugger */ { ?> -<script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script> -<script type="text/javascript" src="js/"></script> +<script src="http://mediaplayer.yahoo.com/js"></script> +<script src="js/"></script> <?php } ?> </body> </html> \ No newline at end of file Modified: trunk/src/moosique.net/js/debug.js =================================================================== --- trunk/src/moosique.net/js/debug.js 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/js/debug.js 2009-10-27 23:02:54 UTC (rev 1895) @@ -1,6 +1,9 @@ -/* activate debugging if firebug is avaiable */ -if (typeof(console) !== 'undefined') { - debug = console; - debug.log("Firebug-Console for moosique.net activated."); -} - +// New Debugger-Class using the mootools-log +var Debugger = new Class({ + Implements: Log, + initialize: function(){ + this.enableLog().log('Log-Console for moosique.net activated.'); + } +}); +// global debugger-instance +var debug = new Debugger; Modified: trunk/src/moosique.net/js/index.php =================================================================== --- trunk/src/moosique.net/js/index.php 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/js/index.php 2009-10-27 23:02:54 UTC (rev 1895) @@ -17,7 +17,8 @@ } /* the javascript-files to include and compress */ -include('mootools-1.2.3-core-yc.js'); +include('mootools-1.2.4-core-yc.js'); +include('mootools-1.2.4.2-more-yc-min.js'); include('moosique.js'); include('start.js'); Modified: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/js/moosique.js 2009-10-27 23:02:54 UTC (rev 1895) @@ -1,9 +1,3 @@ -// initialize an empty debugger, will be activated if firefox/firebug enabled -var debug = {}; -debug.log = function(msg) { - return false; -}; - /** * moosique-Player-Class * @@ -41,36 +35,40 @@ * changed, just change the references here and everything will work fine. */ initVars: function() { - this.main = document.id('content'); - this.menu = document.id('mainMenu'); + // buttons this.playPause = document.id('playPause'); this.prev = document.id('prev'); this.next = document.id('next'); this.stop = document.id('stop'); this.mute = document.id('mute'); - this.status = document.id('status'); - this.playlist = document.id('playlist'); - this.recently = document.id('recently'); + // player info & status display this.nowPlayingInfo = $$('#playing .info'); this.nowPlayingTrack = $$('#playing .track'); this.nowPlayingTime = $$('#playing .time'); + this.status = document.id('status'); + // searchForm elements this.searchForm = document.id('searchForm'); this.searchSubmit = document.id('searchSubmit'); this.searchValue = document.id('searchValue'); this.searchType = document.id('searchType'); this.results = document.id('results'); - this.loading = document.id('loadingImg'); - this.welcome = document.id('welcome'); - this.help = document.id('help'); + // playlist and recently + this.playlist = document.id('playlist'); + this.recently = document.id('recently'); + this.resetPlaylist = document.id('resetPlaylist'); + this.resetRecently = document.id('resetRecently'); + // recommendations this.recommendations = document.id('recommendations'); this.generate = document.id('generateRecommendations'); this.recResults = document.id('recommendationResults'); - this.resetPlaylist = document.id('resetPlaylist'); - this.resetRecently = document.id('resetRecently'); - this.moreInfo = document.id('moreInfo'); - this.temp = document.id('temp'); - this.autoAddCheckbox = document.id('autoAddCheckbox'); this.addRandom = document.id('addRandom'); + this.autoAddCheckbox = document.id('autoAddCheckbox'); + // other + this.content = document.id('content'); + this.nav = document.id('nav'); + this.welcome = document.id('welcome'); + this.help = document.id('help'); + this.moreInfo = document.id('moreInfo'); }, /** @@ -82,11 +80,9 @@ */ applyYahooMediaPlayerConfig: function() { var that = this; - var playerConfig = function() { // display ready-status message that.displayStatusMessage('Player ready.'); - /** * progress: Change the track position and duration displayed every time, as usual in players * @@ -121,7 +117,6 @@ // get the current cookie var recentlyListenedCookie = Cookie.read('moosique'); var recentlyListened = []; - if (recentlyListenedCookie) { // does the cookie exist? recentlyListened = JSON.decode(recentlyListenedCookie).recentlyListened; if (recentlyListened) { // if the cookie is not totally empty @@ -133,15 +128,13 @@ } } } - // add the last played to the array - recentlyListened.push(last); + recentlyListened.push(last); // add the last played to the array // update the cookie recentlyListenedObject = { 'recentlyListened' : recentlyListened }; recentlyListenedCookie = Cookie.write( /* save for one year */ 'moosique', JSON.encode(recentlyListenedObject), { duration: 365 } ); - // update the recently played list that.updateRecently(); that.displayStatusMessage('Added this song to your recently listened to songs.'); @@ -155,44 +148,49 @@ */ var playlistUpdate = function() { // delete button - $$('#playlist .delete').each(function(del) { + that.playlist.getElements('.delete').each(function(del) { del.removeEvents(); del.addEvent('click', function(e) { - e.stop(); - // TODO: if playlist empty or deleted currently playing track: STOP! + e.stop(); // don't folow link + // if current or the last song from the playlist stop playing + if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { + that.stopPlaying(); + } this.getParent().destroy(); // deletes the li-element - // and refresh the playlist if clicked - YAHOO.MediaPlayer.addTracks(that.playlist, '', true); - // TODO: if playlist empty or deleted currently playing track: STOP! + that.refreshPlaylist(); }); }); // up-button - $$('#playlist .moveUp').each(function(up) { + that.playlist.getElements('.moveUp').each(function(up) { up.removeEvents(); up.addEvent('click', function(e) { - e.stop(); // don't folow link + e.stop(); + if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { + that.stopPlaying(); + } var li = up.getParent(); var before = li.getPrevious(); if (before) { // it's not the first one li.inject(before, 'before'); - // and refresh the playlist if clicked - YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + that.refreshPlaylist(); } }); }); // down button - $$('#playlist .moveDown').each(function(down) { + that.playlist.getElements('.moveDown').each(function(down) { down.removeEvents(); down.addEvent('click', function(e) { - e.stop(); // don't folow link + e.stop(); + if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { + that.stopPlaying(); + } var li = down.getParent(); var after = li.getNext(); if (after) { // it's not the first one li.inject(after, 'after'); - // and refresh the playlist if clicked - YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + that.refreshPlaylist(); } }); }); @@ -216,7 +214,7 @@ var trackStart = function() { that.nowPlayingInfo.set('text', 'Currently playing:'); that.nowPlayingTrack.set('text', YAHOO.MediaPlayer.getMetaData().title); - that.playPause.setStyle('background-position', '0px -40px'); + that.playPause.setStyle('background-position', '0px -40px'); // sprite offset // send a request to gather additional artist-information var nowPlayingAlbum = YAHOO.MediaPlayer.getMetaData().anchor.get('rel'); @@ -227,7 +225,6 @@ that.moreInfo.set('html', response); } }).send('info=' + nowPlayingAlbum); - }; /** @@ -271,6 +268,7 @@ onFailure: function() { that.recResults.set('html', '<h2>Unable to get recommendations. Please reset and try again.</h2>'); }, + onSuccess: function(response) { response = response.trim(); if (response != '') { @@ -288,8 +286,6 @@ debug.log('Response from server empty.'); that.recResults.set('html', '<h2>There is nothing in your recently list.</h2><p>You have to listen to some music first, before you can get any recommendations.</p>'); } - - } }).send('get=recommendations'); }, @@ -380,9 +376,9 @@ /** + * This function stops the player and displays the default + * status-message "Player stopped", also refreshes the playlist * - * - * */ stopPlaying: function() { var that = this; @@ -419,38 +415,36 @@ */ initInterface: function() { var that = this; - - that.menu.getElements('a').each(function(tab) { + // tabbed nav + that.nav.getElements('a').each(function(tab) { tab.addEvent('click', function(e) { e.stop(); // dont follow link that.showTab(tab.get('class').toString()); }); }); - // generating recommendations clickable that.generate.addEvent('click', function(e) { e.stop(); that.generateRecommendations(); }); - + // enable resetting recently list that.resetRecently.addEvent('click', function(e) { e.stop(); Cookie.dispose('moosique'); that.updateRecently(); }); - + // enable resetting the playlist that.resetPlaylist.addEvent('click', function(e) { e.stop(); that.playlist.empty(); that.stopPlaying(); }); - + // enable the manual add random to playlist that.addRandom.addEvent('click', function(e) { e.stop(); that.addRandomToPlaylist(); }); - - // make buttons functional + // make player-buttons functional this.addEventsToButtons(); }, @@ -458,22 +452,19 @@ /** * Make the search-Form an ajax-Search form, displaying the results * on the homepage if successful - * - * TODO: sanitize client-side too using regex and displayStatus */ activateSearch: function() { var that = this; - + var spinner = new Spinner(that.searchSubmit); + that.searchForm.addEvent('submit', function(e) { e.stop(); // prevent form submitting the non-ajax way this.set('send', { onRequest: function() { + spinner.show(); that.searchSubmit.set('disabled', 'disabled'); - that.searchSubmit.setStyle('display', 'none'); - // show homescreen for resultdisplaying that.showTab('home'); - // if the welcome-text ist present, cut & paste it to help if (that.welcome) { if (that.welcome.get('html').length > 100) { @@ -481,19 +472,17 @@ that.welcome.destroy(); } } - that.loading.setStyle('display', 'inline'); that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take up to a minute...</p>'); }, onFailure: function() { + spinner.hide(); that.results.set('html', '<h2>Unable to process your search. Try again.</h2>'); }, onSuccess: function(response) { + spinner.hide(); that.searchSubmit.erase('disabled'); // reenable submitbutton - that.searchSubmit.setStyle('display', 'inline'); - that.loading.setStyle('display', 'none'); - // display results that.results.set('html', response); // addEvents to result-links that.makeAddable($$('a.addToPlaylist')); @@ -501,7 +490,7 @@ }); // only send form if value is at least 3 chars long - if (that.searchValue.get('value').length > 2) { + if (that.searchValue.get('value').length >= 3) { this.send(); } else { that.displayStatusMessage('Please enter at least 3 chars for searching...'); @@ -577,7 +566,6 @@ // add the delete, moveUp, moveDown Buttons that.playlist.getChildren().each(function(li) { var children = li.getChildren(); - // only add the buttons if they are not there yet if (children.length == 1) { var track = li.getFirst(); @@ -590,68 +578,58 @@ delButton.inject(downButton, 'after'); } }); - // refresh the playlist and show the player-tab that.refreshPlaylist(); }, /** + * This function adds a random song from a random record from the + * recommendations results to the playlist (enqueue at the end) * - * - * */ addRandomToPlaylist: function() { var that = this; var addableAlbums = that.recResults.getElements('.addToPlaylist'); // pick a random album var randomAlbum = addableAlbums.getRandom(); - + // if there is at least one album to add items from if (randomAlbum) { var href = randomAlbum.get('href'); var rel = randomAlbum.get('rel'); - if (href.match(/jamendo\.com\/get\/track\/id\//gi)) { type = 'playlist'; } - if (href.match(/\.mp3/)) { type = 'mp3File'; } - - // if the addable item is a playlist, we have to get the playlistitems var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', onSuccess: function(response) { // yay, we have the playlist, choose a random song and add it // therefore save it as Element in temp and extract a random song - // TODO a better way would be to just get on <li> from the response - // with a regexp and just use this, without creating new dom nodes etc. - that.temp.set('html', '<ul>' + response + '</ul>'); - var songs = that.temp.getElements('li'); + var songs = Elements.from(response); var randomSong = songs.getRandom(); that.insertIntoPlaylist('<li>' + randomSong.get('html') + '</li>'); - that.temp.empty(); } }).send('get=playlist&playlist=' + href + '&rel=' + rel); } else { debug.log('You currently have no recommendations, adding a random one will not work.'); } - }, /** - * Shows the given tab in the menu, and hides all others + * Shows the given tab in the nav, and hides all others * * @param {String} tabID ID of the Tab to show */ showTab: function(tabID) { var that = this; - that.menu.getElements('li').removeClass('active'); - that.menu.getElements('a.' + tabID).getParent().toggleClass('active'); - that.main.getChildren().setStyle('display', 'none'); + that.nav.getElements('li').removeClass('active'); + that.nav.getElements('a.' + tabID).getParent().toggleClass('active'); + that.content.getChildren().setStyle('display', 'none'); document.id(tabID).setStyle('display', 'block'); }, /** * Converts seconds into a string formatted minutes:seconds - * with leading zeros for seconds + * with leading zeros for seconds for a nicer display * * @param {Float} seconds * @return {String} minsec minutes:seconds Deleted: trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js =================================================================== --- trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js 2009-10-27 08:48:54 UTC (rev 1894) +++ trunk/src/moosique.net/js/mootools-1.2.3-core-nc.js 2009-10-27 23:02:54 UTC (rev 1895) @@ -1,4036 +0,0 @@ -/* -Script: Core.js - MooTools - My Object Oriented JavaScript Tools. - -License: - MIT-style license. - -Copyright: - Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). - -Code & Documentation: - [The MooTools production team](http://mootools.net/developers/). - -Inspiration: - - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) - - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) -*/ - -var MooTools = { - 'version': '1.2.3', - 'build': '4980aa0fb74d2f6eb80bcd9f5b8e1fd6fbb8f607' -}; - -var Native = function(options){ - options = options || {}; - var name = options.name; - var legacy = options.legacy; - var protect = options.protect; - var methods = options.implement; - var generics = options.generics; - var initialize = options.initialize; - var afterImplement = options.afterImplement || function(){}; - var object = initialize || legacy; - generics = generics !== false; - - object.constructor = Native; - object.$family = {name: 'native'}; - if (legacy && initialize) object.prototype = legacy.prototype; - object.prototype.constructor = object; - - if (name){ - var family = name.toLowerCase(); - object.prototype.$family = {name: family}; - Native.typize(object, family); - } - - var add = function(obj, name, method, force){ - if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; - if (generics) Native.genericize(obj, name, protect); - afterImplement.call(obj, name, method); - return obj; - }; - - object.alias = function(a1, a2, a3){ - if (typeof a1 == 'string'){ - var pa1 = this.prototype[a1]; - if ((a1 = pa1)) return add(this, a2, a1, a3); - } - for (var a in a1) this.alias(a, a1[a], a2); - return this; - }; - - object.implement = function(a1, a2, a3){ - if (typeof a1 == 'string') return add(this, a1, a2, a3); - for (var p in a1) add(this, p, a1[p], a2); - return this; - }; - - if (methods) object.implement(methods); - - return object; -}; - -Native.genericize = function(object, property, check){ - if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ - var args = Array.prototype.slice.call(arguments); - return object.prototype[property].apply(args.shift(), args); - }; -}; - -Native.implement = function(objects, properties){ - for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); -}; - -Native.typize = function(object, family){ - if (!object.type) object.type = function(item){ - return ($type(item) === family); - }; -}; - -(function(){ - var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; - for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); - - var types = {'boolean': Boolean, 'native': Native, 'object': Object}; - for (var t in types) Native.typize(types[t], t); - - var generics = { - 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], - 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] - }; - for (var g in generics){ - for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true); - } -})(); - -var Hash = new Native({ - - name: 'Hash', - - initialize: function(object){ - if ($type(object) == 'hash') object = $unlink(object.getClean()); - for (var key in object) this[key] = object[key]; - return this; - } - -}); - -Hash.implement({ - - forEach: function(fn, bind){ - for (var key in this){ - if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); - } - }, - - getClean: function(){ - var clean = {}; - for (var key in this){ - if (this.hasOwnProperty(key)) clean[key] = this[key]; - } - return clean; - }, - - getLength: function(){ - var length = 0; - for (var key in this){ - if (this.hasOwnProperty(key)) length++; - } - return length; - } - -}); - -Hash.alias('forEach', 'each'); - -Array.implement({ - - forEach: function(fn, bind){ - for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); - } - -}); - -Array.alias('forEach', 'each'); - -function $A(iterable){ - if (iterable.item){ - var l = iterable.length, array = new Array(l); - while (l--) array[l] = iterable[l]; - return array; - } - return Array.prototype.slice.call(iterable); -}; - -function $arguments(i){ - return function(){ - return arguments[i]; - }; -}; - -function $chk(obj){ - return !!(obj || obj === 0); -}; - -function $clear(timer){ - clearTimeout(timer); - clearInterval(timer); - return null; -}; - -function $defined(obj){ - return (obj != undefined); -}; - -function $each(iterable, fn, bind){ - var type = $type(iterable); - ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); -}; - -function $empty(){}; - -function $extend(original, extended){ - for (var key in (extended || {})) original[key] = extended[key]; - return original; -}; - -function $H(object){ - return new Hash(object); -}; - -function $lambda(value){ - return ($type(value) == 'function') ? value : function(){ - return value; - }; -}; - -function $merge(){ - var args = Array.slice(arguments); - args.unshift({}); - return $mixin.apply(null, args); -}; - -function $mixin(mix){ - for (var i = 1, l = arguments.length; i < l; i++){ - var object = arguments[i]; - if ($type(object) != 'object') continue; - for (var key in object){ - var op = object[key], mp = mix[key]; - mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); - } - } - return mix; -}; - -function $pick(){ - for (var i = 0, l = arguments.length; i < l; i++){ - if (arguments[i] != undefined) return arguments[i]; - } - return null; -}; - -function $random(min, max){ - return Math.floor(Math.random() * (max - min + 1) + min); -}; - -function $splat(obj){ - var type = $type(obj); - return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; -}; - -var $time = Date.now || function(){ - return +new Date; -}; - -function $try(){ - for (var i = 0, l = arguments.length; i < l; i++){ - try { - return arguments[i](); - } catch(e){} - } - return null; -}; - -function $type(obj){ - if (obj == undefined) return false; - if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; - if (obj.nodeName){ - switch (obj.nodeType){ - case 1: return 'element'; - case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; - } - } else if (typeof obj.length == 'number'){ - if (obj.callee) return 'arguments'; - else if (obj.item) return 'collection'; - } - return typeof obj; -}; - -function $unlink(object){ - var unlinked; - switch ($type(object)){ - case 'object': - unlinked = {}; - for (var p in object) unlinked[p] = $unlink(object[p]); - break; - case 'hash': - unlinked = new Hash(object); - break; - case 'array': - unlinked = []; - for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); - break; - default: return object; - } - return unlinked; -}; - - -/* -Script: Browser.js - The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. - -License: - MIT-style license. -*/ - -var Browser = $merge({ - - Engine: {name: 'unknown', version: 0}, - - Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, - - Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, - - Plugins: {}, - - Engines: { - - presto: function(){ - return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); - }, - - trident: function(){ - return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4); - }, - - webkit: function(){ - return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); - }, - - gecko: function(){ - return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18); - } - - } - -}, Browser || {}); - -Browser.Platform[Browser.Platform.name] = true; - -Browser.detect = function(){ - - for (var engine in this.Engines){ - var version = this.Engines[engine](); - if (version){ - this.Engine = {name: engine, version: version}; - this.Engine[engine] = this.Engine[engine + version] = true; - break; - } - } - - return {name: engine, version: version}; - -}; - -Browser.detect(); - -Browser.Request = function(){ - return $try(function(){ - return new XMLHttpRequest(); - }, function(){ - return new ActiveXObject('MSXML2.XMLHTTP'); - }); -}; - -Browser.Features.xhr = !!(Browser.Request()); - -Browser.Plugins.Flash = (function(){ - var version = ($try(function(){ - return navigator.plugins['Shockwave Flash'].description; - }, function(){ - return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); - }) || '0 r0').match(/\d+/g); - return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; -})(); - -function $exec(text){ - if (!text) return text; - if (window.execScript){ - window.execScript(text); - } else { - var script = document.createElement('script'); - script.setAttribute('type', 'text/javascript'); - script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; - document.head.appendChild(script); - document.head.removeChild(script); - } - return text; -}; - -Native.UID = 1; - -var $uid = (Browser.Engine.trident) ? function(item){ - return (item.uid || (item.uid = [Native.UID++]))[0]; -} : function(item){ - return item.uid || (item.uid = Native.UID++); -}; - -var Window = new Native({ - - name: 'Window', - - legacy: (Browser.Engine.trident) ? null: window.Window, - - initialize: function(win){ - $uid(win); - if (!win.Element){ - win.Element = $empty; - if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 - win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; - } - win.document.window = win; - return $extend(win, Window.Prototype); - }, - - afterImplement: function(property, value){ - window[property] = Window.Prototype[property] = value; - } - -}); - -Window.Prototype = {$family: {name: 'window'}}; - -new Window(window); - -var Document = new Native({ - - name: 'Document', - - legacy: (Browser.Engine.trident) ? null: window.Document, - - initialize: function(doc){ - $uid(doc); - doc.head = doc.getElementsByTagName('head')[0]; - doc.html = doc.getElementsByTagName('html')[0]; - if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ - doc.execCommand("BackgroundImageCache", false, true); - }); - if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() { - doc.window.detachEvent('onunload', arguments.callee); - doc.head = doc.html = doc.window = null; - }); - return $extend(doc, Document.Prototype); - }, - - afterImplement: function(property, value){ - document[property] = Document.Prototype[property] = value; - } - -}); - -Document.Prototype = {$family: {name: 'document'}}; - -new Document(document); - - -/* -Script: Array.js - Contains Array Prototypes like each, contains, and erase. - -License: - MIT-style license. -*/ - -Array.implement({ - - every: function(fn, bind){ - for (var i = 0, l = this.length; i < l; i++){ - if (!fn.call(bind, this[i], i, this)) return false; - } - return true; - }, - - filter: function(fn, bind){ - var results = []; - for (var i = 0, l = this.length; i < l; i++){ - if (fn.call(bind, this[i], i, this)) results.push(this[i]); - } - return results; - }, - - clean: function() { - return this.filter($defined); - }, - - indexOf: function(item, from){ - var len = this.length; - for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ - if (this[i] === item) return i; - } - return -1; - }, - - map: function(fn, bind){ - var results = []; - for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); - return results; - }, - - some: function(fn, bind){ - for (var i = 0, l = this.length; i < l; i++){ - if (fn.call(bind, this[i], i, this)) return true; - } - return false; - }, - - associate: function(keys){ - var obj = {}, length = Math.min(this.length, keys.length); - for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; - return obj; - }, - - link: function(object){ - var result = {}; - for (var i = 0, l = this.length; i < l; i++){ - for (var key in object){ - if (object[key](this[i])){ - result[key] = this[i]; - delete object[key]; - break; - } - } - } - return result; - }, - - contains: function(item, from){ - return this.indexOf(item, from) != -1; - }, - - extend: function(array){ - for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); - return this; - }, - - getLast: function(){ - return (this.length) ? this[this.length - 1] : null; - }, - - getRandom: function(){ - return (this.length) ? this[$random(0, this.length - 1)] : null; - }, - - include: function(item){ - if (!this.contains(item)) this.push(item); - return this; - }, - - combine: function(array){ - for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); - return this; - }, - - erase: function(item){ - for (var i = this.length; i--; i){ - if (this[i] === item) this.splice(i, 1); - } - return this; - }, - - empty: function(){ - this.length = 0; - return this; - }, - - flatten: function(){ - var array = []; - for (var i = 0, l = this.length; i < l; i++){ - var type = $type(this[i]); - if (!type) continue; - array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); - } - return array; - }, - - hexToRgb: function(array){ - if (this.length != 3) return null; - var rgb = this.map(function(value){ - if (value.length == 1) value += value; - return value.toInt(16); - }); - return (array) ? rgb : 'rgb(' + rgb + ')'; - }, - - rgbToHex: function(array){ - if (this.length < 3) return null; - if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; - var hex = []; - for (var i = 0; i < 3; i++){ - var bit = (this[i] - 0).toString(16); - hex.push((bit.length == 1) ? '0' + bit : bit); - } - return (array) ? hex : '#' + hex.join(''); - } - -}); - - -/* -Script: Function.js - Contains Function Prototypes like create, bind, pass, and delay. - -License: - MIT-style license. -*/ - -Function.implement({ - - extend: function(properties){ - for (var property in properties) this[property] = properties[property]; - return this; - }, - - create: function(options){ - var self = this; - options = options || {}; - return function(event){ - var args = options.arguments; - args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); - if (options.event) args = [event || window.event].extend(args); - var returns = function(){ - return self.apply(options.bind || null, args); - }; - if (options.delay) return setTimeout(returns, options.delay); - if (options.periodical) return setInterval(returns, options.periodical); - if (options.attempt) return $try(returns); - return returns(); - }; - }, - - run: function(args, bind){ - return this.apply(bind, $splat(args)); - }, - - pass: function(args, bind){ - return this.create({bind: bind, arguments: args}); - }, - - bind: function(bind, args){ - return this.create({bind: bind, arguments: args}); - }, - - bindWithEvent: function(bind, args){ - return this.create({bind: bind, arguments: args, event: true}); - }, - - attempt: function(args, bind){ - return this.create({bind: bind, arguments: args, attempt: true})(); - }, - - delay: function(delay, bind, args){ - return this.create({bind: bind, arguments: args, delay: delay})(); - }, - - periodical: function(periodical, bind, args){ - return this.create({bind: bind, arguments: args, periodical: periodical})(); - } - -}); - - -/* -Script: Number.js - Contains Number Prototypes like limit, round, times, and ceil. - -License: - MIT-style license. -*/ - -Number.implement({ - - limit: function(min, max){ - return Math.min(max, Math.max(min, this)); - }, - - round: function(precision){ - precision = Math.pow(10, precision || 0); - return Math.round(this * precision) / precision; - }, - - times: function(fn, bind){ - for (var i = 0; i < this; i++) fn.call(bind, i, this); - }, - - toFloat: function(){ - return parseFloat(this); - }, - - toInt: function(base){ - return parseInt(this, base || 10); - } - -}); - -Number.alias('times', 'each'); - -(function(math){ - var methods = {}; - math.each(function(name){ - if (!Number[name]) methods[name] = function(){ - return Math[name].apply(null, [this].concat($A(arguments))); - }; - }); - Number.implement(methods); -})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); - - -/* -Script: String.js - Contains String Prototypes like camelCase, capitalize, test, and toInt. - -License: - MIT-style license. -*/ - -String.implement({ - - test: function(regex, params){ - return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); - }, - - contains: function(string, separator){ - return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; - }, - - trim: function(){ - return this.replace(/^\s+|\s+$/g, ''); - }, - - clean: function(){ - return this.replace(/\s+/g, ' ').trim(); - }, - - camelCase: function(){ - return this.replace(/-\D/g, function(match){ - return match.charAt(1).toUpperCase(); - }); - }, - - hyphenate: function(){ - return this.replace(/[A-Z]/g, function(match){ - return ('-' + match.charAt(0).toLowerCase()); - }); - }, - - capitalize: function(){ - return this.replace(/\b[a-z]/g, function(match){ - return match.toUpperCase(); - }); - }, - - escapeRegExp: function(){ - return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); - }, - - toInt: function(base){ - return parseInt(this, base || 10); - }, - - toFloat: function(){ - return parseFloat(this); - }, - - hexToRgb: function(array){ - var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); - return (hex) ? hex.slice(1).hexToRgb(array) : null; - }, - - rgbToHex: function(array){ - var rgb = this.match(/\d{1,3}/g); - return (rgb) ? rgb.rgbToHex(array) : null; - }, - - stripScripts: function(option){ - var scripts = ''; - var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){ - scripts += arguments[1] + '\n'; - return ''; - }); - if (option === true) $exec(scripts); - else if ($type(option) == 'function') option(scripts, text); - return text; - }, - - substitute: function(object, regexp){ - return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ - if (match.charAt(0) == '\\') return match.slice(1); - return (object[name] != undefined) ? object[name] : ''; - }); - } - -}); - - -/* -Script: Hash.js - Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. - -License: - MIT-style license. -*/ - -Hash.implement({ - - has: Object.prototype.hasOwnProperty, - - keyOf: function(value){ - for (var key in this){ - if (this.hasOwnProperty(key) && this[key] === value) return key; - } - return null; - }, - - hasValue: function(value){ - return (Hash.keyOf(this, value) !== null); - }, - - extend: function(properties){ - Hash.each(properties || {}, function(value, key){ - Hash.set(this, key, value); - }, this); - return this; - }, - - combine: function(properties){ - Hash.each(properties || {}, function(value, key){ - Hash.include(this, key, value); - }, this); - return this; - }, - - erase: function(key){ - if (this.hasOwnProperty(key)) delete this[key]; - return this; - }, - - get: function(key){ - return (this.hasOwnProperty(key)) ? this[key] : null; - }, - - set: function(key, value){ - if (!this[key] || this.hasOwnProperty(key)) this[key] = value; - return this; - }, - - empty: function(){ - Hash.each(this, function(value, key){ - delete this[key]; - }, this); - return this; - }, - - include: function(key, value){ - if (this[key] == undefined) this[key] = value; - return this; - }, - - map: function(fn, bind){ - var results = new Hash; - Hash.each(this, function(value, key){ - results.set(key, fn.call(bind, value, key, this)); - }, this); - return results; - }, - - filter: function(fn, bind){ - var results = new Hash; - Hash.each(this, function(value, key){ - if (fn.call(bind, value, key, this)) results.set(key, value); - }, this); - return results; - }, - - every: function(fn, bind){ - for (var key in this){ - if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; - } - return true; - }, - - some: function(fn, bind){ - for (var key in this){ - if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; - } - return false; - }, - - getKeys: function(){ - var keys = []; - Hash.each(this, function(value, key){ - keys.push(key); - }); - return keys; - }, - - getValues: function(){ - var values = []; - Hash.each(this, function(value){ - values.push(value); - }); - return values; - }, - - toQueryString: function(base){ - var queryString = []; - Hash.each(this, function(value, key){ - if (base) key = base + '[' + key + ']'; - var result; - switch ($type(value)){ - case 'object': result = Hash.toQueryString(value, key); break; - case 'array': - var qs = {}; - value.each(function(val, i){ - qs[i] = val; - }); - result = Hash.toQueryString(qs, key); - break; - default: result = key + '=' + encodeURIComponent(value); - } - if (value != undefined) queryString.push(result); - }); - - return queryString.join('&'); - } - -}); - -Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); - - -/* -Script: Event.js - Contains the Event Native, to make the event object completely crossbrowser. - -License: - MIT-style license. -*/ - -var Event = new Native({ - - name: 'Event', - - initialize: function(event, win){ - win = win || window; - var doc = win.document; - event = event || win.event; - if (event.$extended) return event; - this.$extended = true; - var type = event.type; - var target = event.target || event.srcElement; - while (target && target.nodeType == 3) target = target.parentNode; - - if (type.test(/key/)){ - var code = event.which || event.keyCode; - var key = Event.Keys.keyOf(code); - if (type == 'keydown'){ - var fKey = code - 111; - if (fKey > 0 && fKey < 13) key = 'f' + fKey; - } - key = key || String.fromCharCode(code).toLowerCase(); - } else if (type.match(/(click|mouse|menu)/i)){ - doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; - var page = { - x: event.pageX || event.clientX + doc.scrollLeft, - y: event.pageY || event.clientY + doc.scrollTop - }; - var client = { - x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, - y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY - }; - if (type.match(/DOMMouseScroll|mousewheel/)){ - var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; - } - var rightClick = (event.which == 3) || (event.button == 2); - var related = null; - if (type.match(/over|out/)){ - switch (type){ - case 'mouseover': related = event.relatedTarget || event.fromElement; break; - case 'mouseout': related = event.relatedTarget || event.toElement; - } - if (!(function(){ - while (related && related.nodeType == 3) related = related.parentNode; - return true; - }).create({attempt: Browser.Engine.gecko})()) related = false; - } - } - - return $extend(this, { - event: event, - type: type, - - page: page, - client: client, - rightClick: rightClick, - - wheel: wheel, - - relatedTarget: related, - target: target, - - code: code, - key: key, - - shift: event.shiftKey, - control: event.ctrlKey, - alt: event.altKey, - meta: event.metaKey - }); - } - -}); - -Event.Keys = new Hash({ - 'enter': 13, - 'up': 38, - 'down': 40, - 'left': 37, - 'right': 39, - 'esc': 27, - 'space': 32, - 'backspace': 8, - 'tab': 9, - 'dele... [truncated message content] |
From: <neb...@us...> - 2009-10-28 23:45:41
|
Revision: 1899 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1899&view=rev Author: nebelschwade Date: 2009-10-28 23:45:32 +0000 (Wed, 28 Oct 2009) Log Message: ----------- Nice Code-Documentation and Whitespace for everything. Modified Paths: -------------- trunk/src/moosique.net/README.txt trunk/src/moosique.net/css/index.php trunk/src/moosique.net/css/reset.css trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/debug.js trunk/src/moosique.net/js/index.php trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/DataHelper.php trunk/src/moosique.net/moosique/classes/Debugger.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/LastFM.php trunk/src/moosique.net/moosique/classes/Recommendations.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/index.php trunk/src/moosique.net/moosique/main.wsdl Modified: trunk/src/moosique.net/README.txt =================================================================== --- trunk/src/moosique.net/README.txt 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/README.txt 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,6 +1,8 @@ Installation-Requirements: ========================== +TODO: write me! + See /moosique/config.ini - PHP 5.2.x Modified: trunk/src/moosique.net/css/index.php =================================================================== --- trunk/src/moosique.net/css/index.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/css/index.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,14 +1,18 @@ <?php -/* This little Script takes all included css-files and +/** + * This little Script takes all included css-files and * compresses them by removing comments, line-breaks and * useless space-characters + * + * @package moosique.net + * @author Steffen Becker */ header('Content-type: text/css'); // set offset to 365 days = 1 year $offset = 60 * 60 * 24 * 365; header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $offset) . ' GMT'); -ob_start('compress'); /* uncomment for deployment, smaller css-files */ +ob_start('compress'); /* comment for development, smaller css-files */ // ob_start(); function compress($buffer) { Modified: trunk/src/moosique.net/css/reset.css =================================================================== --- trunk/src/moosique.net/css/reset.css 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/css/reset.css 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,4 +1,4 @@ -/* default minimal basic css reset */ +/* default minimal basic css reset by Steffen Becker */ /* =================================================================== */ @media all { html, body, div, h1, h2, h3, Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/css/style.css 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,3 +1,16 @@ +/* moosique.net by Steffen Becker + +Colors are: + +Green: 1fd611 +Background-Grey: 3a3a3a +Button-BG-Grey 4a4a4a +Highlight-Grey: 5a5a5a +Dark-Grey: 292929 +White (Text): f1f7e4 + +*/ + @media screen { /*=============== Default Styling ===============*/ body { font: normal 12px/18px Verdana, Arial, sans-serif; color: #f1f7e4; @@ -45,7 +58,7 @@ #playerControls { position: absolute; top: 70px; right: 0; width: 170px; height: 60px; padding: 10px 20px; background: #292929; } #playerControls a:active { position: relative; top: 2px; } -#status { background: #393939; height: 60px; line-height: 60px; text-align: center; +#status { background: #3a3a3a; height: 60px; line-height: 60px; text-align: center; font-weight: bold; border: 1px solid #1fd611; z-index: 1000; } #playing span { display: block; margin-bottom: 0; font-size: 10px; } #playing .track { font: bold 12px/32px Verdana, Arial, sans-serif; } @@ -83,8 +96,8 @@ /*=============== Search Results, Recommendations & Playlist ===============*/ .results h3 a { font-weight: normal; } -.results img { border: 2px solid #545454; max-width: 308px; max-height: 308px; } -.results li { float: left; width: 312px; border: 1px solid #545454; padding: 18px; margin-bottom: 18px; } +.results img { border: 2px solid #5a5a5a; max-width: 308px; max-height: 308px; } +.results li { float: left; width: 312px; border: 1px solid #5a5a5a; padding: 18px; margin-bottom: 18px; } .results li.odd { margin-right: 18px; clear: both; } .results ul ul { list-style: disc; } .results li li, Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/index.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,4 +1,11 @@ -<?php session_start(); ?> +<?php + session_start(); + /* + Welcome to moosique.net - a semantic web based internet-radio + + see README.txt for more details + */ +?> <!DOCTYPE html> <html lang="en"> <head> @@ -146,7 +153,7 @@ <?php include('moosique/classes/Config.php'); $c = new Config(); - if ($c->getConfig('debug') == 1) /* debugging active */ { + if ($c->getConfig('debug') == 1) /* if debugging is active include js without compressing anything */ { ?> <script src="http://mediaplayer.yahoo.com/js"></script> <script src="js/mootools-1.2.4-core-nc.js"></script> Modified: trunk/src/moosique.net/js/debug.js =================================================================== --- trunk/src/moosique.net/js/debug.js 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/js/debug.js 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,4 +1,9 @@ -// New Debugger-Class using the mootools-log +/** + * Debugger-Class using the mootools-log + * + * @package moosique.net + * @author Steffen Becker + */ var Debugger = new Class({ Implements: Log, initialize: function(){ Modified: trunk/src/moosique.net/js/index.php =================================================================== --- trunk/src/moosique.net/js/index.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/js/index.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,8 +1,12 @@ <?php -/* This little Script takes all included js-files and +/** + * This little Script takes all included js-files and * compresses them with the PHP-Variant of js-min * found here: http://code.google.com/p/jsmin-php/ - * This file is only used in non-debugging-mode + * This is only used in non-debugging-mode + * + * @package moosique.net + * @author Steffen Becker */ header('Content-type: application/javascript'); $offset = 60 * 60 * 24 * 365; // set offset to 365 days = 1 year Modified: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/js/moosique.js 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,8 +1,11 @@ /** * moosique-Player-Class * + * TODO * * + * @package moosique.net + * @author Steffen Becker */ var Moosique = new Class({ Implements: Options, @@ -76,7 +79,6 @@ * for the YMP-Events and initializes the Player. Events are: * onProgress, onPlaylistUpdate, onTrackPause, onTrackStart, onTrackComplete * where onProgress is the most important event-handler, because this is where the learning-process is fired - * */ applyYahooMediaPlayerConfig: function() { var that = this; @@ -252,7 +254,6 @@ /** * Send an ajax-request to generate the recommendations and passes the * result to the corresponding html-container - * */ generateRecommendations: function() { var that = this; @@ -294,7 +295,6 @@ /** * Updates the recently-Listened-To UL-List Element with the contents * from the recentlyListened-Cookie and makes them re-addable to the playlist - * */ updateRecently: function() { var that = this; @@ -378,7 +378,6 @@ /** * This function stops the player and displays the default * status-message "Player stopped", also refreshes the playlist - * */ stopPlaying: function() { var that = this; @@ -411,7 +410,6 @@ /** * Adds click-Events to the Interface for Tabs and invokes * addEventsToButtons() - * */ initInterface: function() { var that = this; @@ -448,7 +446,7 @@ this.addEventsToButtons(); }, - + /** * Make the search-Form an ajax-Search form, displaying the results * on the homepage if successful @@ -499,7 +497,6 @@ }, - /** * For Recommendations and Search-Results * This function searches for all links with the class addToPlaylist @@ -520,11 +517,11 @@ // determine if the link is to an album or a single track var href = a.get('href'); var rel = a.get('rel'); - + var type = ''; if (href.match(/jamendo\.com\/get\/track\/id\//gi)) { type = 'playlist'; } if (href.match(/\.mp3/)) { type = 'mp3File'; } - + // if the addable item is a playlist, we have to get the playlistitems if (type == 'playlist') { var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', @@ -586,7 +583,6 @@ /** * This function adds a random song from a random record from the * recommendations results to the playlist (enqueue at the end) - * */ addRandomToPlaylist: function() { var that = this; Modified: trunk/src/moosique.net/js/start.js =================================================================== --- trunk/src/moosique.net/js/start.js 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/js/start.js 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,4 +1,4 @@ -// Default Player Config for moosique.net +// Default Yahoo Media Player Config for moosique.net var YMPParams = { autoplay: false, parse: false, // do not parse initial content Modified: trunk/src/moosique.net/moosique/classes/Config.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Config.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/Config.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,8 +1,11 @@ <?php /** - * A General Config-Class for retrieving values from config.ini - * and initializing the Debugger + * The basic Config class, stores all configuration in itself and + * initializes a debugger if debugging is active + * + * @package moosique.net + * @author Steffen Becker */ class Config { @@ -12,6 +15,7 @@ /** * On Class initialization, read the ini file to get * the config values and hand them to $this->config + * and create a new debugger-class if debugging is activated */ function __construct() { $this->config = parse_ini_file(dirname(__FILE__) . '/../config.ini', true); @@ -41,8 +45,8 @@ /** * Returns the value of a last-fm config-entry from config.ini * - * @return String The wanted Configvalue - * @param String Value for the wanted Configvalue + * @return string The wanted LastFM-Configvalue + * @param string Value for the wanted Configvalue */ public function getConfigLastFM($value) { return $this->config['lastFM'][$value]; @@ -52,13 +56,15 @@ /** * Returns the value of an URL defined in config.ini * - * @return String The wanted Url - * @param String Value for the wanted Url + * @return string The wanted Url + * @param string Value for the wanted Url */ public function getConfigUrl($value) { - if ($value == 'wsdlLocal' || $value == 'allTags' || $value == 'allRecords') { + // prepend base-url for wsdl and allRecords + if ($value == 'wsdlLocal' || $value == 'allRecords') { return $this->config['url']['base'] . $this->config['url'][$value]; } + // prepend absPath (file:/) for ontology if ($value == 'tagOntology') { return 'file:' . $this->config['url']['absPath'] . $this->config['url'][$value]; } @@ -67,10 +73,10 @@ /** - * This funtion returns one (if specified) or all learning-Config entries from config.ini + * This funtion returns one (if specified) or all learning-Config values from config.ini * - * @param String Value for a single learning-Configuration - * @return Mixed The wanted value as a string, or - if not specified - complete learingConfig as an array + * @param string Value for a single learning-Configuration, optional + * @return mixed The wanted value as a string, or - if not specified - complete learingConfig as an array */ public function getConfigLearning($prefix = false) { @@ -89,8 +95,8 @@ /** * This funtion returns one (if specified) or all prefixes from the config.ini * - * @param String String-Value for a single prefix - * @return Mixed The wanted prefix as a string, or - if not specified - all Prefixes as an array + * @param string String-Value for a single prefix, optional + * @return mixed The wanted prefix as a string, or - if not specified - all Prefixes as an array */ public function getConfigPrefixes($prefix = false) { if ($prefix !== false) { @@ -106,5 +112,4 @@ } - ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/DataHelper.php =================================================================== --- trunk/src/moosique.net/moosique/classes/DataHelper.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/DataHelper.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,13 +1,19 @@ <?php - +/** + * This class provides functions to get Data from the SPARQL-Endpoints + * and to prepare and use this data with different array/object methods + * + * @package moosique.net + * @author Steffen Becker + */ class DataHelper extends Config { - public $connection; + public $connection; // here we save the dl-learnerconnection for public access /** - * - * - * + * Get config (parent) and establish a connection to the dl-learner webservice + * + * @author Steffen Becker */ function __construct() { parent::__construct(); // init config @@ -16,8 +22,12 @@ /** + * Get Data from a search using a SPARQL-Requst over the DL-Learner * - * + * @param mixed $search String/Array with the search-Value, array for more than one value + * @param string $type the type of search performed (tagSearch, albumSearch etc.) + * @return array The resulting Data, prepared and ready for use + * @author Steffen Becker */ public function getData($search, $type) { $sparql = new SparqlQueryBuilder($search, $type); @@ -38,10 +48,12 @@ * Cleans up objects or retrieves them from a XML-File (for playlists) * and converts them into arrays for use in the view class * - * @param Mixed $data The Data-Object (from a Sparql-Query or a playlist-array) - * @param String $type To define what kind of data to prepare - * @return Array A multidimensional Array ready for processing for HTML-output - */ + * @param mixed $data The Data-Object (from a Sparql-Query or a playlist-array) + * @param string $type the type of search performed (tagSearch, albumSearch etc.) + * @param mixed $search String/Array with the search-Value, array for more than one value + * @return array A multidimensional Array ready for processing for HTML-output + * @author Steffen Becker + */ public function prepareData($data, $type, $search) { $mergedArray = array(); @@ -78,11 +90,12 @@ /** * This function merges the result-Object to a nice array * we can process easily. The array is created by type, - * returning the data sorted for artist, tag or song + * returning the data sorted for artist, tag or song etc. * - * @param Object $data - * @param String $type This can be 'artist', 'tag' or 'song' - * @return Array A Multidimensional array sorted by type for output-use + * @param object $data + * @param string $type This can be 'artist', 'tag' or 'song' etc. without 'Search' + * @return array a Multidimensional array sorted by type for output-use (or false) + * @author Steffen Becker */ private function mergeArray($data, $type) { // convert the $data-response object to an array @@ -105,11 +118,13 @@ } else return false; } + /** * Like the php-function array_unique, but for multidimensional arrays, calls itself recursively * - * @return Array (Multidimensional) array without double entries - * @param Array $array The Array to clean up + * @param array $array The Array to clean up + * @return array (Multidimensional) array without double entries + * @author Steffen Becker */ private function arrayUnique($array) { $newArray = array(); @@ -134,34 +149,32 @@ /** - * Converts a simple Object to an array + * Converts an object to an array recursively * - * @return Array the Array created from the Object - * @param object $obj The Object to convert + * @param object $object The object to convert + * @return the corresponding array created from the object + * @author Steffen Becker */ - private function object2array($obj) { - $arr = array(); - $_arr = is_object($obj) ? get_object_vars($obj) : $obj; - foreach ($_arr as $key => $val) { - $val = (is_array($val) || is_object($val)) ? $this->object2array($val) : $val; - $arr[$key] = $val; + private function object2array($object) { + $array = array(); + $_array = is_object($object) ? get_object_vars($object) : $object; + foreach ($_array as $key => $value) { + $value = (is_array($value) || is_object($value)) ? $this->object2array($value) : $value; + $array[$key] = $value; } - return $arr; + return $array; } /** - * Establishes a new Dl-Learner Connection and saves it in - * private $connection for class-wide use. + * Establishes a new Dl-Learner Connection * - * @return + * @author Steffen Becker */ private function establishConnection() { $this->connection = new DllearnerConnection(); } - } - ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/Debugger.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Debugger.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/Debugger.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -4,34 +4,38 @@ * General Debugger-Class, implementing a FirePHP-Debugger, * for usage see http://www.firephp.org/HQ/Use.htm * - * Usage for Classees implementing Config.php + * Usage for Classees implementing Config.php: * if ($this->debugger) $this->debugger->log($data, "Label"); * + * @package moosique.net + * @author Steffen Becker */ class Debugger { - // instance of the FirePHP-Class - private $fb; + private $fb; // instance of the FirePHP-Class /** * Initializes the Debugger by inlcuding and instanciating FirePHP + * + * @author Steffen Becker */ function __construct() { require_once('FirePHP.class.php'); $this->fb = FirePHP::getInstance(true); } + /** * Logs an Object using FirePHP * - * @param Object $var Any Object, Array, String to log - * @param String $label The Label for the Object to log + * @param mixed $var Any object, array, string etc. to log + * @param string $label The label for the object to log + * @author Steffen Becker */ public function log($var, $label) { $this->fb->log($var, $label); } - } ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/DllearnerConnection.php =================================================================== --- trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,50 +1,52 @@ <?php - /** - * + * This Class handles the connection to the DL-Learner WebService + * and sends/receives all request (Sparql/Learning) to it + * + * @package moosique.net + * @author Steffen Becker */ -class DllearnerConnection extends Config { - - private $knowledgeSourceID; +class DllearnerConnection extends Config { + + private $knowledgeSourceID; // the id for the knowledge-source private $client; // here we store the soap-client private $endpoint; // the currently used endpoint - // use getEndpoint and setEndpoint to change /** - * Object initializing: retrieve ini-values, set the endpoint + * Object initializing: retrieve ini-values (parent::__constuct), set the endpoint * and include the neccessary wsdl-utilities and try to establish * a connection to the dl-learner webservice * + * @author Steffen Becker */ - function __construct() { - parent::__construct(); // init config + function __construct() { + parent::__construct(); // init config // we use jamendo as the default sparql-endpoint $this->setEndpoint($this->getConfigUrl('jamendo')); - // load WSDL files (has to be done due to a Java web service bug) ini_set('soap.wsdl_cache_enabled', '0'); include('Utilities.php'); Utilities::loadWSDLfiles($this->getConfigUrl('wsdl')); $this->connect(); - } + } + /** * Tries to connect to the DL-Learner Webservice using the Tools - * from Utilities.php. Sets private var client. + * from Utilities.php. Sets private var client if successful * + * @author Steffen Becker */ private function connect() { - // connect to DL-Learner-Web-Service - try { - $this->client = new SoapClient($this->getConfigUrl('wsdlLocal')); + try { + $this->client = new SoapClient($this->getConfigUrl('wsdlLocal')); } catch (Exception $e) { if ($this->debugger) $this->debugger->log($e, "Error connecting to the DL-Learner Webservice."); echo '<h2>Could not connect to the DL-Learner Webservice.</h2>'; exit; } - // After establishing the SoapClient we create a Session ID - // and add the default knowledgeSource (see config.ini) + // and add the default knowledgeSource if (isset($_SESSION['sessionID'])) { // if there is a current session running, we don't need to // register a new client at the dl-learner webservice @@ -70,34 +72,37 @@ $_SESSION['sessionID'] = $this->client->generateID(); $this->knowledgeSourceID = $this->client->addKnowledgeSource($_SESSION['sessionID'], 'sparql', $this->endpoint); } - - } - + } + + /** * Sets the SPARQL-endpoint, the DL-Learner Webservice is connecting to - * - * @param String $endpoint The URI of the SPARQL-Endpoint to set + * + * @param string $endpoint The URI of the SPARQL-Endpoint to set + * @author Steffen Becker */ public function setEndpoint($endpoint) { $this->endpoint = $endpoint; } + /** * Returns a String with the URI for the SPARQL-Endpoint currently used * - * @return String The Endpoint URI currently used + * @return string The Endpoint URI currently used + * @author Steffen Becker */ public function getEndpoint() { return $this->endpoint; } + /** - * This method tries to create a connectionID from the DL-Learner - * Webservice and returns a JSON-object with the results from the - * Sparql-Query sent to the current endpoint + * Uses the Webservice to get results from a SPARQL-Query from the current endpoint * - * @return String A JSON-Object with the containing result-set - * @param String $query The SPARQL-Querystring to send + * @param string $query The SPARQL-Querystring to send + * @return string A JSON-Object with the containing results + * @author Steffen Becker */ public function sparqlQuery($query) { $result = $this->client->sparqlQuery($_SESSION['sessionID'], $this->knowledgeSourceID, $query); @@ -107,14 +112,13 @@ /** * Bulid the exclusion-String-Array from config.ini for faster - * recommendation-generation + * recommendation-generation. The Exclusions are the fragments/nodes + * that will not be extracted * - * @param Array $conf The Learning-Conf Array - * @return Array The Array of String with predicates to exclude + * @param array $conf The Learning-Conf Array + * @return array The Array of Strings with predicates to exclude */ private function getExclusions($conf) { - // exclude from node expansion that are not relevant for any learning processes - // this speeds up the general node-extraction $exclusionsArray = array(); $exclude = explode(',', $conf['exclude']); foreach($exclude as $exclusion) { @@ -125,10 +129,14 @@ return $exclusionsArray; } + /** + * Creates a learning request with the given instances an positive Examples * - * - * + * @param array $instances An Array of strings with the URLs to the instances + * @param array $positiveExamples An Array of strings with positive Example URLS + * @return string A JSON Object with the results + * @author Steffen Becker */ public function learn($instances, $positiveExamples) { $result = false; @@ -168,16 +176,19 @@ // after we have set all conf-values, we initialize the learning process $this->client->initAll($id); - $result = $this->client->learnDescriptionsEvaluated($id); return $result; - } + /** * Converts a natural Description in a SPARQL-Query for recommendation retrieval - * - */ + * and adds the global limit set in maxResults + * + * @param string $kb Result-String in KB-Syntax + * @return string A SPARQL-Query String for the KB-Syntax + * @author Steffen Becker + */ public function kbToSqarql($kb) { return $this->client->SparqlRetrieval($kb, $this->getConfig('maxResults')); } Modified: trunk/src/moosique.net/moosique/classes/LastFM.php =================================================================== --- trunk/src/moosique.net/moosique/classes/LastFM.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/LastFM.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,19 +1,35 @@ <?php - +/** + * This class handles all connections to the last.fm-API for retrieving + * tags for a given username. If the user has no tags, the topTags for + * topArtists are used as tags + * + * @package moosique.net + * @author Steffen Becker + */ class LastFM extends Config { - private $topTags; + private $topTags; // save tags here + /** + * Initializing class requires the last.fm username + * + * @param string $user The last.fm Username + * @author Steffen Becker + */ function __construct($user) { parent::__construct(); // init config - $this->getLastFMTags($user); } + /** + * Gets the Top-Tags for a last.fm user. The number of Tags to retrieve + * is set in config.ini * - * - * + * @param string $user The last.fm username + * @return array An array with the top tags for $user + * @author Steffen Becker */ private function getLastFMTags($user) { $allTags = array(); @@ -44,10 +60,15 @@ $this->topTags = $allTags; } + /** + * This is called if the user has no Tags. This function tries to get the + * topArtists from the user and then tries to get the topTags for the + * artists -- the most listened to artists are a good base for useful tags * - * - * + * @param string $user The last.fm Username + * @return array An array with the topTags for the Topartists from $user + * @author Steffen Becker */ private function getTagsFromTopArtists($user) { $allArtists = array(); @@ -69,7 +90,6 @@ $allArtists = array_slice($allArtists, 0, $this->getConfigLastFM('topArtists')); // get the topTags for every artist - foreach($allArtists as $artistName) { $requestUrl = $this->getConfigLastFM('artistsTopTagsUrl') . '&artist=' . urlencode($artistName) @@ -91,16 +111,17 @@ return $finalTags; } + /** + * Returns the topTags * - * - * + * @return array An Array of strings ('rock', 'doom metal' etc.) with the Top-Tags + * @author Steffen Becker */ public function getTopTags() { return $this->topTags; } - } ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/Recommendations.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Recommendations.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/Recommendations.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,19 +1,35 @@ <?php - +/** + * This class provides methods for recommendations-creation, + * setting and getting positive examples and instances and + * creating and retrieving recommendations using a connection + * to the DL-Learner + * + * @package moosique.net + * @author Steffen Becker + */ class Recommendations extends Config { private $posExamples; private $instances; + /** + * Only used for getting the global config in this class + * + * @author Steffen Becker + */ function __construct() { parent::__construct(); // init config } + /** * Returns an array of prepared serach-statements to feed the sparql= * query-bulider with, converted from the natural description of the results * - * + * @param object $connection a reference to a DllearnerConnection Class + * @return mixed A multidimensional array with a SPARQL-Query, the KBsyntax and the score for all results or an error string + * @author Steffen Becker */ public function getQueries($connection) { $queries = array(); @@ -47,7 +63,6 @@ } } } - if ($match) { $sparql = $connection->kbToSqarql($solution->descriptionKBSyntax); // extract the subtring we use for the final sparql-query @@ -58,7 +73,6 @@ $queries[] = $sparql; $scores[] = $score; $kbSyntaxes[] = $solution->descriptionKBSyntax; - } } } @@ -80,11 +94,14 @@ } - /** + * This function sets the positive examples in private $posExamples + * if no array is given, it tries to get the positiveExamples from + * the cookie moosique (set by moosique.js) * - * - * + * @param array $posExamples an Array of url-strings of positive examples + * @return boolean returns false if sth. goes wrong + * @author Steffen Becker */ public function setPosExamples($posExamples = false) { if ($posExamples === false) { @@ -98,7 +115,7 @@ $posExamples = array_unique($posExamples); $this->posExamples = $posExamples; } - } + } } else { if (is_array($posExamples)) { $this->posExamples = $posExamples; @@ -108,20 +125,23 @@ } } + + /** + * This function sets the instances in private $instances + * if no array is given, it tries to create instances from + * posExamples and a random list of records from allRecords.txt + * + * TODO more testing, what is the optimum posExamples/neutral ratio, 50/50? + * for now we assume 50/50, use $totalInstances = $this->getConfigLearning('instances'); * - * - * + * @param array $instances An array of url-strings for records of instances (should contain posExamples) + * @author Steffen Becker */ public function setInstances($instances = false) { - - // TODO more testing, what is the optimum posExamples/neutral ratio, 50/50? - // for now we assume 50/50 - // $totalInstances = $this->getConfigLearning('instances'); - if ($instances === false) { $instances = array(); - // and then add some random Records _not_ in this list + // and then add some random Records _not_ already in this list $allRecords = file($this->getConfigUrl('allRecords')); $countPos = count($this->posExamples); @@ -140,14 +160,14 @@ $this->instances = $instances; } } - - } + /** - * - * - * + * Returns the positive Examples + * + * @return array Array of positive examples + * @author Steffen Becker */ public function getPosExamples() { return $this->posExamples; @@ -155,17 +175,15 @@ /** - * - * - * + * Returns the instances + * + * @return array Array of instances (containing positive Examples) + * @author Steffen Becker */ public function getInstances() { return $this->instances; } - } -?> - - +?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/RequestHandler.php =================================================================== --- trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,32 +1,37 @@ <?php - /** - * + * General Request handler - all requests made from the frontend + * are handled here. Calls the different methods and classes for + * seraching, learning and playlist/info requests. + * only accepts ajax-requests + * + * @package moosique.net + * @author Steffen Becker */ class RequestHandler extends Config { private $response; private $dataHelper; - /* This inits requestHandling, a request is - only processed, if it was called by an - xmlHTTPrequest and the get-method */ + /** + * This inits requestHandling, a request is only processed, if it was + * called by an xmlHTTPrequest and the get-method - we don't use POST at all + * + * @author Steffen Becker + */ function __construct() { parent::__construct(); // init config - $this->dataHelper = new DataHelper(); + $this->dataHelper = new DataHelper(); // we only accept ajax-get requests if ($this->isAjax() && $this->isGet()) { $this->response = $this->processRequest(); - + // and return the response if it is not empty if (!empty($this->response)) { return $this->response; } else { if (isset($_GET['searchType'])) { return "<h2>Sorry, nothing found.</h2>"; - if ($_GET['searchType'] == 'lastFM') { - return '<h2>Nothing found for the last.fm-user »' . $_GET['searchValue'] . '«.'; - } } return "<h2>The repsonse from the server was empty.</h2>"; } @@ -34,23 +39,24 @@ header('Location: ' . $this->getConfigUrl('base')); } } - + + /** - * Processes the request made through ajax, handles - * the different searches and other related requests - * - * @return + * Processes the requests made to the server in the webapplication moosique.net + * This is where the different requests are handled and data is fetched + * + * @return string The response/results as ready-to-use HTML + * @author Steffen Becker */ private function processRequest() { $response = ''; - // ========== SEARCH REQUEST ================================= + // ========== SEARCH REQUEST ============= if (isset($_GET['searchType']) && isset($_GET['searchValue'])) { $type = $_GET['searchType']; - // clean up the search value + // clean up the search value, remove unwanted chars etc. $search = $this->cleanString($_GET['searchValue'], $type); - // a search for "everything" causes 4 searches for artist, tags, album and songs // concatenating the response from all 4 searches if ($type == 'allSearch') { @@ -59,48 +65,52 @@ $response .= $this->createSearch($search, 'albumSearch'); $response .= $this->createSearch($search, 'songSearch'); } - // normal search for artist, tag or song + // normal search for artist, tag, album or song if ($type == 'artistSearch' || $type == 'tagSearch' || $type == 'songSearch' || $type == 'albumSearch') { $response = $this->createSearch($search, $type); } - // last.fm search, initiate the lastFM-Class and get the tags for the user - // then make an exakt-tag search with the result + // last.fm search, initiate the lastFM-Class and get the tags for + // the user ($search) - then make tagSearches for every result if ($type == 'lastFM') { $lastFM = new LastFM($search); $tags = $lastFM->getTopTags(); // no we have the topTags, do a search for related albums if (!empty($tags)) { foreach($tags as $tag) { - // FIXME when using last.fm-Tags for tagSearch, we want exakt results, meaning - // no "darkmetalbeermusic" as result when the lastfm tag is "metal" - // what we do here is nothing but a tag search for each tag + // ALWAYS limit the results for last-FM search $response .= $this->createSearch($this->cleanString($tag, $type), 'tagSearch', $this->getConfig('maxResults')); } - } else { // let the view handle it, displays error + } else { // let the view handle it: <h2>-Error-Message $response .= $this->createSearch($tags, $type, $this->getConfig('maxResults')); } } } - // ========== LEARNING REQUEST ================================= + + // ========== LEARNING REQUEST =========== if (isset($_GET['get']) && $_GET['get'] == 'recommendations') { - $r = new Recommendations(); // init/reset recommendations + // create a new recommendations-class and set the instances/posExamples + $r = new Recommendations(); $r->setPosExamples(); $r->setInstances(); + // get all queries/kbSyntaxes $recommendations = $r->getQueries($this->dataHelper->connection); $results = array(); + // if we have some recommendations and queries for them if (is_array($recommendations) && !empty($recommendations)) { if (!empty($recommendations['queries'])) { foreach($recommendations['queries'] as $query) { - // $data = $this->getData($query, 'recommendations', $this->getConfig('maxResults')); - // TODO no limiting, else it is not really random... + // get the results for each query created $data = $this->dataHelper->getData($query, 'recommendations'); $results[] = $data; } } + // add them to the multi-dimensional recommendations-Array, it now + // contains results, scores, syntaxes and queries $recommendations['results'] = $results; + // finally create the view for the recommendations $response .= $this->createView($recommendations, 'recommendations', '', $this->getConfig('maxResults')); } else { // an error occured during recommendation-retrieval @@ -110,7 +120,8 @@ } - // ========== ARTIST INFORMATION REQUEST ================================= + // ========== ARTIST INFORMATION REQUEST ============= + // TODO artist info, not yet implemented if (isset($_GET['info']) && !(empty($_GET['info']))) { $currentAlbum = $_GET['info']; $response .= '<p>Artist Information coming soon...</p>'; @@ -119,7 +130,7 @@ // ========== PLAYLIST REQUEST ================================= // Due to a bug in YMP we don't directly deliver the .xspf-file, we return a prepared - // list of <li> including the links to the mp3-files, and this is build in the view of course. + // list of <li> including the links to the mp3-files - and this is build in the view of course. if (isset($_GET['get']) && isset($_GET['playlist'])) { $data = array('playlist' => $_GET['playlist'], 'albumID' => $_GET['rel']); $type = $_GET['get']; @@ -128,15 +139,19 @@ $response = $this->createView($preparedData, $type, $search); } - // Finally returning the response + // matched all possible cases, in other cases response is empty return $response; } /** - * - * - * + * Creates a search request for the given SearchValue + * + * @param mixed $search The value to search for, can be a string or and array for tagSeach/lastFM + * @param string $type The type of search: tagSearch, albumSearch, songSearch etc. + * @param int $maxResults Limit for maximum shown results, optional + * @return void + * @author Steffen Becker */ private function createSearch($search, $type, $maxResults = false) { $data = $this->dataHelper->getData($search, $type); @@ -146,9 +161,14 @@ /** - * - * - * + * Creates a view for given data and searchvalue/types + * + * @param array $data The Data-Array to create the view from + * @param string $type The type of search made + * @param mixed $search The search string or array of strings (for tag/lastfm-serach) + * @param int $maxResults A limit for showing results, optional + * @return string The final HTML-Code, ready to use + * @author Steffen Becker */ private function createView($data, $type, $search, $maxResults = false) { $v = new View($data, $type, $search, $maxResults); @@ -163,7 +183,12 @@ * If the search string contains a %20-Space-Char somewhere in the middle * of the string, it returns an array of search-values, divided by " " * Doing this we later can perform more searches for values like "stoner doom metal" - * resulting in an array with [0] => stoner [1] => doom [2] => metal + * resulting in an array with [0] => stoner [1] => doom [2] => metal for better results + * + * @param string $string The searchValue the user entered + * @param string $type The type of search: artistSearch, tagSearch etc. + * @return mixed A cleaned string or an array of cleaned strings + * @author Steffen Becker */ private function cleanString($string, $type) { $remove = array('/', '?', '+', "=", '$', ',', '.', ':', ';', '\'', "\\", "\\\\"); @@ -175,7 +200,6 @@ // if lastFM-Search or exakt search, we split "death metal" into an array // containing "death" and "metal", for better search results - // TODO implement for tagSearch too if ((strpos($string, " ") > 0) && ($type == 'lastFM' || $type == 'tagSearch')) { $string = explode(" ", $string); } @@ -185,9 +209,10 @@ /** - * Returns the HTML stored in the private $response - * - * @return String HTML-Code generated + * Returns the private $response == the final HTML + * + * @return string The final HTML produced by this class + * @author Steffen Becker */ public function getResponse() { return $this->response; @@ -195,10 +220,11 @@ /** - * Checks if the request made is an AJAX-Request and returns true if so - * - * @return Boolean - */ + * Checks for an ajax-request + * + * @return boolean True if the request was made via ajax, false if not + * @author Steffen Becker + */ private function isAjax() { if ( isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') ) { @@ -210,9 +236,10 @@ /** - * Checks if the request made is a GET-Request and returns true if so + * Checks for a GET-Request * - * @return Boolean + * @return boolean True if the request is a GET-Request, false if not + * @author Steffen Becker */ private function isGet() { if (isset($_GET) && !empty($_GET)) { @@ -221,20 +248,6 @@ return false; } } - - - /** - * Checks if the request made is a POST-Request and returns true if so - * - * @return Boolean - */ - private function isPost() { - if (isset($_POST) && !empty($_POST)) { - return true; - } else { - return false; - } - } } Modified: trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,9 +1,10 @@ <?php - /** - * - * - * + * This class provides functions to build the sepcial SPARQL-Queries + * used in moosique.net + * + * @package moosique.net + * @author Steffen Becker */ class SparqlQueryBuilder extends Config { @@ -13,14 +14,13 @@ * Class-Constructor, automatically calls buildQuery with * the given variables when initalizing this class * - * @return - * @param object $search - * @param object $typeOfSearch - * @param object $limit[optional] + * @param mixed $search The clean search-Value, can be an array of values + * @param string $searchType The type of search + * @author Steffen Becker */ - function __construct($search, $searchType, $limit = 0) { + function __construct($search, $searchType) { parent::__construct(); // init config - $this->buildQuery($search, $searchType, $limit); + $this->buildQuery($search, $searchType); } @@ -28,20 +28,18 @@ * Builds the complete Sparql-Query depending on the type of search * and saves it in the private $queryString. * - * @param object $search - * @param object $typeOfSearch - * @param object $limit + * @param mixed $search The clean search-Value, can be an array of values + * @param string $searchType The type of search + * @author Steffen Becker */ private function buildQuery($search, $searchType) { - /* Build up the Prefixes */ $prefixes = ''; foreach($this->getConfigPrefixes() as $prefix => $resource) { $prefixes .= 'PREFIX ' . $prefix . ': <' . $resource . '>' . "\n"; } - // if a global limit is set, we use it - // else we use the optional limit given to the parent class when constructing it + // if the globalLimit-config-value is set, we use maxResults as LIMIT if ($this->getConfig('globalLimit') == 1) { $limit = "\n" . 'LIMIT ' . $this->getConfig('maxResults'); } else { @@ -69,10 +67,6 @@ case 'albumSearch' : $query = $this->queryAlbumSearch($search); break; case 'songSearch' : $query = $this->querySongSearch($search); break; case 'recommendations' : $query = $this->queryRecommendations($search); break; - - /* TODO build functions for other queries - case 'currentInfo' : $query = $this->queryCurrentInfo($search); break; - */ } // save the query $this->queryString = $prefixes . $beginStatement . $baseQuery . $query . $endStatement; @@ -80,10 +74,11 @@ /** - * Returns the Sparql-Query part for an artist-search + * Creates the SPARQL-Query-Part for an artist search * - * @param Mixed - * @return String Sparql-Query part for artist-search + * @param string $search The search value, sth. like "Slayer" or "Jimi Hendrix" + * @return string The SPARQL-query part for an artist search + * @author Steffen Becker */ private function queryArtistSearch($search) { $queryString = ' { @@ -102,13 +97,14 @@ /** * For a Tag-Search we display the playable records, therefore we need record and * artist information too, AlbumCover is optional - * Returns the Sparql-Query part for tag-search + * if $search is an array, this performs an exact-tagSerach instead * - * @return String Sparql-Query part for tag-search + * @param mixed $search The search value, sth. like "metal" or "breakcore", String or Array + * @return string Sparql-Query part for tag-search */ private function queryTagSearch($search) { if (is_array($search)) { - // special case again: if array, we do the exakt tagSearch + // special case: if array, we do the exakt tagSearch, we have sth. like "stoner" and "rock" $queryString = $this->queryExactTagSearch($search); } else { $queryString = ' { @@ -125,17 +121,20 @@ return $queryString; } - + /** - * - * - * - * + * This function returns the SPARQL-Query part for an exact-Tag-Search from + * a search array containing string like "stoner" "doom" "metal" + * Performs an AND-Search, a result has to have all tags from the array + * + * @param mixed $search The search array, containing strings like "stoner", "rock" etc, single string also allowed + * @return string Sparql-Query part for exact-tag-search + * @author Steffen Becker */ private function queryExactTagSearch($search) { $queryString = ' { ?record tags:taggedWithTag ?tag ; '; - + // extra check if no array, we use $search as string if (is_array($search)) { foreach($search as $tag) { $queryString .= ' tags:taggedWithTag <http://dbtune.org/jamendo/tag/' . $tag . '> ; '; @@ -150,15 +149,16 @@ FILTER (regex(str(?image), "1.100.jpg", "i")) . } } '; - return $queryString; } /** - * Returns the Sparql-Query part for album-search - * - * @return String Sparql-Query part for album-search + * Creates the SPARQL-Query part for an album-Search + * + * @param string $search The search-string, a string like "dark side of the moon", "ladyland" etc. + * @return string Sparql-Query part for an album-search + * @author Steffen Becker */ private function queryAlbumSearch($search) { $queryString = ' { @@ -177,9 +177,11 @@ /** - * Returns the Sparql-Query part for song-search - * - * @return String Sparql-Query part for song-search + * Creates the SPARQL-Query part for a song-Search + * + * @param string $search The search-string, a string like "souljacker", "purple haze" etc. + * @return string Sparql-Query part for an album-search + * @author Steffen Becker */ private function querySongSearch($search) { $queryString = ' { @@ -197,11 +199,13 @@ /** + * Creates the SPARQL-Query part for a recommendations search, this + * is much like album/tagSearch, but with additional info * - * - * - * - */ + * @param string $search The SPARQL-String retrieved from the recommendations-learn result + * @return string Sparql-Query part for a recommendation search + * @author Steffen Becker + */ private function queryRecommendations($search) { $queryString = ' { ?record mo:available_as ?playlist ; @@ -215,24 +219,22 @@ } '; // TODO ?record tags:taggedWithTag ?tag makes the queries blow up high - - // and finally we append the sparql-string from kb-Description + // and finally we append the sparql-string from kb-Description-Conversion $queryString .= $search; return $queryString; } /** - * Returns the build Query-String + * Returns the final Query-String * - * @return String Complete SPARQL-Query stored in SparqlQueryBuilder + * @return string The final Complete SPARQL-Query + * @author Steffen Becker */ public function getQuery() { return $this->queryString; } - } - ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/View.php =================================================================== --- trunk/src/moosique.net/moosique/classes/View.php 2009-10-28 11:05:25 UTC (rev 1898) +++ trunk/src/moosique.net/moosique/classes/View.php 2009-10-28 23:45:32 UTC (rev 1899) @@ -1,30 +1,46 @@ <?php /** - * This class handles all HTML-Output for all different kinds of - * requests. No Templating system is used. + * This class handles all HTML-Output for all different kinds of requests. + * It also creates error messages shown in the frontend * - * + * @package moosique.net + * @author Steffen Becker */ class View extends Config { - private $html = ''; - private $limit = 0; + private $html = ''; // the final HTML-Output is stored + private $limit = 0; // limit for showing results - // view modes are debug or both, default is html view + /** + * Creating a View automatically creates the HTML + * + * @param array $data The result-Data-array + * @param string $type the type of search performed + * @param mixed $search A string or array with the searchValues + * @param int $limit The maximum number of results to show/create HTML for, optional + * @author Steffen Becker + */ function __construct($data, $type, $search, $limit = false) { parent::__construct(); // init config - if ($limit === false) { // no special limit set, we use the maxResultsLimit + if ($limit === false) { // if no special limit set, we use maxResults $this->limit = $this->getConfig('maxResults'); } else { $this->limit = $limit; } $this->createOutput($data, $type, $search); } - - + + /** - * + * Starts creating the HTML output. First checks if the data is fine, + * and gets sub-HTML-parts afterwards, if the data is not fine, an + * error-message will be created + * + * @param array $data The result-Data-array + * @param string $type the type of search performed + * @param mixed $search A string or array with the searchValues + * @author Steffen Becker */ private function createOutput($data, $type, $search) { // if we have an array for $search (Tag or lastFM-Search) we implode the searchString @@ -85,11 +101,12 @@ /** - * - * - * - * - * + * This lmits the result-data, to a given number of results stored + * in the private $limit + * + * @param array $data The result-Data-Array + * @return array The limited array + * @author Steffen Becker */ private function limitData($data) { $count = count($data); @@ -114,8 +131,13 @@ /** - * - * @param object $data + * Returns the HTML for an artist serach, containing special stuff + * like homepage-links, album-list etc. + * + * @param array $data The result-Array to create HTML from + * @param string $type type of search to get the template + * @return string HTML for a artistSearch + * @author Steffen Becker */ private function artistSearchHTML($data, $type) { $this->html .= '<div class="artistSearch"><ul class="clearfix">'; @@ -167,8 +189,14 @@ /** - * - * @param object $array + * Returns the HTML for tagSearch results + * This is somewhat special, we first create a list of found tags, + * and then we list the albums found for those tags + * + * @param array $data The result-Array to create HTML from + * @param string $type type of search to get the template + * @return string HTML for a tagSearch + * @author Steffen Becker */ private function tagSearchHTML($data, $type) { $this->html .= '<div class="tagSearch">'; @@ -202,7 +230,7 @@ $j = $i; // default -- non random, no limit // if there is limit set, and randomize is active, we use the random numbers if ($numberOfAlbums > $this->limit && $this->getConfig('randomize') == 1) { - $j = $random[$i]; + $j = $random[$i]; // randomizing the results for the tag } $template = $this->getTemplate($type); @@ -212,9 +240,8 @@ $albumTitle = $this->getValue($tag['albumTitle'], $j); $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getValue($tag['playlist'], $j)); - $addToPlaylist = '<li><a class="addToPlaylist" href="' . $playlist . '" ' - . 'title="' . $artistName . ' - ' . $albumTitle . '" ' - . 'rel="' . $record . '">Click here to add this album to your playlist.</a></li>'; + $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' + . $artistName . ' - ' . $albumTitle . '">Click here to add this album to your playlist</a></li>'; $image = $this->getImage($tag, $artistName. ' - ' . $albumTitle, $j); @@ -229,8 +256,12 @@ /** + * Returns the HTML for albumSearch results * - * + * @param array $data The result-Array to create HTML from + * @param string $type type of search to get the template + * @return string HTML for a albumSearch + * @author Steffen Becker */ private function albumSearchHTML($data, $type) { $this->html .= '<div class="albumSearch"><ul class="clearfix">'; @@ -240,7 +271,7 @@ if (($i % 2) == 0) { $class = 'odd'; } else { $class = ''; } $template = $this->getTemplate($type); - + // $index = 0, we always want a single value and no array here $record = $this->getValue($album['record'], 0); $albumTitle = $this->getValue($album['albumTitle'], 0); $artistName = $this->getValue($album['artistName'], 0); @@ -249,7 +280,6 @@ $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' . $artistName . ' - ' . $albumTitle . '">Click here to add this album to your playlist</a></li>'; - // Artist-Image is optional $image = $this->getImage($album, $artistName . ' - ' . $albumTitle); $tags = $this->getTagList($album['tag']); @@ -264,12 +294,12 @@ /** - * - * - * - * - * - * + * Returns the HTML for songSearch results + * + * @param array $data The result-Array to create HTML from + * @param string $type type of search to get the template + * @return string HTML for a songSearch + * @author Steffen Becker */ private function songSearchHTML($data, $type) { $this->html .= '<div class="songSearch"><ul class="clearfix">'; @@ -303,12 +333,12 @@ /** - * - * - * - * - * - * + * Returns the HTML for recommendations + * + * @param array $data The result-Array to create HTML from + * @param string $type type of search to get the template + * @return string HTML for recommendations + * @author Steffen Becker */ private function recommendationsHTML($data, $type) { $count = count($data['scores']); // doesnt matter if scores or results... @@ -330,15 +360,14 @@ foreach ($resultSet as $record => $result) { // alternating classes for li-elements if (($j % 2) == 0) { $class = 'odd'; } else { $class = ''; } - $template = $this->getTemplate($type); $artistName = $this->getValue($result['artistName']); $albumTitle = $this->getValue($result['albumTitle']); $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getValue($result['playlist'])); - $addToPlaylist = '<li><a class="addToPlaylist" href="' . $playlist . '" ' - . 'title="' . $artistName . ' - ' . $albumTitle . '" ' - . 'rel="' . $record . '">Click here to add this album to your playlist.</a></li>'; + + $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' + . $artistName . ' - ' . $albumTitle . '">Click here to add this album to your playlist</a></li>'; $image = $this->getImage($result, $artistName . ' - ' . $albumTitle); @@ -357,9 +386,11 @@ /** + * Returns a list... [truncated message content] |
From: <neb...@us...> - 2009-11-01 22:53:57
|
Revision: 1901 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1901&view=rev Author: nebelschwade Date: 2009-11-01 22:53:41 +0000 (Sun, 01 Nov 2009) Log Message: ----------- Added albumSearch Added More Info Tab-Functionality, displaying external RDF-Data for currently playing artist. Minor Bugfixes and Enhancements (Download this song etc.) HTML5/CSS3 Interface Modified Paths: -------------- trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/classes/DataHelper.php trunk/src/moosique.net/moosique/classes/Debugger.php trunk/src/moosique.net/moosique/classes/LastFM.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/main.wsdl Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/css/style.css 2009-11-01 22:53:41 UTC (rev 1901) @@ -13,82 +13,100 @@ @media screen { /*=============== Default Styling ===============*/ -body { font: normal 12px/18px Verdana, Arial, sans-serif; color: #f1f7e4; - background: url('../img/bg.png') top left repeat #3a3a3a; border-top: 5px solid #1fd611; } +body { font: normal 14px/20px Verdana, Arial, sans-serif; color: #f1f7e4; + background: url('../img/bg.png') top left repeat #3a3a3a; } input, select { background: #292929; border: 1px solid #5a5a5a; outline: none; padding: 5px; } input[type=submit] { padding: 5px 10px; } input:focus, select:focus { border: 1px solid #1fd611; } a:hover { color: #1fd611; } a.button { background: #4a4a4a; color: #f1f7e4; padding: 5px 10px; text-decoration: none; } a.button:hover { border: 1px solid #1fd611; padding: 4px 9px; } -h1 { font: 32px/32px Georgia, Times, serif; } -h2 { font: 28px/28px Georgia, Times, serif; } -h3 { font: 20px/20px Georgia, Times, serif; } -h4 { font: 16px/16px Georgia, Times, serif; } -h5 { font: 12px/12px Georgia, Times, serif; } -h6 { font: 10px/10px Georgia, Times, serif; } +h1 { font: 36px/36px Georgia, Times, serif; } +h2 { font: 30px/30px Georgia, Times, serif; } +h3 { font: 24px/24px Georgia, Times, serif; } +h4 { font: 18px/18px Georgia, Times, serif; } +h5 { font: 14px/14px Georgia, Times, serif; } +h6 { font: 12px/12px Georgia, Times, serif; } pre { font: normal 10px/14px Monaco, Courier, monospace; } p, h1, h2, h3, h4, h5, h6, -ul, ol, pre, form { margin-bottom: 18px; } +ul, ol, pre, form { margin-bottom: 20px; } /* Initial hiding */ -#recommendations, #information, +#recommendations, #info, #header h1, #player, #help { display: none; } -/* Rounded Corners */ +/* Rounded Corners and drop shadows, CSS3 */ input, select, a.button { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } #content, #status, #playing, -#playerControls, .results li { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } +#playerControls, .results li, +iframe { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } #nav a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; - border-bottom-left-radius: 10px; border-top-left-radius: 10px; } + border-bottom-left-radius: 10px; border-bottom-left-radius: 10px; } +#info .linkList li { -moz-border-radius-topleft: 10px; -moz-border-radius-topright: 10px; + -webkit-border-top-left-radius: 10px; -webkit-border-top-right-radius: 10px; + border-top-left-radius: 10px; border-top-left-radius: 10px; } +#content, #status, #playing, +#playerControls, #topBorder, +#searchValue, #searchType, +#searchSubmit, #nav a, +#info .linkList li { -moz-box-shadow: 2px 2px 3px #191919; -webkit-box-shadow: 2px 2px 3px #191919; + box-shadow: 2px 2px 3px #191919; } +#nav .active a, .results img, +a.button, #info .image img { -moz-box-shadow: 3px 3px 3px #191919; -webkit-box-shadow: 3px 3px 3px #191919; + box-shadow: 3px 3px 3px #191919; } + /*=============== Default Containers ===============*/ #container, #header, #content, #playlist li { position: relative; } -#container { width: 760px; margin: 0 auto; } -#header { height: 150px; padding-top: 20px; } -#content { background: #292929; padding: 20px; } -#footer { font: normal 10px/14px Verdana, Arial, sans-serif; padding: 20px; text-align: center; } +#topBorder { position: relative; height: 6px; background: #1fd611; z-index: 5; } +#container { width: 900px; margin: 0 auto; } +#header { height: 175px; padding-top: 25px; } +#content { background: #292929; padding: 25px; } +#footer { font: normal 11px/14px Verdana, Arial, sans-serif; padding-top: 40px; text-align: center; } /*=============== Player Controls, Status, Playing ===============*/ -#status, #playing { position: absolute; top: 70px; left: 0; width: 490px; height: 60px; +#status, #playing { position: absolute; top: 85px; left: 0; width: 590px; height: 70px; background: #292929; padding: 10px 20px; } -#playerControls { position: absolute; top: 70px; right: 0; width: 170px; height: 60px; +#playerControls { position: absolute; top: 85px; right: 0; width: 210px; height: 70px; padding: 10px 20px; background: #292929; } #playerControls a:active { position: relative; top: 2px; } -#status { background: #3a3a3a; height: 60px; line-height: 60px; text-align: center; +#status { background: #3a3a3a; line-height: 70px; text-align: center; font-weight: bold; border: 1px solid #1fd611; z-index: 1000; } #playing span { display: block; margin-bottom: 0; font-size: 10px; } -#playing .track { font: bold 12px/32px Verdana, Arial, sans-serif; } +#playing .track { font: bold 14px/32px Verdana, Arial, sans-serif; } #playing .time { position: absolute; bottom: 10px; right: 20px; } +#playing .download { position: absolute; top: 10px; right: 20px; } #prev, #next, #stop, -#playPause, #mute { display: block; width: 20px; height: 40px; text-indent: -10000px; - float: left; margin: 10px 0 0 10px; } +#playPause, #mute { display: block; width: 30px; height: 40px; text-indent: -10000px; + float: left; margin: 15px 0 0 10px; } #prev { background: url(../img/controls.png) 0px -160px no-repeat; } #next { background: url(../img/controls.png) 0px -120px no-repeat; } #stop { background: url(../img/controls.png) 0px -80px no-repeat; } -#mute { background: url(../img/controls.png) 0px -280px no-repeat; margin-right: 0; width: 23px; } -#playPause { background: url(../img/controls.png) 0px 0px no-repeat; width: 26px; } +#mute { background: url(../img/controls.png) 0px -280px no-repeat; margin-right: 0; } +#playPause { background: url(../img/controls.png) 0px 0px no-repeat; width: 37px; } /*=============== Search Form ===============*/ -#searchValue { margin: 0 5px; width: 100px; } +#searchValue { margin: 0 5px; width: 150px; } .spinner { position: absolute; z-index: 10; background: url('../img/bg.png') top left repeat #3a3a3a; } .spinner-img { background: url('../img/spinner.gif') top left no-repeat; width: 24px; height: 24px; margin: 0 auto; } /*=============== Content & General ===============*/ #addRandom { text-decoration: underline; } -#footer a { padding: 0 10px; } +#footer a { padding: 0 12px; color: #5a5a5a; } +#footer a:hover { color: #f1f7e4; } +#help ul { list-style: disc; margin-left: 40px; } - /*=============== Menu ===============*/ #nav ul { position: absolute; top: 0; right: 0; } #nav li { float: left; } -#nav a { display: block; margin-left: 10px; line-height: 30px; height: 30px; - padding: 10px 12px; color: #f1f7e4; background: #4a4a4a; } +#nav a { position: relative; display: block; margin-left: 12px; height: 40px; padding: 10px 12px; color: #f1f7e4; + background: #4a4a4a; font: normal 12px/50px Verdana, Arial, sans-serif; } +#nav .active a { z-index: 10; } #nav .active a, #nav .active a:hover { background: #1fd611; } #nav a:hover { text-decoration: none; background: #5a5a5a; } @@ -96,21 +114,23 @@ /*=============== Search Results, Recommendations & Playlist ===============*/ .results h3 a { font-weight: normal; } -.results img { border: 2px solid #5a5a5a; max-width: 308px; max-height: 308px; } -.results li { float: left; width: 312px; border: 1px solid #5a5a5a; padding: 18px; margin-bottom: 18px; } -.results li.odd { margin-right: 18px; clear: both; } -.results ul ul { list-style: disc; } +.results img { max-width: 373px; max-height: 373px; } +.results li { float: left; width: 373px; border: 1px solid #5a5a5a; padding: 20px; margin-bottom: 20px; } +.results li.odd { margin-right: 20px; clear: both; } +.results ul ul { list-style: disc; margin-bottom: 0; } .results li li, .artistSearch li li, -.tagSearch li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; +.tagSearch li li, +#info li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; width: auto; height: auto; float: none; } .results h4 { display: inline; } #recommendationResults ul ul, -.tagSearch ul ul { clear: both; } -.results .image { text-align: center; margin-bottom: 18px; } +.tagSearch ul ul, +#info ul ul { clear: both; } +.results .image { text-align: center; margin-bottom: 20px; } #recommendationResults.results .image, -.results .tagSearch .image { margin: 0 18px 18px 0; width: 104px; height: 104px; float: left; } +.results .tagSearch .image { margin: 0 20px 20px 0; width: 104px; height: 104px; float: left; } #autoAdd { float: right; } #playlist, #recently { margin-left: 36px; list-style: decimal; } @@ -129,7 +149,12 @@ /*=============== Information & Help ===============*/ +#info h3 { clear: both; } +#info .image { width: auto; float: left; margin: 0 20px 20px 0;} +#info iframe { border: 1px solid #5a5a5a; width: 100%; height: 600px; } +#info .linkList { overflow: hidden; margin: 0 0 0 20px; } +#info .linkList li { float: left; padding: 10px; margin-right: 10px; background: #4a4a4a; } +#info .linkList li.active { background: #1fd611; } - } /* end @media screen */ \ No newline at end of file Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/index.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -14,78 +14,67 @@ <title>moosique.net</title> </head> <body> +<div id="topBorder"></div> <div id="container"> <div id="header"> <h1>moosique.net</h1> - <div id="nav"> <ul class="clearfix"> - <li class="active"><a href="#" class="home">Search</a></li> - <li><a href="#" class="player">Playlist</a></li> - <li><a href="#" class="recommendations">Recommendations</a></li> - <li><a href="#" class="information">Info</a></li> - <li><a href="#" class="help">?</a></li> + <li class="active"><a href="search/" class="home">Search</a></li> + <li><a href="playlist/" class="player">Playlist</a></li> + <li><a href="recommendations/" class="recommendations">Recommendations</a></li> + <li><a href="more-info/" class="info">More Info</a></li> + <li><a href="help/" class="help">Help</a></li> </ul> </div> - <form id="searchForm" method="get" action="moosique/"> <div> <select name="searchType" id="searchType"> <option value="allSearch">All</option> - <option value="artistSearch">Artist</option> - <option value="tagSearch">Tag</option> - <option value="albumSearch">Album</option> - <option value="songSearch">Song</option> + <option value="artistSearch">Artists</option> + <option value="tagSearch">Tags</option> + <option value="albumSearch">Albums</option> + <option value="songSearch">Songs</option> <option value="lastFM">last.fm</option> </select> <input id="searchValue" name="searchValue" type="text" /> <input id="searchSubmit" name="searchSubmit" value="Search" title="Search" type="submit" /> </div> </form> - <div id="playerControls"> - <a href="#" id="playPause" title="Play/Pause">Play / Pause</a> - <a href="#" id="stop" title="Stop playing">Stop</a> - <a href="#" id="prev" title="Play previous Track in Playlist">Previous Tack</a> - <a href="#" id="next" title="Play next Track in Playlist">Next Track</a> - <a href="#" id="mute" title="Sound on/off">Mute</a> + <a href="play-pause/" id="playPause" title="Play/Pause">Play / Pause</a> + <a href="stop/" id="stop" title="Stop playing">Stop</a> + <a href="previous/" id="prev" title="Play previous Track in Playlist">Previous Tack</a> + <a href="next/" id="next" title="Play next Track in Playlist">Next Track</a> + <a href="mute/" id="mute" title="Sound on/off">Mute</a> </div> - <div id="status"> </div> <div id="playing"> <span class="info">Player stopped</span> <span class="track">...</span> <span class="time">0:00 / 0:00</span> + <span class="download"><a href="#">Download this song</a></span> </div> </div> - <div id="content"> <div id="home"> - <div id="welcome"> + <div id="results" class="results"> <h2>Welcome to moosique.net!</h2> <p> - Want to listen to some good free music? Just enter an artist or song - name or search for music using tags and let the moogic - happen. By listening to songs you like, the system will automatically learn about + Want to listen to some good free music? Search for something you like and add it to your playlist. + By listening to songs you like, moosique will automatically try to learn about your musical taste and generate recommendations. You can find them in the tab »Recommendations«. - </p> - <p> You can also enter your <a href="http://last.fm">last.fm</a>-username to automatically use your most-used tags to generate a initial list of recommendations. </p> <p> - You can find information about the song currently playing in the tab »Info« and edit and view - your current Playlist in the »Playlist«-Tab. + After you have found something you want to listen to, just add it to your playlist and click the play-button. </p> <p> - Now get started and add something to the Playlist! + Need help? Click on the »Help«-Tab to get more information about how to use moosique.net </p> </div> - <div id="results" class="results"> - - </div> </div> - <div id="recommendations"> <form id="autoAdd" method="get" action=""> <div> @@ -99,24 +88,16 @@ for at least half it's length, assuming that you liked it. You can click on a recommended album to add it to the playlist, or you can <a href="#" id="addRandom">click here to just add a random song from your recommendations</a>.<br /> - </p> <p> <a href="#" id="generateRecommendations" class="button" title="If there is nothing showing up here, you can generate your list of recommendations by clicking here.">Reload recommendations</a> </p> <div id="recommendationResults" class="results"> - - </div> </div> - - <div id="information"> - <h2>About the artist...</h2> - <div id="moreInfo"> - - </div> + <div id="info"> + <h2>Listen to a song to get more info about it.</h2> </div> - <div id="player"> <h2>Playlist</h2> <p> @@ -127,7 +108,6 @@ <li></li> </ol> <p><a href="#" id="resetPlaylist" class="button" title="Click here to delete all tracks from your playlist.">Delete all</a></p> - <h2>Recently Listened to</h2> <p>These are the songs you recently listened to. Click on a song to re-enqueue it to your current playlist.</p> <ol id="recently"> @@ -135,21 +115,45 @@ </ol> <p><a href="#" id="resetRecently" class="button" title="Click here to reset your »recently listened to«-list.">Reset</a></p> </div> - <div id="help"> - + <h2>How to use moosique.net</h2> + <h3>Searching</h3> + <p> + Before you can listen to music, you first have to search for something to add your first song or album to + your playlist. You can search for <em>artists</em>, <em>tags</em>, <em>albums</em> or <em>songs</em>. + If you are lazy and a last.fm-user, you can choose <em>last.fm</em> from the search-dropdown and just enter + your username, moosique.net will then start a search using your most used tags from last.fm.<br /> + If you are searching for tags, and your search is more than one word, the results will be better. + For example: a search for "rock" will give you lots of results, where a search for "hard rock" + will be more specific, giving you better search results. Just try it, you can't break anything. + </p> + <h3>Recommendations</h3> + <p> + moosique.net uses the mighty <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> to generate recommendations + based on the songs you have listened to. + </p> + <h3>Requirements</h3> + <p> + To use moosique.net you should have: + </p> + <ul> + <li>A decent, modern browser, such as <a href="http://getfirefox.com">Firefox</a>, <a href="http://apple.com/de/safari/download/">Safari</a> or <a href="http://google.com/chrome/">Google Chrome</a></li> + <li>JavaScript activated</li> + <li>The <a href="http://www.adobe.com/se/products/flashplayer/">Adobe Flash Player</a> plugin for your browser</li> + <li>A fast internet connection</li> + <li>Some good headphones or loudspeakers of course. It's moosique after all!</li> + </ul> </div> - </div> <!-- end content --> - <div id="footer"> - <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> | - <a href="http://jamendo.com">Jamendo</a> | + <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> + <a href="http://bis.informatik.uni-leipzig.de/">Universität Leipzig BIS</a> + <a href="http://jamendo.com">Jamendo</a> <a href="http://mediaplayer.yahoo.com/">Yahoo! Media Player</a> + <a href="http://mootools.net">mootools</a> + <a href="http://webgefrickel.de">webgefrickel.de</a> </div> - </div> <!-- end container --> - <?php include('moosique/classes/Config.php'); $c = new Config(); Modified: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/js/moosique.js 2009-11-01 22:53:41 UTC (rev 1901) @@ -11,9 +11,9 @@ // set some default options options: { - messageFadeTime: 5000, // Time until a Status message fades out - timeToScrobble: 0.5, // factor for calculating max time a user has to listen to a track until its scrobbled - minSearchLength: 3 // minimum number of chars for a search value (tag, artist, song) + messageFadeTime: 4000, // Time until a Status message fades out in milliseconds, default: 4000 = 4 seconds + timeToScrobble: 0.5, // factor for max time for scrobbling/recommendations, default: 0.5 = half the song + minSearchLength: 3 // minimum number of chars for a search value (tag, artist, song), default: 3 }, /** @@ -48,6 +48,7 @@ this.nowPlayingInfo = $$('#playing .info'); this.nowPlayingTrack = $$('#playing .track'); this.nowPlayingTime = $$('#playing .time'); + this.download = $$('#playing .download a'); this.status = document.id('status'); // searchForm elements this.searchForm = document.id('searchForm'); @@ -71,7 +72,7 @@ this.nav = document.id('nav'); this.welcome = document.id('welcome'); this.help = document.id('help'); - this.moreInfo = document.id('moreInfo'); + this.info = document.id('info'); }, /** @@ -216,6 +217,7 @@ var trackStart = function() { that.nowPlayingInfo.set('text', 'Currently playing:'); that.nowPlayingTrack.set('text', YAHOO.MediaPlayer.getMetaData().title); + that.download.set('href', YAHOO.MediaPlayer.getMetaData().anchor.get('href')); that.playPause.setStyle('background-position', '0px -40px'); // sprite offset // send a request to gather additional artist-information @@ -224,7 +226,9 @@ method: 'get', url: 'moosique/index.php', onSuccess: function(response) { - that.moreInfo.set('html', response); + that.info.set('html', response); + // make the additionals iframe-clickable + that.addLinkListItemToIframe(); } }).send('info=' + nowPlayingAlbum); }; @@ -327,12 +331,19 @@ addEventsToButtons: function() { var that = this; - // the previous/next-Track Buttons - that.prev.addEvent('click', function() { YAHOO.MediaPlayer.previous(); }); - that.next.addEvent('click', function() { YAHOO.MediaPlayer.next(); }); + that.prev.addEvent('click', function(e) { + e.stop(); + YAHOO.MediaPlayer.previous(); + }); + + that.next.addEvent('click', function(e) { + e.stop(); + YAHOO.MediaPlayer.next(); + }); // the Play-Pause Button - that.playPause.addEvent('click', function() { + that.playPause.addEvent('click', function(e) { + e.stop(); // STOPPED: 0, PAUSED: 1, PLAYING: 2,BUFFERING: 5, ENDED: 7 // see http://mediaplayer.yahoo.com/api/ if (YAHOO.MediaPlayer.getPlayerState() == 0 || @@ -345,12 +356,14 @@ }); // the Stop-Playing Button - that.stop.addEvent('click', function() { + that.stop.addEvent('click', function(e) { + e.stop(); that.stopPlaying(); }); // Mute-Toggle-Switch - that.mute.addEvent('click', function() { + that.mute.addEvent('click', function(e) { + e.stop(); if (YAHOO.MediaPlayer.getVolume() > 0) { YAHOO.MediaPlayer.setVolume(0); that.mute.setStyle('background-position', '0px -240px'); @@ -371,7 +384,6 @@ refreshPlaylist: function() { var that = this; YAHOO.MediaPlayer.addTracks(that.playlist, '', true); - that.displayStatusMessage('Playlist updated.'); }, @@ -385,6 +397,7 @@ that.nowPlayingInfo.set('text', 'Player stopped.'); that.nowPlayingTrack.set('text', '...'); that.nowPlayingTime.set('text', '0:00 / 0:00'); + that.download.set('href', '#'); YAHOO.MediaPlayer.stop(); // and reload the playlist that.refreshPlaylist(); @@ -392,18 +405,23 @@ /** - * Displays a status message + * Displays a status message, fades out nicely * * @param {String} message */ displayStatusMessage: function(message) { // Update Status and fade out var that = this; - that.status.set({ - 'text': message, - 'tween': {duration: that.options.messageFadeTime} + var fadeFX = new Fx.Tween(that.status, { + property: 'opacity', + duration: that.options.messageFadeTime / 2, + transition: Fx.Transitions.Expo.easeOut, + link: 'chain' }); - that.status.tween('opacity', [1, 0]); + + that.status.set('text', message); + fadeFX.start(0, 1); + fadeFX.start(1, 0); }, @@ -463,13 +481,6 @@ spinner.show(); that.searchSubmit.set('disabled', 'disabled'); that.showTab('home'); - // if the welcome-text ist present, cut & paste it to help - if (that.welcome) { - if (that.welcome.get('html').length > 100) { - that.help.set('html', that.welcome.get('html')); - that.welcome.destroy(); - } - } that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take up to a minute...</p>'); }, @@ -601,10 +612,12 @@ var songs = Elements.from(response); var randomSong = songs.getRandom(); that.insertIntoPlaylist('<li>' + randomSong.get('html') + '</li>'); + that.displayStatusMessage('Added a random song to your playlist.'); } }).send('get=playlist&playlist=' + href + '&rel=' + rel); } else { - debug.log('You currently have no recommendations, adding a random one will not work.'); + that.displayStatusMessage('You currently have no recommendations, nothing was added.'); + debug.log('You currently have no recommendations, adding a random song will not work.'); } }, @@ -624,6 +637,25 @@ /** + * + * + */ + addLinkListItemToIframe: function() { + var that = this; + that.info.getElements('.linkList a').each(function(a) { + a.addEvent('click', function(e) { + e.stop(); + that.info.getElements('.linkList li').removeClass('active'); + a.getParent().addClass('active'); + href = a.get('href'); + that.info.getElements('iframe').set('src', href); + }); + }); + }, + + + + /** * Converts seconds into a string formatted minutes:seconds * with leading zeros for seconds for a nicer display * Modified: trunk/src/moosique.net/js/start.js =================================================================== --- trunk/src/moosique.net/js/start.js 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/js/start.js 2009-11-01 22:53:41 UTC (rev 1901) @@ -7,5 +7,5 @@ }; // Create an instance of the moosique.net -// TODO 0.025 for debugging purposes -var moo = new Moosique({ timeToScrobble: 0.025 }); +var moo = new Moosique({ timeToScrobble: 0.05 }); // debugging - shorter generation time +// var moo = new Moosique({ timeToScrobble: 0.5 }); Modified: trunk/src/moosique.net/moosique/classes/DataHelper.php =================================================================== --- trunk/src/moosique.net/moosique/classes/DataHelper.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/classes/DataHelper.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -36,8 +36,7 @@ $json = $this->connection->sparqlQuery($query); // convert to useable object $result = json_decode($json); - $resultObject = $result->results->bindings; - + $resultObject = $result->results->bindings; // prepare the data for HTML processing $data = $this->prepareData($resultObject, $type, $search); return $data; @@ -77,7 +76,10 @@ // prepend the album stream-information $mergedArray['albumID'] = $data['albumID']; } - + if ($type == 'info') { // same as artist, but only first array entry needed + $mergedArray = $this->mergeArray($data, 'artist'); + $mergedArray = current($mergedArray); + } // multidimensional array_unique for everything but single-tagSearch and playlist if ($type != 'playlist' && $type != 'tagSearch' && !is_array($search)) { $mergedArray = $this->arrayUnique($mergedArray); Modified: trunk/src/moosique.net/moosique/classes/Debugger.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Debugger.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/classes/Debugger.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -32,7 +32,7 @@ * @param string $label The label for the object to log * @author Steffen Becker */ - public function log($var, $label) { + public function log($var, $label = '') { $this->fb->log($var, $label); } Modified: trunk/src/moosique.net/moosique/classes/LastFM.php =================================================================== --- trunk/src/moosique.net/moosique/classes/LastFM.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/classes/LastFM.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -9,17 +9,14 @@ */ class LastFM extends Config { - private $topTags; // save tags here - /** * Initializing class requires the last.fm username * * @param string $user The last.fm Username * @author Steffen Becker */ - function __construct($user) { + function __construct() { parent::__construct(); // init config - $this->getLastFMTags($user); } @@ -31,7 +28,7 @@ * @return array An array with the top tags for $user * @author Steffen Becker */ - private function getLastFMTags($user) { + public function getTags($user) { $allTags = array(); $requestUrl = $this->getConfigLastFM('topTagsUrl') . '&user=' . $user @@ -57,7 +54,8 @@ if ($this->debugger) $this->debugger->log($user, 'The last.fm-User does not exist. Please try again.'); } if ($this->debugger) $this->debugger->log($allTags, 'Found these Tags for the last.fm-User' . $user); - $this->topTags = $allTags; + + return $allTags; } @@ -113,15 +111,27 @@ /** - * Returns the topTags + * Returns the last.fm artist-page-URL vor a given musicbrainz-ID * - * @return array An Array of strings ('rock', 'doom metal' etc.) with the Top-Tags + * @param string $mbid The musicbrainz-ID + * @return string The URL to the last.fm-page of the artist, or false * @author Steffen Becker */ - public function getTopTags() { - return $this->topTags; + public function getArtistPage($mbid) { + // get the top artists for the user + $requestUrl = $this->getConfigLastFM('artistInfoUrl') + . '&mbid=' . $mbid + . '&api_key=' . $this->getConfigLastFM('apiKey'); + + $artistInfo = @simplexml_load_file($requestUrl); + + if ($artistInfo) { + return $artistInfo->artist->url; + } else { + return false; + } } - + } ?> \ No newline at end of file Modified: trunk/src/moosique.net/moosique/classes/RequestHandler.php =================================================================== --- trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/classes/RequestHandler.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -61,7 +61,11 @@ // concatenating the response from all 4 searches if ($type == 'allSearch') { $response .= $this->createSearch($search, 'artistSearch'); + // do a special search-String-formatting for the tagSearch part + $search = $this->cleanString($_GET['searchValue'], 'tagSearch'); $response .= $this->createSearch($search, 'tagSearch'); + // and reset it afterwards + $search = $this->cleanString($_GET['searchValue'], $type); $response .= $this->createSearch($search, 'albumSearch'); $response .= $this->createSearch($search, 'songSearch'); } @@ -73,8 +77,8 @@ // last.fm search, initiate the lastFM-Class and get the tags for // the user ($search) - then make tagSearches for every result if ($type == 'lastFM') { - $lastFM = new LastFM($search); - $tags = $lastFM->getTopTags(); + $lastFM = new LastFM(); + $tags = $lastFM->getTags($search); // no we have the topTags, do a search for related albums if (!empty($tags)) { foreach($tags as $tag) { @@ -123,8 +127,7 @@ // ========== ARTIST INFORMATION REQUEST ============= // TODO artist info, not yet implemented if (isset($_GET['info']) && !(empty($_GET['info']))) { - $currentAlbum = $_GET['info']; - $response .= '<p>Artist Information coming soon...</p>'; + $response .= $this->createSearch($_GET['info'], 'info'); } @@ -203,7 +206,6 @@ if ((strpos($string, " ") > 0) && ($type == 'lastFM' || $type == 'tagSearch')) { $string = explode(" ", $string); } - return $string; } Modified: trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -67,6 +67,7 @@ case 'albumSearch' : $query = $this->queryAlbumSearch($search); break; case 'songSearch' : $query = $this->querySongSearch($search); break; case 'recommendations' : $query = $this->queryRecommendations($search); break; + case 'info' : $query = $this->queryInfo($search); break; } // save the query $this->queryString = $prefixes . $beginStatement . $baseQuery . $query . $endStatement; @@ -86,7 +87,7 @@ tags:taggedWithTag ?tag . OPTIONAL { ?artist foaf:img ?image . } - OPTIONAL { ?artist foaf:homepage ?artistHomepage . } + OPTIONAL { ?artist foaf:homepage ?homepage . } }'; $queryString .= 'FILTER (regex(str(?artistName), "' . $search . '", "i")) . '; @@ -112,8 +113,8 @@ mo:available_as ?playlist . OPTIONAL { - ?record mo:image ?image . - FILTER (regex(str(?image), "1.100.jpg", "i")) . + ?record mo:image ?cover . + FILTER (regex(str(?cover), "1.100.jpg", "i")) . } } '; $queryString .= ' FILTER (regex(str(?tag), "' . $search . '", "i")) . '; @@ -145,8 +146,8 @@ $queryString .= ' mo:available_as ?playlist . OPTIONAL { - ?record mo:image ?image . - FILTER (regex(str(?image), "1.100.jpg", "i")) . + ?record mo:image ?cover . + FILTER (regex(str(?cover), "1.100.jpg", "i")) . } } '; return $queryString; @@ -166,8 +167,8 @@ mo:available_as ?playlist . OPTIONAL { - ?record mo:image ?image . - FILTER (regex(str(?image), "1.100.jpg", "i")) . + ?record mo:image ?cover . + FILTER (regex(str(?cover), "1.100.jpg", "i")) . } } '; @@ -210,22 +211,51 @@ $queryString = ' { ?record mo:available_as ?playlist ; - OPTIONAL { ?artist foaf:img ?artistImage . } - OPTIONAL { ?artist foaf:homepage ?artistHomepage . } OPTIONAL { - ?record mo:image ?image . - FILTER (regex(str(?image), "1.100.jpg", "i")) . + ?record mo:image ?cover . + FILTER (regex(str(?cover), "1.100.jpg", "i")) . } } '; // TODO ?record tags:taggedWithTag ?tag makes the queries blow up high + // TODO: use artistImage/Homepage etc. additional info in display + // OPTIONAL { ?artist foaf:img ?image . } + // OPTIONAL { ?artist foaf:homepage ?artistHomepage . } + // and finally we append the sparql-string from kb-Description-Conversion $queryString .= $search; return $queryString; } - + /** + * Creates the SPARQL-Query part for additional artist information + * + * @param string $search The relation, an album, sth like + * @return void + * @author Steffen Becker + */ + private function queryInfo($search) { + $queryString = ' { + ?artist foaf:made <' . $search . '> . + ?record mo:available_as ?playlist ; + tags:taggedWithTag ?tag . + + OPTIONAL { ?artist foaf:img ?image . } + OPTIONAL { ?artist foaf:homepage ?homepage . } + OPTIONAL { ?artist foaf:based_near ?location . } + OPTIONAL { ?artist owl:sameAs ?sameAs . } + + OPTIONAL { + ?record mo:image ?cover . + FILTER (regex(str(?cover), "1.100.jpg", "i")) . + } + } '; + return $queryString; + } + + + /** * Returns the final Query-String * * @return string The final Complete SPARQL-Query Modified: trunk/src/moosique.net/moosique/classes/View.php =================================================================== --- trunk/src/moosique.net/moosique/classes/View.php 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/classes/View.php 2009-11-01 22:53:41 UTC (rev 1901) @@ -58,11 +58,12 @@ case 'songSearch' : $this->html = '<h2>No songs found for »' . $searchText . '«</h2>'; break; case 'lastFM' : $this->html = '<h2>The last.fm-user »' . $searchText . '« does not exist.</h2>'; break; case 'recommendations' : $this->html = '<h2>' . $data . '</h2>'; break; + case 'info' : $this->html = '<h2>Could not find any information about the currently playing song or artist.</h2>'; } } else { // finally we are producing html, depending on the type of request - // use the limits on the data before creating html, except for the playlist-html - if ($type != 'playlist') { + // use the limits on the data before creating html, except for the playlist-html and more info + if ($type != 'playlist' && $type != 'info') { $data = $this->limitData($data); } @@ -92,6 +93,9 @@ case 'recommendations' : $this->recommendationsHTML($data, $type); break; + case 'info' : + $this->infoHTML($data, $type); + break; case 'playlist' : $this->playlistHTML($data); break; @@ -154,8 +158,7 @@ if (is_array($recordArray)) { foreach($recordArray as $key => $record) { $records .= '<li><a class="addToPlaylist" href="' - // remove the last part of the uri, defaults to mp3, because - // the yahooMediaPlayer can't play ogg + // remove the last part of the uri, defaults to mp3, because the yahooMediaPlayer can't play ogg . str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $artist['playlist']['value'][$key]) . '" rel="' . $artist['record']['value'][$key] . '">' . $this->getValue($artist['artistName']) . ' - ' @@ -170,12 +173,12 @@ } $artistName = $this->getValue($artist['artistName']); - $image = $this->getImage($artist, $artistName); + $image = $this->getImage($artist, 'Image of ' . $artistName); $tags = $this->getTagList($artist['tag']); $homepage = ''; // homepagelink if avaiable - if (!empty($artist['artistHomepage'])) { - $homepage = '<a href="' . $this->getValue($artist['artistHomepage']) . '">(Homepage)</a>'; + if (!empty($artist['homepage'])) { + $homepage = '<a href="' . $this->getValue($artist['homepage']) . '">(Homepage)</a>'; } $this->html .= sprintf($template, @@ -189,13 +192,12 @@ /** - * Returns the HTML for tagSearch results + * Builds the HTML for tagSearch results * This is somewhat special, we first create a list of found tags, * and then we list the albums found for those tags * * @param array $data The result-Array to create HTML from * @param string $type type of search to get the template - * @return string HTML for a tagSearch * @author Steffen Becker */ private function tagSearchHTML($data, $type) { @@ -243,7 +245,7 @@ $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' . $artistName . ' - ' . $albumTitle . '">Click here to add this album to your playlist</a></li>'; - $image = $this->getImage($tag, $artistName. ' - ' . $albumTitle, $j); + $image = $this->getImage($tag, 'Cover for ' . $artistName. ' - ' . $albumTitle, $j, 'cover'); $this->html .= sprintf($template, $class, $image, $artistName, $albumTitle, $addToPlaylist @@ -256,11 +258,10 @@ /** - * Returns the HTML for albumSearch results + * Builds the HTML for albumSearch results * * @param array $data The result-Array to create HTML from * @param string $type type of search to get the template - * @return string HTML for a albumSearch * @author Steffen Becker */ private function albumSearchHTML($data, $type) { @@ -280,7 +281,7 @@ $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' . $artistName . ' - ' . $albumTitle . '">Click here to add this album to your playlist</a></li>'; - $image = $this->getImage($album, $artistName . ' - ' . $albumTitle); + $image = $this->getImage($album, 'Cover for ' . $artistName . ' - ' . $albumTitle, 0, 'cover'); $tags = $this->getTagList($album['tag']); $this->html .= sprintf($template, @@ -294,11 +295,10 @@ /** - * Returns the HTML for songSearch results + * Builds the HTML for songSearch results * * @param array $data The result-Array to create HTML from * @param string $type type of search to get the template - * @return string HTML for a songSearch * @author Steffen Becker */ private function songSearchHTML($data, $type) { @@ -320,7 +320,7 @@ . $artistName . ' - ' . $songTitle . '">Click here to add this song to your playlist</a></li>'; $tags = $this->getTagList($song['tag']); - $image = $this->getImage($song, $artistName); + $image = $this->getImage($song, 'Image of ' . $artistName); $this->html .= sprintf($template, $class, $artistName . ' - ' . $songTitle, $image, $tags, $addToPlaylist @@ -333,11 +333,11 @@ /** - * Returns the HTML for recommendations + * Builds the HTML for recommendations + * TOOD enhance display: more info * * @param array $data The result-Array to create HTML from * @param string $type type of search to get the template - * @return string HTML for recommendations * @author Steffen Becker */ private function recommendationsHTML($data, $type) { @@ -369,7 +369,7 @@ $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' . $artistName . ' - ' . $albumTitle . '">Click here to add this album to your playlist</a></li>'; - $image = $this->getImage($result, $artistName . ' - ' . $albumTitle); + $image = $this->getImage($result, 'Cover for ' . $artistName . ' - ' . $albumTitle, 0, 'cover'); $this->html .= sprintf($template, $class, $image, $artistName, $albumTitle, $addToPlaylist @@ -379,17 +379,97 @@ $this->html .= '</ul>'; } } else { - $this->html = '<h2>Could not create any recommendations...</h2>'; + $this->html = '<h2>Could not create any recommendations.</h2>'; $this->html .= '<p>Listen to some more music or reset your recently listened to list.</p>'; } } + /** + * Builds the HTML for additional information for and artist + * + * @param array $data An array of additional information + * @author Steffen Becker + */ + private function infoHTML($data, $type) { + $template = $this->getTemplate($type); + $albumTemplate = $this->getTemplate('tagSearch'); + $artist = $this->getValue($data['artist']); + $artistName = $this->getValue($data['artistName']); + $image = $this->getImage($data, $artistName); + $tags = $this->getTagList($data['tag']); + $homepage = ''; + if (isset($data['homepage'])) { + $homepage = '<p>Homepage: <a href="' . $this->getValue($data['homepage']) . '">' + . $this->getValue($data['homepage']) . '</a></li>'; + } + $albumList = ''; + $records = $this->getValue($data['record']); + if (is_array($records)) { + // if there is more than one record... + $j = 0; + foreach($records as $key => $record) { + if (($j % 2) == 0) { $class = 'odd'; } else { $class = ''; } + $albumTitles = $this->getValue($data['albumTitle']); + $playlists = $this->getValue($data['playlist']); + $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getValue($data['playlist'], $key)); + $cover = $this->getImage($data, 'Cover for '. $albumTitles[$key], $key, 'cover'); + $addToPlaylist = '<li><a rel="' . $record . '" class="addToPlaylist" href="' . $playlist . '" title="' + . $artistName . ' - ' . $albumTitles[$key] . '">Click here to add this album to your playlist</a></li>'; + // use the template + $albumList .= sprintf($albumTemplate, + $class, $cover, $artistName, $albumTitles[$key], $addToPlaylist + ); + $j++; + } + } else { // only one record + $playlist = str_replace('?item_o=track_no_asc&aue=ogg2&n=all', '', $this->getValue($data['playlist'])); + $addToPlaylist = '<li><a rel="' . $records . '" class="addToPlaylist" href="' . $playlist . '" title="' + . $artistName . ' - ' . $this->getValue($data['albumTitle']) . '">Click here to add this album to your playlist</a></li>'; + + $albumList .= sprintf($albumTemplate, + '', $this->getImage($data, 'Cover for '. $this->getValue($data['albumTitle']), 0, 'cover'), + $artistName, $this->getValue($data['albumTitle']), $addToPlaylist + ); + } + + $additionalInfo = ''; + if (isset($data['location'])) { + $additionalInfo .= '<li><a href="' . $this->getValue($data['location']) . '">Geonames Location</a></li>'; + } + if (isset($data['sameAs'])) { + // woot! we have a musicbrainz-ID, fetch more information, and link profiles + $link = $this->getValue($data['sameAs']); + $mbid = str_replace('http://zitgist.com/music/artist/', '', $link); + + $additionalInfo .= '<li><a href="' . $link . '">Zitgist-Dataviewer</a></li>'; + // append musicbrainz-link + $mbLink = 'http://musicbrainz.org/show/artist/?mbid=' . $mbid; + $additionalInfo .= '<li><a href="' . $mbLink . '">Musicbrainz profile</a></li>'; + // append last-fm information, if avaiable + $last = new LastFM(); + $lastfmLink = $last->getArtistPage($mbid); + if ($lastfmLink) { + $additionalInfo .= '<li><a href="' . $lastfmLink . '">Artist page on last.fm</a></li>'; + } + } + // show the frame if we have additional information + if (isset($data['location']) || isset($data['sameAs'])) { + $additionalInfo = '<h3>Information from external sources</h3><ul class="linkList">' . $additionalInfo; + $additionalInfo .= '</ul><iframe src=""></iframe>'; + } + + $this->html .= sprintf($template, + $artistName, $image, $tags, $homepage, $albumList, $additionalInfo + ); + + } + + /** - * Returns a list of <li>s with playlist-entries, no surrounding <ul> + * Builds a list of <li>s with playlist-entries, no surrounding <ul> * * @param array $data An array of playlist-items - * @return string playlist-HTML ready to use * @author Steffen Becker */ private function playlistHTML($data) { @@ -420,15 +500,16 @@ * @param array $image The complete result-array * @param string $altText The alt-Text the image will have * @param int $index optional, used for getValue for specific value-retrieval - * @return void + * @param string $type optional, default is image, can be set to 'cover' + * @return string The <img>-Tag * @author Steffen Becker */ - private function getImage($image, $altText, $index = 0) { + private function getImage($image, $altText, $index = 0, $type = 'image') { // in most cases the image is optional, so it could be empty $img = '<img src="img/noimage.png" alt="No image found..." />'; - if (isset($image['image'])) { - $image = $image['image']; - if (!empty($image)) { + if (isset($image[$type])) { + $image = $image[$type]; + if ($this->getValue($image, $index)) { $img = '<img src="' . $this->getValue($image, $index) . '" alt="' . $altText . '" />'; } } @@ -474,7 +555,7 @@ <strong>Tags:</strong><br/ > <p>%s</p> <p> - <strong>Avaiable records:</strong><br /> + <strong>Avaiable albums:</strong><br /> </p> <ul>%s</ul> <p>Click on an album to add it to your playlist.</p> @@ -492,14 +573,29 @@ } if ($type == 'albumSearch' || $type == 'songSearch') { $template = ' - <li class="clearfix %s"> - <h3>%s</h3> - <div class="image">%s</div> - <p>Tags: %s</p> - <ul>%s</ul> - </li> - '; + <li class="clearfix %s"> + <h3>%s</h3> + <div class="image">%s</div> + <p>Tags: %s</p> + <ul>%s</ul> + </li> + '; } + if ($type == 'info') { + $template = ' + <h2>More Information for »%s«</h2> + <div class="image">%s</div> + <p>Tags: %s</p> + %s + <h3>Avaiable albums</h3> + <div class="results"> + <ul> + %s + </ul> + </div> + %s + '; + } return $template; } @@ -522,7 +618,11 @@ return $value[0]; } if (count($value) > 1 && $index !== false) { - return $value[$index]; + if (isset($value[$index])) { // the index could not be set + return $value[$index]; + } else { + return ''; + } } else { // an array is requested, tagList for example return $value; } Modified: trunk/src/moosique.net/moosique/config.ini =================================================================== --- trunk/src/moosique.net/moosique/config.ini 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/config.ini 2009-11-01 22:53:41 UTC (rev 1901) @@ -37,6 +37,7 @@ topTagsUrl = "http://ws.audioscrobbler.com/2.0/?method=user.gettoptags" topArtistsUrl = "http://ws.audioscrobbler.com/2.0/?method=user.gettopartists" artistsTopTagsUrl = "http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags" +artistInfoUrl = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo" ; number of tags we fetch results for topTags = 5 ; if the user has no tags, number of artists to fetch tags for Modified: trunk/src/moosique.net/moosique/main.wsdl =================================================================== --- trunk/src/moosique.net/moosique/main.wsdl 2009-10-29 08:18:43 UTC (rev 1900) +++ trunk/src/moosique.net/moosique/main.wsdl 2009-11-01 22:53:41 UTC (rev 1901) @@ -0,0 +1,1520 @@ +<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://server.dllearner.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://server.dllearner.org/" name="DLLearnerWSService"> + <types> + <xsd:schema> + <xsd:import schemaLocation="def0.xsd" namespace="http://server.dllearner.org/"></xsd:import> + </xsd:schema> + <xsd:schema> + <xsd:import schemaLocation="def1.xsd" namespace="http://jaxb.dev.java.net/array"></xsd:import> + </xsd:schema> + </types> + <message name="init"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:int"></part> + </message> + <message name="initResponse"></message> + <message name="ClientNotKnownException"> + <part element="tns:ClientNotKnownException" name="fault"></part> + </message> + <message name="UnknownComponentException"> + <part element="tns:UnknownComponentException" name="fault"></part> + </message> + <message name="ComponentInitException"> + <part element="tns:ComponentInitException" name="fault"></part> + </message> + <message name="stop"> + <part name="arg0" type="xsd:int"></part> + </message> + <message name="stopResponse"></message> + <message name="getBuild"></message> + <message name="getBuildResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="ping"></message> + <message name="pingResponse"> + <part name="return" type="xsd:boolean"></part> + </message> + <message name="generateID"></message> + <message name="generateIDResponse"> + <part name="return" type="xsd:int"></part> + </message> + <message name="getComponents"></message> + <message name="getComponentsResponse"> + <part xmlns:ns1="http://jaxb.dev.java.net/array" name="return" type="ns1:stringArray"></part> + </message> + <message name="getKnowledgeSources"></message> + <message name="getKnowledgeSourcesResponse"> + <part xmlns:ns2="http://jaxb.dev.java.net/array" name="return" type="ns2:stringArray"></part> + </message> + <message name="getReasoners"></message> + <message name="getReasonersResponse"> + <part xmlns:ns3="http://jaxb.dev.java.net/array" name="return" type="ns3:stringArray"></part> + </message> + <message name="getLearningProblems"></message> + <message name="getLearningProblemsResponse"> + <part xmlns:ns4="http://jaxb.dev.java.net/array" name="return" type="ns4:stringArray"></part> + </message> + <message name="getLearningAlgorithms"></message> + <message name="getLearningAlgorithmsResponse"> + <part xmlns:ns5="http://jaxb.dev.java.net/array" name="return" type="ns5:stringArray"></part> + </message> + <message name="getConfigOptions"> + <part name="arg0" type="xsd:string"></part> + <part name="arg1" type="xsd:boolean"></part> + </message> + <message name="getConfigOptionsResponse"> + <part xmlns:ns6="http://jaxb.dev.java.net/array" name="return" type="ns6:stringArray"></part> + </message> + <message name="addKnowledgeSource"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:string"></part> + <part name="arg2" type="xsd:string"></part> + </message> + <message name="addKnowledgeSourceResponse"> + <part name="return" type="xsd:int"></part> + </message> + <message name="MalformedURLException"> + <part element="tns:MalformedURLException" name="fault"></part> + </message> + <message name="removeKnowledgeSource"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:int"></part> + </message> + <message name="removeKnowledgeSourceResponse"></message> + <message name="setReasoner"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:string"></part> + </message> + <message name="setReasonerResponse"> + <part name="return" type="xsd:int"></part> + </message> + <message name="setLearningProblem"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:string"></part> + </message> + <message name="setLearningProblemResponse"> + <part name="return" type="xsd:int"></part> + </message> + <message name="setLearningAlgorithm"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:string"></part> + </message> + <message name="setLearningAlgorithmResponse"> + <part name="return" type="xsd:int"></part> + </message> + <message name="LearningProblemUnsupportedException"> + <part element="tns:LearningProblemUnsupportedException" name="fault"></part> + </message> + <message name="initAll"> + <part name="arg0" type="xsd:int"></part> + </message> + <message name="initAllResponse"></message> + <message name="learn"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:string"></part> + </message> + <message name="learnResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="learnDescriptionsEvaluated"> + <part name="arg0" type="xsd:int"></part> + </message> + <message name="learnDescriptionsEvaluatedResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="getCurrentlyBestEvaluatedDescriptions"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:int"></part> + </message> + <message name="getCurrentlyBestEvaluatedDescriptionsResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="learnDescriptionsEvaluatedLimit"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:int"></part> + </message> + <message name="learnDescriptionsEvaluatedLimitResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="learnThreaded"> + <part name="arg0" type="xsd:int"></part> + </message> + <message name="learnThreadedResponse"></message> + <message name="getCurrentlyBestConcept"> + <part name="arg0" type="xsd:int"></part> + </message> + <message name="getCurrentlyBestConceptResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="getCurrentlyBestConcepts"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:int"></part> + <part name="arg2" type="xsd:string"></part> + </message> + <message name="getCurrentlyBestConceptsResponse"> + <part xmlns:ns7="http://jaxb.dev.java.net/array" name="return" type="ns7:stringArray"></part> + </message> + <message name="getCurrentlyBestEvaluatedDescriptionsFiltered"> + <part name="arg0" type="xsd:int"></part> + <part name="arg1" type="xsd:int"></part> + <part name="arg2" type="xsd:double"></part> + <part name="arg3" type="xsd:boolean"></part> + </message> + <message name="getCurrentlyBestEvaluatedDescriptionsFilteredResponse"> + <part name="return" type="xsd:string"></part> + </message> + <message name="isAlgorithmRunning"> + <part name="arg0" type="xsd:int"></part> + </message> + <message name="... [truncated message content] |
From: <neb...@us...> - 2009-11-14 21:07:54
|
Revision: 1911 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1911&view=rev Author: nebelschwade Date: 2009-11-14 21:07:39 +0000 (Sat, 14 Nov 2009) Log Message: ----------- Added a log-history for adding/removing items to the playlist Fixed a major bug that made continuous playing impossible due to a Yahoo-Media-Player-"Bug" Enhanced OWL Major DRY-Refactoring Minor View/Frontend-Issues Help Modified Paths: -------------- trunk/src/moosique.net/README.txt trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/index.php trunk/src/moosique.net/js/moosique.js trunk/src/moosique.net/js/mootools-1.2.4.2-more-yc.js trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/classes/DataHelper.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/Recommendations.php trunk/src/moosique.net/moosique/classes/RequestHandler.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/data/moosique.owl trunk/src/moosique.net/moosique/testing/nodeExtractionBug.conf Added Paths: ----------- trunk/src/moosique.net/moosique/testing/salsaTest.php trunk/src/moosique.net/moosique/testing/stonerTest.php trunk/src/moosique.net/moosique/testing/stonerTestSmall.php Removed Paths: ------------- trunk/src/moosique.net/moosique/testing/jamendo.owl trunk/src/moosique.net/moosique/testing/jamendo_complete.owl trunk/src/moosique.net/moosique/testing/learnTest.php trunk/src/moosique.net/moosique/testing/moosique.conf trunk/src/moosique.net/moosique/testing/moreThan80.owl trunk/src/moosique.net/moosique/testing/newOwl.owl trunk/src/moosique.net/moosique/testing/nodeExtractionBug_2.conf trunk/src/moosique.net/moosique/testing/rocksubset.owl Modified: trunk/src/moosique.net/README.txt =================================================================== --- trunk/src/moosique.net/README.txt 2009-11-11 21:04:26 UTC (rev 1910) +++ trunk/src/moosique.net/README.txt 2009-11-14 21:07:39 UTC (rev 1911) @@ -5,32 +5,25 @@ See /moosique/config.ini -- PHP 5.2.x +- PHP 5.2.x or above (yes, 5.3 works) - output_buffering has to be enabled to use debugging features (if enabled in config.ini) (FirePHP is included in this package) - - installed PEAR-Packages HTTP and HTTP_Request (used by Utilities.php from DL-Learner) + - PEAR-Packages HTTP and HTTP_Request (used by Utilities.php from DL-Learner) - - A running DL-Learner Webservice Instance - - Set paths in config.ini + - Set paths/URLs in config.ini Notes: ====== - This is a modern piece of websoftware, use a modern browser! - - Tested and working in: - - Firefox 3.5.x - - Safari 4.x and Webkit nightly build r49764 - - Google Chrome 4.0.x - - Opera 10.x - - Untested: - - Internet Explorer and other platform-unindependent browsers - -- JavaScript has to be enabled, this is an AJAX-Application and uses the - Yahoo Media Player-Script! - -- - + Tested and working in: + - Firefox 3.5.x + - Safari 4.x and Webkit nightly build r50383 + - Chromium Build 30678 + - Opera 10.x (though not as beautiful) +- JavaScript has to be enabled, this is an after all an AJAX-Application - Debugging makes use of Firebug/FirePHP, thus only working in Firefox - @@ -38,5 +31,13 @@ Known Bugs: =========== +- Moving the current playing song in the playlist down or up + breaks the order of the playlist in the Yahoo Media Player`` -- \ No newline at end of file + +Planned Features: +================= +- RDFa Support for artist information +- Unique URLs for ajax (bookmarkable, Back-Button) +- Scrobbling-Support for last.fm +- Playlist export and Download Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-11-11 21:04:26 UTC (rev 1910) +++ trunk/src/moosique.net/css/style.css 2009-11-14 21:07:39 UTC (rev 1911) @@ -21,12 +21,12 @@ a:hover { color: #1fd611; } a.button { background: #4a4a4a; color: #f1f7e4; padding: 5px 10px; text-decoration: none; } a.button:hover { border: 1px solid #1fd611; padding: 4px 9px; } -h1 { font: 36px/36px Georgia, Times, serif; } -h2 { font: 30px/30px Georgia, Times, serif; } -h3 { font: 24px/24px Georgia, Times, serif; } -h4 { font: 18px/18px Georgia, Times, serif; } -h5 { font: 14px/14px Georgia, Times, serif; } -h6 { font: 12px/12px Georgia, Times, serif; } +h1 { font: 36px/42px Georgia, Times, serif; } +h2 { font: 30px/36px Georgia, Times, serif; } +h3 { font: 24px/28px Georgia, Times, serif; } +h4 { font: 18px/20px Georgia, Times, serif; } +h5 { font: 14px/16px Verdana, Arial, sans-serif; } +h6 { font: 12px/14px Verdana, Arial, sans-serif; } pre { font: normal 10px/14px Monaco, Courier, monospace; } p, h1, h2, h3, h4, h5, h6, ul, ol, pre, form { margin-bottom: 20px; } @@ -43,14 +43,14 @@ #nav a { -moz-border-radius-bottomleft: 10px; -moz-border-radius-bottomright: 10px; -webkit-border-bottom-left-radius: 10px; -webkit-border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; border-bottom-left-radius: 10px; } -#info .linkList li { -moz-border-radius-topleft: 10px; -moz-border-radius-topright: 10px; +#info .externalLinks li { -moz-border-radius-topleft: 10px; -moz-border-radius-topright: 10px; -webkit-border-top-left-radius: 10px; -webkit-border-top-right-radius: 10px; border-top-left-radius: 10px; border-top-left-radius: 10px; } #content, #status, #playing, #playerControls, #topBorder, #searchValue, #searchType, #searchSubmit, #nav a, -#info .linkList li { -moz-box-shadow: 2px 2px 3px #191919; -webkit-box-shadow: 2px 2px 3px #191919; +#info .externalLinks li { -moz-box-shadow: 2px 2px 3px #191919; -webkit-box-shadow: 2px 2px 3px #191919; box-shadow: 2px 2px 3px #191919; } #nav .active a, .results img, a.button, #info .image img { -moz-box-shadow: 3px 3px 3px #191919; -webkit-box-shadow: 3px 3px 3px #191919; @@ -64,7 +64,7 @@ #container { width: 900px; margin: 0 auto; } #header { height: 175px; padding-top: 25px; } #content { background: #292929; padding: 25px; } -#footer { font: normal 11px/14px Verdana, Arial, sans-serif; padding-top: 40px; text-align: center; } +#footer { font: normal 11px/14px Verdana, Arial, sans-serif; padding-top: 40px; height: 54px; text-align: center; } /*=============== Player Controls, Status, Playing ===============*/ @@ -97,6 +97,7 @@ /*=============== Content & General ===============*/ #addRandom { text-decoration: underline; } +#autoAdd { float: right; } #footer a { padding: 0 12px; color: #5a5a5a; } #footer a:hover { color: #f1f7e4; } #help ul { list-style: disc; margin-left: 40px; } @@ -112,30 +113,20 @@ #nav a:hover { text-decoration: none; background: #5a5a5a; } -/*=============== Search Results, Recommendations & Playlist ===============*/ +/*=============== Search Results & Recommendations ===============*/ .results h3 a { font-weight: normal; } -.results img { max-width: 373px; max-height: 373px; } -.results li { float: left; width: 373px; border: 1px solid #5a5a5a; padding: 20px; margin-bottom: 20px; } +.results img { max-width: 373px; max-height: 373px;} +.results ul > li { float: left; width: 373px; border: 1px solid #5a5a5a; padding: 20px; margin-bottom: 20px; } .results li.odd { margin-right: 20px; clear: both; } -.results ul ul { list-style: disc; margin-bottom: 0; } -.results li li, -.artistSearch li li, -.tagSearch li li, -#info li li { border: none; display: list-item; padding: 0; margin: 0 0 0 36px; - width: auto; height: auto; float: none; } +.results ul ul, #log { clear: both; list-style: disc; margin-bottom: 0; } +.results li li, #log li { border: none; display: list-item; padding: 0; margin: 0 0 0 20px; width: auto; } +.results .image { text-align: center; } +.results .tagList { margin-top: 20px; } -.results h4 { display: inline; } -#recommendationResults ul ul, -.tagSearch ul ul, -#info ul ul { clear: both; } -.results .image { text-align: center; margin-bottom: 20px; } -#recommendationResults.results .image, -.results .tagSearch .image { margin: 0 20px 20px 0; width: 104px; height: 104px; float: left; } -#autoAdd { float: right; } - +/*=============== Recently & Playlist ===============*/ #playlist, #recently { margin-left: 36px; list-style: decimal; } #playlist li, #recently li { line-height: 24px; } -#playlist .ymp-btn-page-pause { font-weight: bold; } +#playlist .currentlyPlaying a { font-weight: bold; color: #1fd611; } #playlist .delete, #playlist .moveUp, #playlist .moveDown { position: absolute; display: block; top: 5px; right: 20px; width: 14px; height: 14px; @@ -149,12 +140,13 @@ /*=============== Information & Help ===============*/ +#info .image { float: left; margin: 0 20px 20px 0; } +#info .tagList { margin-bottom: 20px; } #info h3 { clear: both; } -#info .image { width: auto; float: left; margin: 0 20px 20px 0;} #info iframe { border: 1px solid #5a5a5a; width: 100%; height: 600px; } -#info .linkList { overflow: hidden; margin: 0 0 0 20px; } -#info .linkList li { float: left; padding: 10px; margin-right: 10px; background: #4a4a4a; } -#info .linkList li.active { background: #1fd611; } +#info .externalLinks { overflow: hidden; margin: 0 0 0 20px; } +#info .externalLinks li { float: left; padding: 10px; margin-right: 10px; background: #4a4a4a; } +#info .externalLinks li.active { background: #1fd611; } } /* end @media screen */ \ No newline at end of file Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-11-11 21:04:26 UTC (rev 1910) +++ trunk/src/moosique.net/index.php 2009-11-14 21:07:39 UTC (rev 1911) @@ -1,10 +1,9 @@ <?php - session_start(); - /* - Welcome to moosique.net - a semantic web based internet-radio - - see README.txt for more details - */ +session_start(); +/* +Welcome to moosique.net - a semantic web based internet-radio +see README.txt and moosique/config.ini for more details +*/ ?> <!DOCTYPE html> <html lang="en"> @@ -61,17 +60,18 @@ <div id="results" class="results"> <h2>Welcome to moosique.net!</h2> <p> - Want to listen to some good free music? Search for something you like and add it to your playlist. + Want to listen to some good free music? Search for something you like and add it to your playlist. + You can search for artists, albums, songs and of course tags. + You can also enter your <a href="http://last.fm">last.fm</a>-username to automatically use your + most-used tags to generate a initial list of recommendations. By listening to songs you like, moosique will automatically try to learn about your musical taste and generate recommendations. You can find them in the tab »Recommendations«. - You can also enter your <a href="http://last.fm">last.fm</a>-username to automatically use your - most-used tags to generate a initial list of recommendations. </p> <p> After you have found something you want to listen to, just add it to your playlist and click the play-button. </p> <p> - Need help? Click on the »Help«-Tab to get more information about how to use moosique.net + Need help? Click on the »Help«-Tab to get more information about how to use moosique.net. </p> </div> </div> @@ -114,6 +114,10 @@ <li></li> </ol> <p><a href="#" id="resetRecently" class="button" title="Click here to reset your »recently listened to«-list.">Reset</a></p> + <h2>History</h2> + <ul id="log"> + <li>Nothing happened yet.</li> + </ul> </div> <div id="help"> <h2>How to use moosique.net</h2> @@ -126,12 +130,44 @@ If you are searching for tags, and your search is more than one word, the results will be better. For example: a search for "rock" will give you lots of results, where a search for "hard rock" will be more specific, giving you better search results. Just try it, you can't break anything. + Sometimes searching can take quite some time, this is where you just have to be patient... but + the system will always give you feedback on what it is doing at the moment. </p> + <h3>Player and playlist functions</h3> + <p> + The player-interface is visible, no matter where on the page your are or what you are doing. + You can always get information about the currently playing song in the status-planel on the + left, and you can always control the player with the buttons on the top-right. If you click + on the tab »Playlist« you will see what songs will play next and you can change + their order, or even delete songs from your playlist. There is also a »Recently listened + to«-list where you have an overview of the last 10 songs you have listened to. + You can reset both of these lists to "restart" from the beginning. + You can always download a song to your computer you are listening to by clicking on the link + »Download this song« in the player status panel. + </p> <h3>Recommendations</h3> <p> - moosique.net uses the mighty <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> to generate recommendations - based on the songs you have listened to. + moosique.net uses <a href="http://aksw.org/Projects/DLLearner">DL-Learner</a> to generate recommendations + based on the songs you have listened to. These songs can be found when clicking on the tab »Playlist«. + The recommendations are based on the tags of an album, or song + from an album, you have listened to. Recommendations are created every time you listen to a song for at + least half its length, just like scrobbling on last.fm. You can also manually generate your recommendations + by clicking on the corresponding link. If you have »Autoadd recommendations« checked, a new + song from your recommendations is added, everytime they are generated. The system always remembers your + 10 most recently listened to songs by storing them in a cookie. So you can come back a week later and + restart, where you left. </p> + <p> + If something goes wrong and you don't get any recommendations or they are not what you expected, + just try resetting your »recently listened to«-list and listen to some more songs. + </p> + <h3>More Info</h3> + <p> + Every time you start listening to a song, the tab »More Info« refreshes to show + more infomation about the artist, you are currently listening to. If there are any external + sources of information, you can access them at the bottom of the page, by clicking on the + different tabs (such as Geonames location, last.fm profile etc.). + </p> <h3>Requirements</h3> <p> To use moosique.net you should have: @@ -140,7 +176,7 @@ <li>A decent, modern browser, such as <a href="http://getfirefox.com">Firefox</a>, <a href="http://apple.com/de/safari/download/">Safari</a> or <a href="http://google.com/chrome/">Google Chrome</a></li> <li>JavaScript activated</li> <li>The <a href="http://www.adobe.com/se/products/flashplayer/">Adobe Flash Player</a> plugin for your browser</li> - <li>A fast internet connection</li> + <li>A fast internet connection, it's a streaming application...</li> <li>Some good headphones or loudspeakers of course. It's moosique after all!</li> </ul> </div> Modified: trunk/src/moosique.net/js/index.php =================================================================== --- trunk/src/moosique.net/js/index.php 2009-11-11 21:04:26 UTC (rev 1910) +++ trunk/src/moosique.net/js/index.php 2009-11-14 21:07:39 UTC (rev 1911) @@ -22,7 +22,7 @@ /* the javascript-files to include and compress */ include('mootools-1.2.4-core-yc.js'); -include('mootools-1.2.4.2-more-yc-min.js'); +include('mootools-1.2.4.2-more-yc.js'); include('moosique.js'); include('start.js'); Modified: trunk/src/moosique.net/js/moosique.js =================================================================== --- trunk/src/moosique.net/js/moosique.js 2009-11-11 21:04:26 UTC (rev 1910) +++ trunk/src/moosique.net/js/moosique.js 2009-11-14 21:07:39 UTC (rev 1911) @@ -1,13 +1,18 @@ /** * moosique-Player-Class * - * TODO - * - * * @package moosique.net * @author Steffen Becker */ var Moosique = new Class({ Implements: Options, + + /* used for the ymp-bug when refreshing the playlist + Explanation: If the playlist for the YMP ist reloaded using + YAHOO.MediaPlayer.addTracks(that.playlist, null, true) the "active" + track will always be reset to the first on in the playlist. + Thus we try to remember where the active track was before reloading + the playlist and use this number as next/previous multiplicator */ + currentPlaylistPosition: 0, // set some default options options: { @@ -59,6 +64,7 @@ // playlist and recently this.playlist = document.id('playlist'); this.recently = document.id('recently'); + this.log = document.id('log'); this.resetPlaylist = document.id('resetPlaylist'); this.resetRecently = document.id('resetRecently'); // recommendations @@ -75,6 +81,7 @@ this.info = document.id('info'); }, + /** * Applies Config-Vars to the Yahoo Media Player as described in http://mediaplayer.yahoo.com/api/ * for the YMP-Events and initializes the Player. Events are: @@ -100,7 +107,6 @@ if (Math.ceil(YAHOO.MediaPlayer.getTrackPosition()) == Math.ceil(YAHOO.MediaPlayer.getTrackDuration() * that.options.timeToScrobble)) { - // first, we update the cookie with the last played song and then var lastListenedListItem = YAHOO.MediaPlayer.getMetaData().anchor.getParent().clone(); var lastListened = lastListenedListItem.getFirst(); @@ -132,7 +138,6 @@ } } recentlyListened.push(last); // add the last played to the array - // update the cookie recentlyListenedObject = { 'recentlyListened' : recentlyListened }; recentlyListenedCookie = Cookie.write( /* save for one year */ @@ -147,59 +152,12 @@ /** * playlistUpdate: every time the playlist is updated we add the events for - * delete/up/down-buttons to each playlistitem and update the status on what happened + * delete/up/down-buttons to each playlistitem */ var playlistUpdate = function() { - // delete button - that.playlist.getElements('.delete').each(function(del) { - del.removeEvents(); - del.addEvent('click', function(e) { - e.stop(); // don't folow link - // if current or the last song from the playlist stop playing - if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { - that.stopPlaying(); - } - this.getParent().destroy(); // deletes the li-element - that.refreshPlaylist(); - }); - }); - - // up-button - that.playlist.getElements('.moveUp').each(function(up) { - up.removeEvents(); - up.addEvent('click', function(e) { - e.stop(); - if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { - that.stopPlaying(); - } - var li = up.getParent(); - var before = li.getPrevious(); - if (before) { // it's not the first one - li.inject(before, 'before'); - that.refreshPlaylist(); - } - }); - }); - - // down button - that.playlist.getElements('.moveDown').each(function(down) { - down.removeEvents(); - down.addEvent('click', function(e) { - e.stop(); - if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { - that.stopPlaying(); - } - var li = down.getParent(); - var after = li.getNext(); - if (after) { // it's not the first one - li.inject(after, 'after'); - that.refreshPlaylist(); - } - }); - }); - that.displayStatusMessage('Playlist updated.'); + that.addEventsToPlaylistButtons(); }; - + /** * trackPause: we change the Pause-Button to a Play-Button * and Update the status on #now @@ -208,17 +166,19 @@ that.nowPlayingInfo.set('text', 'Player paused.'); that.playPause.setStyle('background-position', '0px 0px'); }; - + /** * trackStart: we change the Play-Button to a Pause-Button * and Update the status on #now and display whats playing - * TODO: when a track started playing, fetch additional information about artist etc. using musicbrainz + * and fetch/display more information about the artist in the + * more-info-tab */ var trackStart = function() { that.nowPlayingInfo.set('text', 'Currently playing:'); that.nowPlayingTrack.set('text', YAHOO.MediaPlayer.getMetaData().title); that.download.set('href', YAHOO.MediaPlayer.getMetaData().anchor.get('href')); that.playPause.setStyle('background-position', '0px -40px'); // sprite offset + that.toggleCurrentlyPlaying(); // send a request to gather additional artist-information var nowPlayingAlbum = YAHOO.MediaPlayer.getMetaData().anchor.get('rel'); @@ -232,16 +192,19 @@ } }).send('info=' + nowPlayingAlbum); }; - + /** * trackComplete: we change the Pause-Button to a Play-Button - * and execute the autoAdd-Function for adding recommendations + * and stop playing, use the special nextTrack() function to get rid + * of the "restart from the beginning"-YMP-bug and start start playing again */ var trackComplete = function() { that.playPause.setStyle('background-position', '0px 0px'); - that.autoAddToPlaylist(); + that.stopPlaying(); + that.nextTrack(); + YAHOO.MediaPlayer.play(); }; - + // add the configuration to the events by subscribing YAHOO.MediaPlayer.onProgress.subscribe(progress); YAHOO.MediaPlayer.onPlaylistUpdate.subscribe(playlistUpdate); @@ -249,7 +212,6 @@ YAHOO.MediaPlayer.onTrackStart.subscribe(trackStart); YAHOO.MediaPlayer.onTrackComplete.subscribe(trackComplete); }; - // Initialize YMP if ready and apply the config YAHOO.MediaPlayer.onAPIReady.subscribe(playerConfig); }, @@ -269,11 +231,9 @@ onRequest: function() { that.recResults.set('html', '<h2>Generating new recommendations...</h2><p>Please be patient, this may take up to a minute...</p>'); }, - onFailure: function() { that.recResults.set('html', '<h2>Unable to get recommendations. Please reset and try again.</h2>'); }, - onSuccess: function(response) { response = response.trim(); if (response != '') { @@ -281,9 +241,9 @@ that.makeAddable($$('a.addToPlaylist')); that.showTab('recommendations'); that.displayStatusMessage('You have new recommendations!'); - + if (that.autoAddCheckbox.checked) { - that.addRandomToPlaylist(); + that.addRandomToPlaylist('auto'); } else { debug.log('Autoadding songs from recommendations is disabled.'); } @@ -323,70 +283,45 @@ that.recently.set('html', '<li></li>'); } }, - - + + /** - * Adds click-events to all player-related buttons, like play, next etc. buttons + * This function is called everytime a track starts playing + * and adds the class currentlyPlaying to the parent-li of + * the currently playing song */ - addEventsToButtons: function() { + toggleCurrentlyPlaying: function() { var that = this; - - that.prev.addEvent('click', function(e) { - e.stop(); - YAHOO.MediaPlayer.previous(); - }); - - that.next.addEvent('click', function(e) { - e.stop(); - YAHOO.MediaPlayer.next(); - }); - - // the Play-Pause Button - that.playPause.addEvent('click', function(e) { - e.stop(); - // STOPPED: 0, PAUSED: 1, PLAYING: 2,BUFFERING: 5, ENDED: 7 - // see http://mediaplayer.yahoo.com/api/ - if (YAHOO.MediaPlayer.getPlayerState() == 0 || - YAHOO.MediaPlayer.getPlayerState() == 1 || - YAHOO.MediaPlayer.getPlayerState() == 7) { - YAHOO.MediaPlayer.play(); - } else { - YAHOO.MediaPlayer.pause(); - } - }); - - // the Stop-Playing Button - that.stop.addEvent('click', function(e) { - e.stop(); - that.stopPlaying(); - }); - - // Mute-Toggle-Switch - that.mute.addEvent('click', function(e) { - e.stop(); - if (YAHOO.MediaPlayer.getVolume() > 0) { - YAHOO.MediaPlayer.setVolume(0); - that.mute.setStyle('background-position', '0px -240px'); - that.displayStatusMessage('Player muted.'); - } else { - YAHOO.MediaPlayer.setVolume(1); - that.mute.setStyle('background-position', '0px -280px'); - that.displayStatusMessage('Player unmuted.'); - } - }); + that.playlist.getElements('li.currentlyPlaying').removeClass('currentlyPlaying'); + var currentTrack = YAHOO.MediaPlayer.getMetaData().anchor; + currentTrack.getParent().addClass('currentlyPlaying'); }, - + /** - * Refreshes the YMP-playlist by emptying the current one - * and re-adding all items from the the playlist-container + * Set the current active playlist position using the class + * currentlyPlaying to determine the active item. Saves the + * position as an int in this.currentPlaylistPosition */ - refreshPlaylist: function() { + setCurrentPlaylistPosition: function() { var that = this; - YAHOO.MediaPlayer.addTracks(that.playlist, '', true); + var tracks = that.playlist.getChildren(); + var tracksInPlaylist = tracks.length; + var playing = false; + // go through all playlistitems and save the position of the currentlyPlaying one + for (var i = 0; i < tracksInPlaylist; i++ ) { + if (tracks[i].get('class') == 'currentlyPlaying') { + that.currentPlaylistPosition = i; + playing = true; + } + } + // if there was no currentlyPlaying-item set the currentPlaylistPosition to 0 + if (!playing) { + that.currentPlaylistPosition = 0; + } }, - - + + /** * This function stops the player and displays the default * status-message "Player stopped", also refreshes the playlist @@ -399,112 +334,32 @@ that.nowPlayingTime.set('text', '0:00 / 0:00'); that.download.set('href', '#'); YAHOO.MediaPlayer.stop(); - // and reload the playlist + // and refresh the playlist that.refreshPlaylist(); }, - - - /** - * Displays a status message, fades out nicely - * - * @param {String} message - */ - displayStatusMessage: function(message) { - // Update Status and fade out - var that = this; - var fadeFX = new Fx.Tween(that.status, { - property: 'opacity', - duration: that.options.messageFadeTime / 2, - transition: Fx.Transitions.Expo.easeOut, - link: 'chain' - }); - - that.status.set('text', message); - fadeFX.start(0, 1); - fadeFX.start(1, 0); - }, /** - * Adds click-Events to the Interface for Tabs and invokes - * addEventsToButtons() + * Skips to the track for x+1 times from the beginning, where x is + * the current active position in the playlist */ - initInterface: function() { + nextTrack: function() { var that = this; - // tabbed nav - that.nav.getElements('a').each(function(tab) { - tab.addEvent('click', function(e) { - e.stop(); // dont follow link - that.showTab(tab.get('class').toString()); - }); - }); - // generating recommendations clickable - that.generate.addEvent('click', function(e) { - e.stop(); - that.generateRecommendations(); - }); - // enable resetting recently list - that.resetRecently.addEvent('click', function(e) { - e.stop(); - Cookie.dispose('moosique'); - that.updateRecently(); - }); - // enable resetting the playlist - that.resetPlaylist.addEvent('click', function(e) { - e.stop(); - that.playlist.empty(); - that.stopPlaying(); - }); - // enable the manual add random to playlist - that.addRandom.addEvent('click', function(e) { - e.stop(); - that.addRandomToPlaylist(); - }); - // make player-buttons functional - this.addEventsToButtons(); + for (var i = 0; i < that.currentPlaylistPosition + 1; i++) { + YAHOO.MediaPlayer.next(); + } }, /** - * Make the search-Form an ajax-Search form, displaying the results - * on the homepage if successful + * Skips to the track for x-1 times from the beginning, where x is + * the current active position in the playlist */ - activateSearch: function() { + previousTrack: function() { var that = this; - var spinner = new Spinner(that.searchSubmit); - - that.searchForm.addEvent('submit', function(e) { - e.stop(); // prevent form submitting the non-ajax way - this.set('send', { - - onRequest: function() { - spinner.show(); - that.searchSubmit.set('disabled', 'disabled'); - that.showTab('home'); - that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take up to a minute...</p>'); - }, - - onFailure: function() { - spinner.hide(); - that.results.set('html', '<h2>Unable to process your search. Try again.</h2>'); - }, - - onSuccess: function(response) { - spinner.hide(); - that.searchSubmit.erase('disabled'); // reenable submitbutton - that.results.set('html', response); - // addEvents to result-links - that.makeAddable($$('a.addToPlaylist')); - } - }); - - // only send form if value is at least 3 chars long - if (that.searchValue.get('value').length >= 3) { - this.send(); - } else { - that.displayStatusMessage('Please enter at least 3 chars for searching...'); - } - }); + for (var i = 0; i < that.currentPlaylistPosition - 1; i++) { + YAHOO.MediaPlayer.next(); + } }, @@ -538,6 +393,7 @@ var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', onSuccess: function(response) { that.insertIntoPlaylist(response); + that.addToLog(a, 0, ''); that.showTab('player'); } }).send('get=' + type + '&playlist=' + href + '&rel=' + rel); @@ -545,6 +401,7 @@ if (type == 'mp3File') { var itemHTML = '<li>' + a.getParent().get('html') + '</li>'; that.insertIntoPlaylist(itemHTML); + that.addToLog(a, 0, ''); that.showTab('player'); } }); @@ -553,6 +410,22 @@ /** + * Resets the class for all music-links in the playlist to htrack + */ + cleanPlaylist: function() { + var that = this; + // remove all classes from the links, except for htrack + that.playlist.getElements('a').each(function(a) { + if (a.hasClass('moveUp') || a.hasClass('moveDown') || a.hasClass('delete')) { + // we don't touch the playlist-moving-buttons + } else { // reset to htrack, nothing else + a.set('class', 'htrack'); + } + }); + }, + + + /** * appends prepared html code to the playlist, empties the playlist if the first * element is an empty li and refreshed the playlist and shows the playlist tab * @@ -560,7 +433,6 @@ */ insertIntoPlaylist: function(newItems) { var that = this; - // if the first li item of the playlist is empty, kill it if (that.playlist.getFirst()) { if (that.playlist.getFirst().get('text') == '') { @@ -570,6 +442,7 @@ // append new html to the playlist var oldPlaylist = that.playlist.get('html'); that.playlist.set('html', oldPlaylist + newItems); + that.cleanPlaylist(); // add the delete, moveUp, moveDown Buttons that.playlist.getChildren().each(function(li) { @@ -592,10 +465,24 @@ /** + * Refreshes the YMP-playlist by emptying the current one + * and re-adding all items from the the playlist-container + */ + refreshPlaylist: function() { + var that = this; + that.cleanPlaylist(); + that.setCurrentPlaylistPosition(); + YAHOO.MediaPlayer.addTracks(that.playlist, null, true); + }, + + + /** * This function adds a random song from a random record from the * recommendations results to the playlist (enqueue at the end) + * + * @param {String} type can be set to auto */ - addRandomToPlaylist: function() { + addRandomToPlaylist: function(type) { var that = this; var addableAlbums = that.recResults.getElements('.addToPlaylist'); // pick a random album @@ -604,7 +491,7 @@ if (randomAlbum) { var href = randomAlbum.get('href'); var rel = randomAlbum.get('rel'); - + var getPlaylist = new Request({method: 'get', url: 'moosique/index.php', onSuccess: function(response) { // yay, we have the playlist, choose a random song and add it @@ -612,40 +499,283 @@ var songs = Elements.from(response); var randomSong = songs.getRandom(); that.insertIntoPlaylist('<li>' + randomSong.get('html') + '</li>'); + // add an item to the history-log with additionalInfo + var extraInfoH3 = randomAlbum.getParent().getParent().getParent().getPrevious(); + var extraInfo = '(From ' + extraInfoH3.get('text') + ')'; + if (type == 'auto') { + that.addToLog(randomSong.get('html'), 2, extraInfo); + } else { + that.addToLog(randomSong.get('html'), 0, extraInfo); + } that.displayStatusMessage('Added a random song to your playlist.'); } }).send('get=playlist&playlist=' + href + '&rel=' + rel); } else { that.displayStatusMessage('You currently have no recommendations, nothing was added.'); - debug.log('You currently have no recommendations, adding a random song will not work.'); } }, /** - * Shows the given tab in the nav, and hides all others + * Adds a history-log entry for given link-elements * - * @param {String} tabID ID of the Tab to show + * @param {String} text The Text to add to the history-log + * @param {int} deleted If set to 1, the text displayed will be "You deleted..." if 2 "The System added" */ - showTab: function(tabID) { + addToLog: function(a, mode, extraString) { var that = this; - that.nav.getElements('li').removeClass('active'); - that.nav.getElements('a.' + tabID).getParent().toggleClass('active'); - that.content.getChildren().setStyle('display', 'none'); - document.id(tabID).setStyle('display', 'block'); + var item = false; + if ($type(a) == 'string') { item = Elements.from(a)[0]; } + else { item = a.clone(); } + // if the first item of the log is empty, remove it + if (that.log.getFirst()) { + if (that.log.getFirst().get('text') == 'Nothing happened yet.') { + that.log.empty(); + } + } + // slighty format the link + item.set('href', item.get('rel')); + item.removeProperties('rel', 'title', 'class'); + + if (item.getFirst()) { + if (item.getFirst().get('tag') == 'img') { + var title = item.getFirst().get('alt'); + item.set('text', title); + } + } + // a helper parent to convert to html + var parent = new Element('div'); + item.inject(parent); + + var text = 'You added <em>' + parent.get('html') + '</em> to your playlist'; + if (mode == 1) { text = 'You deleted the song <em>' + parent.get('html') + '</em> from your playlist.'; } + if (mode == 2) { text = 'The system added the song <em>' + parent.get('html') + 'to your playlist.'; } + + if (extraString != '') { text = text + ' ' + extraString; } + + var time = new Date().format('%H:%M:%S'); + var newLogEntry = new Element('li', { + 'class': 'someclass', + 'html': time + " — " + text + }); + newLogEntry.inject(that.log, 'top'); }, /** - * - * + * Adds click-Events to the Interface for Tabs and invokes + * addEventsToPlayerButtons() */ + initInterface: function() { + var that = this; + // tabbed nav + that.nav.getElements('a').each(function(tab) { + tab.addEvent('click', function(e) { + e.stop(); // dont follow link + that.showTab(tab.get('class').toString()); + }); + }); + // generating recommendations clickable + that.generate.addEvent('click', function(e) { + e.stop(); + that.generateRecommendations(); + }); + // enable resetting recently list + that.resetRecently.addEvent('click', function(e) { + e.stop(); + Cookie.dispose('moosique'); + that.updateRecently(); + }); + // enable resetting the playlist + that.resetPlaylist.addEvent('click', function(e) { + e.stop(); + that.playlist.empty(); + that.stopPlaying(); + }); + // enable the manual add random to playlist + that.addRandom.addEvent('click', function(e) { + e.stop(); + that.addRandomToPlaylist(''); + }); + // make player-buttons functional + this.addEventsToPlayerButtons(); + }, + + + /** + * Adds the events to the playlist buttons for removing or moving + * them around from/in the playlist + */ + addEventsToPlaylistButtons: function() { + var that = this; + // all buttons + that.playlist.getElements('.delete, .moveUp, .moveDown').each(function(all) { + all.removeEvents(); + all.addEvent('click', function(e) { + e.stop(); // don't folow link + // if current or the last song from the playlist stop playing + if (YAHOO.MediaPlayer.getMetaData().anchor.getParent() == this.getParent()) { + that.stopPlaying(); + } + // switch/case different buttons + var typeOfButton = all.get('class'); + var li = all.getParent(); + switch(typeOfButton) { + case 'delete' : + that.addToLog(this.getParent().getFirst(), 1, ''); + li.destroy(); // deletes the li-element + break; + case 'moveUp' : + var before = li.getPrevious(); + if (before) { // it's not the first one + li.inject(before, 'before'); + that.refreshPlaylist(); + } + break; + case 'moveDown' : + var after = li.getNext(); + if (after) { // it's not the first one + li.inject(after, 'after'); + that.refreshPlaylist(); + } + break; + } + // always refresh the playlist + that.refreshPlaylist(); + }); + }); + }, + + + /** + * Adds click-events to all player-related buttons, like play, next etc. buttons + */ + addEventsToPlayerButtons: function() { + var that = this; + + that.prev.addEvent('click', function(e) { + e.stop(); + that.stopPlaying(); + that.previousTrack(); + YAHOO.MediaPlayer.play(); + }); + + that.next.addEvent('click', function(e) { + e.stop(); + that.stopPlaying(); + that.nextTrack(); + YAHOO.MediaPlayer.play(); + }); + + // the Play-Pause Button + that.playPause.addEvent('click', function(e) { + e.stop(); + // STOPPED: 0, PAUSED: 1, PLAYING: 2,BUFFERING: 5, ENDED: 7 + // see http://mediaplayer.yahoo.com/api/ + if (YAHOO.MediaPlayer.getPlayerState() == 0 || + YAHOO.MediaPlayer.getPlayerState() == 1 || + YAHOO.MediaPlayer.getPlayerState() == 7) { + YAHOO.MediaPlayer.play(); + } else { + YAHOO.MediaPlayer.pause(); + } + }); + + // the Stop-Playing Button + that.stop.addEvent('click', function(e) { + e.stop(); + that.stopPlaying(); + }); + + // Mute-Toggle-Switch + that.mute.addEvent('click', function(e) { + e.stop(); + if (YAHOO.MediaPlayer.getVolume() > 0) { + YAHOO.MediaPlayer.setVolume(0); + that.mute.setStyle('background-position', '0px -240px'); + that.displayStatusMessage('Player muted.'); + } else { + YAHOO.MediaPlayer.setVolume(1); + that.mute.setStyle('background-position', '0px -280px'); + that.displayStatusMessage('Player unmuted.'); + } + }); + }, + + + /** + * Make the search-Form an ajax-Search form, displaying the results + * on the homepage if successful + */ + activateSearch: function() { + var that = this; + var spinner = new Spinner(that.searchSubmit); + + that.searchForm.addEvent('submit', function(e) { + e.stop(); // prevent form submitting the non-ajax way + this.set('send', { + + onRequest: function() { + spinner.show(); + that.searchSubmit.set('disabled', 'disabled'); + that.showTab('home'); + that.results.set('html', '<h2>Searching...</h2><p>Please be patient, this may take up to a minute...</p>'); + }, + + onFailure: function() { + spinner.hide(); + that.results.set('html', '<h2>Unable to process your search. Try again.</h2>'); + }, + + onSuccess: function(response) { + spinner.hide(); + that.searchSubmit.erase('disabled'); // reenable submitbutton + that.results.set('html', response); + // addEvents to result-links + that.makeAddable($$('a.addToPlaylist')); + } + }); + + // only send form if value is at least 3 chars long + if (that.searchValue.get('value').length >= 3) { + this.send(); + } else { + that.displayStatusMessage('Please enter at least 3 chars for searching...'); + } + }); + }, + + + /** + * Displays a status message, fades out nicely + * + * @param {String} message + */ + displayStatusMessage: function(message) { + // Update Status and fade out + var that = this; + var fadeFX = new Fx.Tween(that.status, { + property: 'opacity', + duration: that.options.messageFadeTime / 5, + transition: Fx.Transitions.Expo.easeOut, + link: 'chain' + }); + + that.status.set('text', message); + fadeFX.start(0, 1).wait(that.options.messageFadeTime).start(1, 0); + }, + + + /** + * This function makes the external links from more Information behave + * so, that clicking opens the link in the iframe below. + */ addLinkListItemToIframe: function() { var that = this; - that.info.getElements('.linkList a').each(function(a) { + that.info.getElements('.externalLinks a').each(function(a) { a.addEvent('click', function(e) { e.stop(); - that.info.getElements('.linkList li').removeClass('active'); + that.info.getElements('.externalLinks li').removeClass('active'); a.getParent().addClass('active'); href = a.get('href'); that.info.getElements('iframe').set('src', href); @@ -654,7 +784,20 @@ }, + /** + * Shows the given tab in the nav, and hides all others + * + * @param {String} tabID ID of the Tab to show + */ + showTab: function(tabID) { + var that = this; + that.nav.getElements('li').removeClass('active'); + that.nav.getElements('a.' + tabID).getParent().toggleClass('active'); + that.content.getChildren().setStyle('display', 'none'); + document.id(tabID).setStyle('display', 'block'); + }, + /** * Converts seconds into a string formatted minutes:seconds * with leading zeros for seconds for a nicer display @@ -672,5 +815,4 @@ return minsec; } - }); \ No newline at end of file Modified: trunk/src/moosique.net/js/mootools-1.2.4.2-more-yc.js =================================================================== --- trunk/src/moosique.net/js/mootools-1.2.4.2-more-yc.js 2009-11-11 21:04:26 UTC (rev 1910) +++ trunk/src/moosique.net/js/mootools-1.2.4.2-more-yc.js 2009-11-14 21:07:39 UTC (rev 1911) @@ -1,37 +1,79 @@ //MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License. -MooTools.More={version:"1.2.4.2",build:"bd5a93c0913cce25917c48cbdacde568e15e02ef"};(function(){var c=this;var b=function(){if(c.console&&console.log){try{console.log.apply(console,arguments); -}catch(d){console.log(Array.slice(arguments));}}else{Log.logged.push(arguments);}return this;};var a=function(){this.logged.push(arguments);return this; -};this.Log=new Class({logged:[],log:a,resetLog:function(){this.logged.empty();return this;},enableLog:function(){this.log=b;this.logged.each(function(d){this.log.apply(this,d); -},this);return this.resetLog();},disableLog:function(){this.log=a;return this;}});Log.extend(new Log).enableLog();Log.logger=function(){return this.log.apply(this,arguments); -};})();Class.refactor=function(b,a){$each(a,function(e,d){var c=b.prototype[d];if(c&&(c=c._origin)&&typeof e=="function"){b.implement(d,function(){var f=this.previous; -this.previous=c;var g=e.apply(this,arguments);this.previous=f;return g;});}else{b.implement(d,e);}});return b;};Class.Mutators.Binds=function(a){return a; -};Class.Mutators.initialize=function(a){return function(){$splat(this.Binds).each(function(b){var c=this[b];if(c){this[b]=c.bind(this);}},this);return a.apply(this,arguments); -};};Class.Occlude=new Class({occlude:function(c,b){b=document.id(b||this.element);var a=b.retrieve(c||this.property);if(a&&!$defined(this.occluded)){return this.occluded=a; -}this.occluded=false;b.store(c||this.property,this);return this.occluded;}});String.implement({parseQueryString:function(){var b=this.split(/[&;]/),a={}; -if(b.length){b.each(function(g){var c=g.indexOf("="),d=c<0?[""]:g.substr(0,c).match(/[^\]\[]+/g),e=decodeURIComponent(g.substr(c+1)),f=a;d.each(function(j,h){var k=f[j]; -if(h<d.length-1){f=f[j]=k||{};}else{if($type(k)=="array"){k.push(e);}else{f[j]=$defined(k)?[k,e]:e;}}});});}return a;},cleanQueryString:function(a){return this.split("&").filter(function(e){var b=e.indexOf("="),c=b<0?"":e.substr(0,b),d=e.substr(b+1); -return a?a.run([c,d]):$chk(d);}).join("&");}});Elements.from=function(e,d){if($pick(d,true)){e=e.stripScripts();}var b,c=e.match(/^\s*<(t[dhr]|tbody|tfoot|thead)/i); -if(c){b=new Element("table");var a=c[1].toLowerCase();if(["td","th","tr"].contains(a)){b=new Element("tbody").inject(b);if(a!="tr"){b=new Element("tr").inject(b); -}}}return(b||new Element("div")).set("html",e).getChildren();};(function(){var d=/(.*?):relay\(([^)]+)\)$/,c=/[+>~\s]/,f=function(g){var h=g.match(d);return !h?{event:g}:{event:h[1],selector:h[2]}; -},b=function(m,g){var k=m.target;if(c.test(g=g.trim())){var j=this.getElements(g);for(var h=j.length;h--;){var l=j[h];if(k==l||l.hasChild(k)){return l; -}}}else{for(;k&&k!=this;k=k.parentNode){if(Element.match(k,g)){return document.id(k);}}}return null;};var a=Element.prototype.addEvent,e=Element.prototype.removeEvent; -Element.implement({addEvent:function(j,i){var k=f(j);if(k.selector){var h=this.retrieve("$moo:delegateMonitors",{});if(!h[j]){var g=function(m){var l=b.call(this,m,k.selector); -if(l){this.fireEvent(j,[m,l],0,l);}}.bind(this);h[j]=g;a.call(this,k.event,g);}}return a.apply(this,arguments);},removeEvent:function(j,i){var k=f(j);if(k.selector){var h=this.retrieve("events"); -if(!h||!h[j]||(i&&!h[j].keys.contains(i))){return this;}if(i){e.apply(this,[j,i]);}else{e.apply(this,j);}h=this.retrieve("events");if(h&&h[j]&&h[j].length==0){var g=this.retrieve("$moo:delegateMonitors",{}); -e.apply(this,[k.event,g[j]]);delete g[j];}return this;}return e.apply(this,arguments);},fireEvent:function(j,h,g,k){var i=this.retrieve("events");if(!i||!i[j]){return this; -}i[j].keys.each(function(l){l.create({bind:k||this,delay:g,arguments:h})();},this);return this;}});})();Element.implement({measure:function(e){var g=function(h){return !!(!h||h.offsetHeight||h.offsetWidth); -};if(g(this)){return e.apply(this);}var d=this.getParent(),f=[],b=[];while(!g(d)&&d!=document.body){b.push(d.expose());d=d.getParent();}var c=this.expose(); -var a=e.apply(this);c();b.each(function(h){h();});return a;},expose:function(){if(this.getStyle("display")!="none"){return $empty;}var a=this.style.cssText; -this.setStyles({display:"block",position:"absolute",visibility:"hidden"});return function(){this.style.cssText=a;}.bind(this);},getDimensions:function(a){a=$merge({computeSize:false},a); -var f={};var d=function(g,e){return(e.computeSize)?g.getComputedSize(e):g.getSize();};var b=this.getParent("body");if(b&&this.getStyle("display")=="none"){f=this.measure(function(){return d(this,a); -});}else{if(b){try{f=d(this,a);}catch(c){}}else{f={x:0,y:0};}}return $chk(f.x)?$extend(f,{width:f.x,height:f.y}):$extend(f,{x:f.width,y:f.height});},getComputedSize:function(a){a=$merge({styles:["padding","border"],plains:{height:["top","bottom"],width:["left","right"]},mode:"both"},a); -var c={width:0,height:0};switch(a.mode){case"vertical":delete c.width;delete a.plains.width;break;case"horizontal":delete c.height;delete a.plains.height; -break;}var b=[];$each(a.plains,function(g,f){g.each(function(h){a.styles.each(function(i){b.push((i=="border")?i+"-"+h+"-width":i+"-"+h);});});});var e={}; -b.each(function(f){e[f]=this.getComputedStyle(f);},this);var d=[];$each(a.plains,function(g,f){var h=f.capitalize();c["total"+h]=c["computed"+h]=0;g.each(function(i){c["computed"+i.capitalize()]=0; -b.each(function(k,j){if(k.test(i)){e[k]=e[k].toInt()||0;c["total"+h]=c["total"+h]+e[k];c["computed"+i.capitalize()]=c["computed"+i.capitalize()]+e[k];}if(k.test(i)&&f!=k&&(k.test("border")||k.test("padding"))&&!d.contains(k)){d.push(k); -c["computed"+h]=c["computed"+h]-e[k];}});});});["Width","Height"].each(function(g){var f=g.toLowerCase();if(!$chk(c[f])){return;}c[f]=c[f]+this["offset"+g]+c["computed"+g]; -c["total"+g]=c[f]+c["total"+g];delete c["computed"+g];},this);return $extend(e,c);}});(function(){var a=Element.prototype.position;Element.implement({position:function(h){if(h&&($defined(h.x)||$defined(h.y))){return a?a.apply(this,arguments):this; +MooTools.More={version:"1.2.4.2",build:"bd5a93c0913cce25917c48cbdacde568e15e02ef"};(function(){var a={language:"en-US",languages:{"en-US":{}},cascades:["en-US"]}; +var b;MooTools.lang=new Events();$extend(MooTools.lang,{setLanguage:function(c){if(!a.languages[c]){return this;}a.language=c;this.load();this.fireEvent("langChange",c); +return this;},load:function(){var c=this.cascade(this.getCurrentLanguage());b={};$each(c,function(e,d){b[d]=this.lambda(e);},this);},getCurrentLanguage:function(){return a.language; +},addLanguage:function(c){a.languages[c]=a.languages[c]||{};return this;},cascade:function(e){var c=(a.languages[e]||{}).cascades||[];c.combine(a.cascades); +c.erase(e).push(e);var d=c.map(function(f){return a.languages[f];},this);return $merge.apply(this,d);},lambda:function(c){(c||{}).get=function(e,d){return $lambda(c[e]).apply(this,$splat(d)); +};return c;},get:function(e,d,c){if(b&&b[e]){return(d?b[e].get(d,c):b[e]);}},set:function(d,e,c){this.addLanguage(d);langData=a.languages[d];if(!langData[e]){langData[e]={}; +}$extend(langData[e],c);if(d==this.getCurrentLanguage()){this.load();this.fireEvent("langChange",d);}return this;},list:function(){return Hash.getKeys(a.languages); +}});})();(function(){var c=this;var b=function(){if(c.console&&console.log){try{console.log.apply(console,arguments);}catch(d){console.log(Array.slice(arguments)); +}}else{Log.logged.push(arguments);}return this;};var a=function(){this.logged.push(arguments);return this;};this.Log=new Class({logged:[],log:a,resetLog:function(){this.logged.empty(); +return this;},enableLog:function(){this.log=b;this.logged.each(function(d){this.log.apply(this,d);},this);return this.resetLog();},disableLog:function(){this.log=a; +return this;}});Log.extend(new Log).enableLog();Log.logger=function(){return this.log.apply(this,arguments);};})();Class.refactor=function(b,a){$each(a,function(e,d){var c=b.prototype[d]; +if(c&&(c=c._origin)&&typeof e=="function"){b.implement(d,function(){var f=this.previous;this.previous=c;var g=e.apply(this,arguments);this.previous=f;return g; +});}else{b.implement(d,e);}});return b;};Class.Mutators.Binds=function(a){return a;};Class.Mutators.initialize=function(a){return function(){$splat(this.Binds).each(function(b){var c=this[b]; +if(c){this[b]=c.bind(this);}},this);return a.apply(this,arguments);};};Class.Occlude=new Class({occlude:function(c,b){b=document.id(b||this.element);var a=b.retrieve(c||this.property); +if(a&&!$defined(this.occluded)){return this.occluded=a;}this.occluded=false;b.store(c||this.property,this);return this.occluded;}});(function(){var a={wait:function(b){return this.chain(function(){this.callChain.delay($pick(b,500),this); +}.bind(this));}};Chain.implement(a);if(window.Fx){Fx.implement(a);["Css","Tween","Elements"].each(function(b){if(Fx[b]){Fx[b].implement(a);}});}Element.implement({chains:function(b){$splat($pick(b,["tween","morph","reveal"])).each(function(c){c=this.get(c); +if(!c){return;}c.setOptions({link:"chain"});},this);return this;},pauseFx:function(c,b){this.chains(b).get($pick(b,"tween")).wait(c);return this;}});})(); +(function(){var i=this.Date;if(!i.now){i.now=$time;}i.Methods={ms:"Milliseconds",year:"FullYear",min:"Minutes",mo:"Month",sec:"Seconds",hr:"Hours"};["Date","Day","FullYear","Hours","Milliseconds","Minutes","Month","Seconds","Time","TimezoneOffset","Week","Timezone","GMTOffset","DayOfYear","LastMonth","LastDayOfMonth","UTCDate","UTCDay","UTCFullYear","AMPM","Ordinal","UTCHours","UTCMilliseconds","UTCMinutes","UTCMonth","UTCSeconds"].each(function(p){i.Methods[p.toLowerCase()]=p; +});var d=function(q,p){return new Array(p-String(q).length+1).join("0")+q;};i.implement({set:function(t,r){switch($type(t)){case"object":for(var s in t){this.set(s,t[s]); +}break;case"string":t=t.toLowerCase();var q=i.Methods;if(q[t]){this["set"+q[t]](r);}}return this;},get:function(q){q=q.toLowerCase();var p=i.Methods;if(p[q]){return this["get"+p[q]](); +}return null;},clone:function(){return new i(this.get("time"));},increment:function(p,r){p=p||"day";r=$pick(r,1);switch(p){case"year":return this.increment("month",r*12); +case"month":var q=this.get("date");this.set("date",1).set("mo",this.get("mo")+r);return this.set("date",q.min(this.get("lastdayofmonth")));case"week":return this.increment("day",r*7); +case"day":return this.set("date",this.get("date")+r);}if(!i.units[p]){throw new Error(p+" is not a supported interval");}return this.set("time",this.get("time")+r*i.units[p]()); +},decrement:function(p,q){return this.increment(p,-1*$pick(q,1));},isLeapYear:function(){return i.isLeapYear(this.get("year"));},clearTime:function(){return this.set({hr:0,min:0,sec:0,ms:0}); +},diff:function(q,p){if($type(q)=="string"){q=i.parse(q);}return((q-this)/i.units[p||"day"](3,3)).toInt();},getLastDayOfMonth:function(){return i.daysInMonth(this.get("mo"),this.get("year")); +},getDayOfYear:function(){return(i.UTC(this.get("year"),this.get("mo"),this.get("date")+1)-i.UTC(this.get("year"),0,1))/i.units.day();},getWeek:function(){return(this.get("dayofyear")/7).ceil(); +},getOrdinal:function(p){return i.getMsg("ordinal",p||this.get("date"));},getTimezone:function(){return this.toString().replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3"); +},getGMTOffset:function(){var p=this.get("timezoneOffset");return((p>0)?"-":"+")+d((p.abs()/60).floor(),2)+d(p%60,2);},setAMPM:function(p){p=p.toUpperCase(); +var q=this.get("hr");if(q>11&&p=="AM"){return this.decrement("hour",12);}else{if(q<12&&p=="PM"){return this.increment("hour",12);}}return this;},getAMPM:function(){return(this.get("hr")<12)?"AM":"PM"; +},parse:function(p){this.set("time",i.parse(p));return this;},isValid:function(p){return !!(p||this).valueOf();},format:function(p){if(!this.isValid()){return"invalid date"; +}p=p||"%x %X";p=k[p.toLowerCase()]||p;var q=this;return p.replace(/%([a-z%])/gi,function(s,r){switch(r){case"a":return i.getMsg("days")[q.get("day")].substr(0,3); +case"A":return i.getMsg("days")[q.get("day")];case"b":return i.getMsg("months")[q.get("month")].substr(0,3);case"B":return i.getMsg("months")[q.get("month")]; +case"c":return q.toString();case"d":return d(q.get("date"),2);case"H":return d(q.get("hr"),2);case"I":return((q.get("hr")%12)||12);case"j":return d(q.get("dayofyear"),3); +case"m":return d((q.get("mo")+1),2);case"M":return d(q.get("min"),2);case"o":return q.get("ordinal");case"p":return i.getMsg(q.get("ampm"));case"S":return d(q.get("seconds"),2); +case"U":return d(q.get("week"),2);case"w":return q.get("day");case"x":return q.format(i.getMsg("shortDate"));case"X":return q.format(i.getMsg("shortTime")); +case"y":return q.get("year").toString().substr(2);case"Y":return q.get("year");case"T":return q.get("GMTOffset");case"Z":return q.get("Timezone");}return r; +});},toISOString:function(){return this.format("iso8601");}});i.alias("toISOString","toJSON");i.alias("diff","compare");i.alias("format","strftime");var k={db:"%Y-%m-%d %H:%M:%S",compact:"%Y%m%dT%H%M%S",iso8601:"%Y-%m-%dT%H:%M:%S%T",rfc822:"%a, %d %b %Y %H:%M:%S %Z","short":"%d %b %H:%M","long":"%B %d, %Y %H:%M"}; +var g=[];var e=i.parse;var n=function(s,u,r){var q=-1;var t=i.getMsg(s+"s");switch($type(u)){case"object":q=t[u.get(s)];break;case"number":q=t[month-1]; +if(!q){throw new Error("Invalid "+s+" index: "+index);}break;case"string":var p=t.filter(function(v){return this.test(v);},new RegExp("^"+u,"i"));if(!p.length){throw new Error("Invalid "+s+" string"); +}if(p.length>1){throw new Error("Ambiguous "+s);}q=p[0];}return(r)?t.indexOf(q):q;};i.extend({getMsg:function(q,p){return MooTools.lang.get("Date",q,p); +},units:{ms:$lambda(1),second:$lambda(1000),minute:$lambda(60000),hour:$lambda(3600000),day:$lamb... [truncated message content] |
From: <neb...@us...> - 2009-11-30 02:47:49
|
Revision: 1925 http://dl-learner.svn.sourceforge.net/dl-learner/?rev=1925&view=rev Author: nebelschwade Date: 2009-11-30 02:47:39 +0000 (Mon, 30 Nov 2009) Log Message: ----------- - this is almost the final diploma-thesis-version, - added README.txt - changed some SPARQL-Queries - optimized config.ini - documentation added to code - performanceTesting Script Modified Paths: -------------- trunk/src/moosique.net/README.txt trunk/src/moosique.net/css/reset.css trunk/src/moosique.net/css/style.css trunk/src/moosique.net/index.php trunk/src/moosique.net/js/start.js trunk/src/moosique.net/moosique/classes/Config.php trunk/src/moosique.net/moosique/classes/DllearnerConnection.php trunk/src/moosique.net/moosique/classes/Recommendations.php trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php trunk/src/moosique.net/moosique/classes/View.php trunk/src/moosique.net/moosique/config.ini trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt trunk/src/moosique.net/moosique/helpers/getAllTags.php trunk/src/moosique.net/moosique/helpers/tagsToOwl.php trunk/src/moosique.net/moosique/main.wsdl Added Paths: ----------- trunk/src/moosique.net/moosique/helpers/getAllTaggedRecords.php trunk/src/moosique.net/moosique/testing/learnPerformanceTest.php trunk/src/moosique.net/moosique.owl Removed Paths: ------------- trunk/src/moosique.net/moosique/data/moosique.owl trunk/src/moosique.net/moosique/testing/def0.xsd trunk/src/moosique.net/moosique/testing/def1.xsd trunk/src/moosique.net/moosique/testing/main.wsdl Modified: trunk/src/moosique.net/README.txt =================================================================== --- trunk/src/moosique.net/README.txt 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/README.txt 2009-11-30 02:47:39 UTC (rev 1925) @@ -1,18 +1,17 @@ Installation-Requirements: ========================== - -TODO: write me! - -See /moosique/config.ini - - PHP 5.2.x or above (yes, 5.3 works) - output_buffering has to be enabled to use debugging features (if enabled in config.ini) - (FirePHP is included in this package) + (FirePHP is included in this package, but you have to install FirePHP in Firefox of course) - PEAR-Packages HTTP and HTTP_Request (used by Utilities.php from DL-Learner) - - - + - PHP Soap functionality has to be enabled (compile --enable-soap or use sth. like "yum install php-soap") - A running DL-Learner Webservice Instance - - Set paths/URLs in config.ini + - Set paths/URLs in config.ini (default values are set) + - For compiling and usage instructions visit: http://dl-learner.org/Projects/DLLearner + - Java Version 6 is required! +- If you want to use your own sparql-endpoint (virtuoso, sesame etc.) just set + "jamendo" in config.ini +- Have a look at /moosique/config.ini for all configuration options and explanation Notes: @@ -20,24 +19,43 @@ - This is a modern piece of websoftware, use a modern browser! Tested and working in: - Firefox 3.5.x - - Safari 4.x and Webkit nightly build r50383 - - Chromium Build 30678 + - Safari 4.x and Webkit nightly builds + - Chromium nightly builds and Google Chrome 4.x - Opera 10.x (though not as beautiful) -- JavaScript has to be enabled, this is an after all an AJAX-Application +- Not tested in Internet Explorer, IE8 should work, though +- JavaScript has to be enabled, this is after all an AJAX-Application - Debugging makes use of Firebug/FirePHP, thus only working in Firefox +- A decent broadband connection will be helpful for streaming and downloading music -- - Known Bugs: =========== -- Moving the current playing song in the playlist down or up - breaks the order of the playlist in the Yahoo Media Player`` +- On Mac OS X Snow Leopard if using the default JVM everything will be terribly + slow. Using another JVM (soylatte, openjdk) will cause some problems, but there + is a fix for this in the config.ini Planned Features: ================= - RDFa Support for artist information -- Unique URLs for ajax (bookmarkable, Back-Button) -- Scrobbling-Support for last.fm -- Playlist export and Download +- Unique URLs for ajax (bookmarkable, Back-Button-Support), + see: http://ajaxpatterns.org/Unique_URLs +- Better accessibility and keyboard support + + +Maybe someday: +============== +- User profiles --> + - Scrobbling-Support for last.fm + - Playlist export and Download, saving the playlist state for future visits +- Geonames-based search + + + +Questions? Visit me at http://nebelschwa.de and write me an email, or use +the DL-Learner racker for reporting bugs or posting feature Requests: +http://sourceforge.net/tracker/?group_id=203619 + +Best regards, + +Steffen Becker. \ No newline at end of file Modified: trunk/src/moosique.net/css/reset.css =================================================================== --- trunk/src/moosique.net/css/reset.css 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/css/reset.css 2009-11-30 02:47:39 UTC (rev 1925) @@ -1,5 +1,5 @@ -/* default minimal basic css reset by Steffen Becker */ -/* =================================================================== */ +/* default minimal basic css reset by Steffen Becker, based on YUI and eric meyers css-reset */ +/* ========================================================================================= */ @media all { html, body, div, h1, h2, h3, h4, h5, h6, ul, ol, dl, li, Modified: trunk/src/moosique.net/css/style.css =================================================================== --- trunk/src/moosique.net/css/style.css 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/css/style.css 2009-11-30 02:47:39 UTC (rev 1925) @@ -11,7 +11,7 @@ */ -@media screen { +@media screen, projection { /*=============== Default Styling ===============*/ body { font: normal 14px/20px Verdana, Arial, sans-serif; color: #f1f7e4; background: url('../img/bg.png') top left repeat #3a3a3a; } Modified: trunk/src/moosique.net/index.php =================================================================== --- trunk/src/moosique.net/index.php 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/index.php 2009-11-30 02:47:39 UTC (rev 1925) @@ -79,7 +79,7 @@ <form id="autoAdd" method="get" action=""> <div> <label for="autoAddCheckbox" title="Check this to automatically add a random song from your recommendations to your playlist everytime your recommendations are updated.">Autoadd recommendations</label> - <input type="checkbox" id="autoAddCheckbox" checked="checked" /> + <input type="checkbox" id="autoAddCheckbox" /> </div> </form> <h2>Recommendations</h2> @@ -193,7 +193,7 @@ <?php include('moosique/classes/Config.php'); $c = new Config(); - if ($c->getConfig('debug') == 1) /* if debugging is active include js without compressing anything */ { + if ($c->getConfig('debug')) { /* if debugging is active include js without compressing anything */ ?> <script src="http://mediaplayer.yahoo.com/js"></script> <script src="js/mootools-1.2.4-core-nc.js"></script> Modified: trunk/src/moosique.net/js/start.js =================================================================== --- trunk/src/moosique.net/js/start.js 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/js/start.js 2009-11-30 02:47:39 UTC (rev 1925) @@ -7,5 +7,5 @@ }; // Create an instance of the moosique.net -var moo = new Moosique({ timeToScrobble: 0.05 }); // debugging - shorter generation time -// var moo = new Moosique({ timeToScrobble: 0.5 }); +// var moo = new Moosique({ timeToScrobble: 0.05 }); // debugging - shorter generation time +var moo = new Moosique({ timeToScrobble: 0.5 }); Modified: trunk/src/moosique.net/moosique/classes/Config.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Config.php 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/classes/Config.php 2009-11-30 02:47:39 UTC (rev 1925) @@ -21,7 +21,7 @@ $this->config = parse_ini_file(dirname(__FILE__) . '/../config.ini', true); // we activate the debugger output if debugging is active - if ($this->getConfig('debug') == 1) { + if ($this->getConfig('debug')) { require_once('Debugger.php'); $this->debugger = new Debugger(); ob_start(); Modified: trunk/src/moosique.net/moosique/classes/DllearnerConnection.php =================================================================== --- trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/classes/DllearnerConnection.php 2009-11-30 02:47:39 UTC (rev 1925) @@ -143,15 +143,16 @@ $conf = $this->getConfigLearning(); if ($this->debugger) $this->debugger->log(array($instances, $positiveExamples), "Instances and positive examples are"); - /* FIXME extra ID is necessary?! - if using the already created sessionID and knowLedgeSourceID for learning, - there will always be an error, when trying to use initAll - */ - $id = $_SESSION['sessionID']; - $kID = $this->knowledgeSourceID; - // the two lines below will work, the two lines above won't - // $id = $this->client->generateID(); - // $kID = $this->client->addKnowledgeSource($id, 'sparql', $this->endpoint); + // if there are any problems with java, generate a new ID, this + // fixes broken openjdk/soap implementations + if ($this->getConfig('javaProblems')) { + $id = $this->client->generateID(); + $kID = $this->client->addKnowledgeSource($id, 'sparql', $this->endpoint); + + } else { + $id = $_SESSION['sessionID']; + $kID = $this->knowledgeSourceID; + } $this->client->addKnowledgeSource($id, 'owlfile', $this->getConfigUrl('tagOntology')); $this->client->setReasoner($id, $conf['reasoner']); @@ -164,7 +165,10 @@ // recursion-depth and fragment saving $this->client->applyConfigEntryInt($id, $kID, 'recursionDepth', $conf['recursionDepth']); $this->client->applyConfigEntryBoolean($id, $kID, 'saveExtractedFragment', $conf['saveExtractedFragment']); - + + // cache the sparql-queries? + $this->client->applyConfigEntryBoolean($id, $kID, 'useCache', $this->getConfig('useCache')); + // algorithm config $learnID = $this->client->setLearningAlgorithm($id, $conf['algorithm']); $this->client->applyConfigEntryInt($id, $learnID, 'maxExecutionTimeInSeconds', $conf['maxExecutionTimeInSeconds']); @@ -176,8 +180,11 @@ array($this->getConfigPrefixes('tags') . 'taggedWithTag'), array($this->getConfigPrefixes('rdf') . 'type') ); - // and exclude some items from this learning process fastening up things a bit - $this->client->applyConfigEntryStringArray($id, $kID, 'predList', $this->getExclusions($conf)); + // and exclude some items from this learning process to fasten things up + $exclude = $this->getExclusions($conf); + if ($conf['recursionDepth'] > 1 && is_array($exclude) && !empty($exclude)) { + $this->client->applyConfigEntryStringArray($id, $kID, 'predList', $exclude); + } // after we have set all conf-values, we initialize the learning process $this->client->initAll($id); Modified: trunk/src/moosique.net/moosique/classes/Recommendations.php =================================================================== --- trunk/src/moosique.net/moosique/classes/Recommendations.php 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/classes/Recommendations.php 2009-11-30 02:47:39 UTC (rev 1925) @@ -48,25 +48,23 @@ // precentage-value, can also be used for display, nicely formatted $score = round($solution->scoreValue*100, 2); // scores below threshold are not used for recommendations - if ($score > $this->getConfig('threshold')) { + if ($score >= $this->getConfig('threshold')) { // check for everything that is quoted $match = true; $kbSyntax = $solution->descriptionKBSyntax; - $this->debugger->log($kbSyntax); - // everything in quotes is a potential tag preg_match_all('/\"(\\.|[^\"])*\"/', $kbSyntax, $quoted); foreach($quoted[0] as $url) { if (preg_match('/^\"http:\/\//', $url)) { // if a URL, check if URL to Tag // if only one of the URLS used is not a tag, we don't use it if (!preg_match('/^\"http:\/\/dbtune\.org\/jamendo\/tag\//', $url)) { - //$match = false; + $match = false; } } } if ($match) { - $sparql = $connection->kbToSqarql($solution->descriptionKBSyntax); + $sparql = $connection->kbToSqarql($kbSyntax); // extract the subtring we use for the final sparql-query $sparql = str_replace("SELECT ?subject \nWHERE", '', $sparql); $sparql = str_replace('LIMIT ' . $this->getConfig('maxResults'), '', $sparql); @@ -74,7 +72,7 @@ // push it to the queries-array and $queries[] = $sparql; $scores[] = $score; - $kbSyntaxes[] = $solution->descriptionKBSyntax; + $kbSyntaxes[] = $kbSyntax; } } } @@ -113,7 +111,6 @@ foreach($recent as $link) { // extract relation from the cookie-link preg_match_all('#<a\s*(?:rel=[\'"]([^\'"]+)[\'"])?.*?>((?:(?!</a>).)*)</a>#i', $link, $record); - $this->debugger->log($record); $posExamples[] = $record[1][0]; $posExamples = array_unique($posExamples); $this->posExamples = $posExamples; Modified: trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php =================================================================== --- trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/classes/SparqlQueryBuilder.php 2009-11-30 02:47:39 UTC (rev 1925) @@ -39,8 +39,8 @@ $prefixes .= 'PREFIX ' . $prefix . ': <' . $resource . '>' . "\n"; } - // if the globalLimit-config-value is set, we use maxResults as LIMIT - if ($this->getConfig('globalLimit') == 1) { + // if the globalLimit-config-value is set to true, we use maxResults as LIMIT + if ($this->getConfig('globalLimit')) { $limit = "\n" . 'LIMIT ' . $this->getConfig('maxResults'); } else { $limit = ''; @@ -48,17 +48,18 @@ // we need all information we are asking for everytime, thus * $beginStatement = 'SELECT DISTINCT * WHERE { ' . "\n"; + // we always want the xspf-playlist only, the search filters is // flagged with "i" for case-insensitive search $endStatement = "\n" . ' FILTER (regex(str(?playlist), "xspf", "i")) . } ' . $limit; - $baseQuery = ' { + $baseQuery = ' ?artist rdf:type mo:MusicArtist ; foaf:name ?artistName ; foaf:made ?record . ?record rdf:type mo:Record ; dc:title ?albumTitle . - } '; + '; $query = ''; switch($searchType) { Modified: trunk/src/moosique.net/moosique/classes/View.php =================================================================== --- trunk/src/moosique.net/moosique/classes/View.php 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/classes/View.php 2009-11-30 02:47:39 UTC (rev 1925) @@ -118,7 +118,7 @@ $count = count($data); // dont limit anything if limit == 0 if ($count > $this->limit && $this->limit > 0) { - if ($this->getConfig('randomize') == 1) { + if ($this->getConfig('randomize')) { $random = array_rand($data, $this->limit); $newData = array(); foreach($random as $randRecord) { @@ -179,7 +179,7 @@ * @author Steffen Becker */ private function showRandomLimitNote($count) { - if ($this->getConfig('randomize') == 1) { + if ($this->getConfig('randomize')) { return '<p><strong>Note:</strong> Found ' . $count . ' results, showing ' . $this->limit . ' random results.'; } else { return '<p><strong>Note:</strong> Found ' . $count . ' results, showing the first ' . $this->limit . ' results.'; @@ -373,12 +373,14 @@ * Builds the HTML for additional information for and artist * * @param array $data An array of additional information + * @param string $type the type of search * @author Steffen Becker */ private function infoHTML($data, $type) { $template = $this->getTemplate($type); $artist = $this->getValue($data['artist']); $artistName = $this->getValue($data['artistName']); + // TODO $albumList = $this->createAlbumListHTML(array($data), 'tagSearch'); $homepage = ''; // could be empty Modified: trunk/src/moosique.net/moosique/config.ini =================================================================== --- trunk/src/moosique.net/moosique/config.ini 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/config.ini 2009-11-30 02:47:39 UTC (rev 1925) @@ -1,39 +1,60 @@ ; Config file for moosique.net +; Use this values to config your installation of DL-Learner and the +; usage of the webapplication moosqiue.net [general] ; Activates global debugging, using FirePHP and Firebug -debug = 1 -; If globalLimit = 1 maxResults is used for a global SPARQL-Query LIMIT, -; if set to 0 maxResults will only be used for viewing results +debug = true +; If globalLimit = true maxResults is used for a global SPARQL-Query LIMIT, +; if set to false maxResults will only be used for viewing results ; PLEASE NOTE: global limiting to e.g. 20 may show only one result, because ; one result can have >20 tags, and this counts as total-limit -globalLimit = 0 +globalLimit = false ; setting this to 0 disables result-limitation for everything -; recommendation results and last-fm search always uses this value +; recommendation results and last-fm search always use this value +; it is highly recommended to not set this value to sth. btw. 10 and 100 +; depending on how much results you want to show the user and how +; fast you want them do display in the frontend maxResults = 20 -; this should always be 1, else the results are always the same (first ones) -randomize = 1 -; %-score a recommendation needs to have to be recommended -threshold = 30 +; this should always be true, else the results are always the same (first ones) +randomize = true +; %-score a recommendation-result needs to have to be recommended +threshold = 80 +; de/avtivate caching of sparql-queries, active = true = default +; this is mainly used for endpoint-performance testing, dont deactivate +; this in a live enviroment, searching and learning will be sloooow +useCache = true +; this is used for crappy mac osx java implementation. set to true +; if you have problems with the learning process and get soap-errors +javaProblems = true [url] +; the url the webapplication is running under base = "http://localhost/moosique.net/" +; the absolute path on your system, this is needed for the owl-file absPath = "/Users/nebelschwade/Sites/moosique.net/" -local = "http://127.0.0.1/" +; this is where the dl-learner webservice will be reachable, don't +; change this value, if you are using a default installation of the ws wsdl = "http://localhost:8181/services?wsdl" +; this is where the knowledge comes from, DBTune ftw! jamendo = "http://dbtune.org/jamendo/sparql/" -musicbrainz = "http://dbtune.org/musicbrainz/sparql/" -zitgistdata = "http://dataviewer.zitgist.com/?uri=" -; using relative paths here, abspath or base-path are added automatically +; You can use a local sparql-endpoint too, of course. +; jamendo = "http://localhost:8890/sparql/" +; using relative paths for the next values, +; abspath or base-path are added automatically +; the wdsl-file for the soap-connection, default wsdlLocal = "moosique/main.wsdl" +; this is where the random instances are gathered from allRecords = "moosique/data/allRecordsWithTags.txt" -tagOntology = "moosique/data/moosique.owl" +; the ontology of tags +tagOntology = "moosique.owl" [lastFM] ; change the api-key if you have your own apiKey = "b9877a7391416d0846ad5f240a1838f9" +; some urls for data retrieval from the last-fm api topTagsUrl = "http://ws.audioscrobbler.com/2.0/?method=user.gettoptags" topArtistsUrl = "http://ws.audioscrobbler.com/2.0/?method=user.gettopartists" artistsTopTagsUrl = "http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags" @@ -46,33 +67,46 @@ ; you don't have to change [learning]-config-vars in most cases [learning] +; the learning problem here ist positive examples only +problem = "posOnlyLP" +; here we define the used learning algorithm, celoe ist the best +; one, you could also use bruteForce or Random for posOnlyLP algorithm = "celoe" -maxExecutionTimeInSeconds = 10 +; 2-5 seconds seem to be the optimum, depending on server speed +; for more than 5 seconds, the algorithm does not give any better +; results, thus higher than 5 seconds ist not needed in most cases +maxExecutionTimeInSeconds = 3 useHasValueConstructor = true valueFrequencyThreshold = 2 -problem = "posOnlyLP" +; using the default dl-learner reasoner, faster than the others (fact, pellet) reasoner = "fastInstanceChecker" -recursionDepth = 2 +recursionDepth = 1 +; save the owl in the cache-library saveExtractedFragment = true -instances = 3 +; the number of random instances to add to the posExamples +; 3-5 will give the best results +instances = 4 ; excluding predicates from sparql-extraction for faster learning, ; with prefixes - comma-seperated list -exclude = "mo:image,mo:available_as,mo:track,serql:directType" +exclude = "mo:image,mo:available_as,mo:track,serql:directType,dc:title" + ; you don't have to change the prefixes in most cases, but you can of course add some +; all used prefixes are already here, some used concepts from jamendo/dbtune are also +; defined here, but since they are not used in the sparql queries, they are commented out [prefix] -bio = "http://purl.org/vocab/bio/0.1/" -db = "http://dbtune.org/musicbrainz/resource/" dc = "http://purl.org/dc/elements/1.1/" -event = "http://purl.org/NET/c4dm/event.owl#" foaf = "http://xmlns.com/foaf/0.1/" geo = "http://www.geonames.org/ontology#" -mbz = "http://purl.org/ontology/mbz#" mo = "http://purl.org/ontology/mo/" owl = "http://www.w3.org/2002/07/owl#" rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdfs = "http://www.w3.org/2000/01/rdf-schema#" -rel = "http://purl.org/vocab/relationship/" tags = "http://www.holygoat.co.uk/owl/redwood/0.1/tags/" xsd = "http://www.w3.org/2001/XMLSchema#" -serql = "http://www.openrdf.org/schema/serql#" +;bio = "http://purl.org/vocab/bio/0.1/" +;db = "http://dbtune.org/musicbrainz/resource/" +;rel = "http://purl.org/vocab/relationship/" +;mbz = "http://purl.org/ontology/mbz#" +;event = "http://purl.org/NET/c4dm/event.owl#" +;serql = "http://www.openrdf.org/schema/serql#" Modified: trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt =================================================================== --- trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/data/allTagsByPopularity.txt 2009-11-30 02:47:39 UTC (rev 1925) @@ -91,21 +91,21 @@ #http://dbtune.org/jamendo/tag/breakbeat : 96 # http://dbtune.org/jamendo/tag/rockfrancais : 94 # http://dbtune.org/jamendo/tag/zen : 93 -http://dbtune.org/jamendo/tag/original : 93 -http://dbtune.org/jamendo/tag/new : 92 + #http://dbtune.org/jamendo/tag/original : 93 + # http://dbtune.org/jamendo/tag/new : 92 #http://dbtune.org/jamendo/tag/postrock : 92 # http://dbtune.org/jamendo/tag/classical : 91 # http://dbtune.org/jamendo/tag/70s : 90 -http://dbtune.org/jamendo/tag/batterie : 88 + # http://dbtune.org/jamendo/tag/batterie : 88 #http://dbtune.org/jamendo/tag/ska : 87 # http://dbtune.org/jamendo/tag/fun : 86 #http://dbtune.org/jamendo/tag/chansons : 85 -http://dbtune.org/jamendo/tag/libre : 83 + # http://dbtune.org/jamendo/tag/libre : 83 # http://dbtune.org/jamendo/tag/80s : 82 -http://dbtune.org/jamendo/tag/festif : 82 +# http://dbtune.org/jamendo/tag/festif : 82 #http://dbtune.org/jamendo/tag/trash : 81 # http://dbtune.org/jamendo/tag/film : 80 - #http://dbtune.org/jamendo/tag/inclassable : 79 + #http://dbtune.org/jamendo/tag/inclassable : 79 ------ yeah, right. #http://dbtune.org/jamendo/tag/rockindependant : 79 http://dbtune.org/jamendo/tag/beat : 78 #http://dbtune.org/jamendo/tag/electropop : 78 @@ -113,7 +113,7 @@ #http://dbtune.org/jamendo/tag/acid : 76 http://dbtune.org/jamendo/tag/underground : 75 http://dbtune.org/jamendo/tag/live : 75 -http://dbtune.org/jamendo/tag/courdesmiracles : 73 + # http://dbtune.org/jamendo/tag/courdesmiracles : 73 http://dbtune.org/jamendo/tag/solo : 71 #http://dbtune.org/jamendo/tag/death : 70 #http://dbtune.org/jamendo/tag/electrojazz : 68 @@ -121,7 +121,7 @@ # http://dbtune.org/jamendo/tag/energique : 68 # http://dbtune.org/jamendo/tag/tacelectronic : 66 #http://dbtune.org/jamendo/tag/garage : 66 - #http://dbtune.org/jamendo/tag/free : 66 ------------ ??? (free style, free jazz etc.) + #http://dbtune.org/jamendo/tag/free : 66 ------------ ??? (free style, free jazz, free music? etc.) http://dbtune.org/jamendo/tag/sympa : 65 http://dbtune.org/jamendo/tag/ghisa : 65 http://dbtune.org/jamendo/tag/artlibre : 64 @@ -130,18 +130,18 @@ # http://dbtune.org/jamendo/tag/meditation : 63 # http://dbtune.org/jamendo/tag/relaxing : 62 http://dbtune.org/jamendo/tag/club : 61 -http://dbtune.org/jamendo/tag/soft : 61 +# http://dbtune.org/jamendo/tag/soft : 61 #http://dbtune.org/jamendo/tag/drumnbass : 61 #http://dbtune.org/jamendo/tag/excellent : 60 #http://dbtune.org/jamendo/tag/gothic : 60 http://dbtune.org/jamendo/tag/ballade : 59 http://dbtune.org/jamendo/tag/intimiste : 59 #http://dbtune.org/jamendo/tag/musicbrainz : 59 - #http://dbtune.org/jamendo/tag/good : 59 -http://dbtune.org/jamendo/tag/doux : 59 -http://dbtune.org/jamendo/tag/reposant : 58 + #http://dbtune.org/jamendo/tag/good : 59 +# http://dbtune.org/jamendo/tag/doux : 59 +# http://dbtune.org/jamendo/tag/reposant : 58 #http://dbtune.org/jamendo/tag/independant : 57 -http://dbtune.org/jamendo/tag/psycho : 56 +# http://dbtune.org/jamendo/tag/psycho : 56 #http://dbtune.org/jamendo/tag/jamendo : 56 #http://dbtune.org/jamendo/tag/rocknroll : 56 # http://dbtune.org/jamendo/tag/symphonique : 55 @@ -149,23 +149,23 @@ #http://dbtune.org/jamendo/tag/soul : 54 # http://dbtune.org/jamendo/tag/german : 54 # http://dbtune.org/jamendo/tag/easylistening : 54 -http://dbtune.org/jamendo/tag/poetique : 54 +# http://dbtune.org/jamendo/tag/poetique : 54 # http://dbtune.org/jamendo/tag/france : 53 #http://dbtune.org/jamendo/tag/jazzrock : 53 -http://dbtune.org/jamendo/tag/delirant : 53 +# http://dbtune.org/jamendo/tag/delirant : 53 #http://dbtune.org/jamendo/tag/electrorock : 53 -http://dbtune.org/jamendo/tag/poesie : 52 +# http://dbtune.org/jamendo/tag/poesie : 52 #http://dbtune.org/jamendo/tag/emo : 52 # http://dbtune.org/jamendo/tag/violon : 51 # http://dbtune.org/jamendo/tag/prog : 50 #http://dbtune.org/jamendo/tag/elektro : 50 -http://dbtune.org/jamendo/tag/envoutant : 49 +# http://dbtune.org/jamendo/tag/envoutant : 49 #http://dbtune.org/jamendo/tag/genial : 49 #http://dbtune.org/jamendo/tag/mix : 49 #http://dbtune.org/jamendo/tag/super : 49 http://dbtune.org/jamendo/tag/age : 49 -http://dbtune.org/jamendo/tag/slow : 49 -http://dbtune.org/jamendo/tag/smooth : 48 +# http://dbtune.org/jamendo/tag/slow : 49 +# http://dbtune.org/jamendo/tag/smooth : 48 # http://dbtune.org/jamendo/tag/malesinger : 48 # http://dbtune.org/jamendo/tag/synthetiseur : 48 # http://dbtune.org/jamendo/tag/flute : 47 @@ -184,7 +184,7 @@ # http://dbtune.org/jamendo/tag/retro : 44 # http://dbtune.org/jamendo/tag/oriental : 44 # http://dbtune.org/jamendo/tag/love : 44 -http://dbtune.org/jamendo/tag/indus : 44 +# http://dbtune.org/jamendo/tag/indus : 44 # http://dbtune.org/jamendo/tag/synth : 44 #http://dbtune.org/jamendo/tag/ambience : 43 #http://dbtune.org/jamendo/tag/ethnic : 43 @@ -208,7 +208,7 @@ #http://dbtune.org/jamendo/tag/black : 38 # http://dbtune.org/jamendo/tag/deutsch : 38 # http://dbtune.org/jamendo/tag/electroacoustique : 38 -http://dbtune.org/jamendo/tag/puissant : 37 +# http://dbtune.org/jamendo/tag/puissant : 37 # http://dbtune.org/jamendo/tag/espanol : 37 #http://dbtune.org/jamendo/tag/ebm : 37 #http://dbtune.org/jamendo/tag/album : 37 @@ -227,7 +227,7 @@ http://dbtune.org/jamendo/tag/culte : 35 http://dbtune.org/jamendo/tag/engage : 35 # http://dbtune.org/jamendo/tag/electrique : 35 -http://dbtune.org/jamendo/tag/mystic : 35 +# http://dbtune.org/jamendo/tag/mystic : 35 # http://dbtune.org/jamendo/tag/roots : 34 # http://dbtune.org/jamendo/tag/accordeon : 34 http://dbtune.org/jamendo/tag/rythme : 34 @@ -241,7 +241,7 @@ http://dbtune.org/jamendo/tag/power : 33 #http://dbtune.org/jamendo/tag/bien : 33 # http://dbtune.org/jamendo/tag/meditative : 33 -http://dbtune.org/jamendo/tag/trippant : 33 +# http://dbtune.org/jamendo/tag/trippant : 33 #http://dbtune.org/jamendo/tag/drumbass : 33 # http://dbtune.org/jamendo/tag/kitsch : 33 #http://dbtune.org/jamendo/tag/nujazz : 32 @@ -254,22 +254,22 @@ # http://dbtune.org/jamendo/tag/bizarre : 32 # http://dbtune.org/jamendo/tag/crossover : 31 # http://dbtune.org/jamendo/tag/avantgarde : 31 -http://dbtune.org/jamendo/tag/melodico : 31 -http://dbtune.org/jamendo/tag/son : 31 +# http://dbtune.org/jamendo/tag/melodico : 31 + # http://dbtune.org/jamendo/tag/son : 31 http://dbtune.org/jamendo/tag/bossa : 31 #http://dbtune.org/jamendo/tag/d : 31 # http://dbtune.org/jamendo/tag/ambiente : 31 http://dbtune.org/jamendo/tag/break : 31 # http://dbtune.org/jamendo/tag/relaxant : 31 # http://dbtune.org/jamendo/tag/psyche : 31 -http://dbtune.org/jamendo/tag/amour : 31 -http://dbtune.org/jamendo/tag/romantic : 31 +# http://dbtune.org/jamendo/tag/amour : 31 +# http://dbtune.org/jamendo/tag/romantic : 31 #http://dbtune.org/jamendo/tag/ethno : 31 http://dbtune.org/jamendo/tag/politique : 30 http://dbtune.org/jamendo/tag/neo : 30 #http://dbtune.org/jamendo/tag/et : 30 # http://dbtune.org/jamendo/tag/tranquille : 30 -http://dbtune.org/jamendo/tag/dreams : 30 +# http://dbtune.org/jamendo/tag/dreams : 30 #http://dbtune.org/jamendo/tag/la : 30 # http://dbtune.org/jamendo/tag/english : 30 # http://dbtune.org/jamendo/tag/celtique : 30 @@ -280,13 +280,13 @@ http://dbtune.org/jamendo/tag/school : 29 #http://dbtune.org/jamendo/tag/musica : 29 http://dbtune.org/jamendo/tag/paroles : 29 -http://dbtune.org/jamendo/tag/sensual : 29 -http://dbtune.org/jamendo/tag/impressive : 28 +# http://dbtune.org/jamendo/tag/sensual : 29 + # http://dbtune.org/jamendo/tag/impressive : 28 # http://dbtune.org/jamendo/tag/whawha : 28 # http://dbtune.org/jamendo/tag/psy : 28 #http://dbtune.org/jamendo/tag/worldmusic : 28 -http://dbtune.org/jamendo/tag/rigolo : 28 -http://dbtune.org/jamendo/tag/agreable : 28 +# http://dbtune.org/jamendo/tag/rigolo : 28 +# http://dbtune.org/jamendo/tag/agreable : 28 # http://dbtune.org/jamendo/tag/espagnol : 27 #http://dbtune.org/jamendo/tag/tribal : 27 #http://dbtune.org/jamendo/tag/copyleft : 27 @@ -299,7 +299,7 @@ #http://dbtune.org/jamendo/tag/bigbeat : 27 http://dbtune.org/jamendo/tag/samples : 26 #http://dbtune.org/jamendo/tag/country : 26 -http://dbtune.org/jamendo/tag/soyouthinkyoucantell : 26 + # http://dbtune.org/jamendo/tag/soyouthinkyoucantell : 26 http://dbtune.org/jamendo/tag/concept : 26 # http://dbtune.org/jamendo/tag/minimalistic : 26 # http://dbtune.org/jamendo/tag/chansonatexte : 26 @@ -313,7 +313,7 @@ # http://dbtune.org/jamendo/tag/berlin : 25 # http://dbtune.org/jamendo/tag/sad : 25 # http://dbtune.org/jamendo/tag/brasil : 25 -http://dbtune.org/jamendo/tag/sensuel : 25 +# http://dbtune.org/jamendo/tag/sensuel : 25 #http://dbtune.org/jamendo/tag/heavymetal : 25 #http://dbtune.org/jamendo/tag/thrash : 25 http://dbtune.org/jamendo/tag/sexy : 25 @@ -343,7 +343,7 @@ # http://dbtune.org/jamendo/tag/out : 23 http://dbtune.org/jamendo/tag/pechu : 23 http://dbtune.org/jamendo/tag/female : 23 -http://dbtune.org/jamendo/tag/emotional : 22 +# http://dbtune.org/jamendo/tag/emotional : 22 http://dbtune.org/jamendo/tag/spiritual : 22 # http://dbtune.org/jamendo/tag/bretagne : 22 #http://dbtune.org/jamendo/tag/stoner : 22 @@ -352,7 +352,7 @@ #http://dbtune.org/jamendo/tag/compilation : 22 http://dbtune.org/jamendo/tag/cuivres : 22 http://dbtune.org/jamendo/tag/chanteuse : 22 -http://dbtune.org/jamendo/tag/talentueux : 22 + # http://dbtune.org/jamendo/tag/talentueux : 22 http://dbtune.org/jamendo/tag/univers : 22 #http://dbtune.org/jamendo/tag/independent : 22 # http://dbtune.org/jamendo/tag/trombone : 22 @@ -370,7 +370,7 @@ # http://dbtune.org/jamendo/tag/percussion : 21 http://dbtune.org/jamendo/tag/art : 20 #http://dbtune.org/jamendo/tag/of : 20 -http://dbtune.org/jamendo/tag/nice : 20 + # http://dbtune.org/jamendo/tag/nice : 20 http://dbtune.org/jamendo/tag/fantasy : 20 http://dbtune.org/jamendo/tag/game : 20 http://dbtune.org/jamendo/tag/epic : 20 @@ -390,7 +390,7 @@ # http://dbtune.org/jamendo/tag/poland : 19 http://dbtune.org/jamendo/tag/dejante : 19 http://dbtune.org/jamendo/tag/sciencefiction : 19 -http://dbtune.org/jamendo/tag/acustico : 18 +# http://dbtune.org/jamendo/tag/acustico : 18 # http://dbtune.org/jamendo/tag/hardstyle : 18 http://dbtune.org/jamendo/tag/cosmic : 18 #http://dbtune.org/jamendo/tag/pro : 18 @@ -414,7 +414,7 @@ #http://dbtune.org/jamendo/tag/dancehall : 17 #http://dbtune.org/jamendo/tag/in : 17 http://dbtune.org/jamendo/tag/cold : 17 -http://dbtune.org/jamendo/tag/dreamy : 17 +# http://dbtune.org/jamendo/tag/dreamy : 17 # http://dbtune.org/jamendo/tag/italian : 17 #http://dbtune.org/jamendo/tag/realnice : 17 # http://dbtune.org/jamendo/tag/saxo : 17 @@ -423,7 +423,7 @@ #http://dbtune.org/jamendo/tag/cyberpunk : 17 #http://dbtune.org/jamendo/tag/darkambient : 17 # http://dbtune.org/jamendo/tag/powerpop : 17 -http://dbtune.org/jamendo/tag/weird : 17 +# http://dbtune.org/jamendo/tag/weird : 17 http://dbtune.org/jamendo/tag/bruitiste : 17 # http://dbtune.org/jamendo/tag/alternativo : 17 # http://dbtune.org/jamendo/tag/chiptune : 17 @@ -437,7 +437,7 @@ # http://dbtune.org/jamendo/tag/ambiental : 16 # http://dbtune.org/jamendo/tag/alternativ : 16 http://dbtune.org/jamendo/tag/political : 16 -http://dbtune.org/jamendo/tag/funny : 16 +# http://dbtune.org/jamendo/tag/funny : 16 http://dbtune.org/jamendo/tag/conscient : 16 http://dbtune.org/jamendo/tag/synthetique : 16 #http://dbtune.org/jamendo/tag/8bits : 16 @@ -451,7 +451,7 @@ # http://dbtune.org/jamendo/tag/sitar : 15 http://dbtune.org/jamendo/tag/horror : 15 # http://dbtune.org/jamendo/tag/guitares : 15 -http://dbtune.org/jamendo/tag/magique : 15 +# http://dbtune.org/jamendo/tag/magique : 15 http://dbtune.org/jamendo/tag/simple : 15 http://dbtune.org/jamendo/tag/energic : 15 http://dbtune.org/jamendo/tag/mysterieux : 15 @@ -466,24 +466,24 @@ #http://dbtune.org/jamendo/tag/tecno : 15 http://dbtune.org/jamendo/tag/style : 15 http://dbtune.org/jamendo/tag/mozeclic : 15 -http://dbtune.org/jamendo/tag/quiet : 15 -http://dbtune.org/jamendo/tag/debile : 15 +# http://dbtune.org/jamendo/tag/quiet : 15 +# http://dbtune.org/jamendo/tag/debile : 15 #http://dbtune.org/jamendo/tag/goth : 15 # http://dbtune.org/jamendo/tag/polska : 15 # http://dbtune.org/jamendo/tag/videogame : 15 # http://dbtune.org/jamendo/tag/midi : 14 -http://dbtune.org/jamendo/tag/melodies : 14 +# http://dbtune.org/jamendo/tag/melodies : 14 http://dbtune.org/jamendo/tag/piec : 14 #http://dbtune.org/jamendo/tag/skapunk : 14 # http://dbtune.org/jamendo/tag/paris : 14 -http://dbtune.org/jamendo/tag/touchant : 14 +# http://dbtune.org/jamendo/tag/touchant : 14 # http://dbtune.org/jamendo/tag/reggaeton : 14 # http://dbtune.org/jamendo/tag/clarinette : 14 #http://dbtune.org/jamendo/tag/mp3 : 14 #http://dbtune.org/jamendo/tag/very : 14 #http://dbtune.org/jamendo/tag/flamenco : 14 # http://dbtune.org/jamendo/tag/tacfolk : 14 -http://dbtune.org/jamendo/tag/hypnotic : 14 +# http://dbtune.org/jamendo/tag/hypnotic : 14 #http://dbtune.org/jamendo/tag/realgood : 14 http://dbtune.org/jamendo/tag/background : 14 # http://dbtune.org/jamendo/tag/freestyle : 14 @@ -491,12 +491,12 @@ #http://dbtune.org/jamendo/tag/tekno : 14 #http://dbtune.org/jamendo/tag/perfect : 14 #http://dbtune.org/jamendo/tag/n : 14 -http://dbtune.org/jamendo/tag/theatre : 14 +# http://dbtune.org/jamendo/tag/theatre : 14 # http://dbtune.org/jamendo/tag/downbeat : 14 http://dbtune.org/jamendo/tag/brutal : 14 -http://dbtune.org/jamendo/tag/contemporary : 14 +# http://dbtune.org/jamendo/tag/contemporary : 14 # http://dbtune.org/jamendo/tag/drums : 14 -http://dbtune.org/jamendo/tag/gesang : 13 +# http://dbtune.org/jamendo/tag/gesang : 13 http://dbtune.org/jamendo/tag/modern : 13 # http://dbtune.org/jamendo/tag/electronoise : 13 #http://dbtune.org/jamendo/tag/hot : 13 @@ -521,17 +521,17 @@ http://dbtune.org/jamendo/tag/detente : 12 # http://dbtune.org/jamendo/tag/italiano : 12 http://dbtune.org/jamendo/tag/marrant : 12 -http://dbtune.org/jamendo/tag/trippy : 12 -http://dbtune.org/jamendo/tag/enfant : 12 +# http://dbtune.org/jamendo/tag/trippy : 12 +# http://dbtune.org/jamendo/tag/enfant : 12 # http://dbtune.org/jamendo/tag/depressive : 12 # http://dbtune.org/jamendo/tag/medieval : 12 http://dbtune.org/jamendo/tag/flow : 12 # http://dbtune.org/jamendo/tag/doom : 12 -http://dbtune.org/jamendo/tag/electroindus : 12 +# http://dbtune.org/jamendo/tag/electroindus : 12 http://dbtune.org/jamendo/tag/nostalgique : 12 # http://dbtune.org/jamendo/tag/italia : 12 # http://dbtune.org/jamendo/tag/britpop : 12 -http://dbtune.org/jamendo/tag/emotions : 12 +# http://dbtune.org/jamendo/tag/emotions : 12 # http://dbtune.org/jamendo/tag/japan : 12 http://dbtune.org/jamendo/tag/lyrics : 12 # http://dbtune.org/jamendo/tag/hardtrance : 12 @@ -621,7 +621,7 @@ http://dbtune.org/jamendo/tag/spoken : 10 # http://dbtune.org/jamendo/tag/espana : 10 # http://dbtune.org/jamendo/tag/christian : 10 -http://dbtune.org/jamendo/tag/rockfestif : 10 +# http://dbtune.org/jamendo/tag/rockfestif : 10 # http://dbtune.org/jamendo/tag/electrodark : 10 # http://dbtune.org/jamendo/tag/numetal : 10 # http://dbtune.org/jamendo/tag/distorsion : 10 @@ -641,7 +641,7 @@ # http://dbtune.org/jamendo/tag/arabic : 10 # http://dbtune.org/jamendo/tag/neoclassical : 10 http://dbtune.org/jamendo/tag/barre : 9 -http://dbtune.org/jamendo/tag/parodie : 9 +# http://dbtune.org/jamendo/tag/parodie : 9 http://dbtune.org/jamendo/tag/energy : 9 # http://dbtune.org/jamendo/tag/bioteckrecords : 9 http://dbtune.org/jamendo/tag/air : 9 @@ -817,7 +817,7 @@ http://dbtune.org/jamendo/tag/recherche : 7 # http://dbtune.org/jamendo/tag/italodance : 7 http://dbtune.org/jamendo/tag/cantautor : 7 -http://dbtune.org/jamendo/tag/femalevocals : 7 +# http://dbtune.org/jamendo/tag/femalevocals : 7 http://dbtune.org/jamendo/tag/lento : 7 http://dbtune.org/jamendo/tag/violento : 7 http://dbtune.org/jamendo/tag/real : 7 @@ -858,12 +858,12 @@ http://dbtune.org/jamendo/tag/soulful : 7 http://dbtune.org/jamendo/tag/vate : 7 http://dbtune.org/jamendo/tag/dulce : 7 -http://dbtune.org/jamendo/tag/rockguitar : 7 +# http://dbtune.org/jamendo/tag/rockguitar : 7 # http://dbtune.org/jamendo/tag/est : 7 http://dbtune.org/jamendo/tag/relajante : 7 # http://dbtune.org/jamendo/tag/us : 7 http://dbtune.org/jamendo/tag/tipunk : 7 -http://dbtune.org/jamendo/tag/distortion : 7 +# http://dbtune.org/jamendo/tag/distortion : 7 http://dbtune.org/jamendo/tag/sense : 7 http://dbtune.org/jamendo/tag/nexus : 7 http://dbtune.org/jamendo/tag/cabaret : 7 Deleted: trunk/src/moosique.net/moosique/data/moosique.owl =================================================================== --- trunk/src/moosique.net/moosique/data/moosique.owl 2009-11-26 14:18:29 UTC (rev 1924) +++ trunk/src/moosique.net/moosique/data/moosique.owl 2009-11-30 02:47:39 UTC (rev 1925) @@ -1,4298 +0,0 @@ -@prefix : <http://dbtune.org/jamendo/tag/> . -@prefix mo: <http://purl.org/ontology/mo/> . -@prefix dc: <http://purl.org/dc/elements/1.1/> . -@prefix moosique: <http://moosique.net/> . -@prefix tag: <http://dbtune.org/jamendo/tag/> . -@prefix tag4: <http://dbtune.org/jamendo/tag/90> . -@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . -@prefix tag5: <http://dbtune.org/jamendo/tag/8> . -@prefix tag2: <http://dbtune.org/jamendo/tag/80> . -@prefix tag3: <http://dbtune.org/jamendo/tag/60> . -@prefix owl2xml: <http://www.w3.org/2006/12/owl2-xml#> . -@prefix tag6: <http://dbtune.org/jamendo/tag/70> . -@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . -@prefix owl: <http://www.w3.org/2002/07/owl#> . -@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . -@base <http://dbtune.org/jamendo/tag/> . - -<http://dbtune.org/jamendo/tag/> rdf:type owl:Ontology . - - -################################################################# -# -# Classes -# -################################################################# - - -### http://dbtune.org/jamendo/tag/60s - -tag3:s rdf:type owl:Class ; - - rdfs:subClassOf :rock . - - - -### http://dbtune.org/jamendo/tag/70s - -tag6:s rdf:type owl:Class ; - - rdfs:subClassOf :pop . - - - -### http://dbtune.org/jamendo/tag/80s - -tag2:s rdf:type owl:Class ; - - rdfs:subClassOf :pop . - - - -### http://dbtune.org/jamendo/tag/8bit - -tag5:bit rdf:type owl:Class ; - - owl:equivalentClass tag5:bits , - :atari , - :chiptune , - :midi ; - - rdfs:subClassOf :computer . - - - -### http://dbtune.org/jamendo/tag/8bits - -tag5:bits rdf:type owl:Class ; - - rdfs:subClassOf :computer . - - - -### http://dbtune.org/jamendo/tag/90s - -tag4:s rdf:type owl:Class ; - - rdfs:subClassOf :pop . - - - -### http://dbtune.org/jamendo/tag/accordeon - -:accordeon rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/acid - -:acid rdf:type owl:Class ; - - owl:equivalentClass :bigbeat ; - - rdfs:subClassOf :house . - - - -### http://dbtune.org/jamendo/tag/acidjazz - -:acidjazz rdf:type owl:Class ; - - rdfs:subClassOf :jazz . - - - -### http://dbtune.org/jamendo/tag/acidrock - -:acidrock rdf:type owl:Class ; - - rdfs:subClassOf :psychedelic . - - - -### http://dbtune.org/jamendo/tag/acoustique - -:acoustique rdf:type owl:Class ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/africa - -:africa rdf:type owl:Class ; - - owl:equivalentClass :afrique ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/afrique - -:afrique rdf:type owl:Class ; - - owl:equivalentClass :afro ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/afro - -:afro rdf:type owl:Class ; - - rdfs:subClassOf :world . - - - -### http://dbtune.org/jamendo/tag/alternatif - -:alternatif rdf:type owl:Class ; - - owl:equivalentClass :alternativ , - :alternativo ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/alternativ - -:alternativ rdf:type owl:Class ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/alternativo - -:alternativo rdf:type owl:Class ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/ambiance - -:ambiance rdf:type owl:Class ; - - owl:equivalentClass :ambience , - :ambient ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/ambience - -:ambience rdf:type owl:Class ; - - owl:equivalentClass :ambient ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/ambient - -:ambient rdf:type owl:Class ; - - owl:equivalentClass :ambiental , - :ambiente , - :downtempo , - :planant , - :tacambient ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/ambiental - -:ambiental rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/ambiente - -:ambiente rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/anarchie - -:anarchie rdf:type owl:Class ; - - rdfs:subClassOf :punkrock . - - - -### http://dbtune.org/jamendo/tag/anglais - -:anglais rdf:type owl:Class ; - - owl:equivalentClass :english ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/arabic - -:arabic rdf:type owl:Class ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/argentina - -:argentina rdf:type owl:Class ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/asia - -:asia rdf:type owl:Class ; - - owl:equivalentClass :asian ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/asian - -:asian rdf:type owl:Class ; - - owl:equivalentClass :eastern ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/atari - -:atari rdf:type owl:Class ; - - rdfs:subClassOf :computer . - - - -### http://dbtune.org/jamendo/tag/atmospherique - -:atmospherique rdf:type owl:Class ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/avantgarde - -:avantgarde rdf:type owl:Class ; - - rdfs:subClassOf :electro , - :experimental , - :jazz . - - - -### http://dbtune.org/jamendo/tag/barcelona - -:barcelona rdf:type owl:Class ; - - rdfs:subClassOf :spanish . - - - -### http://dbtune.org/jamendo/tag/baroque - -:baroque rdf:type owl:Class ; - - rdfs:subClassOf :classique . - - - -### http://dbtune.org/jamendo/tag/basse - -:basse rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/belgique - -:belgique rdf:type owl:Class ; - - owl:equivalentClass :belgium ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/belgium - -:belgium rdf:type owl:Class ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/berlin - -:berlin rdf:type owl:Class ; - - rdfs:subClassOf :german . - - - -### http://dbtune.org/jamendo/tag/bigbeat - -:bigbeat rdf:type owl:Class ; - - rdfs:subClassOf :techno . - - - -### http://dbtune.org/jamendo/tag/bizzare - -:bizzare rdf:type owl:Class ; - - owl:equivalentClass :etrange ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/black - -:black rdf:type owl:Class ; - - owl:equivalentClass :blackmetal ; - - rdfs:subClassOf :house , - :metal , - :soul . - - - -### http://dbtune.org/jamendo/tag/blackmetal - -:blackmetal rdf:type owl:Class ; - - rdfs:subClassOf :metal . - - - -### http://dbtune.org/jamendo/tag/blues - -:blues rdf:type owl:Class ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/bluesrock - -:bluesrock rdf:type owl:Class ; - - rdfs:subClassOf :blues , - :rock . - - - -### http://dbtune.org/jamendo/tag/bossanova - -:bossanova rdf:type owl:Class ; - - rdfs:subClassOf :latin . - - - -### http://dbtune.org/jamendo/tag/brasil - -:brasil rdf:type owl:Class ; - - owl:equivalentClass :brazil , - :brazilian ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/brass - -:brass rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/brazil - -:brazil rdf:type owl:Class ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/brazilian - -:brazilian rdf:type owl:Class ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/breakbeat - -:breakbeat rdf:type owl:Class ; - - owl:equivalentClass :breakbeats ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/breakbeats - -:breakbeats rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/breakcore - -:breakcore rdf:type owl:Class ; - - rdfs:subClassOf :drumnbass , - :industriel , - :techno . - - - -### http://dbtune.org/jamendo/tag/bretagne - -:bretagne rdf:type owl:Class ; - - rdfs:subClassOf :francais . - - - -### http://dbtune.org/jamendo/tag/british - -:british rdf:type owl:Class ; - - owl:equivalentClass :britpop ; - - rdfs:subClassOf :uk . - - - -### http://dbtune.org/jamendo/tag/britpop - -:britpop rdf:type owl:Class ; - - rdfs:subClassOf :pop , - :uk . - - - -### http://dbtune.org/jamendo/tag/calm - -:calm rdf:type owl:Class ; - - owl:equivalentClass :calme ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/calme - -:calme rdf:type owl:Class ; - - owl:equivalentClass :tranquille ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/celta - -:celta rdf:type owl:Class ; - - owl:equivalentClass :celtique ; - - rdfs:subClassOf :world . - - - -### http://dbtune.org/jamendo/tag/celtique - -:celtique rdf:type owl:Class ; - - rdfs:subClassOf :world , - dc:language . - - - -### http://dbtune.org/jamendo/tag/chanson - -:chanson rdf:type owl:Class ; - - owl:equivalentClass :chansons ; - - rdfs:subClassOf :vocal . - - - -### http://dbtune.org/jamendo/tag/chansonatexte - -:chansonatexte rdf:type owl:Class ; - - rdfs:subClassOf :texte . - - - -### http://dbtune.org/jamendo/tag/chansonfrancaise - -:chansonfrancaise rdf:type owl:Class ; - - rdfs:subClassOf :chanson . - - - -### http://dbtune.org/jamendo/tag/chansons - -:chansons rdf:type owl:Class ; - - owl:equivalentClass :chant ; - - rdfs:subClassOf :vocal . - - - -### http://dbtune.org/jamendo/tag/chant - -:chant rdf:type owl:Class ; - - rdfs:subClassOf :vocal . - - - -### http://dbtune.org/jamendo/tag/chill - -:chill rdf:type owl:Class ; - - owl:equivalentClass :chillout ; - - rdfs:subClassOf :ambient . - - - -### http://dbtune.org/jamendo/tag/chillout - -:chillout rdf:type owl:Class ; - - rdfs:subClassOf :ambient . - - - -### http://dbtune.org/jamendo/tag/chiptune - -:chiptune rdf:type owl:Class ; - - owl:equivalentClass :chiptunes , - :videogame ; - - rdfs:subClassOf :computer , - :synth . - - - -### http://dbtune.org/jamendo/tag/chiptunes - -:chiptunes rdf:type owl:Class ; - - rdfs:subClassOf :computer . - - - -### http://dbtune.org/jamendo/tag/christian - -:christian rdf:type owl:Class ; - - owl:equivalentClass :gospel ; - - rdfs:subClassOf :world . - - - -### http://dbtune.org/jamendo/tag/clarinette - -:clarinette rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/clash - -:clash rdf:type owl:Class ; - - owl:equivalentClass :electroclash ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/classic - -:classic rdf:type owl:Class ; - - owl:equivalentClass :classique ; - - rdfs:subClassOf :rock , - mo:Genre . - - - -### http://dbtune.org/jamendo/tag/classical - -:classical rdf:type owl:Class ; - - owl:equivalentClass :classique ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/classique - -:classique rdf:type owl:Class ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/clavier - -:clavier rdf:type owl:Class ; - - owl:equivalentClass :claviers , - :piano ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/claviers - -:claviers rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/computer - -:computer rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/contrebass - -:contrebass rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/cooljazz - -:cooljazz rdf:type owl:Class ; - - rdfs:subClassOf :jazz . - - - -### http://dbtune.org/jamendo/tag/country - -:country rdf:type owl:Class ; - - rdfs:subClassOf mo:Genre . - - - -### http://dbtune.org/jamendo/tag/crossover - -:crossover rdf:type owl:Class ; - - rdfs:subClassOf :rock . - - - -### http://dbtune.org/jamendo/tag/cyperpunk - -:cyperpunk rdf:type owl:Class ; - - rdfs:subClassOf :punk . - - - -### http://dbtune.org/jamendo/tag/dance - -:dance rdf:type owl:Class ; - - owl:equivalentClass :danse ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/dancefloor - -:dancefloor rdf:type owl:Class ; - - rdfs:subClassOf :dance , - :techno . - - - -### http://dbtune.org/jamendo/tag/dancehall - -:dancehall rdf:type owl:Class ; - - rdfs:subClassOf :hiphop , - :reggae . - - - -### http://dbtune.org/jamendo/tag/danse - -:danse rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/dark - -:dark rdf:type owl:Class ; - - owl:equivalentClass :darkelectro , - :electrodark , - :sombre ; - - rdfs:subClassOf :ambient , - :electro , - :house , - :metal . - - - -### http://dbtune.org/jamendo/tag/darkambient - -:darkambient rdf:type owl:Class ; - - rdfs:subClassOf :ambient . - - - -### http://dbtune.org/jamendo/tag/darkelectro - -:darkelectro rdf:type owl:Class ; - - owl:equivalentClass :electrodark ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/darkwave - -:darkwave rdf:type owl:Class ; - - rdfs:subClassOf :newwave . - - - -### http://dbtune.org/jamendo/tag/death - -:death rdf:type owl:Class ; - - owl:equivalentClass :deathmetal ; - - rdfs:subClassOf :metal . - - - -### http://dbtune.org/jamendo/tag/deathmetal - -:deathmetal rdf:type owl:Class ; - - rdfs:subClassOf :metal . - - - -### http://dbtune.org/jamendo/tag/deephouse - -:deephouse rdf:type owl:Class ; - - rdfs:subClassOf :house . - - - -### http://dbtune.org/jamendo/tag/delirant - -:delirant rdf:type owl:Class ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/depressif - -:depressif rdf:type owl:Class ; - - owl:equivalentClass :depressive ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/depressive - -:depressive rdf:type owl:Class ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/deutsch - -:deutsch rdf:type owl:Class ; - - owl:equivalentClass :german ; - - rdfs:subClassOf dc:language . - - - -### http://dbtune.org/jamendo/tag/deutschpunk - -:deutschpunk rdf:type owl:Class ; - - rdfs:subClassOf :german , - :punk . - - - -### http://dbtune.org/jamendo/tag/didgeridoo - -:didgeridoo rdf:type owl:Class ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/disco - -:disco rdf:type owl:Class ; - - rdfs:subClassOf :electro , - :funk . - - - -### http://dbtune.org/jamendo/tag/distorsion - -:distorsion rdf:type owl:Class ; - - owl:equivalentClass :distortion , - :fuzz ; - - rdfs:subClassOf :guitare . - - - -### http://dbtune.org/jamendo/tag/distortion - -:distortion rdf:type owl:Class ; - - rdfs:subClassOf :guitare . - - - -### http://dbtune.org/jamendo/tag/dj - -:dj rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/dnb - -:dnb rdf:type owl:Class ; - - owl:equivalentClass :drumnbass ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/doom - -:doom rdf:type owl:Class ; - - rdfs:subClassOf :metal . - - - -### http://dbtune.org/jamendo/tag/downbeat - -:downbeat rdf:type owl:Class ; - - owl:equivalentClass :downtempo ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/downtempo - -:downtempo rdf:type owl:Class ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/dream - -:dream rdf:type owl:Class ; - - rdfs:subClassOf mo:Mood . - - - -### http://dbtune.org/jamendo/tag/drone - -:drone rdf:type owl:Class ; - - rdfs:subClassOf :doom . - - - -### http://dbtune.org/jamendo/tag/drum - -:drum rdf:type owl:Class ; - - owl:equivalentClass :drums ; - - rdfs:subClassOf mo:Instrument . - - - -### http://dbtune.org/jamendo/tag/drumandbass - -:drumandbass rdf:type owl:Class ; - - owl:equivalentClass :drumnbass ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/drumbass - -:drumbass rdf:type owl:Class ; - - owl:equivalentClass :drumnbass ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/drumn - -:drumn rdf:type owl:Class ; - - owl:equivalentClass :drumnbass ; - - rdfs:subClassOf :electro . - - - -### http://dbtune.org/jamendo/tag/drumnbass - -:drumnbass rdf:type owl:Class ; - - rdfs... [truncated message content] |