1
0
Fork 0
mirror of https://github.com/Yetangitu/ampache synced 2025-10-03 09:49:30 +02:00

Add SoundCloud catalog type (fix #14)

Fix stats order
This commit is contained in:
Afterster 2013-11-24 02:43:19 +01:00
parent beae0b97a2
commit 92580278bd
9 changed files with 1666 additions and 10 deletions

View file

@ -173,7 +173,7 @@ class Rating extends database_object
$type = Stats::validate_type($type); $type = Stats::validate_type($type);
$sql = "SELECT `object_id` as `id`, AVG(`rating`) AS `rating` FROM rating" . $sql = "SELECT `object_id` as `id`, AVG(`rating`) AS `rating` FROM rating" .
" WHERE object_type = '" . $type . "'" . " WHERE object_type = '" . $type . "'" .
" GROUP BY object_id ORDER BY `rating` "; " GROUP BY object_id ORDER BY `rating` DESC ";
return $sql; return $sql;
} }
@ -195,7 +195,7 @@ class Rating extends database_object
/* Select Top objects counting by # of rows */ /* Select Top objects counting by # of rows */
$sql = self::get_highest_sql($type); $sql = self::get_highest_sql($type);
$sql .= "DESC LIMIT $limit"; $sql .= "LIMIT $limit";
$db_results = Dba::read($sql, array($type)); $db_results = Dba::read($sql, array($type));
$results = array(); $results = array();

View file

@ -172,7 +172,7 @@ class Stats
/* Select Top objects counting by # of rows */ /* Select Top objects counting by # of rows */
$sql = "SELECT object_id as `id`, COUNT(*) AS `count` FROM object_count" . $sql = "SELECT object_id as `id`, COUNT(*) AS `count` FROM object_count" .
" WHERE object_type = '" . $type ."' AND date >= '" . $date . "'" . " WHERE object_type = '" . $type ."' AND date >= '" . $date . "'" .
" GROUP BY object_id ORDER BY `count` "; " GROUP BY object_id ORDER BY `count` DESC ";
return $sql; return $sql;
} }
@ -195,7 +195,7 @@ class Stats
} }
$sql = self::get_top_sql($type, $threshold); $sql = self::get_top_sql($type, $threshold);
$sql .= "DESC LIMIT $limit"; $sql .= "LIMIT $limit";
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
$results = array(); $results = array();
@ -309,7 +309,7 @@ class Stats
{ {
$type = self::validate_type($type); $type = self::validate_type($type);
$sql = "SELECT DISTINCT(`$type`) as `id`, MIN(`addition_time`) AS `real_atime` FROM `song` GROUP BY `$type` ORDER BY `real_atime` "; $sql = "SELECT DISTINCT(`$type`) as `id`, MIN(`addition_time`) AS `real_atime` FROM `song` GROUP BY `$type` ORDER BY `real_atime` DESC ";
return $sql; return $sql;
} }
@ -328,7 +328,7 @@ class Stats
} }
$sql = self::get_newest_sql($type); $sql = self::get_newest_sql($type);
$sql .= "DESC LIMIT $limit"; $sql .= " LIMIT $limit";
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
$items = array(); $items = array();

View file

