summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/ampache.cfg.php.dist5
-rwxr-xr-xdocs/CHANGELOG4
-rw-r--r--lib/class/stream.class.php85
-rw-r--r--lib/class/update.class.php41
-rw-r--r--lib/general.lib.php4
-rw-r--r--lib/stream.lib.php119
-rw-r--r--lib/ui.lib.php37
-rw-r--r--play/index.php11
-rw-r--r--templates/show_now_playing.inc.php1
-rw-r--r--templates/show_now_playing_row.inc.php2
10 files changed, 186 insertions, 123 deletions
diff --git a/config/ampache.cfg.php.dist b/config/ampache.cfg.php.dist
index beba1357..40ddd3b5 100644
--- a/config/ampache.cfg.php.dist
+++ b/config/ampache.cfg.php.dist
@@ -49,6 +49,11 @@ database_password = password
; DEFAULT: 900
session_length = 900
+; Length that the session for a single streaming instance will last
+; the default is 15min. With some clients, and long songs this can
+; cause playback to stop, increase this value if you experience that
+stream_length = 900
+
; This length defines how long a 'remember me' session and cookie will
; last, the default is 900, same as length. It is up to the administrator
; of the box to increase this, for reference 86400 = 1 day
diff --git a/docs/CHANGELOG b/docs/CHANGELOG
index a8a8c1d7..494a0a97 100755
--- a/docs/CHANGELOG
+++ b/docs/CHANGELOG
@@ -4,6 +4,10 @@
--------------------------------------------------------------------------
v.3.4-Alpha2
+ - Fixed now playing, hopefully once and for all
+ - Added distinct sessions for each stream action, also allows
+ for independent session lengths between interface
+ and streaming
- Added paging on all song displays including search
- Fixed searching via quicksearch bar
- Added 'Your' playlists to leftbar with play and view links
diff --git a/lib/class/stream.class.php b/lib/class/stream.class.php
index 6fca492c..fe40de79 100644
--- a/lib/class/stream.class.php
+++ b/lib/class/stream.class.php
@@ -45,13 +45,14 @@ class Stream {
$this->type = $type;
$this->songs = $song_ids;
$this->web_path = Config::get('web_path');
+ $this->user_id = $GLOBALS['user']->id;
if (Config::get('force_http_play')) {
$this->web_path = preg_replace("/https/", "http",$this->web_path);
}
- $this->sess = session_id();
- $this->user_id = $GLOBALS['user']->id;
+ // Generate the session ID
+ $this->session = md5(uniqid(rand(), true));;
} // Constructor
@@ -67,6 +68,12 @@ class Stream {
return false;
}
+ // We're starting insert the session into session_stream
+ if (!$this->insert_session()) {
+ debug_event('stream','Session Insertion failure, aboring','3');
+ return false;
+ }
+
$methods = get_class_methods('Stream');
$create_function = "create_" . $this->type;
@@ -94,6 +101,68 @@ class Stream {
} // manual_url_add
/**
+ * insert_session
+ * This inserts a row into the session_stream table
+ */
+ private function insert_session() {
+
+ $expire = time() + Config::get('stream_length');
+
+ $sql = "INSERT INTO `session_stream` (`id`,`expire`,`user`) " .
+ "VALUES('$this->session','$expire','$this->user_id')";
+ $db_results = Dba::query($sql);
+
+ if (!$db_results) { return false; }
+
+ return true;
+
+ } // insert_session
+
+ /**
+ * session_exists
+ * This checks to see if the passed stream session exists and is valid
+ */
+ public static function session_exists($sid) {
+
+ $sid = Dba::escape($sid);
+ $time = time();
+
+ $sql = "SELECT * FROM `session_stream` WHERE `id`='$sid' AND `expire` > '$time'";
+ $db_results = Dba::query($sql);
+
+ if ($row = Dba::fetch_assoc($db_results)) {
+ return true;
+ }
+
+ return false;
+
+ } // session_exists
+
+ /**
+ * extend_session
+ * This takes the passed sid and does a replace into also setting the user
+ * agent and IP also do a little GC in this function
+ */
+ public static function extend_session($sid,$uid) {
+
+ $expire = time() + Config::get('stream_length');
+ $sid = Dba::escape($sid);
+ $agent = Dba::escape($_SERVER['HTTP_USER_AGENT']);
+ $ip = ip2int($_SERVER['REMOTE_ADDR']);
+ $uid = Dba::escape($uid);
+
+ $sql = "UPDATE `session_stream` SET `expire`='$expire', `agent`='$agent', `ip`='$ip' " .
+ "WHERE `id`='$sid'";
+ $db_results = Dba::query($sql);
+
+ $sql = "DELETE FROM `session_stream` WHERE `ip`='$ip' AND `agent`='$agent' AND `user`='$uid' AND `id` != '$sid'";
+ $db_results = Dba::query($sql);
+
+ return true;
+
+ } // extend_session
+
+ /**
* create_simplem3u
* this creates a simple m3u without any of the extended information
*/
@@ -118,7 +187,7 @@ class Stream {
if ($GLOBALS['user']->prefs['play_type'] == 'downsample') {
$ds = $GLOBALS['user']->prefs['sample_rate'];
}
- echo "$this->web_path/play/index.php?song=$song_id&uid=$this->user_id&sid=$this->sess&ds=$ds&stupidwinamp=." . $song->type . "\n";
+ echo $song->get_url($this->session);
} // end foreach
/* Foreach the additional URLs */
@@ -155,7 +224,7 @@ class Stream {
$song->format();
echo "#EXTINF:$song->time," . $song->f_artist_full . " - " . $song->title . "\n";
- echo $song->get_url() . "\n";
+ echo $song->get_url($this->session) . "\n";
} // end foreach
/* Foreach URLS */
@@ -186,7 +255,7 @@ class Stream {
$song = new Song($song_id);
$song->format();
$song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type;
- $song_url = $song->get_url();
+ $song_url = $song->get_url($this->session);
echo "File" . $i . "=$song_url\n";
echo "Title" . $i . "=$song_name\n";
echo "Length" . $i . "=$song->time\n";
@@ -220,7 +289,7 @@ class Stream {
foreach ($this->songs as $song_id) {
$song = new Song($song_id);
$song->format();
- $url = $song->get_url();
+ $url = $song->get_url($this->session);
$song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type;
echo "<ENTRY>\n";
@@ -264,7 +333,7 @@ class Stream {
$song->format();
$xml = array();
- $xml['track']['location'] = $song->get_url() . $flash_hack;
+ $xml['track']['location'] = $song->get_url($this->session) . $flash_hack;
$xml['track']['identifier'] = $xml['track']['location'];
$xml['track']['title'] = $song->title;
$xml['track']['creator'] = $song->f_artist_full;
@@ -392,7 +461,7 @@ class Stream {
header("Content-Type: audio/x-pn-realaudio ram;");
foreach ($this->songs as $song_id) {
$song = new Song($song_id);
- echo "$this->web_path/play/index.php?song=$song_id&uid=$this->user_id&sid=$this->sess&stupidwinamp=." . $song->type . "\n";
+ echo $song->get_url($this->session);
} // foreach songs
} // create_ram
diff --git a/lib/class/update.class.php b/lib/class/update.class.php
index bd1be7af..2af04264 100644
--- a/lib/class/update.class.php
+++ b/lib/class/update.class.php
@@ -215,6 +215,11 @@ class Update {
$version[] = array('version' => '340006','description' => $update_string);
+ $update_string = '- Added new session_stream table for sessions tied directly to stream instances.<br />' .
+ '- Altered the session table, making value a LONGTEXT.<br />';
+
+ $version[] = array('version' => '340007','description' => $update_string);
+
return $version;
} // populate_version
@@ -807,5 +812,41 @@ class Update {
} // update_340006
+ /**
+ * update_340007
+ * This update converts the session.value to a longtext
+ * and adds a session_stream table
+ */
+ public static function update_340007() {
+
+ // Tweak the session table to handle larger session vars for my page-a-nation hotness
+ $sql = "ALTER TABLE `session` CHANGE `value` `value` LONGTEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL";
+ $db_results = Dba::query($sql);
+
+ // Create the new stream table where we will store stream SIDs
+ $sql = "CREATE TABLE `session_stream` ( " .
+ "`id` VARCHAR( 64 ) NOT NULL , " .
+ "`user` INT( 11 ) UNSIGNED NOT NULL , " .
+ "`agent` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL , " .
+ "`expire` INT( 11 ) UNSIGNED NOT NULL , " .
+ "`ip` INT( 11 ) UNSIGNED NULL , " .
+ "PRIMARY KEY ( `id` ) " .
+ ") ENGINE = MYISAM";
+ $db_results = Dba::query($sql);
+
+ // Change the now playing to use stream session ids for its ID
+ $sql = "ALTER TABLE `now_playing` CHANGE `id` `id` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL";
+ $db_results = Dba::query($sql);
+
+ // Now longer needed because of the new hotness
+ $sql = "ALTER TABLE `now_playing` DROP `session`";
+ $db_results = Dba::query($sql);
+
+ self::set_version('db_version','340007');
+
+ return true;
+
+ } // update_340007
+
} // end update class
?>
diff --git a/lib/general.lib.php b/lib/general.lib.php
index 5c724f18..3d60014f 100644
--- a/lib/general.lib.php
+++ b/lib/general.lib.php
@@ -114,10 +114,6 @@ function error_results($param,$clobber=0)
/**
* session_exists
* checks to make sure they've specified a valid session, can handle xmlrpc
- * @package General
- * @cataogry Verify
- * @todo Have XMLRPC check extend remote session
- * @todo actually check
*/
function session_exists($sid,$xml_rpc=0) {
diff --git a/lib/stream.lib.php b/lib/stream.lib.php
index 00416a7d..df07e821 100644
--- a/lib/stream.lib.php
+++ b/lib/stream.lib.php
@@ -20,30 +20,6 @@
*/
-/**
- * delete_now_playing
- * This function checks to see if we should delete the last now playing entry now that it's
- * finished streaming the song. Basicly this is an exception for WMP10
- * @package General
- * @catagory Now Playing
- */
-function delete_now_playing($insert_id) {
-
- $user_agent = $_SERVER['HTTP_USER_AGENT'];
-
- // Account for WMP and the Flash Player
-// if (stristr($user_agent,"NSPlayer") || $_REQUEST['flash_hack'] == 1) {
- // Commented out until I can figure out the
- // trick to making this work
-// return true;
-// }
-
- // Remove the song from the now_playing table
- $sql = "DELETE FROM `now_playing` WHERE `id` = '$insert_id'";
- $db_result = Dba::query($sql);
-
-} // delete_now_playing
-
/**
* gc_now_playing
* this is a garbage collection function for now playing this is called every time something
@@ -53,18 +29,16 @@ function delete_now_playing($insert_id) {
*/
function gc_now_playing() {
- /* Account for WMP11's Initial Streaming */
- //if (strstr($_SERVER['HTTP_USER_AGENT'],"WMFSDK/11")) { return false; }
+ // Delete expired songs
+ $sql = "DELETE FROM `now_playing` WHERE `expire` < '$time'";
+ $db_result = Dba::query($sql);
- $time = time();
- $session_id = Dba::escape($_REQUEST['sid']);
- if (strlen($session_id)) {
- $session_sql = " OR session = '$session_id'";
- }
+ // Remove any now playing entries for session_streams that have been GC'd
+ $sql = "DELETE FROM `now_playing` USING `now_playing` " .
+ "LEFT JOIN `session_stream` ON `session_stream`.`id`=`now_playing`.`id` " .
+ "WHERE `session_stream`.`id` IS NULL";
+ $db_results = Dba::query($sql);
- $sql = "DELETE FROM `now_playing` WHERE `expire` < '$time'" . $session_sql;
- $db_result = Dba::query($sql);
-
} // gc_now_playing
/**
@@ -73,41 +47,16 @@ function gc_now_playing() {
* we use this function because we need to do thing differently
* depending upon which play is actually streaming
*/
-function insert_now_playing($song_id,$uid,$song_length) {
+function insert_now_playing($song_id,$uid,$song_length,$sid) {
- $user_agent = $_SERVER['HTTP_USER_AGENT'];
$time = time()+$song_length;
- $session_id = Dba::escape($_REQUEST['sid']);
-
- /* Check for against a list of clients that have abusive traffic patterns causing
- * faulty now playing data and return without inserting
- */
- $banned_clients = array('Audacious/1.3');
-
- foreach ($banned_clients as $banned_agent) {
- if (stristr($user_agent,$banned_agent)) {
- debug_event('Banned Agent',$banned_agent . ' clients now playing data not entered because Ampache is unable to handle its request pattern','5');
- return false;
- }
- }
-
- /* Windows Media Player is evil and it makes multiple requests per song */
- if (stristr($user_agent,"Windows-Media-Player")) { $session_id = ' '; }
-
- /* Check for Windows Media Player 11 */
- if (strstr($user_agent,'NSPlayer/11') AND !strstr($user_agent,'WMFSDK/11')) { $session_id = ' '; }
-
- // If they are using Windows media player
- if (strstr($user_agent,"NSPlayer") || $_REQUEST['flash_hack'] == 1) { $session_id = ' '; }
+ $session_id = Dba::escape($sid);
- $sql = "INSERT INTO now_playing (`song_id`, `user`, `expire`,`session`)" .
- " VALUES ('$song_id', '$uid', '$time','$session_id')";
-
- $db_result = Dba::query($sql);
-
- $insert_id = Dba::insert_id();
-
- return $insert_id;
+ // Do a replace into ensuring that this client always only has a single row
+ $sql = "REPLACE INTO `now_playing` (`id`,`song_id`, `user`, `expire`)" .
+ " VALUES ('$session_id','$song_id', '$uid', '$time')";
+
+ $db_result = Dba::query($sql);
} // insert_now_playing
@@ -126,6 +75,44 @@ function clear_now_playing() {
} // clear_now_playing
/**
+ * show_now_playing
+ * shows the now playing template
+ */
+function show_now_playing() {
+
+ $web_path = Config::get('web_path');
+ $results = get_now_playing();
+ require Config::get('prefix') . '/templates/show_now_playing.inc.php';
+
+} // show_now_playing
+
+/**
+ * get_now_playing
+ * gets the now playing information
+ */
+function get_now_playing($filter='') {
+
+ $sql = "SELECT `session_stream`.`agent`,`now_playing`.`song_id`,`now_playing`.`user` FROM `now_playing` " .
+ "LEFT JOIN `session_stream` ON `session_stream`.`id`=`now_playing`.`id` " .
+ "ORDER BY `now_playing`.`expire` DESC";
+ $db_results = Dba::query($sql);
+
+ $results = array();
+
+ /* While we've got stuff playing */
+ while ($r = Dba::fetch_assoc($db_results)) {
+ $song = new Song($r['song_id']);
+ $song->format();
+ $np_user = new User($r['user']);
+ $results[] = array('song'=>$song,'user'=>$np_user,'agent'=>$r['agent']);
+ } // end while
+
+ return $results;
+
+} // get_now_playing
+
+
+/**
* check_lock_songs
* This checks to see if the song is already playing, if it is then it prevents the user
* from streaming it
diff --git a/lib/ui.lib.php b/lib/ui.lib.php
index 5c0ec15a..7e164e45 100644
--- a/lib/ui.lib.php
+++ b/lib/ui.lib.php
@@ -222,18 +222,6 @@ function show_footer() {
} // show_footer
/**
- * show_now_playing
- * shows the now playing template
- */
-function show_now_playing() {
-
- $web_path = Config::get('web_path');
- $results = get_now_playing();
- require Config::get('prefix') . '/templates/show_now_playing.inc.php';
-
-} // show_now_playing
-
-/**
* show_user_registration
* this function is called for a new user
* registration
@@ -257,31 +245,6 @@ function show_play_selected() {
} // show_play_selected
-/**
- * get_now_playing
- * gets the now playing information
- * @package Web Interface
- * @catagory Get
- */
-function get_now_playing($filter='') {
-
- $sql = "SELECT `song_id`,`user` FROM `now_playing` ORDER BY `id` DESC";
- $db_results = Dba::query($sql);
-
- $results = array();
-
- /* While we've got stuff playing */
- while ($r = Dba::fetch_assoc($db_results)) {
- $song = new Song($r['song_id']);
- $song->format();
- $np_user = new User($r['user']);
- $results[] = array('song'=>$song,'user'=>$np_user);
- } // end while
-
- return $results;
-
-} // get_now_playing
-
/*
* Artist Ratings - Implemented by SoundOfEmotion
*
diff --git a/play/index.php b/play/index.php
index 438db254..cf4d4963 100644
--- a/play/index.php
+++ b/play/index.php
@@ -73,15 +73,15 @@ if (Config::get('xml_rpc')) {
}
// If require session is set then we need to make sure we're legit
-if (Config::get('require_session') OR $xml_rpc) {
- if(!session_exists($sid,$xml_rpc)) {
+if (Config::get('require_session')) {
+ if(!Stream::session_exists($sid)) {
debug_event('session_expired',"Streaming Access Denied: " . $GLOBALS['user']->username . "'s session has expired",'3');
die(_("Session Expired: please log in again at") . " " . Config::get('web_path') . "/login.php");
}
// Now that we've confirmed the session is valid
// extend it
- extend_session($sid);
+ Stream::extend_session($sid,$uid);
}
@@ -272,7 +272,7 @@ $chunk_size = '4096';
$song->size = $song->size + ($chunk_size*2);
// Put this song in the now_playing table
-$lastid = insert_now_playing($song->id,$uid,$song->time);
+insert_now_playing($song->id,$uid,$song->time,$sid);
if ($start) {
debug_event('seek','Content-Range header recieved, skipping ahead ' . $start . ' bytes out of ' . $song->size,'5');
@@ -305,9 +305,6 @@ while (!feof($fp) && (connection_status() == 0)) {
$bytesStreamed += $chunk_size;
}
-/* Delete the Now Playing Entry */
-delete_now_playing($lastid);
-
if ($bytesStreamed > $minBytesStreamed) {
$user->update_stats($song->id);
/* If this is a voting tmp playlist remove the entry */
diff --git a/templates/show_now_playing.inc.php b/templates/show_now_playing.inc.php
index 0bdba057..3e5b259f 100644
--- a/templates/show_now_playing.inc.php
+++ b/templates/show_now_playing.inc.php
@@ -35,6 +35,7 @@ if (count($results)) {
foreach ($results as $item) {
$song = $item['song'];
$np_user = $item['user'];
+ $agent = $item['agent'];
/* If we've gotten a non-song object just skip this row */
if (!is_object($song)) { continue; }
diff --git a/templates/show_now_playing_row.inc.php b/templates/show_now_playing_row.inc.php
index 0ff867b6..cb4331d4 100644
--- a/templates/show_now_playing_row.inc.php
+++ b/templates/show_now_playing_row.inc.php
@@ -25,7 +25,7 @@ $album = scrub_out(truncate_with_ellipsis($song->f_album_full,'25'));
$artist = scrub_out(truncate_with_ellipsis($song->f_artist_full,'25'));
?>
<td class="np_cell_left"><b><?php echo _('Username'); ?></b>:<br />
- <a href="<?php echo $web_path; ?>/stats.php?action=show_user&amp;user_id=<?php echo $np_user->id; ?>"><?php echo scrub_out($np_user->fullname); ?></a><br /><br />
+ <a title="<?php echo scrub_out($agent); ?>" href="<?php echo $web_path; ?>/stats.php?action=show_user&amp;user_id=<?php echo $np_user->id; ?>"><?php echo scrub_out($np_user->fullname); ?></a><br /><br />
<!-- ## modified ##-->
<strong><?php echo _('Song'); ?></strong><br />
<a title="<?php echo scrub_out($song->title); ?>" href="<?php echo $web_path; ?>/stream.php?action=single_song&amp;song_id=<?php echo $song->id; ?>">