librefm-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Librefm-commits] [1109] merge nixtape from trunk


From: Clint Adams
Subject: [Librefm-commits] [1109] merge nixtape from trunk
Date: Sat, 02 May 2009 04:00:58 +0000

Revision: 1109
          http://svn.sv.gnu.org/viewvc/?view=rev&root=librefm&revision=1109
Author:   clint
Date:     2009-05-02 04:00:56 +0000 (Sat, 02 May 2009)
Log Message:
-----------
merge nixtape from trunk

Modified Paths:
--------------
    branches/stable/nixtape/.htaccess
    branches/stable/nixtape/2.0/index.php
    branches/stable/nixtape/auth.php
    branches/stable/nixtape/data/Album.php
    branches/stable/nixtape/data/Artist.php
    branches/stable/nixtape/data/Server.php
    branches/stable/nixtape/data/TagCloud.php
    branches/stable/nixtape/data/Track.php
    branches/stable/nixtape/data/User.php
    branches/stable/nixtape/database.php
    branches/stable/nixtape/index.php
    branches/stable/nixtape/install.php
    branches/stable/nixtape/invite.php
    branches/stable/nixtape/js/player.js
    branches/stable/nixtape/licenses.php
    branches/stable/nixtape/login.php
    branches/stable/nixtape/register.php
    branches/stable/nixtape/resolve-external.php
    branches/stable/nixtape/scrobble-proxy.php
    branches/stable/nixtape/templating.php
    branches/stable/nixtape/themes/librefm/alpha.css
    branches/stable/nixtape/themes/librefm/librefm.css
    branches/stable/nixtape/themes/librefm/player.css
    branches/stable/nixtape/themes/librefm/templates/album.tpl
    branches/stable/nixtape/themes/librefm/templates/header.tpl
    branches/stable/nixtape/themes/librefm/templates/login.tpl
    branches/stable/nixtape/themes/librefm/templates/menu.tpl
    branches/stable/nixtape/themes/librefm/templates/player.tpl
    branches/stable/nixtape/themes/librefm/templates/register.tpl
    branches/stable/nixtape/themes/librefm/templates/track.tpl
    branches/stable/nixtape/themes/librefm/templates/welcome.tpl
    branches/stable/nixtape/utils/human-time.php
    branches/stable/nixtape/version.php

Added Paths:
-----------
    branches/stable/nixtape/data/Group.php
    branches/stable/nixtape/edit_group.php
    branches/stable/nixtape/free.php
    branches/stable/nixtape/group.php
    branches/stable/nixtape/js/user-edit.js
    branches/stable/nixtape/listen.php
    branches/stable/nixtape/location.php
    branches/stable/nixtape/themes/librefm/templates/edit_group.tpl
    branches/stable/nixtape/themes/librefm/templates/group-list.tpl
    branches/stable/nixtape/themes/librefm/templates/group.tpl
    branches/stable/nixtape/themes/librefm/templates/listen.tpl
    branches/stable/nixtape/themes/librefm/templates/location-country.tpl
    branches/stable/nixtape/themes/librefm/templates/maxiprofile.tpl
    branches/stable/nixtape/themes/librefm/templates/miniprofile.tpl
    branches/stable/nixtape/themes/librefm/templates/user-edit.tpl
    branches/stable/nixtape/themes/librefm/templates/user-groups.tpl
    branches/stable/nixtape/themes/librefm/templates/user-journal.tpl
    branches/stable/nixtape/themes/librefm/templates/user-profile.tpl
    branches/stable/nixtape/themes/librefm/templates/user-recent-tracks.tpl
    branches/stable/nixtape/themes/librefm/templates/user-stats.tpl
    branches/stable/nixtape/user-edit.php
    branches/stable/nixtape/user-groups.php
    branches/stable/nixtape/user-journal.php
    branches/stable/nixtape/user-profile.php
    branches/stable/nixtape/user-recent-tracks.php
    branches/stable/nixtape/user-stats.php
    branches/stable/nixtape/utils/get_absolute_url.php

Removed Paths:
-------------
    branches/stable/nixtape/edit_profile.php
    branches/stable/nixtape/js/edit_profile.js
    branches/stable/nixtape/profile.php
    branches/stable/nixtape/stats.php
    branches/stable/nixtape/themes/librefm/templates/edit_profile.tpl
    branches/stable/nixtape/themes/librefm/templates/profile.tpl
    branches/stable/nixtape/themes/librefm/templates/stats.tpl

Modified: branches/stable/nixtape/.htaccess
===================================================================
--- branches/stable/nixtape/.htaccess   2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/.htaccess   2009-05-02 04:00:56 UTC (rev 1109)
@@ -1,10 +1,17 @@
 Options +FollowSymLinks
 RewriteEngine on
 
-RewriteRule ^user/([^/]+)/?$                                   
profile.php?user=$1                     [B,NC]
+RewriteRule ^user/([^/]+)/?$                                   
user-profile.php?user=$1                [B,NC]
+RewriteRule ^user/([^/]+)/journal/?$                            
user-journal.php?user=$1                [B,NC]
+RewriteRule ^user/([^/]+)/groups/?$                             
user-groups.php?user=$1                 [B,NC]
+RewriteRule ^user/([^/]+)/recent-tracks/?$                      
user-recent-tracks.php?user=$1          [B,NC,QSA]
+RewriteRule ^user/([^/]+)/stats/?$                              
user-stats.php?user=$1                  [B,NC]
 RewriteRule ^artist/([^/]+)/track/([^/]+)/?$                   
track.php?artist=$1&track=$2            [B,NC]
 RewriteRule ^artist/([^/]+)/album/([^/]+)/track/([^/]+)/?$     
track.php?artist=$1&album=$2&track=$3   [B,NC]
 RewriteRule ^artist/([^/]+)/album/([^/]+)/?$                   
album.php?artist=$1&album=$2            [B,NC]
 RewriteRule ^artist/([^/]+)/?$                                 
artist.php?artist=$1                    [B,NC]
+RewriteRule ^group/new$                                         
edit_group.php?group=new                [B,NC]
+RewriteRule ^group/([^/]+)/?$                                   
group.php?group=$1                      [B,NC,QSA]
+RewriteRule ^group/?$                                           group.php      
                         [B,NC]
+RewriteRule ^country/([^/]+)/?$                                        
location.php?country=$1                 [B,NC]
 RewriteRule ^logout                                            
login.php?action=logout                 [B,NC]
-ErrorDocument 404 /register.php

Modified: branches/stable/nixtape/2.0/index.php
===================================================================
--- branches/stable/nixtape/2.0/index.php       2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/2.0/index.php       2009-05-02 04:00:56 UTC (rev 
1109)
@@ -128,17 +128,21 @@
        if (!isset($_GET['authToken']))
                report_failure(LFM_INVALID_TOKEN);
 
-       // Check for a token that (1) is bound to a user, and (2) is not bound 
to a session
-       $result = $mdb2->query('SELECT username FROM Users WHERE '
-               . 'username = ' . $mdb2->quote($_GET['username'], 'text')
-               . 'AND MD5(CONCAT(username, password)) = '
-               . $mdb2->quote($_GET['authToken'], 'text'));
-       if (PEAR::isError($result))
+       // Check for a token that is bound to a user
+       $result = $mdb2->queryRow('SELECT username, password FROM Users WHERE '
+               . 'username = ' . $mdb2->quote($_GET['username'], 'text'));
+       if (PEAR::isError($result)) {
                report_failure(LFM_SERVICE_OFFLINE);
-       if (!$result->numRows())
+       }
+       if (is_null($result)) {
                report_failure(LFM_INVALID_TOKEN);
+       }
 
-       $username = $result->fetchOne(0);
+       list($username, $password) = $result;
+       if (md5($username . $password) != $_GET['authToken']) {
+               report_failure(LFM_INVALID_TOKEN);
+       }
+
        $key = md5(time() . rand());
        $session = md5(time() . rand());
 