@ -215,8 +215,8 @@ class Catalog_dropbox extends Catalog
echo "<br />"; echo "<br />";
} }
protected function completeAuthToken() protected function completeAuthToken()
{ {
$webAuth = $this->getWebAuth(); $webAuth = $this->getWebAuth();
list($accessToken, $userId) = $webAuth->finish($this->authcode); list($accessToken, $userId) = $webAuth->finish($this->authcode);
debug_event('dropbox_catalog', 'Dropbox authentication token generated for user ' . $userId . '.', 1); debug_event('dropbox_catalog', 'Dropbox authentication token generated for user ' . $userId . '.', 1);
@ -224,7 +224,7 @@ class Catalog_dropbox extends Catalog
$sql = 'UPDATE `catalog_dropbox` SET `authtoken` = ? WHERE `catalog_id` = ?'; $sql = 'UPDATE `catalog_dropbox` SET `authtoken` = ? WHERE `catalog_id` = ?';
Dba::write($sql, array($this->authtoken, $this->catalog_id)); Dba::write($sql, array($this->authtoken, $this->catalog_id));
} }
/** /**
* add_to_catalog * add_to_catalog

View file

@ -0,0 +1,441 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
/**
* SoundCloud Catalog Class
*
* This class handles all actual work in regards to SoundCloud.
*
*/
class Catalog_soundcloud extends Catalog
{
private $version = '000001';
private $type = 'soundcloud';
private $description = 'Remote SoundCloud Catalog';
/**
* get_description
* This returns the description of this catalog
*/
public function get_description()
{
return $this->description;
} // get_description
/**
* get_version
* This returns the current version
*/
public function get_version()
{
return $this->version;
} // get_version
/**
* get_type
* This returns the current catalog type
*/
public function get_type()
{
return $this->type;
} // get_type
/**
* get_create_help
* This returns hints on catalog creation
*/
public function get_create_help()
{
$help = "<ul><li>Go to http://soundcloud.com/you/apps/new</li>" .
"<li>Give a name to your application and click Register</li>" .
"<li>Add the following OAuth redirect URIs: <i>" . $this->getRedirectUri() . "</i></li>" .
"<li>Copy your Client ID and Secret here, and Save the app</li></ul>";
return $help;
} // get_create_help
/**
* is_installed
* This returns true or false if remote catalog is installed
*/
public function is_installed()
{
$sql = "DESCRIBE `catalog_soundcloud`";
$db_results = Dba::query($sql);
return Dba::num_rows($db_results);
} // is_installed
/**
* install
* This function installs the remote catalog
*/
public function install()
{
$sql = "CREATE TABLE `catalog_soundcloud` (`id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , ".
"`userid` VARCHAR( 255 ) COLLATE utf8_unicode_ci NOT NULL , " .
"`secret` VARCHAR( 255 ) COLLATE utf8_unicode_ci NOT NULL , " .
"`authtoken` VARCHAR( 255 ) COLLATE utf8_unicode_ci NULL , " .
"`catalog_id` INT( 11 ) NOT NULL" .
") ENGINE = MYISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci";
$db_results = Dba::query($sql);
return true;
} // install
public function catalog_fields()
{
$fields['userid'] = array('description' => T_('User ID'),'type'=>'textbox');
$fields['secret'] = array('description' => T_('Secret'),'type'=>'textbox');
return $fields;
}
public $userid;
public $secret;
public $authtoken;
/**
* Constructor
*
* Catalog class constructor, pulls catalog information
*/
public function __construct($catalog_id = null)
{
if ($catalog_id) {
$this->id = intval($catalog_id);
$info = $this->get_info($catalog_id);
foreach ($info as $key=>$value) {
$this->$key = $value;
}
}
require_once Config::get('prefix') . '/modules/php-soundcloud/Soundcloud.php';
}
protected function getRedirectUri() {
return Config::get('web_path') . "/show_get.php?param_name=code";
}
/**
* create_type
*
* This creates a new catalog type entry for a catalog
* It checks to make sure its parameters is not already used before creating
* the catalog.
*/
public static function create_type($catalog_id, $data)
{
$userid = $data['userid'];
$secret = $data['secret'];
if (!strlen($userid) OR !strlen($secret)) {
Error::add('general', T_('Error: UserID and Secret Required for SoundCloud Catalogs'));
return false;
}
// Make sure this email isn't already in use by an existing catalog
$sql = 'SELECT `id` FROM `catalog_soundcloud` WHERE `userid` = ?';
$db_results = Dba::read($sql, array($userid));
if (Dba::num_rows($db_results)) {
debug_event('catalog', 'Cannot add catalog with duplicate user id ' . $userid, 1);
Error::add('general', sprintf(T_('Error: Catalog with %s already exists'), $userid));
return false;
}
$sql = 'INSERT INTO `catalog_soundcloud` (`userid`, `secret`, `catalog_id`) VALUES (?, ?, ?)';
Dba::write($sql, array($userid, $secret, $catalog_id));
return true;
}
protected function showAuthToken()
{
$api = new Services_Soundcloud($this->userid, $this->secret, $this->getRedirectUri());
$authurl = $api->getAuthorizeUrl(array('scope' => 'non-expiring'));
echo "<br />Go to <strong><a href='" . $authurl . "' target='_blank'>" . $authurl . "</a></strong> to generate the authorization code, then enter it bellow.<br />";
echo "<form action='' method='post' enctype='multipart/form-data'>";
if ($_POST['action']) {
echo "<input type='hidden' name='action' value='add_to_catalog' />";
echo "<input type='hidden' name='catalogs[]' value='". $this->id ."' />";
}
echo "<input type='text' name='authcode' size='30' />";
echo "<input type='submit' value='Ok' />";
echo "</form>";
echo "<br />";
}
protected function completeAuthToken()
{
$api = new Services_Soundcloud($this->userid, $this->secret, $this->getRedirectUri());
$this->authtoken = $api->accessToken($this->authcode)['access_token'];
debug_event('soundcloud_catalog', 'SoundCloud authentication token generated for userid ' . $this->userid . '.', 1);
$sql = 'UPDATE `catalog_soundcloud` SET `authtoken` = ? WHERE `catalog_id` = ?';
Dba::write($sql, array($this->authtoken, $this->catalog_id));
}
/**
* add_to_catalog
* this function adds new files to an
* existing catalog
*/
public function add_to_catalog($options = null)
{
// Prevent the script from timing out
set_time_limit(0);
if ($options != null) {
$this->authcode = $options['authcode'];
}
UI::show_box_top(T_('Running SoundCloud Remote Update') . '. . .');
$this->update_remote_catalog();
UI::show_box_bottom();
return true;
} // add_to_catalog
public function createClient()
{
if ($this->authcode) {
$this->completeAuthToken();
}
if (!$this->authtoken) {
$this->showAuthToken();
return null;
}
$api = new Services_Soundcloud($this->userid, $this->secret);
$api->setAccessToken($this->authtoken);
return $api;
}
/**
* update_remote_catalog
*
* Pulls the data from a remote catalog and adds any missing songs to the
* database.
*/
public function update_remote_catalog()
{
$songsadded = 0;
try {
$api = $this->createClient();
if ($api != null) {
// Get all liked songs
$songs = json_decode($api->get('me/favorites'));
if ($songs) {
foreach ($songs as $song) {
if ($song->streamable == true && $song->kind == 'track') {
$data = Array();
$data['artist'] = $song->user->username;
$data['album'] = $data['artist'];
$data['title'] = $song->title;
$data['year'] = $song->release_year;
$data['mode'] = 'vbr';
$data['genre'] = explode(' ', $song->genre);
$data['comment'] = $song->description;
$data['file'] = $song->stream_url . '.mp3'; // Always stream as mp3, if evolve => $song->original_format;
$data['size'] = $song->original_content_size;
$data['time'] = intval($song->duration / 1000);
if ($this->check_remote_song($data)) {
debug_event('soundcloud_catalog', 'Skipping existing song ' . $data['file'], 5);
} else {
$data['catalog'] = $this->id;
debug_event('soundcloud_catalog', 'Adding song ' . $data['file'], 5, 'ampache-catalog');
if (!Song::insert($data)) {
debug_event('soundcloud_catalog', 'Insert failed for ' . $data['file'], 1);
Error::add('general', T_('Unable to Insert Song - %s'), $data['file']);
Error::display('general');
flush();
} else {
$songsadded++;
}
}
}
}
echo "<p>" . T_('Completed updating SoundCloud catalog(s).') . " " . $songsadded . " " . T_('Songs added.') . "</p><hr />\n";
flush();
// Update the last update value
$this->update_last_update();
} else {
echo "<p>" . T_('API Error: cannot get song list.') . "</p><hr />\n";
flush();
}
} else {
echo "<p>" . T_('API Error: cannot connect to SoundCloud.') . "</p><hr />\n";
flush();
}
}
catch (Exception $ex) {
echo "<p>" . T_('SoundCloud exception: ') . $ex->getMessage() . "</p><hr />\n";
}
return true;
}
public function verify_catalog_proc()
{
return array('total' => 0, 'updated' => 0);
}
/**
* clean_catalog_proc
*
* Removes songs that no longer exist.
*/
public function clean_catalog_proc()
{
$dead = 0;
try {
$api = $this->createClient();
if ($api != null) {
$sql = 'SELECT `id`, `file` FROM `song` WHERE `catalog` = ?';
$db_results = Dba::read($sql, array($this->id));
while ($row = Dba::fetch_assoc($db_results)) {
debug_event('soundcloud-clean', 'Starting work on ' . $row['file'] . '(' . $row['id'] . ')', 5, 'ampache-catalog');
$remove = false;
try {
$track = $this->url_to_track($row['file']);
$song = json_decode($api->get('tracks/' . $track));
if ($song->user_favorite != true) {
$remove = true;
}
} catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) {
if ($e->getHttpCode() == '404') {
$remove = true;
} else {
debug_event('soundcloud-clean', 'Clean error: ' . $e->getMessage(), 5, 'ampache-catalog');
}
} catch (Exception $e) {
debug_event('soundcloud-clean', 'Clean error: ' . $e->getMessage(), 5, 'ampache-catalog');
}
if (!$remove) {
debug_event('soundcloud-clean', 'keeping song', 5, 'ampache-catalog');
} else {
debug_event('soundcloud-clean', 'removing song', 5, 'ampache-catalog');
$dead++;
Dba::write('DELETE FROM `song` WHERE `id` = ?', array($row['id']));
}
}
} else {
echo "<p>" . T_('API Error: cannot connect to SoundCloud.') . "</p><hr />\n";
flush();
}
}
catch (Exception $ex) {
echo "<p>" . T_('SoundCloud exception: ') . $ex->getMessage() . "</p><hr />\n";
}
return $dead;
}
public function url_to_track($url)
{
$track = 0;
preg_match('/tracks\/([0-9]*)\/stream/', $url, $matches);
if (count($matches)) {
$track = $matches[1];
}
return $track;
}
public function get_rel_path($file_path)
{
return $file_path;
}
/**
* check_remote_song
*
* checks to see if a remote song exists in the database or not
* if it find a song it returns the UID
*/
public function check_remote_song($song)
{
$url = $song['file'];
$sql = 'SELECT `id` FROM `song` WHERE `file` = ?';
$db_results = Dba::read($sql, array($url));
if ($results = Dba::fetch_assoc($db_results)) {
return $results['id'];
}
return false;
}
/**
* format
*
* This makes the object human-readable.
*/
public function format()
{
parent::format();
$this->f_info = UI::truncate($this->userid, Config::get('ellipse_threshold_title'));
}
public function prepare_media($media)
{
try {
$api = $this->createClient();
if ($api != null) {
$track = $this->url_to_track($media->file);
debug_event('play', 'Starting stream - ' . $track, 5);
$headers = $api->stream($track);
if (isset($headers['Location'])) {
header('Location: ' . $headers['Location']);
debug_event('play', 'Started remote stream - ' . $headers['Location'], 5);
} else {
debug_event('play', 'Cannot get remote stream for song ' . $media->file, 5);
}
} else {
echo "<p>" . T_('API Error: cannot connect to SoundCloud.') . "</p><hr />\n";
flush();
}
}
catch (Exception $ex) {
echo "<p>" . T_('SoundCloud exception: ') . $ex->getMessage() . "</p><hr />\n";
}
return null;
}
} // end of catalog class

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,146 @@
<?php
/**
* Soundcloud missing client id exception.
*
* @category Services
* @package Services_Soundcloud
* @author Anton Lindqvist <anton@qvister.se>
* @copyright 2010 Anton Lindqvist <anton@qvister.se>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://github.com/mptre/php-soundcloud
*/
class Services_Soundcloud_Missing_Client_Id_Exception extends Exception {
/**
* Default message.
*
* @access protected
*
* @var string
*/
protected $message = 'All requests must include a consumer key. Referred to as client_id in OAuth2.';
}
/**
* Soundcloud invalid HTTP response code exception.
*
* @category Services
* @package Services_Soundcloud
* @author Anton Lindqvist <anton@qvister.se>
* @copyright 2010 Anton Lindqvist <anton@qvister.se>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://github.com/mptre/php-soundcloud
*/
class Services_Soundcloud_Invalid_Http_Response_Code_Exception extends Exception {
/**
* HTTP response body.
*
* @access protected
*
* @var string
*/
protected $httpBody;
/**
* HTTP response code.
*
* @access protected
*
* @var integer
*/
protected $httpCode;
/**
* Default message.
*
* @access protected
*
* @var string
*/
protected $message = 'The requested URL responded with HTTP code %d.';
/**
* Constructor.
*
* @param string $message
* @param string $code
* @param string $httpBody
* @param integer $httpCode
*
* @return void
*/
function __construct($message = null, $code = 0, $httpBody = null, $httpCode = 0) {
$this->httpBody = $httpBody;
$this->httpCode = $httpCode;
$message = sprintf($this->message, $httpCode);
parent::__construct($message, $code);
}
/**
* Get HTTP response body.
*
* @return mixed
*/
function getHttpBody() {
return $this->httpBody;
}
/**
* Get HTTP response code.
*
* @return mixed
*/
function getHttpCode() {
return $this->httpCode;
}
}
/**
* Soundcloud unsupported response format exception.
*
* @category Services
* @package Services_Soundcloud
* @author Anton Lindqvist <anton@qvister.se>
* @copyright 2010 Anton Lindqvist <anton@qvister.se>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://github.com/mptre/php-soundcloud
*/
class Services_Soundcloud_Unsupported_Response_Format_Exception extends Exception {
/**
* Default message.
*
* @access protected
*
* @var string
*/
protected $message = 'The given response format is unsupported.';
}
/**
* Soundcloud unsupported audio format exception.
*
* @category Services
* @package Services_Soundcloud
* @author Anton Lindqvist <anton@qvister.se>
* @copyright 2010 Anton Lindqvist <anton@qvister.se>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://github.com/mptre/php-soundcloud
*/
class Services_Soundcloud_Unsupported_Audio_Format_Exception extends Exception {
/**
* Default message.
*
* @access protected
*
* @var string
*/
protected $message = 'The given audio format is unsupported.';
}