Modified: branches/stable/nixtape/auth.php
===================================================================
--- branches/stable/nixtape/auth.php    2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/auth.php    2009-05-02 04:00:56 UTC (rev 1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -21,19 +21,20 @@
 
 require_once('database.php');
 require_once('data/User.php');
-
 session_start();
-if(isset($_SESSION['session_id'])) {
+if(isset($_COOKIE['session_id'])) {
        $res = $mdb2->query('SELECT username FROM Scrobble_Sessions WHERE '
-               . 'sessionid = ' . $mdb2->quote($_SESSION['session_id'], 'text')
+               . 'sessionid = ' . $mdb2->quote($_COOKIE['session_id'], 'text')
                . ' AND expires > ' . $mdb2->quote(time(), 'integer'));
        if(PEAR::isError ($res) || !$res->numRows()) {
                // Session is invalid
-               unset($_SESSION['session_id']);
+               setcookie('session_id', '', time() - 3600);
+               session_unset();
+               session_destroy();
        } else {
                $logged_in = true;
                $row = $res->fetchRow(MDB2_FETCHMODE_ASSOC);
-               $u_user = new User($row['username']);
+               $this_user = new User($row['username']);
        }
 }
 ?>

Modified: branches/stable/nixtape/data/Album.php
===================================================================
--- branches/stable/nixtape/data/Album.php      2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/data/Album.php      2009-05-02 04:00:56 UTC (rev 
1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by

Modified: branches/stable/nixtape/data/Artist.php
===================================================================
--- branches/stable/nixtape/data/Artist.php     2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/data/Artist.php     2009-05-02 04:00:56 UTC (rev 
1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by

Added: branches/stable/nixtape/data/Group.php
===================================================================
--- branches/stable/nixtape/data/Group.php                              (rev 0)
+++ branches/stable/nixtape/data/Group.php      2009-05-02 04:00:56 UTC (rev 
1109)
@@ -0,0 +1,295 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once($install_path . '/database.php');
+require_once($install_path . '/data/sanitize.php');
+require_once($install_path . '/utils/human-time.php');
+require_once($install_path . '/data/Server.php');
+require_once($install_path . '/data/TagCloud.php');
+require_once($install_path . '/data/User.php');
+
+/**
+ * Represents Group data
+ *
+ * General attributes are accessible as public variables.
+ *
+ */
+class Group {
+
+       public $name, $owner, $fullname, $bio, $homepage, $count, $grouptype, 
$id, $avatar_uri, $users;
+
+       /**
+        * User constructor
+        *
+        * @param string $name The name of the user to load
+        */
+       function __construct($name, $data=null) {
+
+               global $base_url;
+               $base = preg_replace('#/$#', '', $base_url);
+
+               if (is_array($data)) {
+                       $row = $data;
+               }
+               else {
+                       global $mdb2;
+                       $res = $mdb2->query('SELECT * FROM Groups WHERE 
lower(groupname) = ' . $mdb2->quote(strtolower($name), 'text'));
+                       
+                       if(PEAR::isError($res)) {
+                               header("Content-Type: text/plain");
+                               print_r($res);
+                               exit;
+                       }
+
+                       if($res->numRows()) {
+                               $row = $res->fetchRow(MDB2_FETCHMODE_ASSOC);
+                       }
+               }
+                       
+               if (is_array($row)) {
+                       $this->name         = $row['groupname'];
+                       $this->fullname     = $row['fullname'];
+                       $this->homepage     = $row['homepage'];
+                       $this->bio          = $row['bio'];
+                       $this->avatar_uri   = $row["avatar_uri"];
+                       $this->owner        = new User($row['owner']);
+                       $this->count        = -1;
+                       $this->users        = array();
+
+                       if (! preg_match('/\:/', $this->id))
+                               $this->id = $base.'/group/' . 
urlencode($this->name) . '#group';
+               }               
+       }
+       
+       static function create ($name, $owner)
+       {
+               global $mdb2;
+               
+               // Should check to make sure no existing group with same name 
(case-insensitive).
+               
+               $q = sprintf("INSERT INTO Groups (groupname, owner, created, 
modified) VALUES (%s, %s, %d, %d)"
+                               , $mdb2->quote($name, 'text')
+                               , $mdb2->quote($owner->name, 'text')
+                               , time()
+                               , time());
+               $res = $mdb2->query($q);
+               
+               if(PEAR::isError($res)) {
+                       header("Content-Type: text/plain");
+                       print_r($res);
+                       exit;
+               }
+
+               $q = sprintf("INSERT INTO Group_Members (groupname, member, 
joined) VALUES (%s, %s, %d)"
+                               , $mdb2->quote($name, 'text')
+                               , $mdb2->quote($owner->name, 'text')
+                               , time());
+               $res = $mdb2->query($q);
+               
+               if(PEAR::isError($res)) {
+                       header("Content-Type: text/plain");
+                       print_r($res);
+                       exit;
+               }
+
+               return 1;
+       }
+       
+       static function groupList ($user=false)
+       {
+               global $mdb2;
+
+               if ($user)
+               {
+                       $res = $mdb2->query("SELECT gc.* FROM "
+                               . "Group_Members m "
+                               ."INNER JOIN (SELECT g.groupname, g.owner, 
g.fullname, g.bio, g.homepage, g.created, g.modified, g.avatar_uri, 
g.grouptype, COUNT(*) AS member_count "
+                               ."FROM Groups g "
+                               ."LEFT JOIN Group_Members gm ON 
gm.groupname=g.groupname "
+                               ."GROUP BY g.groupname, g.owner, g.fullname, 
g.bio, g.homepage, g.created, g.modified, g.avatar_uri, g.grouptype) gc "
+                               ."ON m.groupname=gc.groupname "
+                               ."WHERE m.member=".$mdb2->quote($user->name, 
'text'));
+               }
+               else
+               {
+                       $res = $mdb2->query("SELECT g.groupname, g.owner, 
g.fullname, g.bio, g.homepage, g.created, g.modified, g.avatar_uri, 
g.grouptype, COUNT(*) AS member_count "
+                               ."FROM Groups g "
+                               ."LEFT JOIN Group_Members gm ON 
gm.groupname=g.groupname "
+                               ."GROUP BY g.groupname, g.owner, g.fullname, 
g.bio, g.homepage, g.created, g.modified, g.avatar_uri, g.grouptype");
+               }
+               
+               if(PEAR::isError($res))
+               {
+                       header("Content-Type: text/plain");
+                       print_r($res);
+                       exit;
+               }
+
+               $list = array();
+               while ($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC))
+               {
+                       $g = new Group($row['group_name'], $row);
+                       $g->count = $row['member_count'];
+                       $list[] = $g;
+               }
+
+               return $list;
+       }
+       
+       function save ()
+       {
+               global $mdb2;
+               
+               $q = sprintf("UPDATE Groups SET "
+                               . "owner=%s, "
+                               . "fullname=%s, "
+                               . "homepage=%s, "
+                               . "bio=%s, "
+                               . "avatar_uri=%s, "
+                               . "modified=%d "
+                               . "WHERE groupname=%s"
+                               , $mdb2->quote($this->owner->name, 'text')
+                               , $mdb2->quote($this->fullname, 'text')
+                               , $mdb2->quote($this->homepage, 'text')
+                               , $mdb2->quote($this->bio, 'text')
+                               , $mdb2->quote($this->avatar_uri, 'text')
+                               , time()
+                               , $mdb2->quote($this->name, 'text'));
+                               
+               $res = $mdb2->query($q);
+               
+               if(PEAR::isError($res)) {
+                       header("Content-Type: text/plain");
+                       print_r($res);
+                       exit;
+               }
+
+               return 1;
+       }
+
+       /**
+        * Retrieve a user's avatar via the gravatar service
+        *
+        * @param int $size The desired size of the avatar (between 1 and 512 
pixels)
+        * @return A URL to the user's avatar image
+        */
+       function getAvatar($size=64) {
+               global $base_uri;
+               if (!empty($this->avatar_uri))
+                       return $this->avatar_uri;
+               return $base_uri . "/i/qm50.png";
+       }
+
+       function getURL() {
+               return Server::getGroupURL($this->name);
+       }
+       
+       function getURLAction ($action) {
+               $url = $this->getURL();
+               if (strstr($url, '?'))
+                       return $url . '&action=' . urlencode($action);
+               else
+                       return $url . '?action=' . urlencode($action);
+       }
+       
+       function getUsers () {
+               global $mdb2;
+
+               if (!isset($this->users[0]))
+               {
+                       $res = $mdb2->query("SELECT u.* "
+                               . "FROM Users u "
+                               . "INNER JOIN Group_Members gm ON 
u.username=gm.member "
+                               . "WHERE 
gm.groupname=".$mdb2->quote($this->name,'text')
+                               . " ORDER BY gm.joined");
+                       if ($res->numRows())
+                       {
+                               while ($row = 
$res->fetchRow(MDB2_FETCHMODE_ASSOC))
+                               {
+                                       $this->users[ $row['username'] ] = new 
User($row['username'], $row);
+                               }
+                       }
+                       
+                       $this->count = count($this->users);
+               }
+
+               return $this->users;
+       }
+
+       function memberCheck ($user) {
+               $users = $this->getUsers();
+               if ($users[ $user->name ]->name == $user->name)
+                       return true;
+               return false;
+       }
+       
+       function memberJoin ($user) {
+               if ($this->memberCheck($user))
+                       return false;
+               
+               global $mdb2;
+               $res = $mdb2->query(sprintf("INSERT INTO Group_Members VALUES 
(%s, %s, %d)",
+                       $mdb2->quote($this->name, 'text'),
+                       $mdb2->quote($user->name, 'text'),
+                       time()));
+               
+               if(PEAR::isError($res))
+               {
+                       return false;
+               }
+                       
+               $this->users[ $user->name ] = $user;
+               return true;
+       }
+
+       function memberLeave ($user) {
+               if (!$this->memberCheck($user))
+                       return false;
+               
+               // Group owner cannot leave, so we need a way to reassign 
ownership.
+               if ($this->owner->name == $user->name)
+                       return false;
+               
+               global $mdb2;
+               $res = $mdb2->query(sprintf("DELETE FROM Group_Members WHERE 
groupname=%s AND member=%s",
+                       $mdb2->quote($this->name, 'text'),
+                       $mdb2->quote($user->name, 'text')));
+               
+               if(PEAR::isError($res))
+                       return false;
+                       
+               $this->users[ $user->name ] = null;
+               // The array key still exists though. That's annoying. PHP 
needs an equivalent of Perl's 'delete'.
+               // This shouldn't actually cause us any problems, but people 
should be aware of the oddness.
+               return true;
+       }
+
+       function tagCloudData () {
+               return TagCloud::generateTagCloud(
+                       'Scrobbles INNER JOIN Group_Members ON 
Scrobbles.username=Group_Members.member',
+                       'artist',
+                       40,
+                       $this->name,
+                       'groupname');
+       }
+
+}
+

Modified: branches/stable/nixtape/data/Server.php
===================================================================
--- branches/stable/nixtape/data/Server.php     2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/data/Server.php     2009-05-02 04:00:56 UTC (rev 
1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -21,11 +21,13 @@
 
 require_once($install_path . '/database.php');
 require_once($install_path . '/data/Artist.php');
+require_once($install_path . '/data/Group.php');
 require_once($install_path . '/data/Track.php');
 require_once($install_path . '/data/User.php');
 require_once($install_path . "/data/sanitize.php");
 require_once($install_path . '/utils/linkeddata.php');
-require_once($install_path . "/resolve-external.php");
+require_once($install_path . '/utils/arc/ARC2.php');
+require_once($install_path . "/resolve-external.php"); // why isn't this in a 
subdir?
 require_once($install_path . '/licenses.php'); // why isn't this in a subdir?
 
 /**
@@ -56,7 +58,7 @@
                                        a.mbid AS artist_mbid,
                                        l.mbid AS album_mbid,
                                        l.image AS album_image,
-                                        l.artwork_license,
+                                       l.artwork_license,
                                        t.license
                                FROM Scrobbles s 
                                LEFT JOIN Artist a
@@ -85,7 +87,7 @@
                                        a.mbid AS artist_mbid,
                                        l.mbid AS album_mbid,
                                        l.image AS album_image,
-                                        l.artwork_license,
+                                       l.artwork_license,
                                        t.license
                                FROM Scrobbles s
                                LEFT JOIN Artist a
@@ -179,9 +181,50 @@
                global $mdb2;
 
                if($username) {
-                       $res = $mdb2->query('SELECT username, artist, album, 
track, client, ClientCodes.name, ClientCodes.url, ClientCodes.free, 
Now_Playing.mbid from Now_Playing LEFT OUTER JOIN Scrobble_Sessions ON 
Now_Playing.sessionid=Scrobble_Sessions.sessionid LEFT OUTER JOIN ClientCodes 
ON Scrobble_Sessions.client=ClientCodes.code WHERE lower(username) = ' . 
$mdb2->quote(strtolower($username), "text") . ' ORDER BY Now_Playing.expires 
DESC LIMIT ' . $mdb2->quote($number, "integer"));
+                       $res = $mdb2->query("SELECT
+                                               username,
+                                               n.artist,
+                                               n.track,
+                                               n.album,
+                                               client,
+                                               ClientCodes.name,
+                                               ClientCodes.url,
+                                               ClientCodes.free,
+                                               n.mbid,
+                                               t.license
+                                       FROM Now_Playing n
+                                       LEFT OUTER JOIN Scrobble_Sessions
+                                               ON 
n.sessionid=Scrobble_Sessions.sessionid
+                                       LEFT OUTER JOIN ClientCodes
+                                               ON 
Scrobble_Sessions.client=ClientCodes.code
+                                       LEFT OUTER JOIN Track t
+                                               ON lower(n.artist) = 
lower(t.artist)
+                                               AND lower(n.album) = 
lower(t.album)
+                                               AND lower(n.track) = 
lower(t.name)
+                                       WHERE lower(username) = " . 
$mdb2->quote(strtolower($username), "text") . "
+                                       ORDER BY t.streamable DESC, n.expires 
DESC LIMIT " . $mdb2->quote($number, "integer"));
                } else {
-                       $res = $mdb2->query('SELECT username, artist, track, 
album, client, ClientCodes.name, ClientCodes.url, ClientCodes.free, 
Now_Playing.mbid from Now_Playing LEFT OUTER JOIN Scrobble_Sessions ON 
Now_Playing.sessionid=Scrobble_Sessions.sessionid LEFT OUTER JOIN ClientCodes 
ON Scrobble_Sessions.client=ClientCodes.code ORDER BY Now_Playing.expires DESC 
LIMIT ' . $mdb2->quote($number, "integer"));
+                       $res = $mdb2->query("SELECT
+                                               username,
+                                               n.artist,
+                                               n.track,
+                                               n.album,
+                                               client,
+                                               ClientCodes.name,
+                                               ClientCodes.url,
+                                               ClientCodes.free,
+                                               n.mbid,
+                                               t.license
+                                       FROM Now_Playing n
+                                       LEFT OUTER JOIN Scrobble_Sessions
+                                               ON 
n.sessionid=Scrobble_Sessions.sessionid
+                                       LEFT OUTER JOIN ClientCodes
+                                               ON 
Scrobble_Sessions.client=ClientCodes.code
+                                       LEFT OUTER JOIN Track t
+                                               ON lower(n.artist) = 
lower(t.artist)
+                                               AND lower(n.album) = 
lower(t.album)
+                                               AND lower(n.track) = 
lower(t.name)
+                                       ORDER BY t.streamable DESC, n.expires 
DESC LIMIT " . $mdb2->quote($number, "integer"));
                }
 
                if(PEAR::isError($res)) {
@@ -206,6 +249,9 @@
                        
                        // We really want to get an image URI from the database 
and only fall back to qm50.png if we can't find an image.
                        $row['albumart'] = $base_url . '/i/qm50.png';
+
+                       $row["licenseurl"] = $row["license"];
+                       $row["license"] = simplify_license($row["licenseurl"]);
                        
                        $result[] = $row;
                }
@@ -220,40 +266,118 @@
         * @param string $username The username we want a URL for
         * @return A string containing URL to the user's profile
         */
-       static function getUserURL($username) {
+       static function getUserURL ($username, $component='profile')
+       {
                global $friendly_urls, $base_url;
+               if ($component == 'edit')
+               {
+                       return $base_url . "/user-edit.php";
+               }
+               elseif($friendly_urls)
+               {
+                       if ($component == 'profile')
+                               $component = '';
+                       else
+                               $component = "/{$component}";
+                       return $base_url . "/user/" . urlencode($username) . 
$component;
+               }
+               else
+               {
+                       return $base_url . "/user-{$component}.php?user=" . 
urlencode($username);
+               }
+       }
+
+       static function getGroupURL($groupname) {
+               global $friendly_urls, $base_url;
                if($friendly_urls) {
-                       return $base_url . "/user/" . 
urlencode(stripslashes($username));
+                       return $base_url . "/group/" . urlencode($groupname);
                } else {
-                       return $base_url . "/profile.php?user=" . 
urlencode(stripslashes($username));
+                       return $base_url . "/group.php?group=" . 
urlencode($groupname);
                }
        }
 
        static function getArtistURL($artist) {
                global $friendly_urls, $base_url;
                if($friendly_urls) {
-                       return $base_url . "/artist/" . 
urlencode(stripslashes($artist));
+                       return $base_url . "/artist/" . urlencode($artist);
                } else {
-                       return $base_url . "/artist.php?artist=" . 
urlencode(stripslashes($artist));
+                       return $base_url . "/artist.php?artist=" . 
urlencode($artist);
                }
        }
 
        static function getAlbumURL($artist, $album) {
                global $friendly_urls, $base_url;
                if($friendly_urls) {
-                       return $base_url . "/artist/" . 
urlencode(stripslashes($artist)) . "/album/" . urlencode(stripslashes($album));
+                       return $base_url . "/artist/" . urlencode($artist) . 
"/album/" . urlencode($album);
                } else {
-                       return $base_url . "/album.php?artist=" . 
urlencode(stripslashes($artist)) . "&album=" . urlencode(stripslashes($album));
+                       return $base_url . "/album.php?artist=" . 
urlencode($artist) . "&album=" . urlencode($album);
                }
        }
 
        static function getTrackURL($artist, $album, $track) {
                global $friendly_urls, $base_url;
-               if($friendly_urls) {
-                       return $base_url . "/artist/" . 
urlencode(stripslashes($artist)) . "/album/" . urlencode(stripslashes($album)) 
. "/track/" . urlencode(stripslashes($track));
+               if ($friendly_urls && $album) {
+                       return $base_url . "/artist/" . urlencode($artist) . 
"/album/" . urlencode($album) . "/track/" . urlencode($track);
+               } elseif ($friendly_urls) {
+                       return $base_url . "/artist/" . urlencode($artist) . 
"/track/" . urlencode($track);
                } else {
-                       return $base_url . "/track.php?artist=" . 
urlencode(stripslashes($artist)) .   "&album=" . 
urlencode(stripslashes($album)) . "&track=" . urlencode(stripslashes($track));
+                       return $base_url . "/track.php?artist=" . 
urlencode($artist) .   "&album=" . urlencode($album) . "&track=" . 
urlencode($track);
                }
        }
 
+       static function getLocationDetails($name) {
+               global $mdb2;
+               
+               if (!$name)
+                       return array();
+
+               $res = $mdb2->query('SELECT p.latitude, p.longitude, p.country, 
c.country_name, c.wikipedia_en '
+                       . 'FROM Places p '
+                       . 'LEFT JOIN Countries c ON p.country=c.country '
+                       . 'WHERE p.location_uri=' . $mdb2->quote($name, 
'text'));
+               
+               if($res->numRows()) {
+               
+                       $rv = $res->fetchRow(MDB2_FETCHMODE_ASSOC);
+                       
+                       if (! ($rv['latitude'] && $rv['longitude'] && 
$rv['country'])) {
+                       
+                               $parser = ARC2::getRDFXMLParser();
+                               $parser->parse($name);
+                               $index = $parser->getSimpleIndex();
+                               
+                               $rv = array(
+                                       'latitude'  => 
$index[$name]['http://www.w3.org/2003/01/geo/wgs84_pos#lat'][0],
+                                       'longitude' => 
$index[$name]['http://www.w3.org/2003/01/geo/wgs84_pos#long'][0],
+                                       'country'   => 
strtoupper(substr($index[$name]['http://www.geonames.org/ontology#inCountry'][0],
 -2))
+                                       );
+
+                               $mdb2->query(sprintf('UPDATE Places SET 
latitude=%f, longitude=%f, country=%s WHERE location_uri=%s',
+                                       (float)$rv['latitude'],
+                                       (float)$rv['longitude'],
+                                       $mdb2->quote($rv['country'], 'text'),
+                                       $mdb2->quote($name, 'text')));
+                       }
+               }
+               else {
+                       $parser = ARC2::getRDFXMLParser();
+                       $parser->parse($name);
+                       $index = $parser->getSimpleIndex();
+                       
+                       $rv = array(
+                               'latitude'  => 
$index[$name]['http://www.w3.org/2003/01/geo/wgs84_pos#lat'][0],
+                               'longitude' => 
$index[$name]['http://www.w3.org/2003/01/geo/wgs84_pos#long'][0],
+                               'country'   => 
strtoupper(substr($index[$name]['http://www.geonames.org/ontology#inCountry'][0],
 -2))
+                               );
+
+                       $mdb2->query(sprintf('INSERT INTO Places VALUES (%s, 
%f, %f, %s)',
+                               $mdb2->quote($name, 'text'),
+                               (float)$rv['latitude'],
+                               (float)$rv['longitude'],
+                               $mdb2->quote($rv['country'], 'text')));
+               }
+                       
+               return $rv;
+       }
+
 }

Modified: branches/stable/nixtape/data/TagCloud.php
===================================================================
--- branches/stable/nixtape/data/TagCloud.php   2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/data/TagCloud.php   2009-05-02 04:00:56 UTC (rev 
1109)
@@ -32,41 +32,40 @@
     * inaccurate @param float $max_font_size maximum font size (px, em, %, etc)
     * @return array tagcloud
     */
-    static function generateTagCloud($table, $field, $limit = 40, $constraint 
= null) {
+    static function generateTagCloud($table, $field, $limit = 40, $constraint 
= null, $constrained_field = false) {
         global $mdb2;
         if (!is_string($field))          return false; 
         if (!is_string($table))          return false;
         if (!is_integer($limit))         return false;
-       $sizes = array('xx-large', 'x-large', 'large', 'medium', 'small', 
'x-small', 'xx-small');
+        $sizes = array('xx-large', 'x-large', 'large', 'medium', 'small', 
'x-small', 'xx-small');
         $query = "SELECT $field, count(*) AS count FROM $table";
-        $query .= (!is_null($constraint) || ($table == "Scrobbles")) ? ' WHERE 
' : null;
-       if ($field == "track") {
-        $query .= (!is_null($constraint)) ? ' artist = ' . 
$mdb2->quote($constraint, 'text') : null;
-       } else {
-        $query .= (!is_null($constraint)) ? ' username = ' . 
$mdb2->quote($constraint, 'text') : null;
-       }
-        $query .= (!is_null($constraint) && ($table == "Scrobbles")) ? ' AND ' 
: null;
-        $query .= ($table == "Scrobbles") ? " rating <> 'S' " : null;
+        $query .= (!is_null($constraint) || (($table == "Scrobbles") || 
($table == "Free_Scrobbles"))) ? ' WHERE ' : null;
+        if ($constrained_field) {
+            $query .= (!is_null($constraint)) ? " $constrained_field  = " . 
$mdb2->quote($constraint, 'text') : null;
+        } elseif ($field == "track") {
+            $query .= (!is_null($constraint)) ? ' artist = ' . 
$mdb2->quote($constraint, 'text') : null;
+        } else {
+            $query .= (!is_null($constraint)) ? ' username = ' . 
$mdb2->quote($constraint, 'text') : null;
+        }
+        $query .= (!is_null($constraint) && (($table == "Scrobbles") || 
($table == "Free_Scrobbles"))) ? ' AND ' : null;
+        $query .= (($table == "Scrobbles") || ($table == "Free_Scrobbles")) ? 
" rating <> 'S' " : null;
         $query .= " GROUP BY $field ORDER BY count DESC LIMIT $limit";
         $res = $mdb2->query($query);
-       if (PEAR::isError($res)) {
-               echo("ERROR" . $res->getMessage());
-       }
-
+        if (PEAR::isError($res)) {
+            echo("ERROR - " . $res->getMessage());
+        }
         if (!$res->numRows()) {
-               return false;
+            return false;
         } else {
-                $data = $res->fetchAll(MDB2_FETCHMODE_ASSOC);
-                foreach($data as $count => &$i) {
-                        $i['size'] = $sizes[(int) ($count/(count($data)/7))];
-                }
-
-                foreach($data as &$i){
-                       $i['pageurl'] = Server::getArtistURL($i['artist']);
-                }
-
-                sort($data);
-                return $data;
+            $data = $res->fetchAll(MDB2_FETCHMODE_ASSOC);
+            foreach($data as $count => &$i) {
+                $i['size'] = $sizes[(int) ($count/(count($data)/7))];
+            }
+            foreach($data as &$i){
+                $i['pageurl'] = Server::getArtistURL($i['artist']);
+            }
+            sort($data);
+            return $data;
         }
     }
 }

Modified: branches/stable/nixtape/data/Track.php
===================================================================
--- branches/stable/nixtape/data/Track.php      2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/data/Track.php      2009-05-02 04:00:56 UTC (rev 
1109)
@@ -48,7 +48,7 @@
                global $mdb2;
                $res = $mdb2->query("SELECT name, artist, album, duration, 
streamable, license, downloadurl, streamurl, mbid FROM Track WHERE "
                        . "name = " . $mdb2->quote($name, "text") . " AND "
-                       . "artist = " . $mdb2->quote($artist, "text"));
+                       . "artist = " . $mdb2->quote($artist, "text") . " AND 
album IS NOT NULL");
                if(!$res->numRows()) {
                        $this->name = "No such track: " . $name;
                } else {

Modified: branches/stable/nixtape/data/User.php
===================================================================
--- branches/stable/nixtape/data/User.php       2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/data/User.php       2009-05-02 04:00:56 UTC (rev 
1109)
@@ -33,26 +33,31 @@
 class User {
 
        public $name, $email, $fullname, $bio, $location, $homepage, $error, 
$userlevel;
-       public $id, $acctid, $avatar_uri, $location_uri, $webid_uri;
-       public $password;
+       public $id, $acctid, $avatar_uri, $location_uri, $webid_uri, 
$laconica_profile, $journal_rss;
+       public $password, $has_identica;
 
        /**
         * User constructor
         *
         * @param string $name The name of the user to load
         */
-       function __construct($name) {
+       function __construct($name, $data=null) {
 
                global $base_url;
                $base = preg_replace('#/$#', '', $base_url);
 
-               global $mdb2;
-               $res = $mdb2->query('SELECT * FROM Users WHERE lower(username) 
= ' . $mdb2->quote(strtolower($name), 'text'));
-
-               if($res->numRows()) {
-
-                       $row = $res->fetchRow(MDB2_FETCHMODE_ASSOC);
-
+               if (is_array($data)) {
+                       $row = $data;
+               }
+               else {
+                       global $mdb2;
+                       $res = $mdb2->query('SELECT * FROM Users WHERE 
lower(username) = ' . $mdb2->quote(strtolower($name), 'text'));
+                       if($res->numRows()) {
+                               $row = $res->fetchRow(MDB2_FETCHMODE_ASSOC);
+                       }
+               }
+                       
+               if (is_array($row)) {
                        $this->name         = $row['username'];
                        $this->password     = $row['password'];
                        $this->email        = $row['email'];
@@ -65,27 +70,26 @@
                        $this->id           = $row["webid_uri"];
                        $this->webid_uri    = $row["webid_uri"];
                        $this->avatar_uri   = $row["avatar_uri"];
-                       $this->acctid       = $base.'/user/' . 
urlencode($this->name) . '#acct';
-               }
-               
-               if (! preg_match('/\:/', $this->id))
-                       $this->id = $base.'/user/' . urlencode($this->name) . 
'#me';
+                       $this->laconica_profile = $row["laconica_profile"];
+                       $this->journal_rss  = $row["journal_rss"];
+                       $this->acctid       = $this->getURL() . '#acct';
+                       
+                       $this->has_identica = 
preg_match('#^http://identi\.ca/#i', $this->laconica_profile);
+                       
+                       if (! preg_match('/\:/', $this->id))
+                               $this->id = $this->getURL() . '#me';
+               }               
        }
        
        function save ()
        {
                global $mdb2;
                
+               // It appears we just discard this data, but this is here for a 
reason!
+               // getLocationDetails will fill in latitude,longitude details 
into the Places table in the database
+               // if it's not already there. This is important as the 
location_uri field is a foreign key.
                if (!empty($this->location_uri))
-               {
-                       $res = $mdb2->query('SELECT * FROM Places WHERE 
location_uri = ' . $mdb2->quote($this->location_uri, 'text'));
-                       
-                       if(! $res->numRows())
-                       {
-                               $mdb2->query('INSERT INTO Places VALUES (' . 
$mdb2->quote($this->location_uri, 'text') . ')');
-                       }
-               }
-
+                       $dummy = 
Server::getLocationDetails($this->location_uri);
                
                $q = sprintf("UPDATE Users SET "
                                . "email=%s, "     # Send a confirmation email 
first??
@@ -97,7 +101,10 @@
                                . "userlevel=%d, "
                                . "webid_uri=%s, "
                                . "location_uri=%s, "
-                               . "avatar_uri=%s "
+                               . "avatar_uri=%s, "
+                               . "laconica_profile=%s, "
+                               . "journal_rss=%s, "
+                               . "modified=%d "
                                . "WHERE username=%s"
                                , $mdb2->quote($this->email, 'text')
                                , $mdb2->quote($this->password, 'text')
@@ -109,6 +116,9 @@
                                , $mdb2->quote($this->id, 'text')
                                , (empty($this->location_uri) ? 'NULL' : 
$mdb2->quote($this->location_uri, 'text'))
                                , $mdb2->quote($this->avatar_uri, 'text')
+                               , $mdb2->quote($this->laconica_profile, 'text')
+                               , $mdb2->quote($this->journal_rss, 'text')
+                               , time()
                                , $mdb2->quote($this->name, 'text'));
                                
                $res = $mdb2->query($q);
@@ -147,8 +157,8 @@
                return "http://www.gravatar.com/avatar/"; . md5($this->email) . 
"?s=" . $size . "&d=monsterid";
        }
 
-       function getURL() {
-               return Server::getUserURL($this->name);
+       function getURL($component='profile') {
+               return Server::getUserURL($this->name, $component);
        }
 
        /**
@@ -177,5 +187,60 @@
                return $session_id;
        }
 
+       /**
+        * Log in to the radio server
+        *
+        * @param string $station The station to be played
+        * @return A string containing the session key to be used for streaming
+        */
+       function getRadioSession($station) {
+               global $mdb2;
+               $session_id = md5(mt_rand() . time());
+               $sql = "INSERT INTO Radio_Sessions(username, session, url, 
expires) VALUES ("
+                       . $mdb2->quote($this->name, "text") . ","
+                       . $mdb2->quote($session_id, "text") . ","
+                       . $mdb2->quote($station, "text") . ","
+                       . $mdb2->quote(time() + 86400) . ")";
+               $mdb2->query($sql);
+               return $session_id;
+       }
+
+       /**
+        * get user's top 20 tracks
+        *
+        * @return user's top 20 tracks
+        */
+       function getTopTracks($number=20) {
+               global $mdb2;
+
+               $res = $mdb2->query("SELECT COUNT(track) as c, artist, album, 
track FROM Scrobbles WHERE rating<>'S' AND 
username=".$mdb2->quote($this->name,"text")." GROUP BY artist,album,track ORDER 
BY c DESC LIMIT $number");
+
+               if(PEAR::isError($res)) {
+                   return $res;
+               }
+
+               $maxcount = 0;
+
+               $data = $res->fetchAll(MDB2_FETCHMODE_ASSOC);
+               foreach($data as $i) {
+                   $row = sanitize($i);
+                   $row["artisturl"] = Server::getArtistURL($row["artist"]);
+                   $row["trackurl"] = 
Server::getTrackURL($row["artist"],$row["album"],$row["track"]);
+                   if ((int)$row["c"] > $maxcount) {
+                       $maxcount = (int)$row["c"];
+                   }
+                   $result[] = $row;
+               }
+
+               if ($maxcount > 0) {
+                       foreach($result as &$row) {
+                       $row["width"]=(int)(100 * ($row["c"]/$maxcount));
+                       }
+               }
+
+               return $result;
+       }
+
+
 }
 

Modified: branches/stable/nixtape/database.php
===================================================================
--- branches/stable/nixtape/database.php        2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/database.php        2009-05-02 04:00:56 UTC (rev 
1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by

Copied: branches/stable/nixtape/edit_group.php (from rev 1108, 
branches/stable/nixtape/edit_profile.php)
===================================================================
--- branches/stable/nixtape/edit_group.php                              (rev 0)
+++ branches/stable/nixtape/edit_group.php      2009-05-02 04:00:56 UTC (rev 
1109)
@@ -0,0 +1,149 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once('database.php');
+require_once('templating.php');
+require_once('data/User.php');
+require_once('data/Group.php');
+require_once('data/TagCloud.php');
+
+if($logged_in == false)
+{
+       $smarty->assign('error', 'Error!');
+       $smarty->assign('details', 'Not logged in! You shouldn\'t be here!');
+       $smarty->display('error.tpl');
+       die();
+}
+
+if ($_REQUEST['group']=='new')
+{
+       if ($_REQUEST['new'])
+       {
+               Group::create($_REQUEST['new'], $this_user);
+               header("Location: 
{$base_url}/edit_group.php?group=".$_REQUEST['new']);
+               exit;
+       }
+       else
+       {
+               $smarty->assign('newform', true);
+               $aTagCloud = TagCloud::GenerateTagCloud('Scrobbles', 'artist');
+               if (!PEAR::isError ($aTagCloud))
+               {
+                       $smarty->assign('tagcloud', $aTagCloud);
+               }
+               $smarty->display('edit_group.tpl');
+               exit();
+       }
+}
+
+$group = new Group($_REQUEST['group']);
+
+if ($group->owner->name != $this_user->name)
+{
+       $smarty->assign('error', 'Error!');
+       $smarty->assign('details', 'You don\'t own this group!');
+       $smarty->display('error.tpl');
+       die();
+}
+
+$errors = array();
+
+if ($_POST['submit'])
+{
+       if (!empty($_POST['homepage']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['homepage']) )
+                       $errors[] = "Homepage must be a URI.";
+               if ( preg_match('/\s/', $_POST['homepage']) )
+                       $errors[] = "Homepage must be a URI. Valid URIs cannot 
contain whitespace.";
+       }
+
+       if (!empty($_POST['avatar_uri']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['avatar_uri']) 
)
+                       $errors[] = "Avatar must be a URI.";
+               if ( preg_match('/\s/', $_POST['avatar_uri']) )
+                       $errors[] = "Avatar must be a URI. Valid URIs cannot 
contain whitespace.";
+       }
+
+       if (!isset($errors[0]))
+       {
+               $group->fullname    = $_POST['fullname'];
+               $group->homepage    = $_POST['homepage'];
+               $group->bio         = $_POST['bio'];
+               $group->avatar_uri  = $_POST['avatar_uri'];
+               
+               $group->save();
+
+               header("Location: " . $group->getURL());
+               exit;
+       }
+
+       if (isset($errors[0]))
+       {
+               header("Content-Type: text/plain");
+               print_r($errors);
+               exit;
+       }
+}
+
+if(isset($group->name))
+{
+       # Stuff which cannot be changed.
+       $smarty->assign('group', $group->name);
+
+       if ($_POST['submit'])
+       {
+               $smarty->assign('fullname',     $_POST['fullname']);
+               $smarty->assign('bio',          $_POST['bio']);
+               $smarty->assign('homepage',     $_POST['homepage']);
+               $smarty->assign('avatar_uri',   $_POST['avatar_uri']);
+       }
+       else
+       {
+               $smarty->assign('fullname',     ($group->fullname));
+               $smarty->assign('bio',          ($group->bio));
+               $smarty->assign('homepage',     ($group->homepage));
+               $smarty->assign('avatar_uri',   ($group->avatar_uri));
+       }
+
+       # And display the page.
+       $smarty->assign('errors', $errors);
+       $smarty->assign('newform', false);
+       $aTagCloud = TagCloud::GenerateTagCloud('Scrobbles', 'artist');
+       if (!PEAR::isError ($aTagCloud))
+       {
+               $smarty->assign('tagcloud', $aTagCloud);
+       }
+       $smarty->display('edit_group.tpl');
+}
+
+else
+{
+       $smarty->assign('error', 'Group not found');
+       $smarty->assign('details', 'Shall I call in a missing peoples report? 
This shouldn\'t happen.');
+       $smarty->display('error.tpl');
+}
+

Deleted: branches/stable/nixtape/edit_profile.php
===================================================================
--- branches/stable/nixtape/edit_profile.php    2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/edit_profile.php    2009-05-02 04:00:56 UTC (rev 
1109)
@@ -1,160 +0,0 @@
-<?php
-
-/* Libre.fm -- a free network service for sharing your music listening habits
-
-   Copyright (C) 2009 Libre.fm Project
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Affero General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program 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 Affero General Public License for more details.
-
-   You should have received a copy of the GNU Affero General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-require_once('database.php');
-require_once('templating.php');
-require_once('data/User.php');
-require_once('data/TagCloud.php');
-
-if($logged_in == false)
-{
-       $smarty->assign('error', 'Error!');
-       $smarty->assign('details', 'Not logged in! You shouldn\'t be here!');
-       $smarty->display('error.tpl');
-       die();
-}
-
-# Doesn't seem to work - $user = $_SESSION['user'];
-$user = new User($_SESSION['user']->name);
-
-$errors = array();
-
-if ($_POST['submit'])
-{
-       if (!empty($_POST['id']))
-       {
-               # Need better URI validation, but this will do for now. I think
-               # PEAR has a suitable module to help out here.
-               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['id']) )
-                       $errors[] = "WebID must be a URI.";
-               if ( preg_match('/\s/', $_POST['id']) )
-                       $errors[] = "WebID must be a URI. Valid URIs cannot 
contain whitespace.";
-       }
-
-       if (!empty($_POST['homepage']))
-       {
-               # Need better URI validation, but this will do for now. I think
-               # PEAR has a suitable module to help out here.
-               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['homepage']) )
-                       $errors[] = "Homepage must be a URI.";
-               if ( preg_match('/\s/', $_POST['homepage']) )
-                       $errors[] = "Homepage must be a URI. Valid URIs cannot 
contain whitespace.";
-       }
-
-       if (!empty($_POST['avatar_uri']))
-       {
-               # Need better URI validation, but this will do for now. I think
-               # PEAR has a suitable module to help out here.
-               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['avatar_uri']) 
)
-                       $errors[] = "Avatar must be a URI.";
-               if ( preg_match('/\s/', $_POST['avatar_uri']) )
-                       $errors[] = "Avatar must be a URI. Valid URIs cannot 
contain whitespace.";
-       }
-
-       if (!empty($_POST['password_1']))
-       {
-               if ($_POST['password_1'] != $_POST['password_2'])
-                       $errors[] = "Passwords do not match.";
-       }
-
-       if (!empty($_POST['location_uri']))
-       {
-               # Currently only allow geonames URIs, but there's no reason we 
can't accept
-               # others at some point in the future. (e.g. dbpedia)
-               if ( !preg_match('/^http:\/\/sws.geonames.org\/[0-9]+\/$/', 
$_POST['location_uri']) )
-                       $errors[] = "This should be a geonames.org semantic web 
service URI.";
-       }
-
-       if (!isset($errors[0]))
-       {
-               # Currently we don't allow them to change e-mail as we probably 
should
-               # have some kind of confirmation login to do so.
-               $user->id           = $_POST['id'];
-               $user->fullname     = $_POST['fullname'];
-               $user->homepage     = $_POST['homepage'];
-               $user->bio          = $_POST['bio'];
-               $user->location     = $_POST['location'];
-               $user->location_uri = $_POST['location_uri'];
-               $user->avatar_uri   = $_POST['avatar_uri'];
-               
-               if (!empty( $_POST['password_1'] ))
-                       $user->password = md5($_POST['password_1']);
-               
-               $user->save();
-
-               header("Location: " . $base_url . "/user/" . $user->name);
-               exit;
-       }
-
-       if (isset($errors[0]))
-       {
-               header("Content-Type: text/plain");
-               print_r($errors);
-               exit;
-       }
-}
-
-if(isset($user->name))
-{
-       # Stuff which cannot be changed.
-       $smarty->assign("acctid", $user->acctid);
-       $smarty->assign('avatar', $user->getAvatar());
-       $smarty->assign('user',   $user->name);
-
-       # Stuff which cannot be changed *here*
-       $smarty->assign('userlevel', $user->userlevel);
-       
-       # Stuff which cannot be changed *yet*
-       $smarty->assign('email', $user->email);
-       
-       if ($_POST['submit'])
-       {
-               $smarty->assign("id",           $_POST['id']);
-               $smarty->assign('fullname',     $_POST['fullname']);
-               $smarty->assign('bio',          $_POST['bio']);
-               $smarty->assign('homepage',     $_POST['homepage']);
-               $smarty->assign('location',     $_POST['location']);
-               $smarty->assign('location_uri', $_POST['location_uri']);
-               $smarty->assign('avatar_uri',   $_POST['avatar_uri']);
-       }
-       else
-       {
-               $smarty->assign("id",           ($user->webid_uri));
-               $smarty->assign('fullname',     ($user->fullname));
-               $smarty->assign('bio',          ($user->bio));
-               $smarty->assign('homepage',     ($user->homepage));
-               $smarty->assign('location',     ($user->location));
-               $smarty->assign('location_uri', ($user->location_uri));
-               $smarty->assign('avatar_uri',   ($user->avatar_uri));
-       }
-
-       # And display the page.
-       $smarty->assign('errors', $errors);
-       $smarty->display('edit_profile.tpl');
-}
-
-else
-{
-       $smarty->assign('error', 'User not found');
-       $smarty->assign('details', 'Shall I call in a missing persons report? 
This shouldn\'t happen.');
-       $smarty->display('error.tpl');
-}
-

Copied: branches/stable/nixtape/free.php (from rev 1108, 
branches/stable/nixtape/index.php)
===================================================================
--- branches/stable/nixtape/free.php                            (rev 0)
+++ branches/stable/nixtape/free.php    2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,45 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once('database.php');
+require_once('templating.php');
+require_once('data/sanitize.php');
+require_once('data/Server.php');
+require_once('data/TagCloud.php');
+
+$aTagCloud = TagCloud::GenerateTagCloud('Free_Scrobbles', 'artist');
+if (!PEAR::isError ($aTagCloud)) {
+       $smarty->assign('tagcloud', $aTagCloud);
+}
+
+$aLastScrobbles = Server::getRecentScrobbles(20);
+if (!PEAR::isError ($aLastScrobbles)) {
+       $smarty->assign('recenttracks', $aLastScrobbles);
+}
+
+$aNowPlaying = Server::getNowPlaying(10);
+if (!PEAR::isError ($aNowPlaying)) {
+       $smarty->assign('nowplaying', $aNowPlaying);
+}
+
+$smarty->assign('welcome', true);
+$smarty->display('welcome.tpl');
+?>

Added: branches/stable/nixtape/group.php
===================================================================
--- branches/stable/nixtape/group.php                           (rev 0)
+++ branches/stable/nixtape/group.php   2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,103 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once('database.php');
+require_once('templating.php');
+require_once('data/Group.php');
+require_once('data/TagCloud.php');
+require_once('data/Server.php');
+
+if (! $_GET['group'])
+{
+       $smarty->assign('groups', Group::groupList());
+       $smarty->assign('extra_head_links', array(
+                       array(
+                               'rel' => 'meta',
+                               'type' => 'application/rdf+xml' ,
+                               'title' => 'FOAF',
+                               'href' => 
$base_url.'/rdf.php?fmt=xml&page='.htmlentities($_SERVER['REQUEST_URI'])
+                               )
+               ));
+       $aTagCloud = TagCloud::GenerateTagCloud('Scrobbles', 'artist');
+       if (!PEAR::isError ($aTagCloud))
+       {
+               $smarty->assign('tagcloud', $aTagCloud);
+       }
+       $smarty->display('group-list.tpl');
+       exit;
+}
+
+$group = new Group($_GET['group']);
+
+if ($_GET['action'] && isset($this_user))
+{
+       if ($_GET['action'] == 'join')
+               $group->memberJoin($this_user);
+       elseif ($_GET['action'] == 'leave')
+               $group->memberLeave($this_user);
+               
+       header("Location: " . $group->getURL());
+       exit;
+}
+
+
+if(isset($group->name)) {
+
+       $smarty->assign("id", $group->id);
+       $smarty->assign('group', $group->name);
+       $smarty->assign('fullname', $group->fullname);
+       $smarty->assign('bio', $group->bio);
+       $smarty->assign('homepage', $group->homepage);
+       $smarty->assign('avatar', $group->getAvatar());
+
+       $aUserTagCloud = $group->tagCloudData();
+       if (!PEAR::isError ($aUserTagCloud)) {
+               $smarty->assign('group_tagcloud',$aUserTagCloud);
+       }
+       
+       $smarty->assign('userlist', $group->getUsers());
+
+       $smarty->assign('ismember', $group->memberCheck($this_user));
+       $smarty->assign('isowner', ($group->owner->name==$this_user->name));
+       $smarty->assign('link_join', $group->getURLAction('join'));
+       $smarty->assign('link_leave', $group->getURLAction('leave'));
+       $smarty->assign('link_edit', 
$base_url.'/edit_group.php?group='.$group->name);
+       $smarty->assign('link', $group->getURL());
+
+       $smarty->assign('extra_head_links', array(
+                       array(
+                               'rel' => 'meta',
+                               'type' => 'application/rdf+xml' ,
+                               'title' => 'FOAF',
+                               'href' => 
$base_url.'/rdf.php?fmt=xml&page='.htmlentities($_SERVER['REQUEST_URI'])
+                               )
+               ));
+       
+       $smarty->assign('profile', true);
+       $smarty->display('group.tpl');
+
+} else {
+       $smarty->assign('error', 'Group not found');
+       $smarty->assign('details', 'Shall I call in a missing peoples report?');
+       $smarty->display('error.tpl');
+}
+
+?>

Modified: branches/stable/nixtape/index.php
===================================================================
--- branches/stable/nixtape/index.php   2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/index.php   2009-05-02 04:00:56 UTC (rev 1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -42,4 +42,4 @@
 
 $smarty->assign('welcome', true);
 $smarty->display('welcome.tpl');
-?>
\ No newline at end of file
+?>

Modified: branches/stable/nixtape/install.php
===================================================================
--- branches/stable/nixtape/install.php 2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/install.php 2009-05-02 04:00:56 UTC (rev 1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -19,11 +19,9 @@
 
 */
 
-?>
-
-<?php
 require_once('MDB2.php');
 require_once('version.php');
+require_once('utils/get_absolute_url.php');
 
 if(file_exists("config.php")) {
        die("A configuration file already exists. Please delete 
<i>config.php</i> if you wish to reinstall.");
@@ -51,9 +49,10 @@
 
        $default_theme = $_POST['default_theme'];
        $base_url = $_POST['base_url'];
+       $submissions_server = $_POST['submissions_server'];
 
        //Write out the configuration
-       $config = "<?php \$config_version = " . $version .";\n \$connect_string 
= '" . $connect_string . "';\n \$default_theme = '" . $default_theme . "';\n 
\$base_url = '" . $base_url . "';\n \$install_path = '" . $install_path . "'; 
?>";
+       $config = "<?php\n \$config_version = " . $version .";\n 
\$connect_string = '" . $connect_string . "';\n \$default_theme = '" . 
$default_theme . "';\n \$base_url = '" . $base_url . "';\n \$submissions_server 
= '" . $submissions_server . "';\n \$install_path = '" . $install_path . "'; 
?>";
 
        $conf_file = fopen("config.php", "w");
        $result = fwrite($conf_file, $config);
@@ -116,7 +115,8 @@
                                }
                        ?>
                        </select><br />
-                       Base URL: <input type="text" name="base_url" /><br />
+                       Base URL: <input type="text" name="base_url" 
value="<?php echo getAbsoluteURL(); ?>" /><br />
+                       Submissions Server: <input type="text" 
name="submissions_server" /> (URL to your gnukebox install)<br />
                        <br /><br />
                        <input type="submit" value="Install" name="install" />
                </form>

Modified: branches/stable/nixtape/invite.php
===================================================================
--- branches/stable/nixtape/invite.php  2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/invite.php  2009-05-02 04:00:56 UTC (rev 1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by

Deleted: branches/stable/nixtape/js/edit_profile.js
===================================================================
--- branches/stable/nixtape/js/edit_profile.js  2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/js/edit_profile.js  2009-05-02 04:00:56 UTC (rev 
1109)
@@ -1,170 +0,0 @@
-/* Libre.fm -- a free network service for sharing your music listening habits
-
-   Copyright (C) 2009 Libre.fm Project
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Affero General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program 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 Affero General Public License for more details.
-
-   You should have received a copy of the GNU Affero General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-function unrecognised ( msg )
-{
-       $('#location_uri')[0].value = '';
-       $('#location_uri_label').removeClass('ok');
-       $('#location_uri_label').addClass('no');
-       $('#location_uri_label').text( msg );
-       return 0;
-}
-
-function LocationCheck ()
-{
-       if ( !$('#location').val() )
-       {
-               return unrecognised("You must enter a location.");
-       }
-
-       ajaxLoading(1);
-       
-       var ajaxSuccess = function (data, status)
-               {
-                       ajaxLoading(0);
-
-                       if (! data.geonames[0])
-                       {
-                               return unrecognised("This location was 
unrecognisable.");
-                       }
-
-                       var list;
-
-                       if ($('#chooser_list')[0])
-                       {
-                               $('#chooser_list').empty();
-                               $('#chooser_list').show();
-                               list = $('#chooser_list')[0];
-                       }
-                       else
-                       {
-                               list = document.createElement('UL');
-                               list.id = 'chooser_list';
-                               $('#chooser')[0].appendChild(list);
-                       }
-                       
-                       for (var g in data.geonames)
-                       {
-                               var G = data.geonames[g];
-                               
-                               var fullName = G.name;
-                               if (G.adminName3) fullName += ", " + 
G.adminName3;
-                               if (G.adminName2) fullName += ", " + 
G.adminName2;
-                               if (G.adminName1) fullName += ", " + 
G.adminName1;
-                               if (G.countryName) fullName += ", " + 
G.countryName;
-                               
-                               var coords = G.lat.toFixed(2) + ';' + 
G.lng.toFixed(2);
-                               
-                               var shortName = G.name;
-                               if (G.countryCode == 'US')
-                                       shortName += ", " + G.adminCode1 + ", 
USA";
-                               else
-                                       shortName += ", " + G.countryCode;
-
-                               var item = document.createElement('LI');
-                               var label1 = document.createElement('B');
-                               
label1.appendChild(document.createTextNode(fullName));
-                               item.appendChild(label1);
-                               item.appendChild(document.createTextNode(' '));
-                               var label2 = document.createElement('SMALL');
-                               
label2.appendChild(document.createTextNode('['+coords+']'));
-                               item.appendChild(label2);
-                               
-                               item.setAttribute('data-geoname', 
'http://sws.geonames.org/' + G.geonameId + '/');
-                               item.setAttribute('data-geoname-name', 
shortName);
-                               item.setAttribute('data-geoname-coords', 
coords);
-                               
-                               item.onclick = function (e) {
-                                       if (!e) var e = window.event;
-                                       var tg = (window.event) ? e.srcElement 
: e.target;
-                                       var geoname = 
$(tg).closest('li').attr('data-geoname');
-                                       $('#location_uri')[0].value = geoname;
-                                       $('#chooser_list').empty();
-                                       $('#chooser_list').hide();
-                                       $('#location_uri_label').text( 
-                                               
$(tg).closest('li').attr('data-geoname-name') 
-                                               + ' ['  + 
$(tg).closest('li').attr('data-geoname-coords') + ']'  );
-                                       $('#location_uri_label').addClass('ok');
-                                       
$('#location_uri_label').removeClass('no');
-                               }               
-                               $(item).hover(function ()
-                                       {
-                                               $(this).addClass('hover');
-                                       }, 
-                                       function ()
-                                       {
-                                               $(this).removeClass('hover');
-                                       }
-                                       );
-                               list.appendChild(item);
-                       }
-               };
-               
-       var ajaxError = function (XMLHttpRequest, textStatus, errorThrown)
-               {
-                       ajaxLoading(0);
-                       return unrecognised("Request error: " + textStatus);
-               };
-
-       $.ajax({
-                       'type' : 'GET' ,
-                       'url' : "/utils/location-ws.php" ,
-                       'data' : { 'q' : $('#location').val() },
-                       'dataType' : 'json' ,
-                       'timeout' : 30000 ,
-                       'success' : ajaxSuccess ,
-                       'error' : ajaxError 
-               });
-}
-
-function ajaxLoading (l)
-{
-       if (l==1)
-       {
-               if ($('#loading')[0])
-               {
-                       $('#loading').show();
-               }
-               else
-               {
-                       var loading = document.createElement('IMG');
-                       loading.id = 'loading';
-                       document.body.appendChild(loading);
-                       loading.src = '/i/loading.gif';
-                       loading.style.height = '32px';
-                       loading.style.width = '32px';
-                       loading.style.position = 'absolute';
-                       loading.style.top = '50%';
-                       loading.style.left = '50%';
-                       loading.style.marginTop = '-16px';
-                       loading.style.marginLeft = '-16px';
-               }
-       }
-       else
-       {
-               $('#loading').hide();
-       }
-}
-
-function webidLookup ()
-{
-       window.open("/utils/webid-finder-ws/form.php?javascript=id",
-               "webid-finder",
-               "status=1,resizable=1,scrollbars=1,width=600,height=500");
-}

Modified: branches/stable/nixtape/js/player.js
===================================================================
--- branches/stable/nixtape/js/player.js        2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/js/player.js        2009-05-02 04:00:56 UTC (rev 
1109)
@@ -1,36 +1,86 @@
-var scrobbled;
-var artist, album, track, session_key;
-var playlist, current_song = 0;
+/*
+   Libre.fm -- a free network service for sharing your music listening hab""s
+
+   Copyright (C) 2009 Libre.fm Project
+
+   @licstart  The following is the entire license notice for the 
+   JavaScript code in this page.
+    
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   @licend  The above is the entire license notice
+   for the JavaScript code in this page.
+*/
+
+var scrobbled, now_playing;
+var artist, album, track, session_key, radio_key;
+var playlist = [], current_song = 0;
+var player_ready = false;
 var playable_songs = false;
+var streaming = false;
 
-function playerInit(list, sk) {
-       //Explicitly call stop() here, since not everything seems to support 
'autoplay="false"' yet
+function playerInit(list, sk, rk) {
        var audio = document.getElementById("audio");
+       if (!list) {
+               // We're playing a stream instead of a playlist
+               streaming = true;
+       }
+
+       session_key = sk;
+       radio_key = rk;
+
        if(typeof audio.duration == "undefined") {
                //Browser doesn't support <audio>
+               if(streaming) {
+                       audio.replaceWith("<p>Sorry, you need a browser capable 
of using the HTML 5 &lt;audio&gt; element to enjoy the streaming service via 
the Javascript player.</p>");
+               }
                return;
        }
-       $("#fallbackembed").replaceWith(""); // Get rid of the fallback embed, 
otherwise html5 browsers will play it in addition to the js player
-       playlist = list;
+       $("#fallbackembed").replaceWith(""); // Get rid of the fallback embed, 
otherwise some html5 browsers will play it in addition to the js player
+       if (streaming) {
+               // Get playlist from radio service
+               getRadioPlaylist();
+       } else {
+               // Otherwise we have a static playlist
+               playlist = list;
+               playerReady();
+       }
+}
+
+function playerReady() {
+       var audio = document.getElementById("audio");
+       
        populatePlaylist();
        if(!playable_songs) {
-               alert("No playable songs");
                return;
        }
-       session_key = sk;
        loadSong(0);
        audio.pause();
        audio.addEventListener("ended", songEnded, false);
        updateProgress();
        $("#play").fadeTo("normal", 1);
        $("#progressbar").progressbar({ value: 0 });
-       scrobbled = false;
        $("#player > #interface").show();
+       player_ready = true;
 }
 
 function play() {
        var audio = document.getElementById("audio");
        audio.play();
+       if(!now_playing) {
+               nowPlaying();
+       }
        $("#play").fadeTo("normal", 0.5); 
        $("#pause").fadeTo("normal", 1);
        $("#seekforward").fadeTo("normal", 1);
@@ -82,6 +132,8 @@
 
 function populatePlaylist() {
        var i, url;
+       //Clear the list
+       $("#playlist > #songs").text("");
        for(i = 0; i < playlist.length; i++) {
                url = playlist[i]["url"];
                // Remove non-streamable tracks
@@ -107,8 +159,8 @@
                //Not authenticated
                return;
        }
-       timestamp = Math.round(new Date().getTime() / 1000)
-       $.post("/scrobble-proxy.php", { "a[0]" : artist, "b[0]" : album, "t[0]" 
: track, "i[0]" : timestamp, "s" : session_key },
+       timestamp = Math.round(new Date().getTime() / 1000);
+       $.post("/scrobble-proxy.php?method=scrobble", { "a[0]" : artist, "b[0]" 
: album, "t[0]" : track, "i[0]" : timestamp, "s" : session_key },
                        function(data){
                                if(data.substring(0, 2) == "OK") {
                                        $("#scrobbled").fadeIn(5000, function() 
{ $("#scrobbled").fadeOut(5000) } );
@@ -119,6 +171,18 @@
                        }, "text");
 }
 
+function nowPlaying() {
+       var timestamp;
+       var audio = document.getElementById("audio");
+       now_playing = true;
+       if(!session_key) {
+               //Not authenticated
+               return;
+       }
+       timestamp = Math.round(new Date().getTime() / 1000);
+       $.post("/scrobble-proxy.php?method=nowplaying", { "a" : artist, "b" : 
album, "t" : track, "l" : audio.duration, "s" : session_key}, function(data) 
{}, "text");
+}
+
 function playSong(song) {
        var audio = document.getElementById("audio");
        loadSong(song);
@@ -133,13 +197,43 @@
        track = playlist[song]["track"];
        current_song = song;
        scrobbled = false;
+       now_playing = false;
        audio.src = url;
        audio.load();
 
+       if(streaming && current_song > playlist.length - 3) {
+               //Update the playlist before the user reaches the end
+               getRadioPlaylist();
+       }
+
        $("#trackinfo > #artistname").text(artist);
        $("#trackinfo > #trackname").text(track);
 }
 
+function getRadioPlaylist() {
+       var tracks, artist, album, title, url, i;
+       $.get("/radio/xspf.php", {'sk' : radio_key, 'desktop' : 0}, 
function(data) { 
+                       parser=new DOMParser();
+                       xmlDoc=parser.parseFromString(data,"text/xml");
+                       tracks = xmlDoc.getElementsByTagName("track")
+                       for(i = 0; i < tracks.length; i++) {
+                               try {
+                                       artist = 
tracks[i].getElementsByTagName("creator")[0].childNodes[0].nodeValue;
+                                       title = 
tracks[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
+                                       album = 
tracks[i].getElementsByTagName("album")[0].childNodes[0].nodeValue;
+                                       url = 
tracks[i].getElementsByTagName("location")[0].childNodes[0].nodeValue;
+                                       playlist.push({"artist" : artist, 
"album" : album, "track" : title, "url" : url});
+                               } catch(err) {
+                               }
+                       }
+                       if(!player_ready) {
+                               playerReady();
+                       } else {
+                               populatePlaylist();
+                       }
+               }, "text");
+}
+
 function friendlyTime(timestamp) {
        mins = Math.floor(timestamp / 60);
        sec = String(Math.floor(timestamp % 60));

Copied: branches/stable/nixtape/js/user-edit.js (from rev 1108, 
branches/stable/nixtape/js/edit_profile.js)
===================================================================
--- branches/stable/nixtape/js/user-edit.js                             (rev 0)
+++ branches/stable/nixtape/js/user-edit.js     2009-05-02 04:00:56 UTC (rev 
1109)
@@ -0,0 +1,195 @@
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+function unrecognised ( msg )
+{
+       $('#location_uri')[0].value = '';
+       $('#location_uri_label').removeClass('ok');
+       $('#location_uri_label').addClass('no');
+       $('#location_uri_label').text( msg );
+       return 0;
+}
+
+function UpdateLocationLabel ()
+{
+       if ($('#location_uri')[0].value)
+       {
+               $('#location_uri_label').text($('#location_uri')[0].value);
+       }
+}
+
+function LocationCheck ()
+{
+       if ( !$('#location').val() )
+       {
+               return unrecognised("You must enter a location.");
+       }
+
+       ajaxLoading(1);
+       
+       var ajaxSuccess = function (data, status)
+               {
+                       ajaxLoading(0);
+
+                       if (! data.geonames[0])
+                       {
+                               return unrecognised("This location was 
unrecognisable.");
+                       }
+
+                       var list;
+
+                       if ($('#chooser_list')[0])
+                       {
+                               $('#chooser_list').empty();
+                               $('#chooser_list').show();
+                               list = $('#chooser_list')[0];
+                       }
+                       else
+                       {
+                               list = document.createElement('UL');
+                               list.id = 'chooser_list';
+                               $('#chooser')[0].appendChild(list);
+                       }
+                       
+                       for (var g in data.geonames)
+                       {
+                               var G = data.geonames[g];
+                               
+                               var fullName = G.name;
+                               if (G.adminName3) fullName += ", " + 
G.adminName3;
+                               if (G.adminName2) fullName += ", " + 
G.adminName2;
+                               if (G.adminName1) fullName += ", " + 
G.adminName1;
+                               if (G.countryName) fullName += ", " + 
G.countryName;
+                               
+                               var coords = G.lat.toFixed(2) + ';' + 
G.lng.toFixed(2);
+                               
+                               var shortName = G.name;
+                               if (G.countryCode == 'US')
+                                       shortName += ", " + G.adminCode1 + ", 
USA";
+                               else
+                                       shortName += ", " + G.countryCode;
+
+                               var item = document.createElement('LI');
+                               var label1 = document.createElement('B');
+                               
label1.appendChild(document.createTextNode(fullName));
+                               item.appendChild(label1);
+                               item.appendChild(document.createTextNode(' '));
+                               var label2 = document.createElement('SMALL');
+                               
label2.appendChild(document.createTextNode('['+coords+']'));
+                               item.appendChild(label2);
+                               
+                               item.setAttribute('data-geoname', 
'http://sws.geonames.org/' + G.geonameId + '/');
+                               item.setAttribute('data-geoname-name', 
shortName);
+                               item.setAttribute('data-geoname-coords', 
coords);
+                               
+                               item.onclick = function (e) {
+                                       if (!e) var e = window.event;
+                                       var tg = (window.event) ? e.srcElement 
: e.target;
+                                       var geoname = 
$(tg).closest('li').attr('data-geoname');
+                                       $('#location_uri')[0].value = geoname;
+                                       $('#chooser_list').empty();
+                                       $('#chooser_list').hide();
+                                       UpdateLocationLabel();
+                                       $('#location_uri_label').addClass('ok');
+                                       
$('#location_uri_label').removeClass('no');
+                               }               
+                               $(item).hover(function ()
+                                       {
+                                               $(this).addClass('hover');
+                                       }, 
+                                       function ()
+                                       {
+                                               $(this).removeClass('hover');
+                                       }
+                                       );
+                               list.appendChild(item);
+                       }
+               };
+               
+       var ajaxError = function (XMLHttpRequest, textStatus, errorThrown)
+               {
+                       ajaxLoading(0);
+                       return unrecognised("Request error: " + textStatus);
+               };
+
+       $.ajax({
+                       'type' : 'GET' ,
+                       'url' : "/utils/location-ws.php" ,
+                       'data' : { 'q' : $('#location').val() },
+                       'dataType' : 'json' ,
+                       'timeout' : 30000 ,
+                       'success' : ajaxSuccess ,
+                       'error' : ajaxError 
+               });
+}
+
+function ajaxLoading (l)
+{
+       if (l==1)
+       {
+               if ($('#loading')[0])
+               {
+                       $('#loading').show();
+               }
+               else
+               {
+                       var loading = document.createElement('IMG');
+                       loading.id = 'loading';
+                       document.body.appendChild(loading);
+                       loading.src = '/i/loading.gif';
+                       loading.style.height = '32px';
+                       loading.style.width = '32px';
+                       loading.style.position = 'absolute';
+                       loading.style.top = '50%';
+                       loading.style.left = '50%';
+                       loading.style.marginTop = '-16px';
+                       loading.style.marginLeft = '-16px';
+               }
+       }
+       else
+       {
+               $('#loading').hide();
+       }
+}
+
+function webidLookup ()
+{
+       window.open("/utils/webid-finder-ws/form.php?javascript=id",
+               "webid-finder",
+               "status=1,resizable=1,scrollbars=1,width=600,height=500");
+}
+
+function laconicaClick ()
+{
+       if ($('#laconica_profile')[0].value == 'http://identi.ca/example')
+               $('#laconica_profile')[0].value = '';
+}
+
+function laconicaChange ()
+{
+       if ($('#laconica_profile')[0].value.match(/^http:\/\/.+\/.+/))
+       {
+               $('#journal_rss')[0].value = $('#laconica_profile')[0].value + 
'/rss';
+       }
+}
+
+UpdateLocationLabel();
+
+if ($('#laconica_profile')[0].value == '')
+       $('#laconica_profile')[0].value = 'http://identi.ca/example';

Modified: branches/stable/nixtape/licenses.php
===================================================================
--- branches/stable/nixtape/licenses.php        2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/licenses.php        2009-05-02 04:00:56 UTC (rev 
1109)
@@ -1,17 +1,17 @@
 <?php
-define(BY1,    1);
-define(BY2,    2);
-define(BY21,   3);
-define(BY25,   4);
-define(BY3,    5);
-define(BYSA1,  6);
-define(BYSA2,  7);
-define(BYSA21, 8);
-define(BYSA25, 9);
-define(BYSA3,  10);
-define(LAL,    11);
+define('BY1',  1);
+define('BY2',  2);
+define('BY21', 3);
+define('BY25', 4);
+define('BY3',  5);
+define('BYSA1',        6);
+define('BYSA2',        7);
+define('BYSA21',       8);
+define('BYSA25',       9);
+define('BYSA3',        10);
+define('LAL',  11);
 
-// Arrays containing regular expressions for each license type 
+// Arrays containing regular expressions for each license type
 // (so we can support multiple URL formats in the future if needed)
 $by1 = array("http://creativecommons.org/licenses/by/1.0/?.*";);
 $by2 = array("http://creativecommons.org/licenses/by/2.0/?.*";);

Copied: branches/stable/nixtape/listen.php (from rev 1108, 
branches/stable/nixtape/index.php)
===================================================================
--- branches/stable/nixtape/listen.php                          (rev 0)
+++ branches/stable/nixtape/listen.php  2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,37 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once('database.php');
+require_once('templating.php');
+require_once('data/TagCloud.php');
+
+$aTagCloud = TagCloud::GenerateTagCloud('Scrobbles', 'artist');
+if (!PEAR::isError ($aTagCloud)) {
+        $smarty->assign('tagcloud', $aTagCloud);
+}
+
+if(isset($_GET['tag'])) {
+       $station = "librefm://globaltags/" . $_GET['tag'];
+       $smarty->assign("station", $station);
+}
+
+$smarty->display("listen.tpl");
+?>

Added: branches/stable/nixtape/location.php
===================================================================
--- branches/stable/nixtape/location.php                                (rev 0)
+++ branches/stable/nixtape/location.php        2009-05-02 04:00:56 UTC (rev 
1109)
@@ -0,0 +1,75 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once('database.php');
+require_once('templating.php');
+require_once('data/sanitize.php');
+require_once('data/Server.php');
+require_once('data/User.php');
+
+if ( strtolower(substr($mdb2->phptype, 0, 5)) == 'mysql'  )
+       $random = 'RAND';
+elseif ( strtolower(substr($mdb2->phptype, 0, 5)) == 'mssql'  )
+       $random = 'NEWID';  // I don't think we try to support MSSQL, but 
here's how it's done theoretically anyway
+else
+       $random = 'RANDOM';  // postgresql, sqlite, possibly others
+       
+if ($_REQUEST['country'])
+{
+       $q = sprintf("SELECT u.* FROM Users u INNER JOIN Places p ON 
u.location_uri=p.location_uri AND p.country=%s ORDER BY %s() LIMIT 100",
+               $mdb2->quote(strtoupper($_REQUEST['country']), 'text'),
+               $random);
+       
+       $res = $mdb2->query($q);
+       
+       while ( $row = $res->fetchRow(MDB2_FETCHMODE_ASSOC) )
+       {
+               $userlist[] = new User($row['username'], $row);         
+       }
+       
+       $smarty->assign('country', strtoupper($_REQUEST['country']));
+       $res = $mdb2->query(sprintf("SELECT * FROM Countries WHERE country=%s 
LIMIT 1",
+               $mdb2->quote(strtoupper($_REQUEST['country']), 'text')));
+       if ( $row = $res->fetchRow(MDB2_FETCHMODE_ASSOC) )
+       {
+               $smarty->assign('country_info', $row);
+       }
+       
+       $smarty->assign('userlist', $userlist);
+       
+       $smarty->assign('extra_head_links', array(
+                       array(
+                               'rel' => 'meta',
+                               'type' => 'application/rdf+xml' ,
+                               'title' => 'FOAF',
+                               'href' => 
$base_url.'/rdf.php?fmt=xml&page='.htmlentities($_SERVER['REQUEST_URI'])
+                               )
+               ));
+               
+       $smarty->display('location-country.tpl');
+}
+
+else
+{
+       $smarty->assign('error', 'Location not found');
+       $smarty->assign('details', 'Shall I call in a missing locations 
report?');
+       $smarty->display('error.tpl');
+}

Modified: branches/stable/nixtape/login.php
===================================================================
--- branches/stable/nixtape/login.php   2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/login.php   2009-05-02 04:00:56 UTC (rev 1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -24,10 +24,9 @@
 require_once('templating.php');
 require_once($install_path . '/data/User.php');
 
-if(isset($_SESSION['session_id']) && $_GET['action'] == 'logout') {
-    session_unset();
-    session_destroy();
-    header('Location: index.php');
+if(isset($_COOKIE['session_id']) && $_GET['action'] == 'logout') {
+       setcookie('session_id', '', time() - 3600);
+       header('Location: index.php');
 }
 
 if(isset($_POST['login'])) {
@@ -35,6 +34,7 @@
        $errors = '';
        $username = $_POST['username'];
        $password = $_POST['password'];
+       $remember = $_POST['remember'];
 
        if(empty($username)) {
                $errors .= 'You must enter a username.<br />';
@@ -52,25 +52,23 @@
                } else {
                        // Give the user a session id, like any other client
                        $session_id = md5(md5($password) . time());
+                       if(isset($remember)){
+                               $session_time = time() + 31536000; // 1 year
+                       } else {
+                               $session_time = time() + 86400; // 1 day
+                       }
                        $mdb2->query('INSERT INTO Scrobble_Sessions (username, 
sessionid, expires) VALUES ('
                                . $mdb2->quote($username, 'text') . ', '
                                . $mdb2->quote($session_id, 'text') . ', '
-                               . $mdb2->quote( time() + 604800, 'integer') . 
')');
+                               . $mdb2->quote($session_time, 'integer') . ')');
 
+                       setcookie('session_id', $session_id, $session_time);
                        $logged_in = true;
-                       $smarty->assign('logged_in', true);
-
-            $_SESSION['user'] = new User($username);
-            $_SESSION['session_id'] = $session_id;
-            $smarty->assign('user', $_SESSION['user']);
                }
        }
 }
 
 if(isset($logged_in) && $logged_in) {
-       // Send the user to the welcome page when they've logged in
-       //$smarty->display('welcome.tpl');
-
        // Check that return URI is on this server. Prevents possible phishing 
uses.
        if ( substr($_POST['return'], 0, 1) == '/' )
                { header(sprintf('Location: http://%s%s', 
$_SERVER['SERVER_NAME'], $_POST['return'])); }

Deleted: branches/stable/nixtape/profile.php
===================================================================
--- branches/stable/nixtape/profile.php 2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/profile.php 2009-05-02 04:00:56 UTC (rev 1109)
@@ -1,85 +0,0 @@
-<?php
-
-/* Libre.fm -- a free network service for sharing your music listening habits
-
-   Copyright (C) 2009 Libre.fm Project
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Affero General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program 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 Affero General Public License for more details.
-
-   You should have received a copy of the GNU Affero General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-require_once('database.php');
-require_once('templating.php');
-require_once('data/User.php');
-require_once('data/TagCloud.php');
-
-if(!isset($_GET['user']) && $logged_in == false) {
-       $smarty->assign('error', 'Error!');
-       $smarty->assign('details', 'User not set! You shouldn\'t be here!');
-       $smarty->display('error.tpl');
-       die();
-}
-
-$user = new User($_GET['user']);
-
-if(isset($user->name)) {
-       $smarty->assign("id", $user->id);
-       $smarty->assign("acctid", $user->acctid);
-       $smarty->assign('user', $user->name);
-       $smarty->assign('email', $user->email);
-       $smarty->assign('fullname', $user->fullname);
-       $smarty->assign('bio', $user->bio);
-       $smarty->assign('homepage', $user->homepage);
-       $smarty->assign('location', $user->location);
-       $smarty->assign('location_uri', $user->location_uri);
-       $aUserScrobbles = $user->getScrobbles(20);
-       if (!PEAR::isError ($aUserScrobbles)) {
-               $smarty->assign('scrobbles', $aUserScrobbles);
-       }
-       $smarty->assign('userlevel', $user->userlevel);
-       $smarty->assign('avatar', $user->getAvatar());
-       $aUserNowPlaying = $user->getNowPlaying(10);
-       if (!PEAR::isError ($aUserNowPlaying)) {
-               $smarty->assign('nowplaying', $aUserNowPlaying);
-       }
-       $aUserTagCloud =  TagCloud::GenerateTagCloud('Scrobbles', 'artist', 40, 
$user->name);
-       if (!PEAR::isError ($aUserTagCloud)) {
-               $smarty->assign('user_tagcloud',$aUserTagCloud);
-       }
-       $smarty->assign('isme', ($_SESSION['user']->name == $user->name));
-       $smarty->assign('profile', true);
-       
-       $smarty->assign('extra_head_links', array(
-                       array(
-                               'rel'=>'alternate',
-                               'type' => 'application/rss+xml' ,
-                               'title' => 'RSS 1.0 Feed (Recent plays)',
-                               'href' => 
$base_url.'/rdf.php?fmt=rss&page='.htmlentities($_SERVER['REQUEST_URI'])
-                               ),
-                       array(
-                               'rel' => 'meta',
-                               'type' => 'application/rdf+xml' ,
-                               'title' => 'FOAF',
-                               'href' => 
$base_url.'/rdf.php?fmt=xml&page='.htmlentities($_SERVER['REQUEST_URI'])
-                               )
-               ));
-       
-       $smarty->display('profile.tpl');
-} else {
-       $smarty->assign('error', 'User not found');
-       $smarty->assign('details', 'Shall I call in a missing persons report?');
-       $smarty->display('error.tpl');
-}
-
-?>

Modified: branches/stable/nixtape/register.php
===================================================================
--- branches/stable/nixtape/register.php        2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/register.php        2009-05-02 04:00:56 UTC (rev 
1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -24,7 +24,7 @@
 require_once("utils/EmailAddressValidator.php");
 
 if($logged_in == true){
-        header("Location: index.php");
+       header("Location: index.php");
 } else {
 
 // Moving to open alpha

Modified: branches/stable/nixtape/resolve-external.php
===================================================================
--- branches/stable/nixtape/resolve-external.php        2009-05-02 04:00:44 UTC 
(rev 1108)
+++ branches/stable/nixtape/resolve-external.php        2009-05-02 04:00:56 UTC 
(rev 1109)
@@ -20,7 +20,7 @@
 
        if (substr($url, 10, 10) == "album/art/") {
                $id = substr($url, 20);
-               return "http://api.jamendo.com/get2/image/album/redirect/?id="; 
. $id . "&imagesize=400";
+               return "http://api.jamendo.com/get2/image/album/redirect/?id="; 
. $id . "&imagesize=200";
        }
 
        // We don't know what this is

Modified: branches/stable/nixtape/scrobble-proxy.php
===================================================================
--- branches/stable/nixtape/scrobble-proxy.php  2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/scrobble-proxy.php  2009-05-02 04:00:56 UTC (rev 
1109)
@@ -21,8 +21,16 @@
 
 require_once('config.php');
 
-$session = curl_init($submissions_url);
+if ($_GET['method'] == "scrobble") {
+       $url = $submissions_server . "/submissions/1.2/";
+} elseif ($_GET['method'] == "nowplaying") {
+       $url = $submissions_server . "/nowplaying/1.2/";
+} else {
+       die("Invalid proxy method\n");
+}
 
+$session = curl_init($url);
+
 $post_vars = '';
 foreach($_POST as $key => $element) {
        if (is_array($element)) {

Deleted: branches/stable/nixtape/stats.php
===================================================================
--- branches/stable/nixtape/stats.php   2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/stats.php   2009-05-02 04:00:56 UTC (rev 1109)
@@ -1,80 +0,0 @@
-<?php
-
-/* Libre.fm -- a free network service for sharing your music listening habits
-
-   Copyright (C) 2009 Libre.fm Project
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Affero General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program 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 Affero General Public License for more details.
-
-   You should have received a copy of the GNU Affero General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-require_once('database.php');
-require_once('templating.php');
-require_once('data/User.php');
-require_once('data/TagCloud.php');
-require_once('data/Statistic.php');
-
-if(!isset($_GET['user']) && $logged_in == false) {
-       $smarty->assign('error', 'Error!');
-       $smarty->assign('details', 'User not set! You shouldn\'t be here!');
-       $smarty->display('error.tpl');
-       die();
-}
-
-$user = new User($_GET['user']);
-
-if(isset($user->name)) {
-       $smarty->assign("id", $user->id);
-       $smarty->assign("acctid", $user->acctid);
-       $smarty->assign('user', $user->name);
-       $smarty->assign('homepage', $user->homepage);
-       $smarty->assign('location', $user->location);
-       $smarty->assign('location_uri', $user->location_uri);
-       $aUserScrobbles = $user->getScrobbles(20);
-       if (!PEAR::isError ($aUserScrobbles)) {
-               $smarty->assign('scrobbles', $aUserScrobbles);
-       }
-       $smarty->assign('userlevel', $user->userlevel);
-       $smarty->assign('avatar', $user->getAvatar());
-       $aUserNowPlaying = $user->getNowPlaying(10);
-       if (!PEAR::isError ($aUserNowPlaying)) {
-               $smarty->assign('nowplaying', $aUserNowPlaying);
-       }
-       $aUserTagCloud =  TagCloud::GenerateTagCloud('Scrobbles', 'artist', 40, 
$user->name);
-       if (!PEAR::isError ($aUserTagCloud)) {
-               $smarty->assign('user_tagcloud',$aUserTagCloud);
-       }
-       
-       $smarty->assign('stat_barwidth', 320);
-       $aUserPlayStat =  Statistic::GeneratePlayStats('Scrobbles', 'artist', 
40, $user->name, 300);
-       if (!PEAR::isError ($aUserPlayStat)) {
-               $smarty->assign('user_playstats',$aUserPlayStat);
-       }
-       
-       $aUserDayStat =  Statistic::generatePlayByDays('Scrobbles', 40, 
$user->name, 300);
-       if (!PEAR::isError ($aUserDayStat)) {
-               $smarty->assign('user_daystats',$aUserDayStat);
-       }
-       
-       $smarty->assign('isme', ($_SESSION['user']->name == $user->name));
-       
-       $smarty->assign('stats', true);
-       $smarty->display('stats.tpl');
-} else {
-       $smarty->assign('error', 'User not found');
-       $smarty->assign('details', 'Shall I call in a missing persons report?');
-       $smarty->display('error.tpl');
-}
-
-?>

Modified: branches/stable/nixtape/templating.php
===================================================================
--- branches/stable/nixtape/templating.php      2009-05-02 04:00:44 UTC (rev 
1108)
+++ branches/stable/nixtape/templating.php      2009-05-02 04:00:56 UTC (rev 
1109)
@@ -2,7 +2,7 @@
 
 /* Libre.fm -- a free network service for sharing your music listening habits
 
-   Copyright (C) 2009 Libre.fm Project
+   Copyright (C) 2009 Free Software Foundation, Inc
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
@@ -30,11 +30,16 @@
 
 $smarty->assign('base_url', $base_url);
 $smarty->assign('this_page', $_SERVER['REQUEST_URI']);
+$smarty->assign('this_page_absolute',
+        (empty($_SERVER['HTTPS']) ? 'http://' : 'http://') 
+       .(empty($_SERVER['HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HOST'])
+       .(($_SERVER['SERVER_PORT']==80) ? '' : (':'.$_SERVER['SERVER_PORT']))
+       . $_SERVER['REQUEST_URI']);
 
 if(isset($logged_in)) {
        $smarty->assign('logged_in', true);
-       // Pre-fix this user's details with u to avoid confusion with other 
users
-       $smarty->assign('u_user', $u_user);
+       // Pre-fix this user's details with 'this_' to avoid confusion with 
other users
+       $smarty->assign('this_user', $this_user);
 }
 
 header("Content-Type: text/html; charset=utf-8");

Modified: branches/stable/nixtape/themes/librefm/alpha.css
===================================================================
--- branches/stable/nixtape/themes/librefm/alpha.css    2009-05-02 04:00:44 UTC 
(rev 1108)
+++ branches/stable/nixtape/themes/librefm/alpha.css    2009-05-02 04:00:56 UTC 
(rev 1109)
@@ -1,8 +1,18 @@
-/*
- * Alpha specific CSS
- *
- */
-a {
+/* 
+
+   Libre.fm -- a free network service for sharing your music listening
+   habits
+
+   Copyright (C) 2009 Free Software Foundation, Inc
+
+   Copying and distribution of this file, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.  This file is offered as-is,
+   without warranty of any kind.
+
+*/
+
+a:link, a:visited {
     text-decoration: none;
     outline: none;
     color: #3465a4;
@@ -29,9 +39,6 @@
  * We should use a class down here ¬¬ (fauno)
  */
 
-form input {font-size: 138.5%;}
-form.notcrazy input { font-size: 99%; }
-
 div#invite,
 div#register,
 div#login {
@@ -96,7 +103,8 @@
 ul.listcloud li dt { margin: 0; padding: 0; }
 ul.listcloud li dd { margin: 0; padding: 0; }
 
-ul.listcloud li dt a { color: #630000; text-decoration: none; }
+ul.listcloud li dt a:link,
+ul.listcloud li dt a:visited { color: #630000; text-decoration: none; }
 ul.listcloud li dt a:hover { text-decoration: underline; }
 
 ul#topartists.listcloud dd, ul#albums.listcloud dd { font-size: 77%; 
line-height: 1.2em; }
@@ -105,8 +113,9 @@
 
 ul#recenttracks.listcloud li { height: 3.4em; }
 /* Users */
-.user .fn {
+.user .fn , .group .fn {
     margin-bottom: .3em;
+    font-size: 93%;
 }
 .avatar {
     max-height: 96px;
@@ -117,14 +126,14 @@
     margin: .3em;
 }
 
-.user .avatar img.photo{ max-width:96px; }
+.user .avatar img.photo, 
+.group .avatar img.photo{ max-width:96px; }
 
-.user .bio {
+.user .bio,
+.group .bio {
 }
-.user .fn {
-    font-size: 93%;
-}
-.user .nickname {
+.user .nickname ,
+.group .nickname {
     color: #666666
 }
   dl.now-playing dt, dl.recent-tracks dt {
@@ -166,7 +175,7 @@
 ul.gobbles * {
     list-style: none;
 }
-    ul.gobbles .contributor a {
+    ul.gobbles .contributor a:link, ul.gobbles .contributor a:visited {
         text-decoration: none;
         color: #2e3436;
         font-weight: bold;
@@ -198,7 +207,7 @@
     clear: both;
 }
 
-.user {
+.user, .group {
     -moz-border-radius-bottomleft:8px;
     -moz-border-radius-bottomright:8px;
     -moz-border-radius-topleft:8px;
@@ -207,6 +216,10 @@
     padding: .4em .4em 0 .1em;
 }
 
+.group {
+       background-color: #DDF;
+}
+
 .vcard .edit { float:right; }
 
 #chooser { position: relative; }
@@ -218,6 +231,18 @@
 #location_uri_label.ok { color: green; }
 #location_uri_label.no { color: red; }
 
+.userlist {
+       padding: 0;
+       margin: 0;
+    list-style-type: none;
+}
+.userlist li
+{
+       padding: 0;
+       margin: 0 0 1em;        
+    list-style-type: none;
+}
+
 ul#albums * {
     padding: 0;
     margin: 0;
@@ -253,6 +278,7 @@
 .stats_artists .bar div{ background: #970102; height: 1em; }
 .stats_artists .counts{ text-align: right; }
 
-dd.libre{background-image: url(/themes/librefm/images/square.png); 
background-repeat: no-repeat; padding-left: 22px; background-color: #eee;}
+dt.libre{background-image: url(/themes/librefm/images/square.png); 
background-repeat: no-repeat; padding-left: 22px; background-color: #eee;}
+li.libre{background-image: url(/themes/librefm/images/square.png); 
background-repeat: no-repeat; padding-left: 22px; background-color: #eee;}
 
-#adbard{width: 150px; margin: 10px auto 5px auto;}
\ No newline at end of file
+#adbard{width: 150px; margin: 10px auto 5px auto;}

Modified: branches/stable/nixtape/themes/librefm/librefm.css
===================================================================
--- branches/stable/nixtape/themes/librefm/librefm.css  2009-05-02 04:00:44 UTC 
(rev 1108)
+++ branches/stable/nixtape/themes/librefm/librefm.css  2009-05-02 04:00:56 UTC 
(rev 1109)
@@ -10,9 +10,9 @@
 
 #hd ul{ margin: 0; padding: 0; line-height: 70px; position: absolute; top: 0; 
right: 20px;}
 
-#hd li a{ color: white; text-decoration: none; }
+#hd li a:link, #hd li a:visited { color: white; text-decoration: none; }
 
-#login a{ color: yellow !important; }
+#login a:link, #login a:visited { color: yellow !important; }
 
 #hd li{ display: inline; font-size: 21px; text-transform: lowercase; 
font-weight: bold; margin-right: 20px;}
 
@@ -41,7 +41,7 @@
      padding: 0;
      }
 
-#hd h1 a{ 
+#hd h1 a { 
        display: block;
        text-decoration: none;
        overflow: hidden;
@@ -77,4 +77,4 @@
 th{background-color: black; color: white;}
 tr.odd{background-color: #edf3fe;}
 
-form {font-size: 140%;}
\ No newline at end of file
+form {font-size: 140%;}

Modified: branches/stable/nixtape/themes/librefm/player.css
===================================================================
--- branches/stable/nixtape/themes/librefm/player.css   2009-05-02 04:00:44 UTC 
(rev 1108)
+++ branches/stable/nixtape/themes/librefm/player.css   2009-05-02 04:00:56 UTC 
(rev 1109)
@@ -1,3 +1,17 @@
+/* 
+
+   Libre.fm -- a free network service for sharing your music listening
+   habits
+
+   Copyright (C) 2009 Free Software Foundation, Inc
+
+   Copying and distribution of this file, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.  This file is offered as-is,
+   without warranty of any kind.
+
+*/
+
 #player > #interface {
        background: #980101 url("images/player/background.jpg") repeat-x;
        width: 300px;

Modified: branches/stable/nixtape/themes/librefm/templates/album.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/album.tpl  2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/album.tpl  2009-05-02 
04:00:56 UTC (rev 1109)
@@ -11,10 +11,10 @@
        {/section}
        ];
 
-       {if isset($u_user)}
-       playerInit(playlist, "{$u_user->getScrobbleSession()}");
+       {if isset($this_user)}
+       playerInit(playlist, "{$this_user->getScrobbleSession()}", false);
        {else}
-       playerInit(playlist, false);
+       playerInit(playlist, false, false);
        {/if}
 </script>
 

Added: branches/stable/nixtape/themes/librefm/templates/edit_group.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/edit_group.tpl             
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/edit_group.tpl     
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,68 @@
+{include file='header.tpl'}
+
+{if $newform}
+
+<h2 property="dc:title">Create a group</h2>
+
+<form action="{$base_url}/edit_group.php" method="post">
+
+<p style="display:center">
+<label for="new">Address for the group:</label><br />
+<b>{$base_url}/group/</b><input id="new" name="new" size="12" /></p>
+
+<p>
+<input name="group" value="new" type="hidden" />
+<input type="submit" value=" Create " />
+</p>
+
+</form>
+
+{else}
+
+<h2 property="dc:title">Edit your group</h2>
+
+<p><strong>The form below is still <em>very</em> experimental. Using this may 
wreck your account!</strong></p>
+
+<form action="{$base_url}/edit_group.php" method="post" class="notcrazy">
+       <table>
+               <tr>
+                       <th align="right" valign="top"><label 
for="fullname">Full name:</label></th>
+                       <td><input name="fullname" id="fullname" 
value="{$fullname|escape:'html':'UTF-8'}" /></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="homepage">Homepage URL:</label></th>
+                       <td><input name="homepage" id="homepage" 
value="{$homepage|escape:'html':'UTF-8'}" /></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="avatar_uri">Logo URL:</label></th>
+                       <td><input name="avatar_uri" id="avatar_uri" 
value="{$avatar_uri|escape:'html':'UTF-8'}" /></td>
+                       <td><a href="#dfn_avatar_uri" rel="glossary">What's 
this?</a></td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="bio">Description:</label></th>
+                       <td><textarea name="bio" id="bio" rows="6" cols="30" 
style="width:100%;min-width:20em">{$bio|escape:'html':'UTF-8'}</textarea></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <td colspan="3" align="center">
+                               <input type="submit" value="Change" />
+                               <input name="submit" value="1" type="hidden" />
+                               <input name="group" 
value="{$group|escape:'html':'UTF-8'}" type="hidden" />
+                       </td>
+               </tr>
+       </table>
+</form>
+
+<h3>Help</h3>
+<dl>
+       <dt id="dfn_avatar_uri">Logo URL</dt>
+       <dd>The web address for a picture to represent your group on libre.fm. 
It should
+       not be more than 80x80 pixels. (64x64 is best.)</dd>
+</dl>
+
+{/if}
+
+
+{include file='footer.tpl'}

Deleted: branches/stable/nixtape/themes/librefm/templates/edit_profile.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/edit_profile.tpl   
2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/edit_profile.tpl   
2009-05-02 04:00:56 UTC (rev 1109)
@@ -1,89 +0,0 @@
-{include file='header.tpl'}
-
-<h2 property="dc:title">Edit your profile</h2>
-
-<p><strong>The form below is still <em>very</em> experimental. Using this may 
wreck your account!</strong></p>
-
-<script type="text/javascript" 
src="{$base_url}/js/jquery-1.3.2.min.js"></script>
-<script type="text/javascript" src="{$base_url}/js/edit_profile.js"></script>
-<form action="{$base_url}/edit_profile.php" method="post" class="notcrazy">
-       <table>
-               <tr>
-                       <th align="right" valign="top"><label 
for="fullname">Full name:</label></th>
-                       <td><input name="fullname" id="fullname" 
value="{$fullname|escape:'html':'UTF-8'}" /></td>
-                       <td>&nbsp;</td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top" rowspan="2"><label 
for="location">Location:</label></th>
-                       <td><input name="location" id="location" 
value="{$location|escape:'html':'UTF-8'}" /></td>
-                       <td>&nbsp;</td>
-               </tr>
-               <tr>
-                       <td id="chooser">
-                               <input type="hidden" name="location_uri" 
id="location_uri" value="{$location_uri|escape:'html':'UTF-8'}" />
-                               <input type="button" value="Check ..." 
onclick="LocationCheck();" />
-                               <span id="location_uri_label"></span>
-                       </td>
-                       <td><a href="#dfn_location_uri" rel="glossary">What's 
this?</a></td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top"><label 
for="homepage">Homepage URL:</label></th>
-                       <td><input name="homepage" id="homepage" 
value="{$homepage|escape:'html':'UTF-8'}" /></td>
-                       <td>&nbsp;</td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top"><label 
for="avatar_uri">Avatar URL:</label></th>
-                       <td><input name="avatar_uri" id="avatar_uri" 
value="{$avatar_uri|escape:'html':'UTF-8'}" /></td>
-                       <td><a href="#dfn_avatar_uri" rel="glossary">What's 
this?</a></td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top"><label for="bio">Mini 
Biography:</label></th>
-                       <td><textarea name="bio" id="bio" rows="6" cols="30" 
style="width:100%;min-width:20em">{$bio|escape:'html':'UTF-8'}</textarea></td>
-                       <td>&nbsp;</td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top"><label for="id">WebID 
(FOAF):</label></th>
-                       <td>
-                               <input name="id" id="id" 
value="{$id|escape:'html':'UTF-8'}" />
-                               <input type="button" onclick="webidLookup();" 
value="find!" />
-                       </td>
-                       <td><a href="#dfn_id" rel="glossary">What's 
this?</a></td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top"><label 
for="password_1">Password:</label></th>
-                       <td><input name="password_1" id="password_1" 
type="password" value="" /></td>
-                       <td rowspan="2">Leave this blank if you don't want to 
change your password.</td>
-               </tr>
-               <tr>
-                       <th align="right" valign="top"><label 
for="password_2">Confirm Password:</label></th>
-                       <td><input name="password_2" id="password_2" 
type="password" value="" /></td>
-               </tr>
-               <tr>
-                       <td colspan="3" align="center">
-                               <input type="submit" value="Change" />
-                               <input name="submit" value="1" type="hidden" />
-                       </td>
-               </tr>
-       </table>
-</form>
-
-<h3>Help</h3>
-<dl>
-       <dt id="dfn_location_uri">Location check</dt>
-       <dd>This feature looks up your location on <a 
href="http://www.geonames.org";
-       >geonames</a>. You don't need to do it, but it will help us find your
-       latitude and longitude, which will help us add some great location-based
-       features in the future.</dd>
-
-       <dt id="dfn_avatar_uri">Avatar URL</dt>
-       <dd>The web address for a picture to represent you on libre.fm. It 
should
-       not be more than 80x80 pixels. If you leave this empty, libre.fm will
-       use <a href="http://gravatar.com";>Gravatar</a> to find an image for 
you.</dd>
-
-       <dt id="dfn_id">WebID (FOAF)</dt>
-       <dd>A URI that represents you in RDF. See <a 
href="http://esw.w3.org/topic/WebID";
-       >WebID</a> for details. If you don't know what this is, it's best to 
leave it
-       blank.</dd>
-</dl>
-
-{include file='footer.tpl'}

Added: branches/stable/nixtape/themes/librefm/templates/group-list.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/group-list.tpl             
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/group-list.tpl     
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,33 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">All Groups</h2>
+
+<div about="#groups" typeof="foaf:Group" property="foaf:name" content="All 
Groups">
+
+<ul rel="foaf:member" class="userlist">
+{foreach from=$groups item=g}
+
+       <li about="{$g->id}" typeof="foaf:Group">
+               <div class="group vcard">
+                       <div class="avatar" rel="foaf:depiction">
+                               <img 
src="{$g->getAvatar()|escape:'html':'UTF-8'}" alt="avatar" class="photo" 
width="64" height="64" />
+                       </div>
+                       <dl>
+                               <dt>
+                                       <span class="fn org" 
property="foaf:name">{$g->fullname|escape:'html':'UTF-8'}</span>
+                                       (<span class="nickname" 
property="foaf:nick">{$g->name|escape:'html':'UTF-8'}</span>)
+                               </dt>
+                               <dd>{if $g->homepage}<a class="url" 
rel="foaf:page" 
href="{$g->homepage|escape:'html':'UTF-8'}">{$g->homepage|escape:'html':'UTF-8'}</a>{/if}</dd>
+                               <dd class="note" 
property="dc:abstract">{$g->bio|escape:'html':'UTF-8'}</dd>
+                               <dd><a rel="foaf:homepage" 
rev="foaf:primaryTopic" property="dc:description" 
href="{$g->getURL()|escape:'html':'UTF-8'}">{$g->count} members</a></dd>
+                       </dl>
+                       <hr style="border: 1px solid transparent; clear: both;" 
/>
+               </div>
+       </li>
+       
+{/foreach}
+</ul>
+
+</div>
+
+{include file='footer.tpl'}

Added: branches/stable/nixtape/themes/librefm/templates/group.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/group.tpl                  
        (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/group.tpl  2009-05-02 
04:00:56 UTC (rev 1109)
@@ -0,0 +1,72 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">Group: {$fullname|escape:'html':'UTF-8'}</h2>
+
+<div about="{$id}" typeof="foaf:Group">
+
+<div class="group vcard">
+       <div class="avatar" rel="foaf:depiction">
+               <img src="{$avatar|escape:'html':'UTF-8'}" alt="avatar" 
class="photo" width="64" height="64" />
+       </div>
+
+       {if $logged_in}
+               {if $ismember}
+                       {if $isowner}
+                       <a class="edit" href="{$link_edit}">[edit]</a>
+                       {else}
+                       <form class="edit" action="{$link}" 
method="get"><div><input type="hidden" name="action" value="leave" /><input 
type="submit" value=" leave " /></div></form>
+                       {/if}
+               {else}
+                       <form class="edit" action="{$link}" 
method="get"><div><input type="hidden" name="action" value="join" /><input 
type="submit" value=" join " /></div></form>
+               {/if}
+       {/if}
+
+       <dl>
+               <dt>
+                       <span class="fn org" 
property="foaf:name">{$fullname|escape:'html':'UTF-8'}</span>
+                       (<span class="nickname" 
property="foaf:nick">{$group|escape:'html':'UTF-8'}</span>)
+               </dt>
+               <dd>{if $homepage}<a class="url" rel="foaf:page" 
href="{$homepage|escape:'html':'UTF-8'}">{$homepage|escape:'html':'UTF-8'}</a>{/if}</dd>
+               <dd class="note" 
property="dc:abstract">{$bio|escape:'html':'UTF-8'}</dd>
+       </dl>
+
+       <hr style="border: 1px solid transparent; clear: both;" 
rel="foaf:homepage" rev="foaf:primaryTopic" resource="" />
+</div>
+
+<ul rel="foaf:member" class="userlist">
+{foreach from=$userlist item=me}
+
+       <li>{include file='miniprofile.tpl'}</li>
+       
+{/foreach}
+</ul>
+
+</div>
+
+
+<!-- Column break -->
+</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
+
+<h3>Top artists</h3>
+<ul class="tagcloud" about="{$id}">
+       {section name=i loop=$group_tagcloud}
+       <li style="font-size:{$group_tagcloud[i].size}"><a
+       href="{$group_tagcloud[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$group_tagcloud[i].size|substr:-5 ==
+       'large'}foaf:interest 
{/if}tag">{$group_tagcloud[i].artist|escape:"html":"UTF-8"}</a></li>
+       {/section}
+</ul>
+
+           <!--Ad Bard advertisement snippet, begin -->
+
+           <script type='text/javascript'>
+            var ab_h = '4bcaab930d3bdfded68fd7be730d7db4';
+            var ab_s = '0';
+           </script>
+           
+            <script type='text/javascript' 
src='http://cdn1.adbard.net/js/ab1.js'></script>
+
+           <!--Ad Bard, end -->
+
+
+
+{include file='footer.tpl'}

Modified: branches/stable/nixtape/themes/librefm/templates/header.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/header.tpl 2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/header.tpl 2009-05-02 
04:00:56 UTC (rev 1109)
@@ -14,6 +14,7 @@
        xmlns:xsd="http://www.w3.org/2001/XMLSchema#";
        xmlns:rss="http://purl.org/rss/1.0/";
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+       xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#";
        xml:lang="en">
        
 <head profile="http://www.w3.org/1999/xhtml/vocab http://purl.org/uF/2008/03/ 
http://purl.org/uF/hAudio/0.9/";>
@@ -27,7 +28,7 @@
        <link rel="license" 
href="http://creativecommons.org/licenses/by-sa/3.0/us/"; />
        <script type="text/javascript" src="{$base_url}/js/player.js"></script>
        <script type="text/javascript" 
src="{$base_url}/js/jquery-1.3.2.min.js"></script>
-       <script tpye="text/javascript" 
src="{$base_url}/js/jquery-ui-1.7.1.custom.min.js"></script>
+       <script type="text/javascript" 
src="{$base_url}/js/jquery-ui-1.7.1.custom.min.js"></script>
 {section name=i loop=$extra_head_links}
        <link rel="{$extra_head_links[i].rel|escape:'html':'UTF-8'}" 
href="{$extra_head_links[i].href|escape:'html':'UTF-8'}" 
type="{$extra_head_links[i].type|escape:'html':'UTF-8'}" 
title="{$extra_head_links[i].title|escape:'html':'UTF-8'}"  />
 {/section}

Added: branches/stable/nixtape/themes/librefm/templates/listen.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/listen.tpl                 
        (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/listen.tpl 2009-05-02 
04:00:56 UTC (rev 1109)
@@ -0,0 +1,25 @@
+{include file='header.tpl'}
+
+<h2>Listen</h2><br />
+
+{if isset($station)}
+       {if isset($this_user)}
+               {include file='player.tpl'}
+<div id='error'></div>
+<script type="text/javascript">
+       {if isset($this_user)}
+       playerInit(false, "{$this_user->getScrobbleSession()}", 
"{$this_user->getRadioSession($station)}");
+       {/if}
+</script>
+       {else}
+<p>Sorry, you need to <a href='{$base_url}/login.php'>login</a> to be able to 
listen to radio streams.</p>
+       {/if}
+{else}
+<p>To listen to 100% free (libre) music simply enter the type of music you'd 
like to hear or select one of the common tags below:</p>
+<p><a href="?tag=folk">Folk</a> <a href="?tag=rock">Rock</a> <a 
href="?tag=metal">Metal</a> <a href="?tag=classical">Classical</a> <a 
href="?tag=pop">Pop</a> <a href="?tag=blues">Blues</a> <a 
href="?tag=jazz">Jazz</a> <a href="?tag=punk">Punk</a> <a 
href="?tag=ambient">Ambient</a></p>
+<p><form method='get' action=''><label for="tag">Custom tag:</label> <input 
type="text" id="tag" name="tag" /> <input type="submit" value="Listen" 
/></form></p>
+{/if}
+<br />
+
+<div class="cleaner">&nbsp;</div>
+{include file='footer.tpl'}

Added: branches/stable/nixtape/themes/librefm/templates/location-country.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/location-country.tpl       
                        (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/location-country.tpl       
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,29 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">Country: 
{$country_info.country_name|escape:'html':'UTF-8'}</h2>
+
+<div about="#usergroup" typeof="foaf:Group">
+
+<div class="group vcard">
+       <dl>
+               <dt>
+                       <span property="foaf:name">Users in 
{$country_info.country_name|escape:'html':'UTF-8'}</span>
+                       (<span class="nickname" 
property="foaf:nick">{$country_info.country|escape:'html':'UTF-8'}</span>)
+               </dt>
+               <dd>{if $country_info.wikipedia_en}<a class="url" 
rel="foaf:page" 
href="{$country_info.wikipedia_en|escape:'html':'UTF-8'}">{$country_info.wikipedia_en|escape:'html':'UTF-8'}</a>{/if}</dd>
+       </dl>
+       <hr style="border: 1px solid transparent; clear: both;" 
rel="foaf:homepage" rev="foaf:primaryTopic" resource="" />
+</div>
+
+<ul rel="foaf:member" class="userlist">
+{foreach from=$userlist item=me}
+
+       <li>{include file='miniprofile.tpl'}</li>
+       
+{/foreach}
+</ul>
+
+</div>
+
+<div class='cleaner'>&nbsp;</div>
+{include file='footer.tpl'}

Modified: branches/stable/nixtape/themes/librefm/templates/login.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/login.tpl  2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/login.tpl  2009-05-02 
04:00:56 UTC (rev 1109)
@@ -14,9 +14,13 @@
 
                        <label 
for='password'>Password<span>&nbsp;</span></label>
                        <input id='password' name='password' type='password' 
value=''/>
-
+                       
+                       <label for='remember'>Remember 
me<span>&nbsp;</span></label>
+                       <input id='remember' name='remember' type='checkbox' 
value='1'/>
+                       
                        <input type='submit' name='login' value='Let me in!' />
                        <input name="return" type="hidden" 
value="{$return|htmlentities}" />
+                       
                </fieldset>
 
        </form>

Added: branches/stable/nixtape/themes/librefm/templates/maxiprofile.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/maxiprofile.tpl            
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/maxiprofile.tpl    
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,64 @@
+<div about="{$me->id|escape:'html':'UTF-8'}" typeof="foaf:Agent" class="user 
vcard">
+
+       <div class="avatar" rel="foaf:depiction">
+               <img src="{$me->getAvatar()|escape:'html':'UTF-8'}" 
alt="avatar" class="photo" width="64" height="64" />
+       </div>
+
+       {if $isme}
+       <a class="edit" 
href="{$me->getURL('edit')|escape:'html':'UTF-8'}">[edit]</a>
+       {/if}
+
+       <dl>
+               <dt>
+                       <span class="fn" 
property="foaf:name">{$me->fullname|escape:'html':'UTF-8'}</span>
+                       <span property="foaf:nick" 
content="{$me->name|escape:'html':'UTF-8'}" rel="foaf:holdsAccount" 
rev="sioc:account_of">
+                               <span 
about="{$me->acctid|escape:'html':'UTF-8'}" typeof="sioc:User">
+                                       (<span class="nickname" 
property="foaf:accountName">{$me->name|escape:'html':'UTF-8'}</span>)
+                                       <span rel="foaf:accountServiceHomepage" 
resource="{$base_url}"></span>
+                                       <span rel="foaf:accountProfilePage" 
rev="foaf:topic" resource="{$me->getURL()|escape:'html':'UTF-8'}"></span>
+                               </span>
+                       </span>
+               </dt>
+               {if $me->homepage}
+               <dd>
+                       <a href="{$me->homepage|escape:'html':'UTF-8'}" rel="me 
foaf:homepage" class="url">{$me->homepage|escape:'html':'UTF-8'}</a>
+               </dd>
+               {/if}
+               {if $me->laconica_profile}
+               <dd>
+                       <a href="{$me->laconica_profile|escape:'html':'UTF-8'}" 
rel="foaf:homepage" class="url">{$me->laconica_profile|escape:'html':'UTF-8'} 
(microblog)</a>
+               </dd>
+               {/if}
+               {if $me->location}
+               <dd rel="foaf:based_near">
+                       <span {if $me->location_uri} 
about="{$me->location_uri|escape:'html':'UTF-8'}"{/if}>
+                               <span class="label" 
property="rdfs:comment">{$me->location|escape:'html':'UTF-8'}</span>
+                               {if $geo.latitude}
+                               <small class="geo">
+                                       [<span class="latitude" 
property="geo:lat">{$geo.latitude|string_format:"%0.3f"}</span>;
+                                       <span class="longitude" 
property="geo:long">{$geo.longitude|string_format:"%0.3f"}</span>]
+                               </small>
+                               {/if}
+                               {if $geo.country}
+                               <small xmlns:gn="http://www.geonames.org/"; 
rel="gn:ontology#inCountry" resource="[gn:countries/#{$geo.country}]">
+                                       (<a rel="foaf:page" 
href="{$base_url}/country/{$geo.country}">Find other people in 
{$geo.country_name|escape:'html':'UTF-8'}</a>)
+                               </small>
+                               {/if}
+                       </span>
+               </dd>
+               {/if}
+               {if $me->bio}
+               <dd class="note" 
property="bio:olb">{$me->bio|escape:'html':'UTF-8'}</dd>
+               {/if}
+       </dl>
+
+       <div style="text-align:right;clear:right;font-size:80%">
+               <a{if $this_page_absolute != $me->getURL()} rel="rdfs:seeAlso" 
href="{$me->getURL()|escape:'html':'UTF-8'}"{/if}>profile</a>
+               &middot; <a{if $this_page_absolute != $me->getURL('stats')} 
rel="rdfs:seeAlso" 
href="{$me->getURL('stats')|escape:'html':'UTF-8'}"{/if}>stats</a>
+               &middot; <a{if $this_page_absolute != 
$me->getURL('recent-tracks')} rel="rdfs:seeAlso" 
href="{$me->getURL('recent-tracks')|escape:'html':'UTF-8'}"{/if}>recent 
tracks</a>
+               {if $me->journal_rss} &middot; <a{if $this_page_absolute != 
$me->getURL('journal')} rel="rdfs:seeAlso" 
href="{$me->getURL('journal')|escape:'html':'UTF-8'}"{/if}>journal</a>{/if}
+               &middot; <a{if $this_page_absolute != $me->getURL('groups')} 
rel="rdfs:seeAlso" 
href="{$me->getURL('groups')|escape:'html':'UTF-8'}"{/if}>groups</a>
+       </div>
+       <hr style="border: 1px solid transparent; clear: both;" rel="foaf:page" 
rev="foaf:primaryTopic" resource="" />
+
+</div>

Modified: branches/stable/nixtape/themes/librefm/templates/menu.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/menu.tpl   2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/menu.tpl   2009-05-02 
04:00:56 UTC (rev 1109)
@@ -1,15 +1,16 @@
     <ul>
 {if ($logged_in)}
-        <li><a href="{$u_user->getURL()}">{$u_user->name}</a></li>
+        <li><a href="{$this_user->getURL()}">{$this_user->name}</a></li>
 {else}
        <li><a href="{$base_url}/register.php">Register</a></li>
 {/if}
 
 {if ($logged_in)}
-    {if $u_user->userlevel > 0}
+    {if $this_user->userlevel > 0}
         <li><a href="/admin.php">admin</a></li>
     {/if}
        <li><a href="{$base_url}/login.php?action=logout">Logout</a></li>
+       <li><a href="{$base_url}/listen.php">Listen</a></li>
 {else}
         <li><a 
href="{$base_url}/login.php?return={$this_page|urlencode|htmlentities}">Login</a></li>
 {/if}

Added: branches/stable/nixtape/themes/librefm/templates/miniprofile.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/miniprofile.tpl            
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/miniprofile.tpl    
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,33 @@
+<div about="{$me->id|escape:'html':'UTF-8'}" typeof="foaf:Agent" class="user 
vcard">
+
+       <div class="avatar" rel="foaf:depiction">
+               <img src="{$me->getAvatar()|escape:'html':'UTF-8'}" 
alt="avatar" class="photo" width="64" height="64" />
+       </div>
+       
+       <dl>
+               <dt>
+                       <span class="fn" 
property="foaf:name">{$me->fullname|escape:'html':'UTF-8'}</span>
+                       <span rel="foaf:holdsAccount" rev="sioc:account_of">
+                               <span 
about="{$me->acctid|escape:'html':'UTF-8'}" typeof="sioc:User">
+                                       (<a class="nickname" 
property="foaf:accountName" href="{$me->getURL()}" 
rel="foaf:accountProfilePage" 
rev="foaf:topic">{$me->name|escape:'html':'UTF-8'}</a>)
+                                       <span rel="foaf:accountServiceHomepage" 
resource="{$base_url}"></span>
+                               </span>
+                       </span>
+               </dt>
+               {if $me->homepage || $me->laconica_profile}
+               <dd>
+                       {if $me->homepage}<a 
href="{$me->homepage|escape:'html':'UTF-8'}" rel="foaf:homepage" 
class="url">{$me->homepage|escape:'html':'UTF-8'}</a>{/if}
+                       {if $me->laconica_profile}{if $me->homepage} // {/if}<a 
href="{$me->laconica_profile|escape:'html':'UTF-8'}" rel="foaf:homepage" 
class="url">{$me->laconica_profile|escape:'html':'UTF-8'}</a>{/if}
+               </dd>
+               {/if}
+               <dd rel="foaf:based_near">
+                       <span {if $me->location_uri} 
about="{$me->location_uri|escape:'html':'UTF-8'}"{/if}>
+                               <span class="label" 
property="rdfs:comment">{$me->location|escape:'html':'UTF-8'}</span>
+                       </span>
+               </dd>
+               <dd class="note" 
property="bio:olb">{$me->bio|escape:'html':'UTF-8'}</dd>
+       </dl>
+
+       <hr style="border: 1px solid transparent; clear: both;" rel="foaf:page" 
rev="foaf:primaryTopic" resource="{$me->getURL()}" />
+
+</div>

Modified: branches/stable/nixtape/themes/librefm/templates/player.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/player.tpl 2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/player.tpl 2009-05-02 
04:00:56 UTC (rev 1109)
@@ -2,6 +2,8 @@
        <audio id="audio">
                {if $track->streamurl}
                        <object id="fallbackembed" 
style="width:200px;height:50px;" type="application/ogg" 
data="{$track->streamurl}"><a type="application/ogg" rel="enclosure" 
href="{$track->streamurl}">Listen to this track</a></object>
+               {elseif isset($station)}
+                       <p>Sorry, you need a browser capable of making use of 
the HTML 5 &lt;audio&gt; tag to enjoy the streaming service via the JavaScript 
player.</p>
                {/if}
        </audio>
        <div id="interface">

Deleted: branches/stable/nixtape/themes/librefm/templates/profile.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/profile.tpl        
2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/profile.tpl        
2009-05-02 04:00:56 UTC (rev 1109)
@@ -1,118 +0,0 @@
-{include file='header.tpl'}
-
-<h2 property="dc:title">{$user|escape:'html':'UTF-8'}'{if $user|substr:-1 != 
's'}s{/if} profile</h2>
-<div about="{$id|escape:'html':'UTF-8'}" typeof="foaf:Agent" class="user 
vcard">
-
-       <div class="avatar" rel="foaf:depiction">
-               <!-- Avatar placeholder  -->
-               <img src="{$avatar|escape:'html':'UTF-8'}" alt="avatar" 
class="photo" />
-       </div>
-
-       {if $isme}
-       <a class="edit" href="{$base_url}/edit_profile.php">[edit]</a>
-       {/if}
-       
-       <dl>
-               <dt>
-                       <span class="fn" 
property="foaf:name">{$fullname|escape:'html':'UTF-8'}</span>
-                       <span rel="foaf:holdsAccount" rev="sioc:account_of">
-                               <span about="{$acctid|escape:'html':'UTF-8'}" 
typeof="sioc:User">
-                                       (<span class="nickname" 
property="foaf:accountName">{$user|escape:'html':'UTF-8'}</span>)
-                                       <span rel="foaf:accountServiceHomepage" 
resource="{$base_url}"></span>
-                                       <span rel="foaf:accountProfilePage" 
rev="foaf:topic" resource=""></span>
-                               </span>
-                       </span>
-               </dt>
-               {if $homepage}
-               <dd>
-                       <a href="{$homepage|escape:'html':'UTF-8'}" rel="me 
foaf:homepage" class="url">{$homepage|escape:'html':'UTF-8'}</a>
-               </dd>
-               {/if}
-               <dd rel="foaf:based_near">
-                       <span{if $location_uri} 
about="{$location_uri|escape:'html':'UTF-8'}"{/if} class="label" 
property="rdfs:comment">{$location|escape:'html':'UTF-8'}</span>
-               </dd>
-               <dd class="note" 
property="bio:olb">{$bio|escape:'html':'UTF-8'}</dd>
-       </dl>
-
-       <hr style="border: 1px solid transparent; clear: both;" rel="foaf:page" 
rev="foaf:primaryTopic" resource="" />
-
-</div>
-
-{if $nowplaying|@count > 0}
-<h3>Now Playing:</h3>
-<!-- We should try to make this list work like the gobbles list. -->
-<dl class='now-playing'>
-    {section name=i loop=$nowplaying}
-    <dt class='track-name'>{$nowplaying[i].track|escape:'html':'UTF-8'}</dt>
-    <dd>by <span class='artist-name'><a 
href='{$nowplaying[i].artisturl|escape:'html':'UTF-8'}'>{$nowplaying[i].artist|escape:'html':'UTF-8'}</a></span></dd>
-    <dd>with <span class='gobbler'>{$nowplaying[i].clientstr}</span></dd>
-    {/section}
-</dl>
-{/if}
-
-<div about="[_:seq1]" typeof="rdf:Seq" rev="rss:items">
-       <h3 typeof="rss:channel" property="rss:title" rel="rss:link" 
resource="#latest_plays" id="latest_plays" 
content="{$user|escape:'html':'UTF-8'}'{if $user|substr:-1 != 's'}s{/if} Latest 
Plays">Latest {$scrobbles|@count} Plays:</h3>
-</div>
-
-<ul class="gobbles" about="{$id|escape:'html':'UTF-8'}" rev="gob:user">
-{section name=i loop=$scrobbles}
-
-       <li about="{$scrobbles[i].id|escape:'html':'UTF-8'}" typeof="rss:item 
gob:ScrobbleEvent" rel="gob:track_played">
-               <div about="{$scrobbles[i].id_track|escape:'html':'UTF-8'}" 
typeof="mo:Track" class="haudio">
-                       <div rev="mo:track">
-                               <div 
about="{$scrobbles[i].id_album|escape:'html':'UTF-8'}" typeof="mo:Record"{if 
$scrobbles[i].album} property="dc:title" 
content="{$scrobbles[i].album|escape:'html':'UTF-8'}"{/if}>
-                                       {if $scrobbles[i].albumurl}<a 
rel="foaf:page" href="{$scrobbles[i].albumurl|escape:'html':'UTF-8'}">{/if}
-                                               <span{if 
$scrobbles[i].album_image} rel="foaf:depiction"{/if}{if $scrobbles[i].albumurl} 
about="{$scrobbles[i].id_album|escape:'html':'UTF-8'}"{/if}>
-                                                       <img height="50" 
width="50" 
-                                                               src="{if 
!$scrobbles[i].album_image}/i/qm50.png{else}{$scrobbles[i].album_image|escape:'html':'UTF-8'}{/if}"
 
-                                                               
class="albumart{if !$scrobbles[i].album_image} photo{/if}" 
-                                                               {if 
$scrobbles[i].album}title="{$scrobbles[i].album|escape:'html':'UTF-8'}" 
alt="Album: {$scrobbles[i].album|escape:'html':'UTF-8'}"{else}alt="Unknown 
album"{/if}  />
-                                               </span>
-                                       {if $scrobbles[i].albumurl}</a>{/if}
-                               </div>
-                       </div>
-                       <div rel="foaf:maker" class="contributor vcard">
-                               <a 
about="{$scrobbles[i].id_artist|escape:'html':'UTF-8'}" typeof="mo:MusicArtist" 
property="foaf:name" rel="foaf:page"
-                                       class="fn url" 
href="{$scrobbles[i].artisturl|escape:'html':'UTF-8'}"
-                                       
>{$scrobbles[i].artist|escape:'html':'UTF-8'}</a>
-                       </div>
-                       <div><a class="fn" property="dc:title" rel="foaf:page" 
href="{$scrobbles[i].trackurl|escape:'html':'UTF-8'}">{$scrobbles[i].track|escape:'html':'UTF-8'}</a></div>
-                       <small about="{$scrobbles[i].id|escape:'html':'UTF-8'}" 
property="dc:date" content="{$scrobbles[i].timeiso}" 
datatype="xsd:dateTime">{$scrobbles[i].timehuman}</small>
-                       <span about="{$scrobbles[i].id|escape:'html':'UTF-8'}" 
property="rss:link" content="{$scrobbles[i].trackurl|escape:'html':'UTF-8'}">
-                               <span property="rss:description" content="{if 
$scrobbles[i].album}{$scrobbles[i].album}{else}Unknown album{/if}">
-                                       <span property="rss:title" 
content="{$scrobbles[i].artist|escape:'html':'UTF-8'}: 
{$scrobbles[i].track|escape:'html':'UTF-8'}" 
rev="rdf:_{$smarty.section.i.index_next}" resource="[_:seq1]"></span>
-                               </span>
-                       </span>
-               </div>
-       </li>
-{/section}
-</ul>
-
-<!-- Column break -->
-</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
-
-<h3>{$user}'{if $user|substr:-1 != 's'}s{/if} top artists</h3>
-<ul class="tagcloud" about="{$id}">
-       {section name=i loop=$user_tagcloud}
-       <li style="font-size:{$user_tagcloud[i].size}"><a
-       href="{$user_tagcloud[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_tagcloud[i].size|substr:-5 ==
-       'large'}foaf:interest 
{/if}tag">{$user_tagcloud[i].artist|escape:"html":"UTF-8"}</a></li>
-       {/section}
-</ul>
-
-       <div id="adbard">
-
-           <!--Ad Bard advertisement snippet, begin -->
-
-           <script type='text/javascript'>
-            var ab_h = '4bcaab930d3bdfded68fd7be730d7db4';
-            var ab_s = '55fd9cde6d855a75f9ca43d854272f6b';
-           </script>
-           
-            <script type='text/javascript' 
src='http://cdn1.adbard.net/js/ab1.js'></script>
-
-           <!--Ad Bard, end -->
-
-       </div>
-
-{include file='footer.tpl'}

Modified: branches/stable/nixtape/themes/librefm/templates/register.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/register.tpl       
2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/register.tpl       
2009-05-02 04:00:56 UTC (rev 1109)
@@ -29,15 +29,15 @@
                <fieldset>
                        <label for='fullname'>You:<span>(that's your real 
name.)</span></label>
                        <input id='fullname' name='fullname' type='text' 
value='{$fullname}' maxlength='255'/>
-       
-                       <label for='username'>Your nickname:<span>(no more than 
16 chars.)</span></label>
-                       <input id='username' name='username' type='text' 
value='{$username}' maxlength='16' />
 
                        <label for='email'>Your e-mail:<span>(must be 
valid!)</span></label>
                        <input id='email' name='email' type='text' 
value='{$email}' maxlength='64' />
        
                        <label for='location'>Location:<span>(like 'CABA, 
Buenos Aires, Argentina')</span></label>
                        <input id='location' name='location' type='text' 
value='{$location}' maxlength='255' />
+                       
+                       <label for='username'>Your nickname:<span>(no more than 
16 chars.)</span></label>
+                       <input id='username' name='username' type='text' 
value='{$username}' maxlength='16' />
 
                        <label for='password'>Your password:<span>(make it hard 
to guess)</span></label>
                        <input id='password' name='password' type='password' 
value=''/>

Deleted: branches/stable/nixtape/themes/librefm/templates/stats.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/stats.tpl  2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/stats.tpl  2009-05-02 
04:00:56 UTC (rev 1109)
@@ -1,62 +0,0 @@
-{include file='header.tpl'}
-
-<h2 property="dc:title">{$user|escape:'html':'UTF-8'}'{if $user|substr:-1 != 
's'}s{/if} statistics</h2>
-<div about="{$id|escape:'html':'UTF-8'}" typeof="foaf:Agent" class="user 
vcard">
-
-       <div class="avatar" rel="foaf:depiction">
-               <!-- Avatar placeholder  -->
-               <img src="{$avatar|escape:'html':'UTF-8'}" alt="avatar" 
class="photo" />
-       </div>
-
-       {if $isme}
-       <a class="edit" href="{$base_url}/edit_profile.php">[edit]</a>
-       {/if}
-       
-       <dl>
-               <dt>
-                       <span class="fn" 
property="foaf:name">{$fullname|escape:'html':'UTF-8'}</span>
-                       <span rel="foaf:holdsAccount" rev="sioc:account_of">
-                               <span about="{$acctid|escape:'html':'UTF-8'}" 
typeof="sioc:User">
-                                       (<span class="nickname" 
property="foaf:accountName">{$user|escape:'html':'UTF-8'}</span>)
-                                       <span rel="foaf:accountServiceHomepage" 
resource="{$base_url}"></span>
-                                       <span rel="foaf:accountProfilePage" 
rev="foaf:topic" resource=""></span>
-                               </span>
-                       </span>
-               </dt>
-               {if $homepage}
-               <dd>
-                       <a href="{$homepage|escape:'html':'UTF-8'}" rel="me 
foaf:homepage" class="url">{$homepage|escape:'html':'UTF-8'}</a>
-               </dd>
-               {/if}
-       </dl>
-
-       <hr style="border: 1px solid transparent; clear: both;" rel="foaf:page" 
rev="foaf:primaryTopic" resource="" />
-</div>
-
-<h3 id="stats_by_artist">{$user}'{if $user|substr:-1 != 's'}s{/if} most played 
artists</h3>
-<table class="stats_artists" about="{$id}">
-       {section name=i loop=$user_playstats}
-       <tr><td class="counts">{$user_playstats[i].count}</td><td class="bar" 
style="width: {$stat_barwidth}px"><div 
style="width:{$user_playstats[i].size}px" class="artist"></div></td><td><a
-       href="{$user_playstats[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_playstats[i].size|substr:-5 ==
-       'large'}foaf:interest 
{/if}tag">{$user_playstats[i].artist|escape:"html":"UTF-8"}</a></td></tr>
-       {/section}
-</table>
-
-<h3 id="stats_by_day">{$user}'{if $user|substr:-1 != 's'}s{/if} scrobbles by 
day</h3>
-<table class="stats_artists" about="{$id}">
-       {section name=i loop=$user_daystats}
-       <tr><td class="counts">{$user_daystats[i].count}</td><td class="bar" 
style="width: {$stat_barwidth}px"><div style="width:{$user_daystats[i].size}px" 
class="artist"></div></td><td class="date">{$user_daystats[i].date}</td></tr>
-       {/section}
-</table>
-
-<!-- Column break -->
-</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
-
-<h3>{$user}'{if $user|substr:-1 != 's'}s{/if} statistics</h3>
-<ul>
-       <li><a href="#stats_by_artist">Most played artists</a></li>
-       <li><a href="#stats_by_day">Scrobbles by day</a></li>
-</ul>
-<p><strong>More coming soon</strong></p>
-
-{include file='footer.tpl'}

Modified: branches/stable/nixtape/themes/librefm/templates/track.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/track.tpl  2009-05-02 
04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/track.tpl  2009-05-02 
04:00:56 UTC (rev 1109)
@@ -5,10 +5,10 @@
 {include file='player.tpl'}
 <script type="text/javascript">
        var playlist = [{ldelim}"artist" : "{$track->artist_name}", "album" : 
"{$track->album_name}", "track" : "{$track->name}", "url" : 
"{$track->streamurl}"{rdelim}];
-       {if isset($u_user)}
-       playerInit(playlist, "{$u_user->getScrobbleSession()}");
+       {if isset($this_user)}
+       playerInit(playlist, "{$this_user->getScrobbleSession()}", false);
        {else}
-       playerInit(playlist, false);
+       playerInit(playlist, false, false);
        {/if}
 </script>
 <br />

Copied: branches/stable/nixtape/themes/librefm/templates/user-edit.tpl (from 
rev 1108, branches/stable/nixtape/themes/librefm/templates/edit_profile.tpl)
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/user-edit.tpl              
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/user-edit.tpl      
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,100 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">Edit your profile</h2>
+
+<p><strong>The form below is still <em>very</em> experimental. Using this may 
wreck your account!</strong></p>
+
+<form action="{$base_url}/user-edit.php" method="post" class="notcrazy">
+       <table>
+               <tr>
+                       <th align="right" valign="top"><label 
for="fullname">Full name:</label></th>
+                       <td><input name="fullname" id="fullname" 
value="{$fullname|escape:'html':'UTF-8'}" /></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="location">Location:</label></th>
+                       <td><input name="location" id="location" 
value="{$location|escape:'html':'UTF-8'}" /></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="location_uri">Geoname:</label></th>
+                       <td id="chooser">
+                               <input type="hidden" name="location_uri" 
id="location_uri" value="{$location_uri|escape:'html':'UTF-8'}" />
+                               <input type="button" value="Find ..." 
onclick="LocationCheck();" />
+                               <span id="location_uri_label"></span>
+                       </td>
+                       <td><a href="#dfn_location_uri" rel="glossary">What's 
this?</a></td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="homepage">Homepage URL:</label></th>
+                       <td><input name="homepage" id="homepage" 
value="{$homepage|escape:'html':'UTF-8'}" /></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="avatar_uri">Avatar URL:</label></th>
+                       <td><input name="avatar_uri" id="avatar_uri" 
value="{$avatar_uri|escape:'html':'UTF-8'}" /></td>
+                       <td><a href="#dfn_avatar_uri" rel="glossary">What's 
this?</a></td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label for="bio">Mini 
Biography:</label></th>
+                       <td><textarea name="bio" id="bio" rows="6" cols="30" 
style="width:100%;min-width:20em">{$bio|escape:'html':'UTF-8'}</textarea></td>
+                       <td>&nbsp;</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label for="id">WebID 
(FOAF):</label></th>
+                       <td>
+                               <input name="id" id="id" 
value="{$id|escape:'html':'UTF-8'}" />
+                               <input type="button" onclick="webidLookup();" 
value="find!" />
+                       </td>
+                       <td><a href="#dfn_id" rel="glossary">What's 
this?</a></td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="laconica_profile">Laconica/identi.ca Profile:</label></th>
+                       <td><input onchange="laconicaChange();" 
onclick="laconicaClick();" name="laconica_profile" id="laconica_profile" 
value="{$laconica_profile|escape:'html':'UTF-8'}" /></td>
+                       <td><a href="#dfn_laconica_profile" 
rel="glossary">What's this?</a></td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="journal_rss">RSS Feed:</label></th>
+                       <td><input name="journal_rss" id="journal_rss" 
value="{$journal_rss|escape:'html':'UTF-8'}" /></td>
+                       <td><a href="#dfn_journal_rss" rel="glossary">What's 
this?</a></td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="password_1">Password:</label></th>
+                       <td><input name="password_1" id="password_1" 
type="password" value="" /></td>
+                       <td rowspan="2">Leave this blank if you don't want to 
change your password.</td>
+               </tr>
+               <tr>
+                       <th align="right" valign="top"><label 
for="password_2">Confirm Password:</label></th>
+                       <td><input name="password_2" id="password_2" 
type="password" value="" /></td>
+               </tr>
+               <tr>
+                       <td colspan="3" align="center">
+                               <input type="submit" value="Change" />
+                               <input name="submit" value="1" type="hidden" />
+                       </td>
+               </tr>
+       </table>
+</form>
+
+<script type="text/javascript" src="{$base_url}/js/user-edit.js"></script>
+
+<h3>Help</h3>
+<dl>
+       <dt id="dfn_location_uri">Location check</dt>
+       <dd>This feature looks up your location on <a 
href="http://www.geonames.org";
+       >geonames</a>. You don't need to do it, but it will help us find your
+       latitude and longitude, which will help us add some great location-based
+       features in the future.</dd>
+
+       <dt id="dfn_avatar_uri">Avatar URL</dt>
+       <dd>The web address for a picture to represent you on libre.fm. It 
should
+       not be more than 80x80 pixels. (64x64 is best.) If you leave this 
empty, libre.fm will
+       use <a href="http://gravatar.com";>Gravatar</a> to find an image for 
you.</dd>
+
+       <dt id="dfn_id">WebID (FOAF)</dt>
+       <dd>A URI that represents you in RDF. See <a 
href="http://esw.w3.org/topic/WebID";
+       >WebID</a> for details. If you don't know what this is, it's best to 
leave it
+       blank.</dd>
+</dl>
+
+{include file='footer.tpl'}

Added: branches/stable/nixtape/themes/librefm/templates/user-groups.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/user-groups.tpl            
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/user-groups.tpl    
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,59 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">{$me->name|escape:'html':'UTF-8'}'s groups</h2>
+
+{include file='maxiprofile.tpl'}
+
+<ul about="{$me->id}" rev="foaf:member" class="userlist">
+{foreach from=$groups item=g}
+
+       <li about="{$g->id}" typeof="foaf:Group">
+               <div class="group vcard">
+                       <div class="avatar" rel="foaf:depiction">
+                               <img 
src="{$g->getAvatar()|escape:'html':'UTF-8'}" alt="avatar" class="photo" 
width="64" height="64" />
+                       </div>
+                       <dl>
+                               <dt>
+                                       <span class="fn org" 
property="foaf:name">{$g->fullname|escape:'html':'UTF-8'}</span>
+                                       (<span class="nickname" 
property="foaf:nick">{$g->name|escape:'html':'UTF-8'}</span>)
+                               </dt>
+                               <dd>{if $g->homepage}<a class="url" 
rel="foaf:page" 
href="{$g->homepage|escape:'html':'UTF-8'}">{$g->homepage|escape:'html':'UTF-8'}</a>{/if}</dd>
+                               <dd class="note" 
property="dc:abstract">{$g->bio|escape:'html':'UTF-8'}</dd>
+                               <dd><a rel="foaf:homepage" 
rev="foaf:primaryTopic" property="dc:description" 
href="{$g->getURL()|escape:'html':'UTF-8'}">{$g->count} members</a></dd>
+                       </dl>
+                       <hr style="border: 1px solid transparent; clear: both;" 
/>
+               </div>
+       </li>
+       
+{/foreach}
+</ul>
+
+<!-- Column break -->
+</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
+
+<h3>{$me->name}'s top artists</h3>
+<ul class="tagcloud" about="{$me->id}">
+       {section name=i loop=$user_tagcloud}
+       <li style="font-size:{$user_tagcloud[i].size}"><a
+       href="{$user_tagcloud[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_tagcloud[i].size|substr:-5 ==
+       'large'}foaf:interest 
{/if}tag">{$user_tagcloud[i].artist|escape:"html":"UTF-8"}</a></li>
+       {/section}
+</ul>
+
+       <div id="adbard">
+
+           <!--Ad Bard advertisement snippet, begin -->
+
+           <script type='text/javascript'>
+            var ab_h = '4bcaab930d3bdfded68fd7be730d7db4';
+            var ab_s = '55fd9cde6d855a75f9ca43d854272f6b';
+           </script>
+           
+            <script type='text/javascript' 
src='http://cdn1.adbard.net/js/ab1.js'></script>
+
+           <!--Ad Bard, end -->
+
+       </div>
+
+{include file='footer.tpl'}
+

Added: branches/stable/nixtape/themes/librefm/templates/user-journal.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/user-journal.tpl           
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/user-journal.tpl   
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,44 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">{$me->name|escape:'html':'UTF-8'}'{if 
$me->name|substr:-1 != 's'}s{/if} journal</h2>
+
+{include file='maxiprofile.tpl'}
+
+<ul about="{$me->id}" rel="foaf:made" rev="foaf:maker" class="hfeed">
+{foreach from=$items item=i}
+       <li {if $i.subject_uri}about="{$i.subject_uri|escape:'html':'UTF-8'}" 
{/if}typeof="sioc:Item rss:item" class="hentry">
+               <b class="entry-title" 
property="dc:title">{$i.title|escape:'html':'UTF-8'}</b><br />
+               <a property="rss:item" rel="bookmark sioc:link" 
href="{$i.link|escape:'html':'UTF-8'}">{$i.link|escape:'html':'UTF-8'}</a>
+               <abbr class="published" property="dc:date" 
content="{$i.date_iso}" title="{$i.date_iso}">{$i.date_human}</abbr>
+       </li>
+{/foreach}
+</ul>
+
+<!-- Column break -->
+</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
+
+<h3>{$me->name}'s top artists</h3>
+<ul class="tagcloud" about="{$me->id}">
+       {section name=i loop=$user_tagcloud}
+       <li style="font-size:{$user_tagcloud[i].size}"><a
+       href="{$user_tagcloud[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_tagcloud[i].size|substr:-5 ==
+       'large'}foaf:interest 
{/if}tag">{$user_tagcloud[i].artist|escape:"html":"UTF-8"}</a></li>
+       {/section}
+</ul>
+
+       <div id="adbard">
+
+           <!--Ad Bard advertisement snippet, begin -->
+
+           <script type='text/javascript'>
+            var ab_h = '4bcaab930d3bdfded68fd7be730d7db4';
+            var ab_s = '55fd9cde6d855a75f9ca43d854272f6b';
+           </script>
+           
+            <script type='text/javascript' 
src='http://cdn1.adbard.net/js/ab1.js'></script>
+
+           <!--Ad Bard, end -->
+
+       </div>
+
+{include file='footer.tpl'}

Copied: branches/stable/nixtape/themes/librefm/templates/user-profile.tpl (from 
rev 1108, branches/stable/nixtape/themes/librefm/templates/profile.tpl)
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/user-profile.tpl           
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/user-profile.tpl   
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,84 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">{$me->name|escape:'html':'UTF-8'}'s profile</h2>
+
+{include file='maxiprofile.tpl'}
+
+{if $nowplaying|@count > 0}
+<h3>Now Playing:</h3>
+<!-- We should try to make this list work like the gobbles list. -->
+<dl class='now-playing'>
+    {section name=i loop=$nowplaying}
+    <dt class='track-name {if $scrobbles[i].license > 
0}libre{/if}'>{$nowplaying[i].track|escape:'html':'UTF-8'}</dt>
+    <dd>by <span class='artist-name'><a 
href='{$nowplaying[i].artisturl|escape:'html':'UTF-8'}'>{$nowplaying[i].artist|escape:'html':'UTF-8'}</a></span></dd>
+    <dd>with <span class='gobbler'>{$nowplaying[i].clientstr}</span></dd>
+    {/section}
+</dl>
+{/if}
+
+<div about="[_:seq1]" typeof="rdf:Seq" rev="rss:items">
+       <h3 typeof="rss:channel" property="rss:title" rel="rss:link" 
resource="#latest_plays" id="latest_plays" 
content="{$me->name|escape:'html':'UTF-8'}'s Latest Plays">Latest 
{$scrobbles|@count} Plays:</h3>
+</div>
+
+<ul class="gobbles" about="{$me->id|escape:'html':'UTF-8'}" rev="gob:user">
+{section name=i loop=$scrobbles}
+
+       <li class="play {if $scrobbles[i].license > 0}libre{/if}" 
about="{$scrobbles[i].id|escape:'html':'UTF-8'}" typeof="rss:item 
gob:ScrobbleEvent" rel="gob:track_played">
+               <div about="{$scrobbles[i].id_track|escape:'html':'UTF-8'}" 
typeof="mo:Track" class="haudio">
+                       <div rev="mo:track">
+                               <div 
about="{$scrobbles[i].id_album|escape:'html':'UTF-8'}" typeof="mo:Record"{if 
$scrobbles[i].album} property="dc:title" 
content="{$scrobbles[i].album|escape:'html':'UTF-8'}"{/if}>
+                                       {if $scrobbles[i].albumurl}<a 
rel="foaf:page" href="{$scrobbles[i].albumurl|escape:'html':'UTF-8'}">{/if}
+                                               <span{if 
$scrobbles[i].album_image} rel="foaf:depiction"{/if}{if $scrobbles[i].albumurl} 
about="{$scrobbles[i].id_album|escape:'html':'UTF-8'}"{/if}>
+                                                       <img height="50" 
width="50" 
+                                                               src="{if 
!$scrobbles[i].album_image}/i/qm50.png{else}{$scrobbles[i].album_image|escape:'html':'UTF-8'}{/if}"
 
+                                                               
class="albumart{if !$scrobbles[i].album_image} photo{/if}" 
+                                                               {if 
$scrobbles[i].album}title="{$scrobbles[i].album|escape:'html':'UTF-8'}" 
alt="Album: {$scrobbles[i].album|escape:'html':'UTF-8'}"{else}alt="Unknown 
album"{/if}  />
+                                               </span>
+                                       {if $scrobbles[i].albumurl}</a>{/if}
+                               </div>
+                       </div>
+                       <div rel="foaf:maker" class="contributor vcard">
+                               <a 
about="{$scrobbles[i].id_artist|escape:'html':'UTF-8'}" typeof="mo:MusicArtist" 
property="foaf:name" rel="foaf:page"
+                                       class="fn url" 
href="{$scrobbles[i].artisturl|escape:'html':'UTF-8'}"
+                                       
>{$scrobbles[i].artist|escape:'html':'UTF-8'}</a>
+                       </div>
+                       <div><a class="fn" property="dc:title" rel="foaf:page" 
href="{$scrobbles[i].trackurl|escape:'html':'UTF-8'}">{$scrobbles[i].track|escape:'html':'UTF-8'}</a></div>
+                       <small about="{$scrobbles[i].id|escape:'html':'UTF-8'}" 
property="dc:date" content="{$scrobbles[i].timeiso}" 
datatype="xsd:dateTime">{$scrobbles[i].timehuman}</small>
+                       <span about="{$scrobbles[i].id|escape:'html':'UTF-8'}" 
property="rss:link" content="{$scrobbles[i].trackurl|escape:'html':'UTF-8'}">
+                               <span property="rss:description" content="{if 
$scrobbles[i].album}{$scrobbles[i].album}{else}Unknown album{/if}">
+                                       <span property="rss:title" 
content="{$scrobbles[i].artist|escape:'html':'UTF-8'}: 
{$scrobbles[i].track|escape:'html':'UTF-8'}" 
rev="rdf:_{$smarty.section.i.index_next}" resource="[_:seq1]"></span>
+                               </span>
+                       </span>
+               </div>
+       </li>
+{/section}
+</ul>
+
+<!-- Column break -->
+</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
+
+<h3>{$me->name}'s top artists</h3>
+<ul class="tagcloud" about="{$me->id}">
+       {section name=i loop=$user_tagcloud}
+       <li style="font-size:{$user_tagcloud[i].size}"><a
+       href="{$user_tagcloud[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_tagcloud[i].size|substr:-5 ==
+       'large'}foaf:interest 
{/if}tag">{$user_tagcloud[i].artist|escape:"html":"UTF-8"}</a></li>
+       {/section}
+</ul>
+
+       <div id="adbard">
+
+           <!--Ad Bard advertisement snippet, begin -->
+
+           <script type='text/javascript'>
+            var ab_h = '4bcaab930d3bdfded68fd7be730d7db4';
+            var ab_s = '55fd9cde6d855a75f9ca43d854272f6b';
+           </script>
+           
+            <script type='text/javascript' 
src='http://cdn1.adbard.net/js/ab1.js'></script>
+
+           <!--Ad Bard, end -->
+
+       </div>
+
+{include file='footer.tpl'}

Copied: branches/stable/nixtape/themes/librefm/templates/user-recent-tracks.tpl 
(from rev 1108, branches/stable/nixtape/themes/librefm/templates/profile.tpl)
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/user-recent-tracks.tpl     
                        (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/user-recent-tracks.tpl     
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,72 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">{$me->name|escape:'html':'UTF-8'}'s recent tracks</h2>
+
+{include file='maxiprofile.tpl'}
+
+<div about="[_:seq1]" typeof="rdf:Seq" rev="rss:items">
+       <h3 typeof="rss:channel" property="rss:title" rel="rss:link" 
resource="#latest_plays" id="latest_plays" 
content="{$me->name|escape:'html':'UTF-8'}'s Latest Plays">Latest 
{$scrobbles|@count} Plays:</h3>
+</div>
+
+<ul class="gobbles" about="{$me->id|escape:'html':'UTF-8'}" rev="gob:user">
+{section name=i loop=$scrobbles}
+
+       <li class="play {if $scrobbles[i].license > 0}libre{/if}" 
about="{$scrobbles[i].id|escape:'html':'UTF-8'}" typeof="rss:item 
gob:ScrobbleEvent" rel="gob:track_played">
+               <div about="{$scrobbles[i].id_track|escape:'html':'UTF-8'}" 
typeof="mo:Track" class="haudio">
+                       <div rev="mo:track">
+                               <div 
about="{$scrobbles[i].id_album|escape:'html':'UTF-8'}" typeof="mo:Record"{if 
$scrobbles[i].album} property="dc:title" 
content="{$scrobbles[i].album|escape:'html':'UTF-8'}"{/if}>
+                                       {if $scrobbles[i].albumurl}<a 
rel="foaf:page" href="{$scrobbles[i].albumurl|escape:'html':'UTF-8'}">{/if}
+                                               <span{if 
$scrobbles[i].album_image} rel="foaf:depiction"{/if}{if $scrobbles[i].albumurl} 
about="{$scrobbles[i].id_album|escape:'html':'UTF-8'}"{/if}>
+                                                       <img height="50" 
width="50" 
+                                                               src="{if 
!$scrobbles[i].album_image}/i/qm50.png{else}{$scrobbles[i].album_image|escape:'html':'UTF-8'}{/if}"
 
+                                                               
class="albumart{if !$scrobbles[i].album_image} photo{/if}" 
+                                                               {if 
$scrobbles[i].album}title="{$scrobbles[i].album|escape:'html':'UTF-8'}" 
alt="Album: {$scrobbles[i].album|escape:'html':'UTF-8'}"{else}alt="Unknown 
album"{/if}  />
+                                               </span>
+                                       {if $scrobbles[i].albumurl}</a>{/if}
+                               </div>
+                       </div>
+                       <div rel="foaf:maker" class="contributor vcard">
+                               <a 
about="{$scrobbles[i].id_artist|escape:'html':'UTF-8'}" typeof="mo:MusicArtist" 
property="foaf:name" rel="foaf:page"
+                                       class="fn url" 
href="{$scrobbles[i].artisturl|escape:'html':'UTF-8'}"
+                                       
>{$scrobbles[i].artist|escape:'html':'UTF-8'}</a>
+                       </div>
+                       <div><a class="fn" property="dc:title" rel="foaf:page" 
href="{$scrobbles[i].trackurl|escape:'html':'UTF-8'}">{$scrobbles[i].track|escape:'html':'UTF-8'}</a></div>
+                       <small about="{$scrobbles[i].id|escape:'html':'UTF-8'}" 
property="dc:date" content="{$scrobbles[i].timeiso}" 
datatype="xsd:dateTime">{$scrobbles[i].timehuman}</small>
+                       <span about="{$scrobbles[i].id|escape:'html':'UTF-8'}" 
property="rss:link" content="{$scrobbles[i].trackurl|escape:'html':'UTF-8'}">
+                               <span property="rss:description" content="{if 
$scrobbles[i].album}{$scrobbles[i].album}{else}Unknown album{/if}">
+                                       <span property="rss:title" 
content="{$scrobbles[i].artist|escape:'html':'UTF-8'}: 
{$scrobbles[i].track|escape:'html':'UTF-8'}" 
rev="rdf:_{$smarty.section.i.index_next}" resource="[_:seq1]"></span>
+                               </span>
+                       </span>
+               </div>
+       </li>
+{/section}
+</ul>
+
+<!-- Column break -->
+</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
+
+<h3>{$me->name}'s top artists</h3>
+<ul class="tagcloud" about="{$me->id}">
+       {section name=i loop=$user_tagcloud}
+       <li style="font-size:{$user_tagcloud[i].size}"><a
+       href="{$user_tagcloud[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_tagcloud[i].size|substr:-5 ==
+       'large'}foaf:interest 
{/if}tag">{$user_tagcloud[i].artist|escape:"html":"UTF-8"}</a></li>
+       {/section}
+</ul>
+
+       <div id="adbard">
+
+           <!--Ad Bard advertisement snippet, begin -->
+
+           <script type='text/javascript'>
+            var ab_h = '4bcaab930d3bdfded68fd7be730d7db4';
+            var ab_s = '55fd9cde6d855a75f9ca43d854272f6b';
+           </script>
+           
+            <script type='text/javascript' 
src='http://cdn1.adbard.net/js/ab1.js'></script>
+
+           <!--Ad Bard, end -->
+
+       </div>
+
+{include file='footer.tpl'}

Added: branches/stable/nixtape/themes/librefm/templates/user-stats.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/user-stats.tpl             
                (rev 0)
+++ branches/stable/nixtape/themes/librefm/templates/user-stats.tpl     
2009-05-02 04:00:56 UTC (rev 1109)
@@ -0,0 +1,52 @@
+{include file='header.tpl'}
+
+<h2 property="dc:title">{$me->name|escape:'html':'UTF-8'}'s statistics</h2>
+
+{include file='maxiprofile.tpl'}
+
+<h3 id="stats_by_artist">{$me->name|escape:'html':'UTF-8'}'s most played 
artists</h3>
+<table class="stats_artists" about="{$me->id}">
+       {section name=i loop=$user_playstats}
+       <tr><td class="counts">{$user_playstats[i].count}</td><td class="bar" 
style="width: {$stat_barwidth}px"><div 
style="width:{$user_playstats[i].size}px" class="artist"></div></td><td><a
+       href="{$user_playstats[i].pageurl|escape:'html':'UTF-8'}" rel="{if 
$user_playstats[i].size|substr:-5 ==
+       'large'}foaf:interest 
{/if}tag">{$user_playstats[i].artist|escape:"html":"UTF-8"}</a></td></tr>
+       {/section}
+</table>
+
+<h3 id="stats_by_track">{$me->name|escape:'html':'UTF-8'}'s top tracks</h3>
+<table class="stats_artists" about="{$me->id}">
+{section name=i loop=$toptracks}
+       <tr>
+               <td class="counts">{$toptracks[i].c}</td>
+               <td class="bar" style="width: {$toptracks[i].width}px">
+                       <div style="width:{$toptracks[i].width}px" 
class="track"></div>
+               </td>
+               <td>
+                       <a 
href="{$toptracks[i].artisturl|escape:'html':'UTF-8'}">{$toptracks[i].artist|escape:'html':'UTF-8'}</a>
+               </td>
+               <td>
+                       <a 
href="{$toptracks[i].trackurl|escape:'html':'UTF-8'}">{$toptracks[i].track|escape:'html':'UTF-8'}</a>
+               </td>
+       </tr>
+{/section}
+</table>
+
+<h3 id="stats_by_day">{$me->name|escape:'html':'UTF-8'}'s scrobbles by day</h3>
+<table class="stats_artists" about="{$me->id}">
+       {section name=i loop=$user_daystats}
+       <tr><td class="counts">{$user_daystats[i].count}</td><td class="bar" 
style="width: {$stat_barwidth}px"><div style="width:{$user_daystats[i].size}px" 
class="artist"></div></td><td class="date">{$user_daystats[i].date}</td></tr>
+       {/section}
+</table>
+
+<!-- Column break -->
+</div></div><div class="yui-u" id="sidebar"><div style="padding: 10px;">
+
+<h3>{$me->name}'s statistics</h3>
+<ul>
+       <li><a href="#stats_by_artist">Most played artists</a></li>
+       <li><a href="#stats_by_track">Top tracks</a></li>
+       <li><a href="#stats_by_day">Scrobbles by day</a></li>
+</ul>
+<p><strong>More coming soon</strong></p>
+
+{include file='footer.tpl'}

Modified: branches/stable/nixtape/themes/librefm/templates/welcome.tpl
===================================================================
--- branches/stable/nixtape/themes/librefm/templates/welcome.tpl        
2009-05-02 04:00:44 UTC (rev 1108)
+++ branches/stable/nixtape/themes/librefm/templates/welcome.tpl        
2009-05-02 04:00:56 UTC (rev 1109)
@@ -8,7 +8,11 @@
 
 <dl class='now-playing'>
   {section name=np loop=$nowplaying}
+{if $nowplaying[np].license > 0}
+    <dt class='artist-name libre'>
+{else}
     <dt class='artist-name'>
+{/if}
         <a 
href='{$nowplaying[np].artisturl}'>{$nowplaying[np].artist|stripslashes|htmlspecialchars}</a>
     </dt>
     <dd class='track-name'>
@@ -30,10 +34,10 @@
 <dl class='recent-tracks'>
   {section name=recent loop=$recenttracks}
 {if $recenttracks[recent].license > 0}
-      <dd class='artist-name libre'><a title="Libre artist" 
href='{$recenttracks[recent].artisturl}'>
+      <dt class='artist-name libre'><a title="Libre artist" 
href='{$recenttracks[recent].artisturl}'>
         {$recenttracks[recent].artist|stripslashes|htmlspecialchars}</a>:
 {else}
-      <dd class='artist-name'><a href='{$recenttracks[recent].artisturl}'>
+      <dt class='artist-name'><a href='{$recenttracks[recent].artisturl}'>
         {$recenttracks[recent].artist|stripslashes|htmlspecialchars}</a>:
 {/if}
       <span class='track-name'><a 
href="{$recenttracks[recent].trackurl}">{$recenttracks[recent].track|stripslashes|htmlspecialchars}</a></span>
 &mdash;

Copied: branches/stable/nixtape/user-edit.php (from rev 1108, 
branches/stable/nixtape/edit_profile.php)
===================================================================
--- branches/stable/nixtape/user-edit.php                               (rev 0)
+++ branches/stable/nixtape/user-edit.php       2009-05-02 04:00:56 UTC (rev 
1109)
@@ -0,0 +1,188 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+require_once('database.php');
+require_once('templating.php');
+require_once('data/User.php');
+require_once('data/TagCloud.php');
+
+if($logged_in == false)
+{
+       $smarty->assign('error', 'Error!');
+       $smarty->assign('details', 'Not logged in! You shouldn\'t be here!');
+       $smarty->display('error.tpl');
+       die();
+}
+
+$errors = array();
+
+if ($_POST['submit'])
+{
+       if (!empty($_POST['id']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['id']) )
+                       $errors[] = "WebID must be a URI.";
+               if ( preg_match('/\s/', $_POST['id']) )
+                       $errors[] = "WebID must be a URI. Valid URIs cannot 
contain whitespace.";
+       }
+
+       if (!empty($_POST['homepage']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['homepage']) )
+                       $errors[] = "Homepage must be a URI.";
+               if ( preg_match('/\s/', $_POST['homepage']) )
+                       $errors[] = "Homepage must be a URI. Valid URIs cannot 
contain whitespace.";
+       }
+
+       if (!empty($_POST['avatar_uri']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', $_POST['avatar_uri']) 
)
+                       $errors[] = "Avatar must be a URI.";
+               if ( preg_match('/\s/', $_POST['avatar_uri']) )
+                       $errors[] = "Avatar must be a URI. Valid URIs cannot 
contain whitespace.";
+       }
+
+       if (!empty($_POST['laconica_profile']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', 
$_POST['laconica_profile']) )
+                       $errors[] = "Laconica profile must be a URI.";
+               if ( preg_match('/\s/', $_POST['laconica_profile']) )
+                       $errors[] = "Laconica profile must be a URI. Valid URIs 
cannot contain whitespace.";
+       }
+
+       if (!empty($_POST['journal_rss']))
+       {
+               # Need better URI validation, but this will do for now. I think
+               # PEAR has a suitable module to help out here.
+               if ( !preg_match('/^[a-z0-9\+\.\-]+\:/i', 
$_POST['journal_rss']) )
+                       $errors[] = "Journal RSS must be a URI.";
+               if ( preg_match('/\s/', $_POST['journal_rss']) )
+                       $errors[] = "Journal RSS must be a URI. Valid URIs 
cannot contain whitespace.";
+       }
+
+       if (!empty($_POST['password_1']))
+       {
+               if ($_POST['password_1'] != $_POST['password_2'])
+                       $errors[] = "Passwords do not match.";
+       }
+
+       if (!empty($_POST['location_uri']))
+       {
+               # Currently only allow geonames URIs, but there's no reason we 
can't accept
+               # others at some point in the future. (e.g. dbpedia)
+               if ( !preg_match('/^http:\/\/sws.geonames.org\/[0-9]+\/$/', 
$_POST['location_uri']) )
+                       $errors[] = "This should be a geonames.org semantic web 
service URI.";
+       }
+
+       if (!isset($errors[0]))
+       {
+               # Currently we don't allow them to change e-mail as we probably 
should
+               # have some kind of confirmation login to do so.
+               $this_user->id           = $_POST['id'];
+               $this_user->fullname     = $_POST['fullname'];
+               $this_user->homepage     = $_POST['homepage'];
+               $this_user->bio          = $_POST['bio'];
+               $this_user->location     = $_POST['location'];
+               $this_user->location_uri = $_POST['location_uri'];
+               $this_user->avatar_uri   = $_POST['avatar_uri'];
+               $this_user->laconica_profile = $_POST['laconica_profile'];
+               $this_user->journal_rss  = $_POST['journal_rss'];
+               
+               if (!empty( $_POST['password_1'] ))
+                       $user->password = md5($_POST['password_1']);
+               
+               $this_user->save();
+
+               header("Location: " . $this_user->getURL());
+               exit;
+       }
+
+       if (isset($errors[0]))
+       {
+               header("Content-Type: text/plain");
+               print_r($errors);
+               exit;
+       }
+}
+
+if(isset($this_user->name))
+{
+       # Stuff which cannot be changed.
+       $smarty->assign("acctid", $this_user->acctid);
+       $smarty->assign('avatar', $this_user->getAvatar());
+       $smarty->assign('user',   $this_user->name);
+
+       # Stuff which cannot be changed *here*
+       $smarty->assign('userlevel', $this_user->userlevel);
+       
+       # Stuff which cannot be changed *yet*
+       $smarty->assign('email', $this_user->email);
+       
+       if ($_POST['submit'])
+       {
+               $smarty->assign("id",           $_POST['id']);
+               $smarty->assign('fullname',     $_POST['fullname']);
+               $smarty->assign('bio',          $_POST['bio']);
+               $smarty->assign('homepage',     $_POST['homepage']);
+               $smarty->assign('location',     $_POST['location']);
+               $smarty->assign('location_uri', $_POST['location_uri']);
+               $smarty->assign('avatar_uri',   $_POST['avatar_uri']);
+               $smarty->assign('laconica_profile', $_POST['laconica_profile']);
+               $smarty->assign('journal_rss',  $_POST['journal_rss']);
+       }
+       else
+       {
+               $smarty->assign("id",           ($this_user->webid_uri));
+               $smarty->assign('fullname',     ($this_user->fullname));
+               $smarty->assign('bio',          ($this_user->bio));
+               $smarty->assign('homepage',     ($this_user->homepage));
+               $smarty->assign('location',     ($this_user->location));
+               $smarty->assign('location_uri', ($this_user->location_uri));
+               $smarty->assign('avatar_uri',   ($this_user->avatar_uri));
+               $smarty->assign('laconica_profile', 
($this_user->laconica_profile));
+               $smarty->assign('journal_rss',  ($this_user->journal_rss));
+       }
+
+       # And display the page.
+       $aTagCloud = TagCloud::GenerateTagCloud('Scrobbles', 'artist');
+       if (!PEAR::isError ($aTagCloud))
+       {
+               $smarty->assign('tagcloud', $aTagCloud);
+       }
+       $smarty->assign('errors', $errors);
+       $smarty->display('user-edit.tpl');
+}
+
+else
+{
+       $smarty->assign('error', 'User not found');
+       $smarty->assign('details', 'Shall I call in a missing persons report? 
This shouldn\'t happen.');
+       $smarty->display('error.tpl');
+}
+


@@ Diff output truncated at 153600 characters. @@




reply via email to

[Prev in Thread] Current Thread [Next in Thread]