View file

@ -0,0 +1,31 @@
<?php
/**
* Soundcloud package version
*
* @category Services
* @package Services_Soundcloud
* @author Anton Lindqvist <anton@qvister.se>
* @copyright 2010 Anton Lindqvist <anton@qvister.se>
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://github.com/mptre/php-soundcloud
*/
class Services_Soundcloud_Version
{
const MAJOR = 2;
const MINOR = 3;
const PATCH = 2;
/**
* Magic to string method
*
* @return string
*
* @access public
*/
function __toString()
{
return implode('.', array(self::MAJOR, self::MINOR, self::PATCH));
}
}

34
show_get.php Normal file
View file

@ -0,0 +1,34 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
if (isset($_REQUEST['param_name'])) {
$name = $_REQUEST['param_name'];
if (isset($_REQUEST[$name])) {
echo $name . ": ". $_REQUEST[$name];
}
}
if (isset($_REQUEST['error'])) {
$error = $_REQUEST['error'];
$error_description = $_REQUEST['error_description'];
echo $error . " error: " . $error_description;
}

View file

@ -157,7 +157,7 @@ if (Config::get('song_page_title') && $iframed) {
</script> </script>
<?php <?php
if ($i == 1 && count($radios) > 0) { if ($i == 1 && count($radios) > 0) {
// Special stuff for web radio // Special stuff for web radio (to better handle Icecast/Shoutcast metadata ...)
$radio = $radios[0]; $radio = $radios[0];
require_once Config::get('prefix') . '/templates/show_radio_player.inc.php'; require_once Config::get('prefix') . '/templates/show_radio_player.inc.php';
} else { } else {