1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/ampache_ynh.git synced 2024-09-03 18:15:55 +02:00

Merge pull request #6 from aymhce/master

ampache version 3.8.0 with add sql correction
This commit is contained in:
abeudin 2015-07-19 15:42:24 +02:00
commit 051cb40820
1887 changed files with 304106 additions and 59660 deletions

View file

@ -1 +1,107 @@
INSERT INTO user(id,username,fullname,access) VALUES("", "yunoadmin", "yunoadmin", "100"); INSERT INTO user(id,username,fullname,access) VALUES("", "yunoadmin", "yunoadmin", "100");
UPDATE `user_preference` SET `value` = 'fr_FR' WHERE `preference` = 31 ;
SET @lastid = LAST_INSERT_ID();
INSERT INTO `user_preference` (`user`, `preference`, `value`) VALUES
(@lastid, 1, '1'),
(@lastid, 4, '10'),
(@lastid, 19, '32'),
(@lastid, 22, 'Ampache :: For the love of Music'),
(@lastid, 23, '0'),
(@lastid, 24, '0'),
(@lastid, 25, '80'),
(@lastid, 41, 'mpd'),
(@lastid, 29, 'web_player'),
(@lastid, 31, 'fr_FR'),
(@lastid, 32, 'm3u'),
(@lastid, 33, 'reborn'),
(@lastid, 34, '27'),
(@lastid, 35, '27'),
(@lastid, 36, '27'),
(@lastid, 51, '50'),
(@lastid, 40, '100'),
(@lastid, 44, '1'),
(@lastid, 45, '1'),
(@lastid, 46, '1'),
(@lastid, 47, '7'),
(@lastid, 49, '1'),
(@lastid, 52, '8192'),
(@lastid, 53, 'default'),
(@lastid, 55, 'default'),
(@lastid, 57, ''),
(@lastid, 69, '0'),
(@lastid, 70, '0'),
(@lastid, 71, '0'),
(@lastid, 72, '0'),
(@lastid, 73, ''),
(@lastid, 74, ''),
(@lastid, 75, ''),
(@lastid, 76, ''),
(@lastid, 77, ''),
(@lastid, 78, ''),
(@lastid, 114, '1'),
(@lastid, 113, '0'),
(@lastid, 112, '-1'),
(@lastid, 111, '1'),
(@lastid, 110, '0'),
(@lastid, 109, '0'),
(@lastid, 108, '0'),
(@lastid, 107, '0'),
(@lastid, 106, '0'),
(@lastid, 105, '0'),
(@lastid, 104, '0'),
(@lastid, 103, '7'),
(@lastid, 102, '0'),
(@lastid, 101, '0'),
(@lastid, 100, '1'),
(@lastid, 99, '0'),
(@lastid, 95, '1'),
(@lastid, 94, '0'),
(@lastid, 93, '1'),
(@lastid, 92, '1'),
(@lastid, 91, '1'),
(@lastid, 90, '1'),
(@lastid, 89, '1'),
(@lastid, 88, '1'),
(@lastid, 87, '0'),
(@lastid, 86, '1'),
(@lastid, 85, '1'),
(@lastid, 84, '0'),
(@lastid, 83, '0'),
(@lastid, 79, '50'),
(@lastid, 80, '50'),
(@lastid, 82, '1'),
(@lastid, 81, '1'),
(@lastid, 115, '0'),
(@lastid, 116, ''),
(@lastid, 117, '1'),
(@lastid, 118, '0'),
(@lastid, 119, ''),
(@lastid, 120, '0'),
(@lastid, 121, '1'),
(@lastid, 122, '1'),
(@lastid, 123, '1'),
(@lastid, 124, '0'),
(@lastid, 125, '1'),
(@lastid, 126, '1'),
(@lastid, 127, '1'),
(@lastid, 128, '1'),
(@lastid, 129, ''),
(@lastid, 130, 'album,ep,live,single'),
(@lastid, 131, '1'),
(@lastid, 132, '10'),
(@lastid, 133, '0'),
(@lastid, 134, '1'),
(@lastid, 135, '1'),
(@lastid, 136, ''),
(@lastid, 137, ''),
(@lastid, 138, ''),
(@lastid, 139, '0'),
(@lastid, 140, '0'),
(@lastid, 96, ''),
(@lastid, 97, ''),
(@lastid, 98, '');

View file

@ -7,19 +7,19 @@
; if this config file is up to date ; if this config file is up to date
; this is compared against a value hard-coded ; this is compared against a value hard-coded
; into the init script ; into the init script
config_version = 16 config_version = 29
;################### ;###################
; Path Vars # ; Path Vars #
;################### ;###################
; The http host of your server. ; The public http host of your server.
; If not set, retrieved automatically from client request. ; If not set, retrieved automatically from client request.
; This setting is required for WebSocket server ; This setting is required for WebSocket server
; DEFAULT: "" ; DEFAULT: ""
http_host = "DOMAINTOCHANGE" http_host = "DOMAINTOCHANGE"
; The path to your ampache install ; The public path to your ampache install
; Do not put a trailing / on this path ; Do not put a trailing / on this path
; For example if your site is located at http://localhost ; For example if your site is located at http://localhost
; than you do not need to enter anything for the web_path ; than you do not need to enter anything for the web_path
@ -28,17 +28,23 @@ http_host = "DOMAINTOCHANGE"
; DEFAULT: "" ; DEFAULT: ""
web_path = "PATHTOCHANGE" web_path = "PATHTOCHANGE"
; The local http url of your server.
; If not set, retrieved automatically from server information.
; DEFAULT: ""
;local_web_path = "http://localhost/ampache"
;############################## ;##############################
; Session and Login Variables # ; Session and Login Variables #
;############################## ;##############################
; Hostname of your database ; Hostname of your database
; For socket authentication, set the path to socket file (e.g. /var/run/mysqld/mysqld.sock)
; DEFAULT: localhost ; DEFAULT: localhost
database_hostname = "localhost" database_hostname = "localhost"
; Port to use when connecting to your database ; Port to use when connecting to your database
; DEFAULT: none ; DEFAULT: none
;database_port = 3306 database_port = ""
; Name of your ampache database ; Name of your ampache database
; DEFAULT: ampache ; DEFAULT: ampache
@ -50,42 +56,46 @@ database_username = "yunouser"
; Password for your ampache database, this can not be blank ; Password for your ampache database, this can not be blank
; this is a 'forced' security precaution, the default value ; this is a 'forced' security precaution, the default value
; will not work ; will not work (except if using socket authentication)
; DEFAULT: "" ; DEFAULT: ""
database_password = "yunopass" database_password = "yunopass"
; Cryptographic secret
; This MUST BE changed with your own secret key. Ampache-specific, just pick any random string you want.
secret_key = "abcdefghijklmnoprqstuvwyz0123456"
; Length that a session will last expressed in seconds. Default is ; Length that a session will last expressed in seconds. Default is
; one hour. ; one hour.
; DEFAULT: 3600 ; DEFAULT: 3600
session_length = "3600" session_length = 3600
; Length that the session for a single streaming instance will last ; Length that the session for a single streaming instance will last
; the default is two hours. With some clients, and long songs this can ; the default is two hours. With some clients, and long songs this can
; cause playback to stop, increase this value if you experience that ; cause playback to stop, increase this value if you experience that
; DEFAULT: 7200 ; DEFAULT: 7200
stream_length = "7200" stream_length = 7200
; This length defines how long a 'remember me' session and cookie will ; This length defines how long a 'remember me' session and cookie will
; last, the default is 7200, same as length. It is up to the administrator ; last, the default is 86400, same as length. It is up to the administrator
; of the box to increase this, for reference 86400 = 1 day ; of the box to increase this, for reference 86400 = 1 day,
; 604800 = 1 week and 2419200 = 1 month ; 604800 = 1 week, and 2419200 = 1 month
; DEFAULT: 86400 ; DEFAULT: 604800
remember_length = "86400" remember_length = 604800
; Name of the Session/Cookie that will sent to the browser ; Name of the Session/Cookie that will sent to the browser
; default should be fine ; default should be fine
; DEFAULT: ampache ; DEFAULT: ampache
session_name = "ampache" session_name = ampache
; Lifetime of the Cookie, 0 == Forever (until browser close) , otherwise in terms of seconds ; Lifetime of the Cookie, 0 == Forever (until browser close) , otherwise in terms of seconds
; If you want cookies to last past a browser close set this to a value in seconds. ; If you want cookies to last past a browser close set this to a value in seconds.
; DEFAULT: 0 ; DEFAULT: 0
session_cookielife = "0" session_cookielife = 0
; Is the cookie a "secure" cookie? This should only be set to 1 (true) if you are ; Is the cookie a "secure" cookie? This should only be set to 1 (true) if you are
; running a secure site (HTTPS). ; running a secure site (HTTPS).
; DEFAULT: 0 ; DEFAULT: 0
session_cookiesecure = "1" session_cookiesecure = 0
; Auth Methods ; Auth Methods
; This defines which auth methods Auth will attempt to use and in which order. ; This defines which auth methods Auth will attempt to use and in which order.
@ -120,15 +130,15 @@ logout_redirect = "https://DOMAINTOCHANGE/yunohost/sso/?action=logout"
; This defines which file types Ampache will attempt to catalog ; This defines which file types Ampache will attempt to catalog
; You can specify any file extension you want in here separating them ; You can specify any file extension you want in here separating them
; with a | ; with a |
; DEFAULT: mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv ; DEFAULT: mp3|mpc|m4p|m4a|aac|ogg|oga|wav|aif|aiff|rm|wma|asf|flac|opus|spx|ra|ape|shn|wv
catalog_file_pattern = "mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv" catalog_file_pattern = "mp3|mpc|m4p|m4a|aac|ogg|oga|wav|aif|aiff|rm|wma|asf|flac|opus|spx|ra|ape|shn|wv"
; Video Pattern ; Video Pattern
; This defines which video file types Ampache will attempt to catalog ; This defines which video file types Ampache will attempt to catalog
; You can specify any file extension you want in here seperating them with ; You can specify any file extension you want in here seperating them with
; a | but ampache may not be able to parse them ; a | but ampache may not be able to parse them
; DEAFULT: avi|mpg|flv|m4v|webm ; DEAFULT: avi|mpg|mpeg|flv|m4v|mp4|webm|mkv|wmv|ogv|mov|divx|m2ts
catalog_video_pattern = "avi|mpg|flv|m4v|webm" catalog_video_pattern = "avi|mpg|mpeg|flv|m4v|mp4|webm|mkv|wmv|ogv|mov|divx|m2ts"
; Playlist Pattern ; Playlist Pattern
; This defines which playlist types Ampache will attempt to catalog ; This defines which playlist types Ampache will attempt to catalog
@ -155,7 +165,7 @@ catalog_prefix_pattern = "The|An|A|Die|Das|Ein|Eine|Les|Le|La"
; will not work without this on. ; will not work without this on.
; NOTE: Default Behavior is DENY FROM ALL ; NOTE: Default Behavior is DENY FROM ALL
; DEFAULT: true ; DEFAULT: true
access_control = "true" access_control = "true"
; Require Session ; Require Session
; If this is set to true ampache will make sure that the URL passed when ; If this is set to true ampache will make sure that the URL passed when
@ -208,12 +218,13 @@ require_localnet_session = "true"
; DEFAULT: false ; DEFAULT: false
;allow_zip_download = "false" ;allow_zip_download = "false"
; File Zip Download Allow Zip Types
; This settings tells Ampache to attempt to save the zip file ; This setting allows/disallows zip download of specific object types
; to the filesystem instead of creating it in memory, you must ; If empty, all supported object types can be zipped.
; also set tmp_dir_path in order for this to work ; Otherwise, only the given object list can be zipped.
; DEFAULT: false ; POSSIBLE VALUES: artist, album, playlist, search, tmp_playlist
;file_zip_download = "false" ; DEFAULT: none
;allow_zip_types = "album"
; File Zip Comment ; File Zip Comment
; This is an optional configuration option that adds a comment ; This is an optional configuration option that adds a comment
@ -234,7 +245,7 @@ require_localnet_session = "true"
;waveform_color = "#FF0000" ;waveform_color = "#FF0000"
; Temporary Directory Path ; Temporary Directory Path
; If File Zip Download or Waveform is enabled this must be set to tell ; If Waveform is enabled this must be set to tell
; Ampache which directory to save the temporary file to. Do not put a ; Ampache which directory to save the temporary file to. Do not put a
; trailing slash or this will not work. ; trailing slash or this will not work.
; DEFAULT: false ; DEFAULT: false
@ -261,13 +272,52 @@ getid3_tag_order = "id3v2,id3v1,vorbiscomment,quicktime,matroska,ape,asf,avi,mpe
; DEFAULT: false ; DEFAULT: false
;getid3_detect_id3v2_encoding = "false" ;getid3_detect_id3v2_encoding = "false"
; This determines if file metadata should be write back to files
; as id3 metadata when updated.
; DEFAULT: false
;write_id3 = "false"
; This determines if album art should be write back to files
; as id3 metadata when updated.
; DEFAULT: false
;write_id3_art = "false"
; This determines if catalog manager users can delete medias from disk.
; DEFAULT: false
;delete_from_disk = "false"
; This determines the order in which metadata sources are used (and in the ; This determines the order in which metadata sources are used (and in the
; case of plugins, checked) ; case of plugins, checked)
; POSSIBLE VALUES (builtins): filename and getID3 ; POSSIBLE VALUES (builtins): filename and getID3
; POSSIBLE VALUES (plugins): MusicBrainz, plus any others you've installed. ; POSSIBLE VALUES (plugins): MusicBrainz,TheAudioDb, plus any others you've installed.
; DEFAULT: getID3 filename ; DEFAULT: getID3 filename
metadata_order = "getID3,filename" metadata_order = "getID3,filename"
; This determines the order in which metadata sources are used (and in the
; case of plugins, checked) for video files
; POSSIBLE VALUES (builtins): filename and getID3
; POSSIBLE VALUES (plugins): Tvdb,Tmdb,Omdb, plus any others you've installed.
; DEFAULT: filename getID3
metadata_order_video = "filename,getID3"
; This determines if extended metadata grabbed from external services should be deferred.
; If enabled, extended metadata is retrieved when browsing the library item.
; If disabled, extended metadata is retrieved at catalog update.
; Today, only Artist information (summary, place formed, ...) can be deferred.
; DEFAULT: true
deferred_ext_metadata = "true"
; Some taggers use delimiters other than \0 for fields
; This list specifies possible delimiters additional to \0
; This setting takes a regex pattern.
; DEFAULT: // / \ | , ;
additional_genre_delimiters = "[/]{2}|[/|\\\\|\|,|;]"
; This determines if a preview image should be retrieved from video files
; It requires encode_get_image transcode settings.
; DEFAULT: false
;generate_video_preview = "true"
; Un comment if don't want ampache to follow symlinks ; Un comment if don't want ampache to follow symlinks
; DEFAULT: false ; DEFAULT: false
;no_symlinks = "false" ;no_symlinks = "false"
@ -284,9 +334,9 @@ use_auth = "true"
; If use_auth is set to false then this option is used ; If use_auth is set to false then this option is used
; to determine the permission level of the 'default' users ; to determine the permission level of the 'default' users
; default is administrator. This setting only takes affect ; default is administrator. This setting only takes affect
; if use_auth if false ; if use_auth is false
; POSSIBLE VALUES: user, admin, manager, guest ; POSSIBLE VALUES: user, admin, manager, guest
; DEFAULT: admin ; DEFAULT: guest
default_auth_level = "user" default_auth_level = "user"
; 5 Star Ratings ; 5 Star Ratings
@ -295,8 +345,8 @@ default_auth_level = "user"
; DEFAULT: true ; DEFAULT: true
ratings = "true" ratings = "true"
; User flags ; User flags/favorites
; This allows user flags for almost any object in ampache ; This allows user flags for almost any object in ampache as favorite
; POSSIBLE VALUES: false true ; POSSIBLE VALUES: false true
; DEFAULT: true ; DEFAULT: true
userflags = "true" userflags = "true"
@ -314,10 +364,10 @@ directplay = "true"
; DEFAULT: true ; DEFAULT: true
sociable = "true" sociable = "true"
; Notify ; License
; This turns on / off all Ampache notifications ; This turns on / off all licensing features on Ampache
; DEFAULT: true ; DEFAULT: false
notify = "true" licensing = "false"
; This options will turn on/off Demo Mode ; This options will turn on/off Demo Mode
; If Demo mode is on you can not play songs or update your catalog ; If Demo mode is on you can not play songs or update your catalog
@ -349,6 +399,42 @@ memory_cache = "true"
; DEFAULT: folder.jpg ; DEFAULT: folder.jpg
;album_art_preferred_filename = "folder.jpg" ;album_art_preferred_filename = "folder.jpg"
; Album Art Store on Disk
; This defines if arts should be stored on disk instead of database.
; DEFAULT: false
;album_art_store_disk = "false"
; Local Metadata Directory
; This define a local metadata directory with write access where to store
; heavy data if enabled (album arts, ...)
; DEFAULT: none
;local_metadata_dir = "/metadata"
; Maximal upload size
; Specify the maximal allowed upload size for images, in bytes.
; DEFAULT: 1048576
;max_upload_size = 1048576
; Album Art Minimum Width
; Specify the minimum width for arts (in pixel).
; DEFAULT: none
;album_art_min_width = 100
; Album Art Maximum Width
; Specify the maximum width for arts (in pixel).
; DEFAULT: none
;album_art_max_width = 1024
; Album Art Minimum Height
; Specify the minimum height for arts (in pixel).
; DEFAULT: none
;album_art_min_height = 100
; Album Art Maximum Height
; Specify the maximum height for arts (in pixel).
; DEFAULT: none
;album_art_max_height = 1024
; Resize Images * Requires PHP-GD * ; Resize Images * Requires PHP-GD *
; Set this to true if you want Ampache to resize the Album ; Set this to true if you want Ampache to resize the Album
; art on the fly, this increases load time and CPU usage ; art on the fly, this increases load time and CPU usage
@ -357,24 +443,23 @@ memory_cache = "true"
; DEFAULT: false ; DEFAULT: false
;resize_images = "false" ;resize_images = "false"
; Statistical Graphs * Requires PHP-GD *
; Set this to true if you want Ampache to generate statistical
; graphs on usages / users.
; DEFAULT: false
;statistical_graphs = "false"
; Art Gather Order ; Art Gather Order
; Simply arrange the following in the order you would like ; Simply arrange the following in the order you would like
; ampache to search. If you want to disable one of the search ; ampache to search. If you want to disable one of the search
; methods simply leave it out. DB should be left as the first ; methods simply leave it out. DB should be left as the first
; method unless you want it to overwrite what's already in the ; method unless you want it to overwrite what's already in the
; database ; database
; POSSIBLE VALUES: db tags folder amazon lastfm musicbrainz google ; POSSIBLE VALUES (builtins): db tags folder lastfm musicbrainz google
; POSSIBLE VALUES (plugins): Amazon,TheAudioDb,Tmdb,Omdb,Flickr
; DEFAULT: db,tags,folder,musicbrainz,lastfm,google ; DEFAULT: db,tags,folder,musicbrainz,lastfm,google
art_order = "db,tags,folder,musicbrainz,lastfm,google" art_order = "db,tags,folder,musicbrainz,lastfm,google"
; Amazon Developer Key
; These are needed in order to actually use the amazon album art
; Your public key is your 'Access Key ID'
; Your private key is your 'Secret Access Key'
; DEFAULT: false
;amazon_developer_public_key = ""
;amazon_developer_private_key = ""
; Recommendations ; Recommendations
; Set this to true to enable display of similar artists or albums ; Set this to true to enable display of similar artists or albums
; while browsing. Requires Last.FM. ; while browsing. Requires Last.FM.
@ -389,14 +474,14 @@ art_order = "db,tags,folder,musicbrainz,lastfm,google"
; Last.FM API Key ; Last.FM API Key
; Set this to your Last.FM api key to actually use Last.FM for ; Set this to your Last.FM api key to actually use Last.FM for
; recommendations. ; recommendations and metadata.
;lastfm_api_key = "" lastfm_api_key = "d5df942424c71b754e54ce1832505ae2"
; Wanted ; Wanted
; Set this to true to enable display missing albums and the ; Set this to true to enable display missing albums and the
; possibility for users to mark it as wanted. ; possibility for users to mark it as wanted.
; DEFAULT: false ; DEFAULT: false
;wanted = "false" wanted = "true"
; Wanted types ; Wanted types
; Set the allowed types of wanted releases (album,compilation,single,ep,live,remix,promotion,official) ; Set the allowed types of wanted releases (album,compilation,single,ep,live,remix,promotion,official)
@ -412,47 +497,38 @@ wanted_types = "album,official"
; EchoNest provides several music services. Currently used for missing song 30 seconds preview. ; EchoNest provides several music services. Currently used for missing song 30 seconds preview.
;echonest_api_key = "" ;echonest_api_key = ""
; Labels
; Use labels to browse artists per label membership.
; DEFAULT: false
;label = "false"
; Broadcasts ; Broadcasts
; Allow users to broadcast music. ; Allow users to broadcast music.
; This feature requires advanced server configuration, please take a look on the wiki for more information. ; This feature requires advanced server configuration, please take a look on the wiki for more information.
; DEFAULT: false ; DEFAULT: false
;broadcast = "false" ;broadcast = "false"
; Channels
; Set this to true to enable channels and the
; possibility for users to create channels from playlists
; DEFAULT: true
channel = "true"
; Live Streams
; Set this to true to enable live streams (radio) and the
; possibility for users to add new live streams.
; DEFAULT: true
live_stream = "true"
; Web Socket address ; Web Socket address
; Declare the web socket server address ; Declare the web socket server address
; DEFAULT: determined automatically ; DEFAULT: determined automatically
;websocket_address = "ws://localhost:8100" ;websocket_address = "ws://localhost:8100"
; Amazon base urls
; An array of Amazon sites to search.
; NOTE: This will search each of these sites in turn so don't expect it
; to be lightning fast!
; It is strongly recommended that only one of these is selected at any
; one time
; POSSIBLE VALUES:
; http://webservices.amazon.com
; http://webservices.amazon.co.uk
; http://webservices.amazon.de
; http://webservices.amazon.co.jp
; http://webservices.amazon.fr
; http://webservices.amazon.ca
; Default: http://webservices.amazon.com
;amazon_base_urls = "http://webservices.amazon.com"
; max_amazon_results_pages
; The maximum number of results pages to pull from EACH amazon site
; NOTE: The art search pages through the results returned by your search
; up to this number of pages. As with the base_urls above, this is going
; to take more time, the more pages you ask it to process.
; Of course a good search will return only a few matches anyway.
; It is strongly recommended that you do _not_ change this value
; DEFAULT: 1 page (10 items)
max_amazon_results_pages = "1"
; Debug ; Debug
; If this is enabled Ampache will write debugging information to the log file ; If this is enabled Ampache will write debugging information to the log file
; DEFAULT: false ; DEFAULT: false
debug = "true" ;debug = "false"
; Debug Level ; Debug Level
; This should always be set in conjunction with the ; This should always be set in conjunction with the
@ -464,7 +540,7 @@ debug = "true"
; 4 == ?? (Profit!) ; 4 == ?? (Profit!)
; 5 == Information (cataloging progress etc.) ; 5 == Information (cataloging progress etc.)
; DEFAULT: 5 ; DEFAULT: 5
debug_level = "5" debug_level = 5
; Path to Log File ; Path to Log File
; This defines where you want ampache to log events to ; This defines where you want ampache to log events to
@ -487,13 +563,12 @@ log_filename = "%name.%Y%m%d.log"
site_charset = "UTF-8" site_charset = "UTF-8"
; Locale Charset ; Locale Charset
; In some cases this has to be different ; Local charset (mainly for file operations) if different
; in order for XHTML and other things to work ; from site_charset.
; This is disabled by default, enabled only ; This is disabled by default, enable only if needed
; if needed. It's specifically needed for Russian ; (for Windows please set lc_charset to ISO8859-1)
; so that is the default ; DEFAULT: ISO8859-1
; DEFAULT: cp1251 ;lc_charset = "ISO8859-1"
;lc_charset = cp1251
; Refresh Limit ; Refresh Limit
; This defines the default refresh limit in seconds for ; This defines the default refresh limit in seconds for
@ -502,6 +577,13 @@ site_charset = "UTF-8"
; Possible Values: Int > 5 ; Possible Values: Int > 5
refresh_limit = "60" refresh_limit = "60"
; Footer Statistics
; This defines whether statistics (Queries, Cache Hits, Load Time)
; are shown in the page footer.
; DEFAULT: true
; Possible values: true, false
show_footer_statistics = "true"
;######################################################### ;#########################################################
; Custom actions (optional) # ; Custom actions (optional) #
;######################################################### ;#########################################################
@ -531,7 +613,7 @@ refresh_limit = "60"
; For OpenLDAP use "uid" ; For OpenLDAP use "uid"
; For Microsoft Active Directory (MAD) use "sAMAccountName" ; For Microsoft Active Directory (MAD) use "sAMAccountName"
; DEFAULT: null ; DEFAULT: null
; ldap_filter = "sAMAccountName" ;ldap_filter = "(sAMAccountName=%v)"
; LDAP objectclass (required) ; LDAP objectclass (required)
; OpanLDAP objectclass = "*" ; OpanLDAP objectclass = "*"
@ -561,7 +643,7 @@ ldap_url = "localhost"
; MAD ldap_name_field = "displayname" ; MAD ldap_name_field = "displayname"
; DEFAULT: null ; DEFAULT: null
;ldap_email_field = "mail" ;ldap_email_field = "mail"
ldap_name_field = "cn" ldap_name_field = "cn"
;######################################################### ;#########################################################
; OpenID login info (optional) # ; OpenID login info (optional) #
@ -616,11 +698,33 @@ auto_create = "true"
auto_user = "user" auto_user = "user"
; This will display the user agreement when registering ; This will display the user agreement when registering
; For agreement text, edit templates/user_agreement.php ; For agreement text, edit config/registration_agreement.php
; User will need to accept the agreement before they can register ; User will need to accept the agreement before they can register
; DEFAULT: false ; DEFAULT: false
;user_agreement = "false" ;user_agreement = "false"
; This disable email confirmation when registering.
; DEFAULT: false
;user_no_email_confirm = "false"
; This will display the cookie disclaimer (EU Cookie Law)
; DEFAULT: false
cookie_disclaimer = "false"
; The fields that will be shown on Registration page
; If a user wants to register.
; Username and email fields are forced.
; POSSIBLE VALUES: fullname,website,state,city
; DEFAULT: "fullname,website"
registration_display_fields = "fullname,website"
; The fields that will be mandatory
; This controls which fields are mandatory for registration.
; Username and email fields are forced mandatory.
; POSSIBLE VALUES: fullname,website,state,city
; DEFAULT: fullname
registration_mandatory_fields = "fullname"
;######################################################## ;########################################################
; These options control the dynamic downsampling based # ; These options control the dynamic downsampling based #
; on current usage # ; on current usage #
@ -658,23 +762,75 @@ min_bit_rate = 48
; (e.g. if you store everything in FLAC, but don't want to ever stream that.) ; (e.g. if you store everything in FLAC, but don't want to ever stream that.)
; transcode_TYPE = {allowed|required|false} ; transcode_TYPE = {allowed|required|false}
; DEFAULT: false ; DEFAULT: false
;transcode_m4a = allowed ;;; Audio
transcode_m4a = required
transcode_flac = required transcode_flac = required
;transcode_mpc = required transcode_mpc = required
transcode_ogg = required
transcode_oga = required
transcode_wav = required
transcode_wma = required
transcode_aif = required
transcode_aiff = required
transcode_ape = required
transcode_shn = required
transcode_mp3 = allowed transcode_mp3 = allowed
;;; Video
transcode_avi = allowed
transcode_mkv = allowed
transcode_mpg = allowed
transcode_mpeg = allowed
transcode_m4v = allowed
transcode_mp4 = allowed
transcode_mov = allowed
transcode_wmv = allowed
transcode_ogv = allowed
transcode_divx = allowed
transcode_m2ts = allowed
transcode_webm = allowed
; Default output format ; Default audio output format
; DEFAULT: none ; DEFAULT: none
encode_target = mp3 encode_target = mp3
; Default video output format
; DEFAULT: none
encode_video_target = webm
; Override the default output format on a per-type basis ; Override the default output format on a per-type basis
; encode_target_TYPE = TYPE ; encode_target_TYPE = TYPE
; DEFAULT: none ; DEFAULT: none
; encode_target_flac = ogg encode_target_flac = ogg
; Override the default TYPE transcoding behavior on a per-player basis
; transcode_player_PLAYER_TYPE = TYPE
; Valid PLAYER is: webplayer, api
; DEFAULT: none
transcode_player_webplayer_m4a = required
;transcode_player_webplayer_flac = required
;transcode_player_webplayer_mpc = required
transcode_player_webplayer_avi = required
transcode_player_webplayer_mkv = required
transcode_player_webplayer_mpg = required
transcode_player_webplayer_mpeg = required
transcode_player_webplayer_m4v = required
transcode_player_webplayer_mp4 = required
transcode_player_webplayer_mov = required
transcode_player_webplayer_wmv = required
transcode_player_webplayer_ogv = required
transcode_player_webplayer_divx = required
transcode_player_webplayer_m2ts = required
; Override the default output format on a per-player basis
; encode_player_PLAYER_target = TYPE
; Valid PLAYER is: webplayer, api
; DEFAULT: none
;encode_player_webplayer_target = mp3
;encode_player_api_target = mp3
; Allow clients to override transcode settings (output type, bitrate, codec ...) ; Allow clients to override transcode settings (output type, bitrate, codec ...)
; DEFAULT: true ; DEFAULT: true
transcode_player_customize = "1" transcode_player_customize = "true"
; Command configuration. Substitutions will be made as follows: ; Command configuration. Substitutions will be made as follows:
; %FILE% => filename ; %FILE% => filename
@ -688,9 +844,12 @@ transcode_player_customize = "1"
; equivalent to the old default, but if you find that necessary you should be ; equivalent to the old default, but if you find that necessary you should be
; clever enough to figure out how on your own. ; clever enough to figure out how on your own.
; DEFAULT: none ; DEFAULT: none
;transcode_cmd = "ffmpeg -i %FILE%" ;transcode_cmd = "ffmpeg"
transcode_cmd = "ffmpeg -i %FILE%" transcode_cmd = "avconv"
;transcode_cmd = "/usr/bin/neatokeen %FILE%" ;transcode_cmd = "/usr/bin/neatokeen"
; Transcode input file argument
transcode_input = "-i %FILE%"
; Specific transcode commands ; Specific transcode commands
; It shouldn't be necessary in most cases, but you can override the transcode ; It shouldn't be necessary in most cases, but you can override the transcode
@ -698,20 +857,33 @@ transcode_cmd = "ffmpeg -i %FILE%"
; encoding arguments, so the easiest approach is to use your normal command as ; encoding arguments, so the easiest approach is to use your normal command as
; a clearing-house. ; a clearing-house.
; transcode_cmd_TYPE = TRANSCODE_CMD ; transcode_cmd_TYPE = TRANSCODE_CMD
;transcode_cmd_mid = "timidity -Or -o – %FILE% | ffmpeg -f s16le -i pipe:0" ;transcode_cmd_mid = "timidity -Or -o %FILE% | ffmpeg -f s16le -i pipe:0"
; Encoding arguments ; Encoding arguments
; For each output format, you should provide the necessary arguments for ; For each output format, you should provide the necessary arguments for
; your transcode_cmd. ; your transcode_cmd.
; encode_args_TYPE = TRANSCODE_CMD_ARGS ; encode_args_TYPE = TRANSCODE_CMD_ARGS
;encode_args_mp3 = "-vn -b:a %SAMPLE%K -c:a libmp3lame -f mp3 pipe:1" encode_args_mp3 = "-vn -b:a %SAMPLE%K -c:a libmp3lame -f mp3 pipe:1"
;encode_args_ogg = "-vn -b:a %SAMPLE%K -c:a libvorbis -f ogg pipe:1" encode_args_ogg = "-vn -b:a %SAMPLE%K -c:a libvorbis -f ogg pipe:1"
;encode_args_m4a = "-vn -b:a %SAMPLE%K -c:a libfdk_aac -f adts pipe:1" encode_args_m4a = "-vn -b:a %SAMPLE%K -c:a libfdk_aac -f adts pipe:1"
;encode_args_wav = "-vn -b:a %SAMPLE%K -c:a pcm_s16le -f wav pipe:1" encode_args_wav = "-vn -b:a %SAMPLE%K -c:a pcm_s16le -f wav pipe:1"
encode_args_ogg = "-vn -b:a max\(%SAMPLE%K\,49K\) -acodec libvorbis -vcodec libtheora -f ogg pipe:1" encode_args_flv = "-b:a %SAMPLE%K -ar 44100 -ac 2 -v 0 -f flv -c:v libx264 -preset superfast -threads 0 pipe:1"
encode_args_mp3 = "-vn -b:a %SAMPLE%K -acodec libmp3lame -f mp3 pipe:1" encode_args_webm = "-q %QUALITY% -f webm -c:v libvpx -maxrate %MAXBITRATE%k -preset superfast -threads 0 pipe:1"
encode_args_ogv = "-vcodec libtheora -acodec libvorbis -ar 44100 -f ogv pipe:1" ;encode_args_webm = "-q %QUALITY% -f webm -c:v libvpx -maxrate 800k -preset superfast -threads 0 pipe:1"
encode_args_mp4 = "-profile:0 baseline -frag_duration 2 -ar 44100 -f mp4 pipe:1" encode_args_ts = "-q %QUALITY% -s %RESOLUTION% -f mpegts -c:v libx264 -c:a libmp3lame -maxrate %MAXBITRATE%k -preset superfast -threads 0 pipe:1"
; Encoding arguments to retrieve an image from a single frame
encode_get_image = "-ss %TIME% -f image2 -vframes 1 pipe:1"
; Encoding argument to encrust subtitle
encode_srt = "-vf \"subtitles='%SRTFILE%'\""
; Encode segment frame argument
encode_ss_frame = "-ss %TIME%"
; Encode segment duration argument
encode_ss_duration = "-t %DURATION%"
;###################################################### ;######################################################
; these options allow you to configure your rss-feed ; these options allow you to configure your rss-feed
@ -719,7 +891,7 @@ encode_args_mp4 = "-profile:0 baseline -frag_duration 2 -ar 44100 -f mp4 pipe:1"
; song is the information in the feed. can be multiple items. ; song is the information in the feed. can be multiple items.
; use_rss = false (values true | false) ; use_rss = false (values true | false)
;DEFAULT: use_rss = false ;DEFAULT: use_rss = false
;use_rss = false ;use_rss = "false"
;##################################################### ;#####################################################
;############################# ;#############################
@ -735,7 +907,7 @@ encode_args_mp4 = "-profile:0 baseline -frag_duration 2 -ar 44100 -f mp4 pipe:1"
; If Ampache is behind an https reverse proxy, force use HTTPS protocol. ; If Ampache is behind an https reverse proxy, force use HTTPS protocol.
;Default: false ;Default: false
force_ssl = true force_ssl = "true"
;############################# ;#############################
; Mail Settings # ; Mail Settings #
@ -794,7 +966,7 @@ force_ssl = true
;Enable SMTP authentication ;Enable SMTP authentication
;DEFAULT: false ;DEFAULT: false
;mail_auth = true ;mail_auth = "true"
;SMTP Username ;SMTP Username
;your mail auth username. ;your mail auth username.

977
conf/ampache.cfg.php.old Normal file
View file

@ -0,0 +1,977 @@
;#<?php exit(); ?>##
;###################
; General Config #
;###################
; This value is used to detect quickly
; if this config file is up to date
; this is compared against a value hard-coded
; into the init script
config_version = 29
;###################
; Path Vars #
;###################
; The public http host of your server.
; If not set, retrieved automatically from client request.
; This setting is required for WebSocket server
; DEFAULT: ""
http_host = "DOMAINTOCHANGE"
; The public path to your ampache install
; Do not put a trailing / on this path
; For example if your site is located at http://localhost
; than you do not need to enter anything for the web_path
; if it is located at http://localhost/music you need to
; set web_path to /music
; DEFAULT: ""
web_path = "PATHTOCHANGE"
; The local http url of your server.
; If not set, retrieved automatically from server information.
; DEFAULT: ""
;local_web_path = "http://localhost/ampache"
;##############################
; Session and Login Variables #
;##############################
; Hostname of your database
; For socket authentication, set the path to socket file (e.g. /var/run/mysqld/mysqld.sock)
; DEFAULT: localhost
database_hostname = "localhost"
; Port to use when connecting to your database
; DEFAULT: none
;database_port = 3306
; Name of your ampache database
; DEFAULT: ampache
database_name = "yunobase"
; Username for your ampache database
; DEFAULT: ""
database_username = "yunouser"
; Password for your ampache database, this can not be blank
; this is a 'forced' security precaution, the default value
; will not work (except if using socket authentication)
; DEFAULT: ""
database_password = "yunopass"
; Cryptographic secret
; This MUST BE changed with your own secret key. Ampache-specific, just pick any random string you want.
secret_key = "abcdefghijklmnoprqstuvwyz0123456"
; Length that a session will last expressed in seconds. Default is
; one hour.
; DEFAULT: 3600
session_length = "3600"
; Length that the session for a single streaming instance will last
; the default is two hours. With some clients, and long songs this can
; cause playback to stop, increase this value if you experience that
; DEFAULT: 7200
stream_length = "7200"
; This length defines how long a 'remember me' session and cookie will
; last, the default is 86400, same as length. It is up to the administrator
; of the box to increase this, for reference 86400 = 1 day,
; 604800 = 1 week, and 2419200 = 1 month
; DEFAULT: 604800
remember_length = "86400"
; Name of the Session/Cookie that will sent to the browser
; default should be fine
; DEFAULT: ampache
session_name = "ampache"
; Lifetime of the Cookie, 0 == Forever (until browser close) , otherwise in terms of seconds
; If you want cookies to last past a browser close set this to a value in seconds.
; DEFAULT: 0
session_cookielife = "0"
; Is the cookie a "secure" cookie? This should only be set to 1 (true) if you are
; running a secure site (HTTPS).
; DEFAULT: 0
session_cookiesecure = "1"
; Auth Methods
; This defines which auth methods Auth will attempt to use and in which order.
; If auto_create isn't enabled the user must exist locally.
; DEFAULT: mysql
; VALUES: mysql,ldap,http,pam,external,openid
auth_methods = "http,mysql"
; External authentication
; This sets the helper used for external authentication. It should conform to
; the interface used by mod_authnz_external
; DEFAULT: none
;external_authenticator = "/usr/sbin/pwauth"
; Automatic local password updating
; Determines whether successful authentication against an external source
; will result in an update to the password stored in the database.
; A locally stored password is needed for API access.
; DEFAULT: false
;auth_password_save = "false"
; Logout redirection target
; Defaults to our own login.php, but we can override it here if, for instance,
; we want to redirect to an SSO provider instead.
logout_redirect = "https://DOMAINTOCHANGE/yunohost/sso/?action=logout"
;#####################
; Program Settings #
;#####################
; File Pattern
; This defines which file types Ampache will attempt to catalog
; You can specify any file extension you want in here separating them
; with a |
; DEFAULT: mp3|mpc|m4p|m4a|aac|ogg|oga|wav|aif|aiff|rm|wma|asf|flac|opus|spx|ra|ape|shn|wv
catalog_file_pattern = "mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv"
; Video Pattern
; This defines which video file types Ampache will attempt to catalog
; You can specify any file extension you want in here seperating them with
; a | but ampache may not be able to parse them
; DEAFULT: avi|mpg|mpeg|flv|m4v|mp4|webm|mkv|wmv|ogv|mov|divx|m2ts
catalog_video_pattern = "avi|mpg|flv|m4v|webm"
; Playlist Pattern
; This defines which playlist types Ampache will attempt to catalog
; You can specify any file extension you want in here seperating them with
; a | but ampache may not be able to parse them
; DEFAULT: m3u|pls|asx|xspf
catalog_playlist_pattern = "m3u|pls|asx|xspf"
; Prefix Pattern
; This defines which prefix Ampache will ignore when importing tags from
; your music. You may add any prefix you want seperating them with a |
; DEFAULT: The|An|A|Die|Das|Ein|Eine|Les|Le|La
catalog_prefix_pattern = "The|An|A|Die|Das|Ein|Eine|Les|Le|La"
; Catalog disable
; This defines if catalog can be disabled without removing database entries
; WARNING: this increase sensibly sql requests and slow down Ampache a lot
; DEFAULT: false
;catalog_disable = "false"
; Use Access List
; Toggle this on if you want ampache to pay attention to the access list
; and only allow streaming/downloading/api-rpc from known hosts api-rpc
; will not work without this on.
; NOTE: Default Behavior is DENY FROM ALL
; DEFAULT: true
access_control = "true"
; Require Session
; If this is set to true ampache will make sure that the URL passed when
; attempting to retrieve a song contains a valid Session ID This prevents
; others from guessing URL's. This setting is ignored if you have use_auth
; disabled.
; DEFAULT: true
require_session = "true"
; Require LocalNet Session
; If this is set to true then ampache will require that a valid session
; is passed even on hosts defined in the Local Network ACL. This setting
; has no effect if access_control is not enabled
; DEFAULT: true
require_localnet_session = "true"
; Multiple Logins
; Added by Vlet 07/25/07
; When this setting is enabled a user may only be logged in from a single
; IP address at any one time, this is to prevent sharing of accounts
; DEFAULT: false
;prevent_multiple_logins = "false"
; Downsample Remote
; If this is set to true and access control is on any users who are not
; coming from a defined 'network' ACL will be automatically downsampled
; regardless of their preferences. Requires access_control to be enabled
; DEFAULT: false
;downsample_remote = "false"
; Track User IPs
; If this is enabled Ampache will log the IP of every completed login
; it will store user,ip,time at one row per login. The results are
; displayed in Admin --> Users
; DEFAULT: false
;track_user_ip = "false"
; User IP Cardinality
; This defines how many days worth of IP history Ampache will track
; As it is one row per login on high volume sites you will want to
; clear it every now and then.
; DEFAULT: 42 days
;user_ip_cardinality = "42"
; Allow Zip Download
; This setting allows/disallows using zlib to zip up an entire
; playlist/album for download. Even if this is turned on you will
; still need to enabled downloading for the specific user you
; want to be able to use this function
; DEFAULT: false
;allow_zip_download = "false"
Allow Zip Types
; This setting allows/disallows zip download of specific object types
; If empty, all supported object types can be zipped.
; Otherwise, only the given object list can be zipped.
; POSSIBLE VALUES: artist, album, playlist, search, tmp_playlist
; DEFAULT: none
;allow_zip_types = "album"
; File Zip Comment
; This is an optional configuration option that adds a comment
; to your zip files, this only applies if you've got allow_zip_downloads
; DEFAULT: Ampache - Zip Batch Download
;file_zip_comment = "Ampache - Zip Batch Download"
; Waveform
; This settings tells Ampache to attempt to generate a waveform
; for each song. It requires transcode and encode_args_wav settings.
; You must also set tmp_dir_path in order for this to work
; DEFAULT: false
;waveform = "false"
; Waveform color
; The waveform color.
; DEFAULT: #FF0000
;waveform_color = "#FF0000"
; Temporary Directory Path
; If Waveform is enabled this must be set to tell
; Ampache which directory to save the temporary file to. Do not put a
; trailing slash or this will not work.
; DEFAULT: false
;tmp_dir_path = "false"
; This setting throttles a persons downloading to the specified
; bytes per second. This is not a 100% guaranteed function, and
; you should really use a server based rate limiter if you want
; to do this correctly.
; DEFAULT: off
; VALUES: any whole number (in bytes per second)
;throttle_download = 10
; This determines the tag order for all cataloged
; music. If none of the listed tags are found then
; ampache will randomly use whatever was found.
; POSSIBLE VALUES: ape asf avi id3v1 id3v2 lyrics3 matroska mpeg quicktime riff
; vorbiscomment
; DEFAULT: id3v2 id3v1 vorbiscomment quicktime matroska ape asf avi mpeg riff
getid3_tag_order = "id3v2,id3v1,vorbiscomment,quicktime,matroska,ape,asf,avi,mpeg,riff"
; Determines whether we try to autodetect the encoding for id3v2 tags.
; May break valid tags.
; DEFAULT: false
;getid3_detect_id3v2_encoding = "false"
; This determines if file metadata should be write back to files
; as id3 metadata when updated.
; DEFAULT: false
;write_id3 = "false"
; This determines if album art should be write back to files
; as id3 metadata when updated.
; DEFAULT: false
;write_id3_art = "false"
; This determines if catalog manager users can delete medias from disk.
; DEFAULT: false
;delete_from_disk = "false"
; This determines the order in which metadata sources are used (and in the
; case of plugins, checked)
; POSSIBLE VALUES (builtins): filename and getID3
; POSSIBLE VALUES (plugins): MusicBrainz,TheAudioDb, plus any others you've installed.
; DEFAULT: getID3 filename
metadata_order = "getID3,filename"
; This determines the order in which metadata sources are used (and in the
; case of plugins, checked) for video files
; POSSIBLE VALUES (builtins): filename and getID3
; POSSIBLE VALUES (plugins): Tvdb,Tmdb,Omdb, plus any others you've installed.
; DEFAULT: filename getID3
metadata_order_video = "filename,getID3"
; This determines if extended metadata grabbed from external services should be deferred.
; If enabled, extended metadata is retrieved when browsing the library item.
; If disabled, extended metadata is retrieved at catalog update.
; Today, only Artist information (summary, place formed, ...) can be deferred.
; DEFAULT: true
deferred_ext_metadata = "true"
; Some taggers use delimiters other than \0 for fields
; This list specifies possible delimiters additional to \0
; This setting takes a regex pattern.
; DEFAULT: // / \ | , ;
additional_genre_delimiters = "[/]{2}|[/|\\\\|\|,|;]"
; This determines if a preview image should be retrieved from video files
; It requires encode_get_image transcode settings.
; DEFAULT: false
;generate_video_preview = "true"
; Un comment if don't want ampache to follow symlinks
; DEFAULT: false
;no_symlinks = "false"
; Use auth?
; If this is set to "Yes" ampache will require a valid
; Username and password. If this is set to false then ampache
; will not ask you for a username and password. false is only
; recommended for internal only instances
; DEFAULT true
use_auth = "true"
; Default Auth Level
; If use_auth is set to false then this option is used
; to determine the permission level of the 'default' users
; default is administrator. This setting only takes affect
; if use_auth is false
; POSSIBLE VALUES: user, admin, manager, guest
; DEFAULT: guest
default_auth_level = "user"
; 5 Star Ratings
; This allows ratings for almost any object in ampache
; POSSIBLE VALUES: false true
; DEFAULT: true
ratings = "true"
; User flags/favorites
; This allows user flags for almost any object in ampache as favorite
; POSSIBLE VALUES: false true
; DEFAULT: true
userflags = "true"
; Direct play
; This allows user to play directly a song or album
; POSSIBLE VALUES: false true
; DEFAULT: true
directplay = "true"
; Sociable
; This turns on / off all of the "social" features of ampache
; default is on, but if you don't care and just want music
; turn this off to disable all social features.
; DEFAULT: true
sociable = "true"
; License
; This turns on / off all licensing features on Ampache
; DEFAULT: false
;licensing = "false"
; This options will turn on/off Demo Mode
; If Demo mode is on you can not play songs or update your catalog
; in other words.. leave this commented out
; DEFAULT: false
;demo_mode = "false"
; Caching
; This turns the caching mechanisms on or off, due to a large number of
; problems with people with very large catalogs and low memory settings
; this is off by default as it does significantly increase the memory
; requirments on larger catalogs. If you have the memory this can create
; a 2-3x speed improvement.
; DEFAULT: false
memory_cache = "true"
; Memory Limit
; This defines the "Min" memory limit for PHP if your php.ini
; has a lower value set Ampache will set it up to this. If you
; set it below 16MB getid3() will not work!
; DEFAULT: 32
;memory_limit = 32
; Album Art Preferred Filename
; Specify a filename to look for if you always give the same filename
; i.e. "folder.jpg" Ampache currently only supports jpg/gif and png
; Especially useful if you have a front and a back image in a folder
; comment out if ampache should search for any jpg,gif or png
; DEFAULT: folder.jpg
;album_art_preferred_filename = "folder.jpg"
; Album Art Store on Disk
; This defines if arts should be stored on disk instead of database.
; DEFAULT: false
;album_art_store_disk = "false"
; Local Metadata Directory
; This define a local metadata directory with write access where to store
; heavy data if enabled (album arts, ...)
; DEFAULT: none
;local_metadata_dir = "/metadata"
; Maximal upload size
; Specify the maximal allowed upload size for images, in bytes.
; DEFAULT: 1048576
;max_upload_size = 1048576
; Album Art Minimum Width
; Specify the minimum width for arts (in pixel).
; DEFAULT: none
;album_art_min_width = 100
; Album Art Maximum Width
; Specify the maximum width for arts (in pixel).
; DEFAULT: none
;album_art_max_width = 1024
; Album Art Minimum Height
; Specify the minimum height for arts (in pixel).
; DEFAULT: none
;album_art_min_height = 100
; Album Art Maximum Height
; Specify the maximum height for arts (in pixel).
; DEFAULT: none
;album_art_max_height = 1024
; Resize Images * Requires PHP-GD *
; Set this to true if you want Ampache to resize the Album
; art on the fly, this increases load time and CPU usage
; and also requires the PHP-GD library. This is very useful
; If you have high-quality album art and a small upload cap
; DEFAULT: false
;resize_images = "false"
; Statistical Graphs * Requires PHP-GD *
; Set this to true if you want Ampache to generate statistical
; graphs on usages / users.
; DEFAULT: false
;statistical_graphs = "false"
; Art Gather Order
; Simply arrange the following in the order you would like
; ampache to search. If you want to disable one of the search
; methods simply leave it out. DB should be left as the first
; method unless you want it to overwrite what's already in the
; database
; POSSIBLE VALUES (builtins): db tags folder lastfm musicbrainz google
; POSSIBLE VALUES (plugins): Amazon,TheAudioDb,Tmdb,Omdb,Flickr
; DEFAULT: db,tags,folder,musicbrainz,lastfm,google
art_order = "db,tags,folder,musicbrainz,lastfm,google"
; Recommendations
; Set this to true to enable display of similar artists or albums
; while browsing. Requires Last.FM.
; DEFAULT: false
;show_similar = "false"
; Concerts
; Set this to true to enable display of artist concerts
; Requires Last.FM.
; DEFAULT: false
;show_concerts = "false"
; Last.FM API Key
; Set this to your Last.FM api key to actually use Last.FM for
; recommendations and metadata.
lastfm_api_key = "d5df942424c71b754e54ce1832505ae2"
; Wanted
; Set this to true to enable display missing albums and the
; possibility for users to mark it as wanted.
; DEFAULT: false
wanted = "true"
; Wanted types
; Set the allowed types of wanted releases (album,compilation,single,ep,live,remix,promotion,official)
; DEFAULT: album,official
wanted_types = "album,official"
; Wanted Auto Accept
; Mark wanted requests as accepted by default (no content manager agreement required)
; DEFAULT: false
;wanted_auto_accept = "false"
; EchoNest API key
; EchoNest provides several music services. Currently used for missing song 30 seconds preview.
;echonest_api_key = ""
; Labels
; Use labels to browse artists per label membership.
; DEFAULT: false
;label = "false"
; Broadcasts
; Allow users to broadcast music.
; This feature requires advanced server configuration, please take a look on the wiki for more information.
; DEFAULT: false
;broadcast = "false"
; Channels
; Set this to true to enable channels and the
; possibility for users to create channels from playlists
; DEFAULT: true
channel = "true"
; Live Streams
; Set this to true to enable live streams (radio) and the
; possibility for users to add new live streams.
; DEFAULT: true
live_stream = "true"
; Web Socket address
; Declare the web socket server address
; DEFAULT: determined automatically
;websocket_address = "ws://localhost:8100"
; Debug
; If this is enabled Ampache will write debugging information to the log file
; DEFAULT: false
debug = "true"
; Debug Level
; This should always be set in conjunction with the
; debug option, it defines how prolific you want the
; debugging in ampache to be. values are 1-5.
; 1 == Errors only
; 2 == Error + Failures (login attempts etc.)
; 3 == ??
; 4 == ?? (Profit!)
; 5 == Information (cataloging progress etc.)
; DEFAULT: 5
debug_level = "5"
; Path to Log File
; This defines where you want ampache to log events to
; this will only happen if debug is turned on. Do not
; include trailing slash. You will need to make sure that
; the specified directory exists and your HTTP server has
; write access.
; DEFAULT: NULL
log_path = "/var/www/ampache/log"
; Log filename pattern
; This defines where the log file name pattern.
; %name.%Y%m%d.log will create a different log file every day.
; DEFAULT: %name.%Y%m%d.log
log_filename = "%name.%Y%m%d.log"
; Charset of generated HTML pages
; Default of UTF-8 should work for most people
; DEFAULT: UTF-8
site_charset = "UTF-8"
; Locale Charset
; Local charset (mainly for file operations) if different
; from site_charset.
; This is disabled by default, enable only if needed
; (for Windows please set lc_charset to ISO8859-1)
; DEFAULT: ISO8859-1
;lc_charset = "ISO8859-1"
; Refresh Limit
; This defines the default refresh limit in seconds for
; pages with dynamic content, such as now playing
; DEFAULT: 60
; Possible Values: Int > 5
refresh_limit = "60"
; Footer Statistics
; This defines whether statistics (Queries, Cache Hits, Load Time)
; are shown in the page footer.
; DEFAULT: true
; Possible values: true, false
show_footer_statistics = "true"
;#########################################################
; Custom actions (optional) #
;#########################################################
; Your custom play action title
;custom_play_action_title_0 = ""
; Your custom play action icon name (stored as /images/icon_[your_image].png)
;custom_play_action_icon_0 = ""
; Your custom action script, where:
; - %f: the media file path
; - %c: the excepted codec target (mp3, ogg, ...)
; - %a: the artist name
; - %A: the album name
; - %t: the song title
;custom_play_action_run_0 = ""
; Example for Karaoke playing
;custom_play_action_title_0 = "Karaoke"
;custom_play_action_icon_0 = "microphone"
;custom_play_action_run_0 = "sox \"%f\" -p oops | ffmpeg -i pipe:0 -f %c pipe:1"
;#########################################################
; LDAP login info (optional) #
;#########################################################
; LDAP filter string to use (required)
; For OpenLDAP use "uid"
; For Microsoft Active Directory (MAD) use "sAMAccountName"
; DEFAULT: null
;ldap_filter = "(sAMAccountName=%v)"
; LDAP objectclass (required)
; OpanLDAP objectclass = "*"
; MAD objectclass = "organizationalPerson"
; DEFAULT null
ldap_objectclass = "posixAccount"
; Initial credentials to bind with for searching (optional)
; DEFAULT: null
;ldap_username = ""
;ldap_password = ""
; Require that the user is in a specific group (optional)
; DEFAULT: null
;ldap_require_group = "cn=yourgroup,ou=yourorg,dc=yoursubdomain,dc=yourdomain,dc=yourtld"
; This is the search dn used to find users (required)
; DEFAULT: null
ldap_search_dn = "dc=yunohost,dc=org"
; This is the address of your ldap server (required)
; DEFAULT: null
ldap_url = "localhost"
; Attributes where additional user information is stored (optional)
; OpenLDAP ldap_name_field = "cn"
; MAD ldap_name_field = "displayname"
; DEFAULT: null
;ldap_email_field = "mail"
ldap_name_field = "cn"
;#########################################################
; OpenID login info (optional) #
;#########################################################
; Requires specific OpenID Provider Authentication Policy
; DEFAULT: null
; VALUES: PAPE_AUTH_MULTI_FACTOR_PHYSICAL,PAPE_AUTH_MULTI_FACTOR,PAPE_AUTH_PHISHING_RESISTANT
;openid_required_pape = ""
;#########################################################
; Public Registration settings, defaults to disabled #
;#########################################################
; This setting will silently create an ampache account
; for anyone who can login using ldap (or any other login
; extension). The default is to create new users as guests
; see auto_user config option if you would like to change this
; DEFAULT: false
auto_create = "true"
; This setting turns on/off public registration. It is
; recommended you leave this off, as it will allow anyone to
; sign up for an account on your server.
; REMEMBER: don't forget to set the mail from address further down in the config.
; DEFAULT: false
;allow_public_registration = "false"
; Require Captcha Text on Image confirmation
; Turning this on requires the user to correctly
; type in the letters in the image created by Captcha
; Default is off because its very hard to detect if it failed
; to draw, or they failed to enter it.
; DEFAULT: false
;captcha_public_reg = "false"
; This setting turns on/off admin notification of registration.
; DEFAULT: false
;admin_notify_reg = "false"
; This setting determines whether the user will be created as a disabled user.
; If this is on, an administrator will need to manually enable the account
; before it's usable.
; DEFAULT: false
;admin_enable_required = "false"
; This setting will allow all registrants/ldap/http users
; to be auto-approved as a user. By default, they will be
; added as a guest and must be promoted by the admin.
; POSSIBLE VALUES: guest, user, admin
; DEFAULT: guest
auto_user = "user"
; This will display the user agreement when registering
; For agreement text, edit config/registration_agreement.php
; User will need to accept the agreement before they can register
; DEFAULT: false
;user_agreement = "false"
; This disable email confirmation when registering.
; DEFAULT: false
;user_no_email_confirm = "false"
; This will display the cookie disclaimer (EU Cookie Law)
; DEFAULT: false
;cookie_disclaimer = "false"
; The fields that will be shown on Registration page
; If a user wants to register.
; Username and email fields are forced.
; POSSIBLE VALUES: fullname,website,state,city
; DEFAULT: "fullname,website"
registration_display_fields = "fullname,website"
; The fields that will be mandatory
; This controls which fields are mandatory for registration.
; Username and email fields are forced mandatory.
; POSSIBLE VALUES: fullname,website,state,city
; DEFAULT: fullname
registration_mandatory_fields = "fullname"
;########################################################
; These options control the dynamic downsampling based #
; on current usage #
; *Note* Transcoding must be enabled and working #
;########################################################
; Attempt to optimize bandwidth by dynamically lowering the bit rate of new
; streams. Since the bit rate is only adjusted at the beginning of a song, the
; actual cumulative bitrate for concurrent streams can be up to around
; double the configured value. It also only applies to streams that are
; transcoded.
; DEFAULT: none
max_bit_rate = "576"
; New dynamically downsampled streams will be denied if they are forced below
; this value.
; DEFAULT: 8
min_bit_rate = "48"
;######################################################
; These are commands used to transcode non-streaming
; formats to the target file type for streaming.
; This can be useful in re-encoding file types that don't stream
; very well, or if your player doesn't support some file types.
;
; 'Downsampling' will also use these commands.
;
; To state the bleeding obvious, any programs referenced in the transcode
; commands must be installed, in the web server's search path (or referenced
; by their full path), and executable by the web server.
; Input type selection
; TYPE is the extension. 'allowed' certifies that transcoding works properly for
; this input format. 'required' further forbids the direct streaming of a format
; (e.g. if you store everything in FLAC, but don't want to ever stream that.)
; transcode_TYPE = {allowed|required|false}
; DEFAULT: false
;;; Audio
;transcode_m4a = allowed
transcode_flac = "required"
;transcode_mpc = required
;transcode_ogg = required
;transcode_oga = required
;transcode_wav = required
;transcode_wma = required
;transcode_aif = required
;transcode_aiff = required
;transcode_ape = required
;transcode_shn = required
transcode_mp3 = "allowed"
;;; Video
;transcode_avi = allowed
;transcode_mkv = allowed
;transcode_mpg = allowed
;transcode_mpeg = allowed
;transcode_m4v = allowed
;transcode_mp4 = allowed
;transcode_mov = allowed
;transcode_wmv = allowed
;transcode_ogv = allowed
;transcode_divx = allowed
;transcode_m2ts = allowed
;transcode_webm = allowed
; Default audio output format
; DEFAULT: none
encode_target = "mp3"
; Default video output format
; DEFAULT: none
;encode_video_target = webm
; Override the default output format on a per-type basis
; encode_target_TYPE = TYPE
; DEFAULT: none
;encode_target_flac = ogg
; Override the default TYPE transcoding behavior on a per-player basis
; transcode_player_PLAYER_TYPE = TYPE
; Valid PLAYER is: webplayer, api
; DEFAULT: none
;transcode_player_webplayer_m4a = required
;transcode_player_webplayer_flac = required
;transcode_player_webplayer_mpc = required
; Override the default output format on a per-player basis
; encode_player_PLAYER_target = TYPE
; Valid PLAYER is: webplayer, api
; DEFAULT: none
;encode_player_webplayer_target = mp3
;encode_player_api_target = mp3
; Allow clients to override transcode settings (output type, bitrate, codec ...)
; DEFAULT: true
transcode_player_customize = "1"
; Command configuration. Substitutions will be made as follows:
; %FILE% => filename
; %SAMPLE% => target sample rate
; You can do fancy things like VBR, but consider whether the consequences are
; acceptable in your environment.
; Master transcode command
; transcode_cmd should be a single command that supports multiple file types,
; such as ffmpeg or avconv. It's still possible to make a configuration that's
; equivalent to the old default, but if you find that necessary you should be
; clever enough to figure out how on your own.
; DEFAULT: none
transcode_cmd = "ffmpeg -i %FILE%"
;transcode_cmd = "avconv"
;transcode_cmd = "/usr/bin/neatokeen"
; Transcode input file argument
transcode_input = "-i %FILE%"
; Specific transcode commands
; It shouldn't be necessary in most cases, but you can override the transcode
; command for specific source formats. It still needs to accept the
; encoding arguments, so the easiest approach is to use your normal command as
; a clearing-house.
; transcode_cmd_TYPE = TRANSCODE_CMD
;transcode_cmd_mid = "timidity -Or -o %FILE% | ffmpeg -f s16le -i pipe:0"
; Encoding arguments
; For each output format, you should provide the necessary arguments for
; your transcode_cmd.
; encode_args_TYPE = TRANSCODE_CMD_ARGS
encode_args_mp3 = "-vn -b:a %SAMPLE%K -acodec libmp3lame -f mp3 pipe:1"
encode_args_ogg = "-vn -b:a max\(%SAMPLE%K\,49K\) -acodec libvorbis -vcodec libtheora -f ogg pipe:1"
encode_args_m4a = "-vn -b:a %SAMPLE%K -c:a libfdk_aac -f adts pipe:1"
encode_args_wav = "-vn -b:a %SAMPLE%K -c:a pcm_s16le -f wav pipe:1"
encode_args_flv = "-b:a %SAMPLE%K -ar 44100 -ac 2 -v 0 -f flv -c:v libx264 -preset superfast -threads 0 pipe:1"
encode_args_webm = "-q %QUALITY% -f webm -c:v libvpx -maxrate %MAXBITRATE%k -preset superfast -threads 0 pipe:1"
encode_args_ts = "-q %QUALITY% -s %RESOLUTION% -f mpegts -c:v libx264 -c:a libmp3lame -maxrate %MAXBITRATE%k -preset superfast -threads 0 pipe:1"
; Encoding arguments to retrieve an image from a single frame
encode_get_image = "-ss %TIME% -f image2 -vframes 1 pipe:1"
; Encoding argument to encrust subtitle
encode_srt = "-vf \"subtitles='%SRTFILE%'\""
; Encode segment frame argument
encode_ss_frame = "-ss %TIME%"
; Encode segment duration argument
encode_ss_duration = "-t %DURATION%"
;######################################################
; these options allow you to configure your rss-feed
; layout. rss exists of two parts, main and song main is the information about the feed
; song is the information in the feed. can be multiple items.
; use_rss = false (values true | false)
;DEFAULT: use_rss = false
;use_rss = "false"
;#####################################################
;#############################
; Proxy Settings (optional) #
;#############################
; If Ampache is behind an http proxy, specifiy the hostname or IP address
; port, proxyusername, and proxypassword here.
;DEFAULT: not in use
;proxy_host = "192.168.0.1"
;proxy_port = "8080"
;proxy_user = ""
;proxy_pass = ""
; If Ampache is behind an https reverse proxy, force use HTTPS protocol.
;Default: false
force_ssl = "1"
;#############################
; Mail Settings #
;#############################
;Method used to send mail
;POSSIBLE VALUES: smtp sendmail php
;DEFAULT: php
;mail_type = "php"
;Mail domain.
;DEFAULT: example.com
;mail_domain = "example.com"
;This will be combined with mail_domain and used as the source address for
;emails generated by Ampache. For example, setting this to 'me' will set the
;sender to 'me@example.com'.
;DEFAULT: info
;mail_user = "info"
;A name to go with the email address.
;DEFAULT: Ampache
;mail_name = "Ampache"
;How strictly email addresses should be checked.
;easy does a regex match, strict actually performs some SMTP transactions
;to see if we can send to this address.
;POSSIBLE VALUES: strict easy none
; DEFAULT: strict
;mail_check = "strict"
;############################
; sendmail Settings #
;############################
;DEFAULT: /usr/sbin/sendmail
;sendmail_path = "/usr/sbin/sendmail"
;#############################
; SMTP Settings #
;#############################
;Mail server (hostname or IP address)
;DEFAULT: localhost
;mail_host = "localhost"
; SMTP port
;DEFAULT: 25
;mail_port = 25
;Secure SMTP
;POSSIBLE VALUES: ssl tls
;DEFAULT: none
;mail_secure_smtp = tls
;Enable SMTP authentication
;DEFAULT: false
;mail_auth = "true"
;SMTP Username
;your mail auth username.
;mail_auth_user = ""
; SMTP Password
; your mail auth password.
;mail_auth_pass = ""
;#############################
; Multibyte Settings #
;#############################
; See http://php.net/manual/mbstring.supported-encodings.php
; If you want ID3v1 encoding detection to work, you should uncomment this line
; so that the ordering is sane.
; DEFAULT: auto
;mb_detect_order = "ASCII,UTF-8,EUC-JP,ISO-2022-JP,SJIS,JIS"
slideshow_time = 0

View file

@ -14,6 +14,7 @@ location PATHTOCHANGE {
include fastcgi_params; include fastcgi_params;
fastcgi_param REMOTE_USER $remote_user; fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $request_filename;
} }
rewrite ^PATHTOCHANGE/play/ssid/(\w+)/type/(\w+)/oid/([0-9]+)/uid/([0-9]+)/name/(.*)$ PATHTOCHANGE/play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&name=$5 last; rewrite ^PATHTOCHANGE/play/ssid/(\w+)/type/(\w+)/oid/([0-9]+)/uid/([0-9]+)/name/(.*)$ PATHTOCHANGE/play/index.php?ssid=$1&type=$2&oid=$3&uid=$4&name=$5 last;

View file

@ -5,6 +5,8 @@ domain=$1
path=$2 path=$2
admin_ampache=$3 admin_ampache=$3
debianversionname=$(lsb_release -a | grep Codename | awk -F' ' '{print $2}')
# Check domain/path availability # Check domain/path availability
sudo yunohost app checkurl $domain$path -a ampache sudo yunohost app checkurl $domain$path -a ampache
if [[ ! $? -eq 0 ]]; then if [[ ! $? -eq 0 ]]; then
@ -64,9 +66,13 @@ echo "127.0.0.1 $domain #yunoampache" | sudo tee -a /etc/hosts
sleep 1 sleep 1
curl -kL -X POST http://$domain$path/update.php?action=update > /dev/null 2>&1 curl -kL -X POST http://$domain$path/update.php?action=update > /dev/null 2>&1
sleep 5 sleep 5
[ "$debianversionname" == "wheezy" ] && \
sudo sed -i 's/;transcode_cmd = "ffmpeg"/transcode_cmd = "ffmpeg"/g' /var/www/ampache/config/ampache.cfg.php && \
sudo sed -i 's/^transcode_cmd = "avconv"/;transcode_cmd = "avconv"/g' /var/www/ampache/config/ampache.cfg.php
sudo yunohost app setting ampache skipped_uris -d sudo yunohost app setting ampache skipped_uris -d
sudo yunohost app setting ampache skipped_uris -v "/rest" sudo yunohost app setting ampache skipped_uris -v "/rest"
sudo yunohost app ssowatconf sudo yunohost app ssowatconf
sudo sed -i '/yunoampache/d' /etc/hosts sudo sed '/yunoampache/d' /etc/hosts > /tmp/hosts.tmp
sudo cp /tmp/hosts.tmp /etc/hosts ; sudo rm -f /tmp/hosts.tmp
mysql -u $db_user -p$db_pwd $db_user < /tmp/admin.sql mysql -u $db_user -p$db_pwd $db_user < /tmp/admin.sql
sudo rm /tmp/admin.sql sudo rm /tmp/admin.sql

63
sources/.gitattributes vendored Normal file
View file

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

12
sources/.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
config/ampache.cfg.php
config/ampache-doped.cfg.php
rest/.htaccess
play/.htaccess
*.phpproj
*.sln
*.v11.suo
*.suo
logs
/nbproject/private/
.pc
/tmp

View file

@ -0,0 +1,22 @@
<?php
/**
* To put your Ampache website in maintenance, just rename this file to .maintenance
* This example redirect your visitors to a default maintenance information page hosted in ampache.org
*/
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST");
$domain = $_SERVER['HTTP_HOST'];
if (empty($domain)) {
$domain = $_SERVER['SERVER_NAME'];
}
$scheme = "http";
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$scheme = "https";
}
$fromurl = rawurlencode($scheme . "://" . $domain . $_SERVER[REQUEST_URI]);
header("Location: http://ampache.org/maintenance/?from=" . $fromurl);
exit;
?>

16
sources/.php_cs Normal file
View file

@ -0,0 +1,16 @@
<?php
use Symfony\CS\FixerInterface;
$finder = Symfony\CS\Finder\DefaultFinder::create()
->exclude('modules')
->exclude('nbproject')
->in(__DIR__)
->in(__DIR__ . '/modules/localplay')
->in(__DIR__ . '/modules/catalog')
->in(__DIR__ . '/modules/ampacheapi')
;
return Symfony\CS\Config\Config::create()
->finder($finder)
;

59
sources/.scrutinizer.yml Normal file
View file

@ -0,0 +1,59 @@
filter:
excluded_paths:
- 'modules/*'
paths: { }
tools:
php_mess_detector:
enabled: true
filter:
excluded_paths:
- 'modules/*'
- 'themes/*'
paths: { }
php_code_sniffer:
enabled: false
php_pdepend:
enabled: true
configuration_file: null
suffixes:
- php
excluded_dirs: { }
filter:
excluded_paths:
- 'modules/*'
paths: { }
php_analyzer:
enabled: true
extensions:
- php
dependency_paths:
- 'modules/*'
filter:
excluded_paths:
- 'modules/*'
- 'themes/*'
paths: { }
path_configs: { }
php_changetracking:
enabled: true
bug_patterns:
- '\bfix(?:es|ed)?\b'
feature_patterns:
- '\badd(?:s|ed)?\b'
- '\bimplement(?:s|ed)?\b'
filter:
excluded_paths:
- 'modules/*'
paths: { }
php_loc:
enabled: true
excluded_dirs:
- 'modules/*'
php_cpd:
enabled: true
excluded_dirs: { }
filter:
excluded_paths:
- 'modules/*'
paths: { }

6
sources/.tgitconfig Normal file
View file

@ -0,0 +1,6 @@
[bugtraq]
url = "https://github.com/ampache/ampache/issues/#BUGID#"
label = GitHub Issue Number
warnifnoissue = false
number = true
logregex = "#\\d+\n\\d+"

17
sources/.travis.yml Normal file
View file

@ -0,0 +1,17 @@
language: php
php:
- 5.4
- 5.5
- 5.6
before_install:
- wget http://cs.sensiolabs.org/get/php-cs-fixer.phar
before_script:
- chmod +x scripts/tests/syntax.sh
- chmod +x scripts/tests/codestyle.sh
script:
- scripts/tests/syntax.sh
- scripts/tests/codestyle.sh

8
sources/.tx/config Normal file
View file

@ -0,0 +1,8 @@
[main]
host = https://www.transifex.com
[project_slug.resource_slug]
file_filter = locale/<lang>_<lang>/LC_MESSAGES/messages.po
source_file = locale/base/messages.pot
source_lang = en_US
type = PO

1
sources/CNAME Normal file
View file

@ -0,0 +1 @@
ampache.org

6
sources/CONTRIBUTING.md Normal file
View file

@ -0,0 +1,6 @@
## Contribution
Please read [Development section](https://github.com/ampache/ampache/wiki#development).
## Bug report
Be sure the bug is not already fixed in `develop` branch or already reported in current open issues.
Please add [some logs](https://github.com/ampache/ampache/wiki/Troubleshooting#enable-logging) with your new issue.

View file

@ -22,11 +22,13 @@ Recommended Version
Currently, the recommended version is [git HEAD](https://github.com/ampache/ampache/archive/master.tar.gz). Currently, the recommended version is [git HEAD](https://github.com/ampache/ampache/archive/master.tar.gz).
[![Build Status](https://api.travis-ci.org/ampache/ampache.png?branch=master)](https://travis-ci.org/ampache/ampache) [![Build Status](https://api.travis-ci.org/ampache/ampache.png?branch=master)](https://travis-ci.org/ampache/ampache)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ampache/ampache/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ampache/ampache/?branch=master)
Latest changes but unstable is [develop branch](https://github.com/ampache/ampache/archive/develop.tar.gz). Latest changes but unstable is [develop branch](https://github.com/ampache/ampache/archive/develop.tar.gz).
[![Build Status](https://api.travis-ci.org/ampache/ampache.png?branch=develop)](https://travis-ci.org/ampache/ampache) [![Build Status](https://api.travis-ci.org/ampache/ampache.png?branch=develop)](https://travis-ci.org/ampache/ampache)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ampache/ampache/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/ampache/ampache/?branch=develop) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ampache/ampache/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/ampache/ampache/?branch=develop)
[![Codacy Badge](https://www.codacy.com/project/badge/b28cdb9e9ee2431c7cb9c23d5438cb80)](https://www.codacy.com/app/afterster_2222/ampache)
[![Code Climate](https://codeclimate.com/github/ampache/ampache/badges/gpa.svg)](https://codeclimate.com/github/ampache/ampache)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/ee067d0e-3432-4062-a969-01b4ee037f48/mini.png)](https://insight.sensiolabs.com/projects/ee067d0e-3432-4062-a969-01b4ee037f48)
Requirements Requirements
------------ ------------
@ -38,7 +40,7 @@ receives the most testing:
* nginx * nginx
* IIS * IIS
* PHP 5.3 or greater. * PHP 5.4 or greater.
* PHP modules: * PHP modules:
* PDO * PDO
@ -46,6 +48,8 @@ receives the most testing:
* hash * hash
* session * session
* json * json
* simplexml (This is not strictly necessary, but may result in a better experience.)
* curl (This is not strictly necessary, but may result in a better experience.)
* MySQL 5.x * MySQL 5.x
@ -59,8 +63,8 @@ Upgrading
If you are upgrading from an older version of Ampache we recommend If you are upgrading from an older version of Ampache we recommend
moving the old directory out of the way, extracting the new copy in moving the old directory out of the way, extracting the new copy in
its place and then copying the old config file into config/. All its place and then copying the old config/ampache.cfg.php, /rest/.htaccess,
database updates will be handled by Ampache. and /play/.htaccess files if any. All database updates will be handled by Ampache.
License License
------- -------
@ -99,6 +103,15 @@ Ampache includes some external modules that carry their own licensing.
* [MediaTable] (https://github.com/edenspiekermann/MediaTable): MIT * [MediaTable] (https://github.com/edenspiekermann/MediaTable): MIT
* [Responsive Elements] (https://github.com/kumailht/responsive-elements): MIT * [Responsive Elements] (https://github.com/kumailht/responsive-elements): MIT
* [Bootstrap] (http://getbootstrap.com): MIT * [Bootstrap] (http://getbootstrap.com): MIT
* [jQuery Knob] (https://github.com/aterrien/jQuery-Knob): MIT
* [jQuery File Upload] (https://github.com/blueimp/jQuery-File-Upload): MIT
* [jsTree] (http://www.jstree.com): MIT
* [php-tmdb-api] (https://github.com/wtfzdotnet/php-tmdb-api) : MIT
* [TvDb] (https://github.com/Moinax/TvDb) : MIT
* [jQuery DateTimePicker] (https://github.com/xdan/datetimepicker) : MIT
* [pChart] (http://www.pchart.net) : GPL v3
* [ZipStream-PHP] (https://github.com/maennchen/ZipStream-PHP) : [ZipStream-PHP license] (modules/zipstream/COPYING)
* [SabreDAV] (https://github.com/fruux/sabre-dav) : New BSD
Translations Translations
@ -109,19 +122,24 @@ following languages. If you are interested in updating an existing
translation or adding a new one please see /locale/base/TRANSLATIONS translation or adding a new one please see /locale/base/TRANSLATIONS
for more instructions. for more instructions.
* English (en_US) * English (en_US)
* German (de_DE) * Arabic (ar_SA)
* Spanish (es_ES) * Catalan (ca_ES)
* Dutch (nl_NL) * Catalan (ca_ES)
* Norwegian (nb_NO) * Czech (cs_CZ)
* UK English (en_GB) * Dutch (nl_NL)
* Italian (it_IT) * French (fr_FR)
* French (fr_FR) * German (de_DE)
* Swedish (sv_SE) * Greek (el_GR)
* Japanese (ja_JP) * Italian (it_IT)
* Catalan (ca_ES) * Japanese (ja_JP)
* Russian (ru_RU) * Norwegian (nb_NO)
* Czech (cs_CZ) * Persian (fa_IR)
* Polish (pl_PL)
* Russian (ru_RU)
* Spanish (es_ES)
* Swedish (sv_SE)
* UK English (en_GB)
Credits Credits
------- -------
@ -137,6 +155,7 @@ more features, encounter bugs, etc.
* [Public Repository](http://github.com/ampache) * [Public Repository](http://github.com/ampache)
* IRC: chat.freenode.net #ampache * IRC: chat.freenode.net #ampache
* [Forum](https://groups.google.com/forum/#!forum/ampache)
* [Issue Tracker](https://github.com/ampache/ampache/issues) * [Issue Tracker](https://github.com/ampache/ampache/issues)
* [Documentation](https://github.com/ampache/ampache/wiki) * [Documentation](https://github.com/ampache/ampache/wiki)

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -30,74 +30,57 @@ if (!Access::check('interface','100')) {
UI::show_header(); UI::show_header();
$catalogs = $_REQUEST['catalogs'];
// If only one catalog, check it is ready.
if (is_array($catalogs) && count($catalogs) == 1 && $_REQUEST['action'] !== 'delete_catalog' && $_REQUEST['action'] !== 'show_delete_catalog') {
// If not ready, display the data to make it ready / stop the action.
$catalog = Catalog::create_from_id($catalogs[0]);
if (!$catalog->isReady()) {
if (!isset($_REQUEST['perform_ready'])) {
$catalog->show_ready_process();
UI::show_footer();
exit;
} else {
$catalog->perform_ready();
}
}
}
$sse_catalogs = urlencode(serialize($catalogs));
/* Big switch statement to handle various actions */ /* Big switch statement to handle various actions */
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'add_to_all_catalogs': case 'add_to_all_catalogs':
$_REQUEST['catalogs'] = Catalog::get_catalogs(); $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=add_to_all_catalogs";
sse_worker($sse_url);
show_confirmation(T_('Catalog Update started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
break;
case 'add_to_catalog': case 'add_to_catalog':
toggle_visible('ajax-loading');
ob_end_flush();
if (AmpConfig::get('demo_mode')) { break; } if (AmpConfig::get('demo_mode')) { break; }
if ($_REQUEST['catalogs']) {
foreach ($_REQUEST['catalogs'] as $catalog_id) { $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=add_to_catalog&catalogs=" . $sse_catalogs;
$catalog = Catalog::create_from_id($catalog_id); sse_worker($sse_url);
$catalog->add_to_catalog($_POST); show_confirmation(T_('Catalog Update started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
}
}
$url = AmpConfig::get('web_path') . '/admin/catalog.php';
$title = T_('Catalog Updated');
$body = '';
show_confirmation($title, $body, $url);
toggle_visible('ajax-loading');
break; break;
case 'update_all_catalogs': case 'update_all_catalogs':
$_REQUEST['catalogs'] = Catalog::get_catalogs(); $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=update_all_catalogs";
sse_worker($sse_url);
show_confirmation(T_('Catalog Update started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
break;
case 'update_catalog': case 'update_catalog':
toggle_visible('ajax-loading'); if (AmpConfig::get('demo_mode')) { break; }
ob_end_flush();
/* If they are in demo mode stop here */
if (AmpConfig::get('demo_mode')) { break; }
if (isset($_REQUEST['catalogs'])) { $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=update_catalog&catalogs=" . $sse_catalogs;
foreach ($_REQUEST['catalogs'] as $catalog_id) { sse_worker($sse_url);
$catalog = Catalog::create_from_id($catalog_id); show_confirmation(T_('Catalog Update started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
$catalog->verify_catalog();
}
}
$url = AmpConfig::get('web_path') . '/admin/catalog.php';
$title = T_('Catalog Updated');
$body = '';
show_confirmation($title,$body,$url);
toggle_visible('ajax-loading');
break; break;
case 'full_service': case 'full_service':
toggle_visible('ajax-loading');
ob_end_flush();
/* Make sure they aren't in demo mode */
if (AmpConfig::get('demo_mode')) { UI::access_denied(); break; } if (AmpConfig::get('demo_mode')) { UI::access_denied(); break; }
if (!$_REQUEST['catalogs']) { $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=full_service&catalogs=" . $sse_catalogs;
$_REQUEST['catalogs'] = Catalog::get_catalogs(); sse_worker($sse_url);
} show_confirmation(T_('Catalog Update started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
/* This runs the clean/verify/add in that order */
foreach ($_REQUEST['catalogs'] as $catalog_id) {
$catalog = Catalog::create_from_id($catalog_id);
$catalog->clean_catalog();
$catalog->count = 0;
$catalog->verify_catalog();
$catalog->count = 0;
$catalog->add_to_catalog();
}
Dba::optimize_tables();
$url = AmpConfig::get('web_path') . '/admin/catalog.php';
$title = T_('Catalog Updated');
$body = '';
show_confirmation($title,$body,$url);
toggle_visible('ajax-loading');
break; break;
case 'delete_catalog': case 'delete_catalog':
/* Make sure they aren't in demo mode */
if (AmpConfig::get('demo_mode')) { break; } if (AmpConfig::get('demo_mode')) { break; }
if (!Core::form_verify('delete_catalog')) { if (!Core::form_verify('delete_catalog')) {
@ -105,15 +88,21 @@ switch ($_REQUEST['action']) {
exit; exit;
} }
$deleted = true;
/* Delete the sucker, we don't need to check perms as thats done above */ /* Delete the sucker, we don't need to check perms as thats done above */
Catalog::delete($_GET['catalog_id']); foreach ($catalogs as $catalog_id) {
$deleted = Catalog::delete($catalog_id);
if (!$deleted) break;
}
$next_url = AmpConfig::get('web_path') . '/admin/catalog.php'; $next_url = AmpConfig::get('web_path') . '/admin/catalog.php';
show_confirmation(T_('Catalog Deleted'), T_('The Catalog and all associated records have been deleted'),$next_url); if ($deleted) {
show_confirmation(T_('Catalog Deleted'), T_('The Catalog and all associated records have been deleted'), $next_url);
} else {
show_confirmation(T_('Error'), T_('Cannot delete the catalog'), $next_url);
}
break; break;
case 'show_delete_catalog': case 'show_delete_catalog':
$catalog_id = scrub_in($_GET['catalog_id']); $next_url = AmpConfig::get('web_path') . '/admin/catalog.php?action=delete_catalog&catalogs[]=' . implode(',', $catalogs);
$next_url = AmpConfig::get('web_path') . '/admin/catalog.php?action=delete_catalog&catalog_id=' . scrub_out($catalog_id);
show_confirmation(T_('Catalog Delete'), T_('Confirm Deletion Request'),$next_url,1,'delete_catalog'); show_confirmation(T_('Catalog Delete'), T_('Confirm Deletion Request'),$next_url,1,'delete_catalog');
break; break;
case 'enable_disabled': case 'enable_disabled':
@ -134,27 +123,14 @@ switch ($_REQUEST['action']) {
show_confirmation($title,$body,$url); show_confirmation($title,$body,$url);
break; break;
case 'clean_all_catalogs': case 'clean_all_catalogs':
$_REQUEST['catalogs'] = Catalog::get_catalogs(); $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=clean_all_catalogs";
sse_worker($sse_url);
show_confirmation(T_('Catalog Clean started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
break;
case 'clean_catalog': case 'clean_catalog':
toggle_visible('ajax-loading'); $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=clean_catalog&catalogs=" . $sse_catalogs;
ob_end_flush(); sse_worker($sse_url);
/* If they are in demo mode stop them here */ show_confirmation(T_('Catalog Clean started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
if (AmpConfig::get('demo_mode')) { break; }
// Make sure they checked something
if (isset($_REQUEST['catalogs'])) {
foreach ($_REQUEST['catalogs'] as $catalog_id) {
$catalog = Catalog::create_from_id($catalog_id);
$catalog->clean_catalog();
} // end foreach catalogs
Dba::optimize_tables();
}
$url = AmpConfig::get('web_path') . '/admin/catalog.php';
$title = T_('Catalog Cleaned');
$body = '';
show_confirmation($title,$body,$url);
toggle_visible('ajax-loading');
break; break;
case 'update_catalog_settings': case 'update_catalog_settings':
/* No Demo Here! */ /* No Demo Here! */
@ -171,23 +147,9 @@ switch ($_REQUEST['action']) {
case 'update_from': case 'update_from':
if (AmpConfig::get('demo_mode')) { break; } if (AmpConfig::get('demo_mode')) { break; }
// First see if we need to do an add $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=update_from&add_path=" . scrub_in($_POST['add_path']) . "&update_path=" . $_POST['update_path'];
if ($_POST['add_path'] != '/' AND strlen($_POST['add_path'])) { sse_worker($sse_url);
if ($catalog_id = Catalog_local::get_from_path($_POST['add_path'])) { show_confirmation(T_('Subdirectory update started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
$catalog = Catalog::create_from_id($catalog_id);
$catalog->add_to_catalog(array('subdirectory'=>$_POST['add_path']));
}
} // end if add
// Now check for an update
if ($_POST['update_path'] != '/' AND strlen($_POST['update_path'])) {
if ($catalog_id = Catalog_local::get_from_path($_POST['update_path'])) {
$songs = Song::get_from_path($_POST['update_path']);
foreach ($songs as $song_id) { Catalog::update_single_item('song',$song_id); }
}
} // end if update
echo T_("Done.");
break; break;
case 'add_catalog': case 'add_catalog':
/* Wah Demo! */ /* Wah Demo! */
@ -218,19 +180,10 @@ switch ($_REQUEST['action']) {
break; break;
} }
$catalog = Catalog::create_from_id($catalog_id); $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=add_catalog&catalog_id=" . $catalog_id . "&options=" . urlencode(serialize($_POST));
sse_worker($sse_url);
// Run our initial add
$catalog->add_to_catalog($_POST);
UI::show_box_top(T_('Catalog Created'), 'box box_catalog_created');
echo "<h2>" . T_('Catalog Created') . "</h2>";
Error::display('general');
Error::display('catalog_add');
UI::show_box_bottom();
show_confirmation('','', AmpConfig::get('web_path').'/admin/catalog.php');
show_confirmation(T_('Catalog Creation started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
} else { } else {
require AmpConfig::get('prefix') . '/templates/show_add_catalog.inc.php'; require AmpConfig::get('prefix') . '/templates/show_add_catalog.inc.php';
} }
@ -275,23 +228,10 @@ switch ($_REQUEST['action']) {
$catalog->format(); $catalog->format();
require_once AmpConfig::get('prefix') . '/templates/show_edit_catalog.inc.php'; require_once AmpConfig::get('prefix') . '/templates/show_edit_catalog.inc.php';
break; break;
case 'gather_album_art': case 'gather_media_art':
toggle_visible('ajax-loading'); $sse_url = AmpConfig::get('web_path') . "/server/sse.server.php?worker=catalog&action=gather_media_art&catalogs=" . $sse_catalogs;
ob_end_flush(); sse_worker($sse_url);
show_confirmation(T_('Media Art Search started...'), '', AmpConfig::get('web_path') . '/admin/catalog.php', 0, 'confirmation', false);
$catalogs = $_REQUEST['catalogs'] ? $_REQUEST['catalogs'] : Catalog::get_catalogs();
// Iterate throught the catalogs and gather as needed
foreach ($catalogs as $catalog_id) {
$catalog = Catalog::create_from_id($catalog_id);
require AmpConfig::get('prefix') . '/templates/show_gather_art.inc.php';
flush();
$catalog->gather_art();
}
$url = AmpConfig::get('web_path') . '/admin/catalog.php';
$title = T_('Album Art Search Finished');
$body = '';
show_confirmation($title,$body,$url);
break; break;
case 'show_catalogs': case 'show_catalogs':
default: default:

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

65
sources/admin/license.php Normal file
View file

@ -0,0 +1,65 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
require_once '../lib/init.php';
if (!Access::check('interface','100')) {
UI::access_denied();
exit;
}
UI::show_header();
switch ($_REQUEST['action']) {
case 'edit':
if (isset($_POST['license_id'])) {
$license = new License($_POST['license_id']);
if ($license->id) {
$license->update($_POST);
}
$text = T_('License Updated');
} else {
License::create($_POST);
$text = T_('License Created');
}
show_confirmation($text,'',AmpConfig::get('web_path').'/admin/license.php');
break;
case 'show_edit':
$license = new License($_REQUEST['license_id']);
case 'show_create':
require_once AmpConfig::get('prefix') . '/templates/show_edit_license.inc.php';
break;
case 'delete':
License::delete($_REQUEST['license_id']);
show_confirmation(T_('License Deleted'),'',AmpConfig::get('web_path').'/admin/license.php');
break;
default:
$browse = new Browse();
$browse->set_type('license');
$browse->set_simple_browse(true);
$license_ids = $browse->get_objects();
$browse->show_objects($license_ids);
$browse->store();
break;
}
UI::show_footer();

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -39,7 +39,10 @@ switch ($_REQUEST['action']) {
// Multi-byte Character Mail // Multi-byte Character Mail
if (function_exists('mb_language')) { if (function_exists('mb_language')) {
ini_set("mbstring.internal_encoding","UTF-8"); $ini_default_charset = version_compare(PHP_VERSION, '5.6', '<') ? 'mbstring.internal_encoding' : 'default_charset';
if (ini_get($ini_default_charset)) {
ini_set($ini_default_charset, "UTF-8");
}
mb_language("uni"); mb_language("uni");
} }

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -48,10 +48,14 @@ switch ($_REQUEST['action']) {
Preference::update('localplay_level',$GLOBALS['user']->id,'100'); Preference::update('localplay_level',$GLOBALS['user']->id,'100');
Preference::update('localplay_controller',$GLOBALS['user']->id,$localplay->type); Preference::update('localplay_controller',$GLOBALS['user']->id,$localplay->type);
header("Location:" . AmpConfig::get('web_path') . '/admin/modules.php?action=show_localplay'); /* Show Confirmation */
$url = AmpConfig::get('web_path') . '/admin/modules.php?action=show_localplay';
$title = T_('Localplay Installed');
$body = '';
show_confirmation($title ,$body, $url);
break; break;
case 'install_catalog_type': case 'install_catalog_type':
$type = scrub_in($_REQUEST['type']); $type = (string) scrub_in($_REQUEST['type']);
$catalog = Catalog::create_catalog_type($type); $catalog = Catalog::create_catalog_type($type);
if ($catalog == null) { if ($catalog == null) {
Error::add('general', T_('Install Failed, Catalog Error')); Error::add('general', T_('Install Failed, Catalog Error'));
@ -68,21 +72,21 @@ switch ($_REQUEST['action']) {
show_confirmation($title ,$body, $url); show_confirmation($title ,$body, $url);
break; break;
case 'confirm_uninstall_localplay': case 'confirm_uninstall_localplay':
$type = scrub_in($_REQUEST['type']); $type = (string) scrub_in($_REQUEST['type']);
$url = AmpConfig::get('web_path') . '/admin/modules.php?action=uninstall_localplay&amp;type=' . $type; $url = AmpConfig::get('web_path') . '/admin/modules.php?action=uninstall_localplay&amp;type=' . $type;
$title = T_('Are you sure you want to remove this plugin?'); $title = T_('Are you sure you want to remove this plugin?');
$body = ''; $body = '';
show_confirmation($title,$body,$url,1); show_confirmation($title,$body,$url,1);
break; break;
case 'confirm_uninstall_catalog_type': case 'confirm_uninstall_catalog_type':
$type = scrub_in($_REQUEST['type']); $type = (string) scrub_in($_REQUEST['type']);
$url = AmpConfig::get('web_path') . '/admin/modules.php?action=uninstall_catalog_type&amp;type=' . $type; $url = AmpConfig::get('web_path') . '/admin/modules.php?action=uninstall_catalog_type&amp;type=' . $type;
$title = T_('Are you sure you want to remove this plugin?'); $title = T_('Are you sure you want to remove this plugin?');
$body = ''; $body = '';
show_confirmation($title,$body,$url,1); show_confirmation($title,$body,$url,1);
break; break;
case 'uninstall_localplay': case 'uninstall_localplay':
$type = scrub_in($_REQUEST['type']); $type = (string) scrub_in($_REQUEST['type']);
$localplay = new Localplay($type); $localplay = new Localplay($type);
$localplay->uninstall(); $localplay->uninstall();
@ -94,7 +98,7 @@ switch ($_REQUEST['action']) {
show_confirmation($title,$body,$url); show_confirmation($title,$body,$url);
break; break;
case 'uninstall_catalog_type': case 'uninstall_catalog_type':
$type = scrub_in($_REQUEST['type']); $type = (string) scrub_in($_REQUEST['type']);
$catalog = Catalog::create_catalog_type($type); $catalog = Catalog::create_catalog_type($type);
if ($catalog == null) { if ($catalog == null) {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -32,8 +32,10 @@ UI::show_header();
// Switch on the incomming action // Switch on the incomming action
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'edit_shout': case 'edit_shout':
$shout_id = $_POST['shout_id']; $shout = new Shoutbox($_REQUEST['shout_id']);
$update = Shoutbox::update($_POST); if ($shout->id) {
$shout->update($_POST);
}
show_confirmation(T_('Shoutbox Post Updated'),'',AmpConfig::get('web_path').'/admin/shout.php'); show_confirmation(T_('Shoutbox Post Updated'),'',AmpConfig::get('web_path').'/admin/shout.php');
break; break;
case 'show_edit': case 'show_edit':

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -39,9 +39,13 @@ switch ($_REQUEST['action']) {
$current = parse_ini_file(AmpConfig::get('prefix') . '/config/ampache.cfg.php'); $current = parse_ini_file(AmpConfig::get('prefix') . '/config/ampache.cfg.php');
$final = generate_config($current); $final = generate_config($current);
$browser = new Horde_Browser(); $browser = new Horde_Browser();
$browser->downloadHeaders('ampache.cfg.php','text/plain',false,filesize(AmpConfig::get('prefix') . '/config/ampache.cfg.php.dist')); $browser->downloadHeaders('ampache.cfg.php', 'text/plain',false,filesize(AmpConfig::get('prefix') . '/config/ampache.cfg.php.dist'));
echo $final; echo $final;
exit; exit;
case 'write_config':
write_config(AmpConfig::get('prefix') . '/config/ampache.cfg.php');
header('Location: '. AmpConfig::get('web_path') . '/index.php');
exit;
case 'reset_db_charset': case 'reset_db_charset':
Dba::reset_db_charset(); Dba::reset_db_charset();
show_confirmation(T_('Database Charset Updated'), T_('Your Database and associated tables have been updated to match your currently configured charset'), AmpConfig::get('web_path').'/admin/system.php?action=show_debug'); show_confirmation(T_('Database Charset Updated'), T_('Your Database and associated tables have been updated to match your currently configured charset'), AmpConfig::get('web_path').'/admin/system.php?action=show_debug');
@ -53,6 +57,14 @@ switch ($_REQUEST['action']) {
} }
require_once AmpConfig::get('prefix') . '/templates/show_debug.inc.php'; require_once AmpConfig::get('prefix') . '/templates/show_debug.inc.php';
break; break;
case 'clear_cache':
switch ($_REQUEST['type']) {
case 'song' : Song::clear_cache(); break;
case 'artist' : Artist::clear_cache(); break;
case 'album' : Album::clear_cache(); break;
}
show_confirmation(T_('Cache cleared'), T_('Your cache has been cleared successfully.'), AmpConfig::get('web_path').'/admin/system.php?action=show_debug');
break;
default: default:
// Rien a faire // Rien a faire
break; break;

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -40,14 +40,17 @@ switch ($_REQUEST['action']) {
} }
/* Clean up the variables */ /* Clean up the variables */
$user_id = intval($_POST['user_id']); $user_id = intval($_POST['user_id']);
$username = scrub_in($_POST['username']); $username = scrub_in($_POST['username']);
$fullname = scrub_in($_POST['fullname']); $fullname = scrub_in($_POST['fullname']);
$email = scrub_in($_POST['email']); $email = scrub_in($_POST['email']);
$website = scrub_in($_POST['website']); $website = scrub_in($_POST['website']);
$access = scrub_in($_POST['access']); $access = scrub_in($_POST['access']);
$pass1 = $_POST['password_1']; $pass1 = $_POST['password_1'];
$pass2 = $_POST['password_2']; $pass2 = $_POST['password_2'];
$state = scrub_in($_POST['state']);
$city = scrub_in($_POST['city']);
$fullname_public = isset($_POST['fullname_public']);
/* Setup the temp user */ /* Setup the temp user */
$client = new User($user_id); $client = new User($user_id);
@ -55,16 +58,27 @@ switch ($_REQUEST['action']) {
/* Verify Input */ /* Verify Input */
if (empty($username)) { if (empty($username)) {
Error::add('username', T_("Error Username Required")); Error::add('username', T_("Error Username Required"));
} else {
if ($username != $client->username) {
if (!User::check_username($username)) {
Error::add('username', T_("Error Username already exists"));
}
}
} }
if ($pass1 !== $pass2 && !empty($pass1)) { if ($pass1 !== $pass2 && !empty($pass1)) {
Error::add('password', T_("Error Passwords don't match")); Error::add('password', T_("Error Passwords don't match"));
} }
/* If we've got an error then break! */ // Check the mail for correct address formation.
if (!Mailer::validate_address($email)) {
Error::add('email', T_('Invalid email address'));
}
/* If we've got an error then show edit form! */
if (Error::occurred()) { if (Error::occurred()) {
$_REQUEST['action'] = 'show_edit'; require_once AmpConfig::get('prefix') . '/templates/show_edit_user.inc.php';
break; break;
} // if we've had an oops! }
if ($access != $client->access) { if ($access != $client->access) {
$client->update_access($access); $client->update_access($access);
@ -81,9 +95,18 @@ switch ($_REQUEST['action']) {
if ($fullname != $client->fullname) { if ($fullname != $client->fullname) {
$client->update_fullname($fullname); $client->update_fullname($fullname);
} }
if ($fullname_public != $client->fullname_public) {
$client->update_fullname_public($fullname_public);
}
if ($pass1 == $pass2 && strlen($pass1)) { if ($pass1 == $pass2 && strlen($pass1)) {
$client->update_password($pass1); $client->update_password($pass1);
} }
if ($state != $client->state) {
$client->update_state($state);
}
if ($city != $client->city) {
$client->update_city($city);
}
$client->upload_avatar(); $client->upload_avatar();
show_confirmation(T_('User Updated'), $client->fullname . "(" . $client->username . ")" . T_('updated'), AmpConfig::get('web_path'). '/admin/users.php'); show_confirmation(T_('User Updated'), $client->fullname . "(" . $client->username . ")" . T_('updated'), AmpConfig::get('web_path'). '/admin/users.php');
@ -96,13 +119,15 @@ switch ($_REQUEST['action']) {
exit; exit;
} }
$username = scrub_in($_POST['username']); $username = scrub_in($_POST['username']);
$fullname = scrub_in($_POST['fullname']); $fullname = scrub_in($_POST['fullname']);
$email = scrub_in($_POST['email']); $email = scrub_in($_POST['email']);
$website = scrub_in($_POST['website']); $website = scrub_in($_POST['website']);
$access = scrub_in($_POST['access']); $access = scrub_in($_POST['access']);
$pass1 = $_POST['password_1']; $pass1 = $_POST['password_1'];
$pass2 = $_POST['password_2']; $pass2 = $_POST['password_2'];
$state = (string) scrub_in($_POST['state']);
$city = (string) scrub_in($_POST['city']);
if ($pass1 !== $pass2 || !strlen($pass1)) { if ($pass1 !== $pass2 || !strlen($pass1)) {
Error::add('password', T_("Error Passwords don't match")); Error::add('password', T_("Error Passwords don't match"));
@ -117,20 +142,25 @@ switch ($_REQUEST['action']) {
Error::add('username', T_('Error Username already exists')); Error::add('username', T_('Error Username already exists'));
} }
if (!Error::occurred()) { // Check the mail for correct address formation.
/* Attempt to create the user */ if (!Mailer::validate_address($email)) {
$user_id = User::create($username, $fullname, $email, $website, $pass1, $access); Error::add('email', T_('Invalid email address'));
if (!$user_id) { }
Error::add('general', T_("Error: Insert Failed"));
}
$user = new User($user_id); /* If we've got an error then show add form! */
$user->upload_avatar(); if (Error::occurred()) {
} // if no errors require_once AmpConfig::get('prefix') . '/templates/show_add_user.inc.php';
else {
$_REQUEST['action'] = 'show_add_user';
break; break;
} }
/* Attempt to create the user */
$user_id = User::create($username, $fullname, $email, $website, $pass1, $access, $state, $city);
if (!$user_id) {
Error::add('general', T_("Error: Insert Failed"));
}
$user = new User($user_id);
$user->upload_avatar();
if ($access == 5) { $access = T_('Guest');} elseif ($access == 25) { $access = T_('User');} elseif ($access == 100) { $access = T_('Admin');} if ($access == 5) { $access = T_('Guest');} elseif ($access == 25) { $access = T_('User');} elseif ($access == 100) { $access = T_('Admin');}
/* HINT: %1 Username, %2 Access num */ /* HINT: %1 Username, %2 Access num */
@ -139,6 +169,9 @@ switch ($_REQUEST['action']) {
case 'enable': case 'enable':
$client = new User($_REQUEST['user_id']); $client = new User($_REQUEST['user_id']);
$client->enable(); $client->enable();
if (!AmpConfig::get('user_no_email_confirm')) {
Registration::send_account_enabled($client->username, $client->fullname, $client->email);
}
show_confirmation(T_('User Enabled'),$client->fullname . ' (' . $client->username . ')', AmpConfig::get('web_path'). '/admin/users.php'); show_confirmation(T_('User Enabled'),$client->fullname . ' (' . $client->username . ')', AmpConfig::get('web_path'). '/admin/users.php');
break; break;
case 'disable': case 'disable':
@ -239,7 +272,7 @@ switch ($_REQUEST['action']) {
$browse = new Browse(); $browse = new Browse();
$browse->reset_filters(); $browse->reset_filters();
$browse->set_type('user'); $browse->set_type('user');
$browse->set_simple_browse(1); $browse->set_simple_browse(true);
$browse->set_sort('name','ASC'); $browse->set_sort('name','ASC');
$user_ids = $browse->get_objects(); $user_ids = $browse->get_objects();
$browse->show_objects($user_ids); $browse->show_objects($user_ids);

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -26,144 +26,33 @@ require_once AmpConfig::get('prefix') . '/templates/header.inc.php';
/* Switch on Action */ /* Switch on Action */
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'clear_art': case 'delete':
if (!$GLOBALS['user']->has_access('75')) { UI::access_denied(); } if (AmpConfig::get('demo_mode')) { break; }
$art = new Art($_GET['album_id'],'album');
$art->reset();
show_confirmation(T_('Album Art Cleared'), T_('Album Art information has been removed from the database'),"/albums.php?action=show&amp;album=" . $art->uid);
break;
// Upload album art
case 'upload_art':
// we didn't find anything $album_id = scrub_in($_REQUEST['album_id']);
if (empty($_FILES['file']['tmp_name'])) { show_confirmation(
show_confirmation(T_('Album Art Not Located'), T_('Album Art could not be located at this time. This may be due to write access error, or the file is not received correctly.'),"/albums.php?action=show&amp;album=" . $_REQUEST['album_id']); T_('Album Deletion'),
break; T_('Are you sure you want to permanently delete this album?'),
} AmpConfig::get('web_path')."/albums.php?action=confirm_delete&album_id=" . $album_id,
1,
'delete_album'
);
break;
case 'confirm_delete':
if (AmpConfig::get('demo_mode')) { break; }
$album = new Album($_REQUEST['album_id']); $album = new Album($_REQUEST['album_id']);
// Pull the image information if (!Catalog::can_remove($album)) {
$data = array('file'=>$_FILES['file']['tmp_name']); debug_event('album', 'Unauthorized to remove the album `.' . $album->id . '`.', 1);
$image_data = Art::get_from_source($data, 'album'); UI::access_denied();
exit;
// If we got something back insert it
if ($image_data) {
$art = new Art($album->id,'album');
$art->insert($image_data,$_FILES['file']['type']);
show_confirmation(T_('Album Art Inserted'),'',"/albums.php?action=show&amp;album=" . $album->id);
}
// Else it failed
else {
show_confirmation(T_('Album Art Not Located'), T_('Album Art could not be located at this time. This may be due to write access error, or the file is not received correctly.'),"/albums.php?action=show&amp;album=" . $album->id);
} }
break; if ($album->remove_from_disk()) {
case 'find_art': show_confirmation(T_('Album Deletion'), T_('Album has been deleted.'), AmpConfig::get('web_path'));
// If not a user then kick em out
if (!Access::check('interface','25')) { UI::access_denied(); exit; }
// Prevent the script from timing out
set_time_limit(0);
// get the Album information
$album = new Album($_GET['album_id']);
$album->format();
$art = new Art($album->id,'album');
$images = array();
$cover_url = array();
// If we've got an upload ignore the rest and just insert it
if (!empty($_FILES['file']['tmp_name'])) {
$path_info = pathinfo($_FILES['file']['name']);
$upload['file'] = $_FILES['file']['tmp_name'];
$upload['mime'] = 'image/' . $path_info['extension'];
$image_data = Art::get_from_source($upload, 'album');
if ($image_data) {
$art->insert($image_data,$upload['0']['mime']);
show_confirmation(T_('Album Art Inserted'),'',"/albums.php?action=show&amp;album=" . $_REQUEST['album_id']);
break;
} // if image data
} // if it's an upload
// Build the options for our search
if (isset($_REQUEST['artist_name'])) {
$artist = scrub_in($_REQUEST['artist_name']);
} elseif ($album->artist_count == '1') {
$artist = $album->f_artist_name;
} else { } else {
$artist = ""; show_confirmation(T_('Album Deletion'), T_('Cannot delete this album.'), AmpConfig::get('web_path'));
} }
if (isset($_REQUEST['album_name'])) {
$album_name = scrub_in($_REQUEST['album_name']);
} else {
$album_name = $album->full_name;
}
$options['artist'] = $artist;
$options['album_name'] = $album_name;
$options['keyword'] = trim($artist . " " . $album_name);
// Attempt to find the art.
$images = $art->gather($options);
if (!empty($_REQUEST['cover'])) {
$path_info = pathinfo($_REQUEST['cover']);
$cover_url[0]['url'] = scrub_in($_REQUEST['cover']);
$cover_url[0]['mime'] = 'image/' . $path_info['extension'];
}
$images = array_merge($cover_url,$images);
// If we've found anything then go for it!
if (count($images)) {
// We don't want to store raw's in here so we need to strip them out into a separate array
foreach ($images as $index=>$image) {
if ($image['raw']) {
unset($images[$index]['raw']);
}
} // end foreach
// Store the results for further use
$_SESSION['form']['images'] = $images;
require_once AmpConfig::get('prefix') . '/templates/show_album_art.inc.php';
}
// Else nothing
else {
show_confirmation(T_('Album Art Not Located'), T_('Album Art could not be located at this time. This may be due to write access error, or the file is not received correctly.'),"/albums.php?action=show&amp;album=" . $album->id);
}
$albumname = $album->name;
$artistname = $artist;
// Remember the last typed entry, if there was one
if (!empty($_REQUEST['album_name'])) { $albumname = scrub_in($_REQUEST['album_name']); }
if (!empty($_REQUEST['artist_name'])) { $artistname = scrub_in($_REQUEST['artist_name']); }
require_once AmpConfig::get('prefix') . '/templates/show_get_albumart.inc.php';
break;
case 'select_art':
/* Check to see if we have the image url still */
$image_id = $_REQUEST['image'];
$album_id = $_REQUEST['album_id'];
// Prevent the script from timing out
set_time_limit(0);
$album = new Album($album_id);
$album_groups = $album->get_group_disks_ids();
$image = Art::get_from_source($_SESSION['form']['images'][$image_id], 'album');
$mime = $_SESSION['form']['images'][$image_id]['mime'];
foreach ($album_groups as $a_id) {
$art = new Art($a_id, 'album');
$art->insert($image, $mime);
}
header("Location:" . AmpConfig::get('web_path') . "/albums.php?action=show&album=" . $album_id);
break; break;
case 'update_from_tags': case 'update_from_tags':
// Make sure they are a 'power' user at least // Make sure they are a 'power' user at least
@ -193,7 +82,7 @@ switch ($_REQUEST['action']) {
if (isset($_GET['order'])) { if (isset($_GET['order'])) {
$songs = explode(";", $_GET['order']); $songs = explode(";", $_GET['order']);
$track = 1; $track = $_GET['offset'] ? (intval($_GET['offset']) + 1) : 1;
foreach ($songs as $song_id) { foreach ($songs as $song_id) {
if ($song_id != '') { if ($song_id != '') {
Song::update_track($track, $song_id); Song::update_track($track, $song_id);

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -28,10 +28,42 @@ UI::show_header();
* Display Switch * Display Switch
*/ */
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'delete':
if (AmpConfig::get('demo_mode')) { break; }
$artist_id = scrub_in($_REQUEST['artist_id']);
show_confirmation(
T_('Artist Deletion'),
T_('Are you sure you want to permanently delete this artist?'),
AmpConfig::get('web_path')."/artists.php?action=confirm_delete&artist_id=" . $artist_id,
1,
'delete_artist'
);
break;
case 'confirm_delete':
if (AmpConfig::get('demo_mode')) { break; }
$artist = new Artist($_REQUEST['artist_id']);
if (!Catalog::can_remove($artist)) {
debug_event('artist', 'Unauthorized to remove the artist `.' . $artist->id . '`.', 1);
UI::access_denied();
exit;
}
if ($artist->remove_from_disk()) {
show_confirmation(T_('Artist Deletion'), T_('Artist has been deleted.'), AmpConfig::get('web_path'));
} else {
show_confirmation(T_('Artist Deletion'), T_('Cannot delete this artist.'), AmpConfig::get('web_path'));
}
break;
case 'show': case 'show':
$artist = new Artist($_REQUEST['artist']); $artist = new Artist($_REQUEST['artist']);
$artist->format(); $artist->format();
$object_ids = $artist->get_albums($_REQUEST['catalog']); if (AmpConfig::get('album_release_type')) {
$multi_object_ids = $artist->get_albums($_REQUEST['catalog'], false, true);
} else {
$object_ids = $artist->get_albums($_REQUEST['catalog']);
}
$object_type = 'album'; $object_type = 'album';
require_once AmpConfig::get('prefix') . '/templates/show_artist.inc.php'; require_once AmpConfig::get('prefix') . '/templates/show_artist.inc.php';
break; break;

169
sources/arts.php Normal file
View file

@ -0,0 +1,169 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
require_once 'lib/init.php';
require_once AmpConfig::get('prefix') . '/templates/header.inc.php';
$object_type = $_GET['object_type'];
$object_id = $_GET['object_id'];
if (!Core::is_library_item($object_type)) { UI::access_denied(); exit; }
$burl = '';
if (isset($_GET['burl'])) {
$burl = base64_decode($_GET['burl']);
}
$item = new $object_type($object_id);
// If not a content manager user then kick em out
if (!Access::check('interface', 50) && (!Access::check('interface', 25) || $item->get_user_owner() != $GLOBALS['user']->id)) { UI::access_denied(); exit; }
/* Switch on Action */
switch ($_REQUEST['action']) {
case 'clear_art':
$art = new Art($object_id, $object_type);
$art->reset();
show_confirmation(T_('Art Cleared'), T_('Art information has been removed from the database'), $burl);
break;
// Upload art
case 'upload_art':
// we didn't find anything
if (empty($_FILES['file']['tmp_name'])) {
show_confirmation(T_('Art Not Located'), T_('Art could not be located at this time. This may be due to write access error, or the file is not received correctly.'), $burl);
break;
}
// Pull the image information
$data = array('file'=>$_FILES['file']['tmp_name']);
$image_data = Art::get_from_source($data, $object_type);
// If we got something back insert it
if ($image_data) {
$art = new Art($object_id, $object_type);
$art->insert($image_data,$_FILES['file']['type']);
show_confirmation(T_('Art Inserted'), '', $burl);
}
// Else it failed
else {
show_confirmation(T_('Art Not Located'), T_('Art could not be located at this time. This may be due to write access error, or the file is not received correctly.'), $burl);
}
break;
case 'find_art':
// Prevent the script from timing out
set_time_limit(0);
$item->format();
$art = new Art($object_id, $object_type);
$images = array();
$cover_url = array();
// If we've got an upload ignore the rest and just insert it
if (!empty($_FILES['file']['tmp_name'])) {
$path_info = pathinfo($_FILES['file']['name']);
$upload['file'] = $_FILES['file']['tmp_name'];
$upload['mime'] = 'image/' . $path_info['extension'];
$image_data = Art::get_from_source($upload, $object_type);
if ($image_data) {
$art->insert($image_data,$upload['0']['mime']);
show_confirmation(T_('Art Inserted'), '', $burl);
break;
} // if image data
} // if it's an upload
$keywords = $item->get_keywords();
$keyword = '';
$options = array();
foreach ($keywords as $key => $word) {
if (isset($_REQUEST['option_' . $key])) {
$word['value'] = $_REQUEST['option_' . $key];
}
$options[$key] = $word['value'];
if ($word['important']) {
if (!empty($word['value'])) {
$keyword .= ' ' . $word['value'];
}
}
}
$options['keyword'] = trim($keyword);
// Attempt to find the art.
$images = $art->gather($options);
if (!empty($_REQUEST['cover'])) {
$path_info = pathinfo($_REQUEST['cover']);
$cover_url[0]['url'] = scrub_in($_REQUEST['cover']);
$cover_url[0]['mime'] = 'image/' . $path_info['extension'];
}
$images = array_merge($cover_url, $images);
// If we've found anything then go for it!
if (count($images)) {
// We don't want to store raw's in here so we need to strip them out into a separate array
foreach ($images as $index=>$image) {
if ($image['raw']) {
unset($images[$index]['raw']);
}
} // end foreach
// Store the results for further use
$_SESSION['form']['images'] = $images;
require_once AmpConfig::get('prefix') . '/templates/show_arts.inc.php';
}
// Else nothing
else {
show_confirmation(T_('Art Not Located'), T_('Art could not be located at this time. This may be due to write access error, or the file is not received correctly.'), $burl);
}
require_once AmpConfig::get('prefix') . '/templates/show_get_art.inc.php';
break;
case 'select_art':
/* Check to see if we have the image url still */
$image_id = $_REQUEST['image'];
// Prevent the script from timing out
set_time_limit(0);
$image = Art::get_from_source($_SESSION['form']['images'][$image_id], 'album');
$mime = $_SESSION['form']['images'][$image_id]['mime'];
// Special case for albums, I'm not sure if we should keep it, remove it or find a generic way
if ($object_type == 'album') {
$album = new $object_type($object_id);
$album_groups = $album->get_group_disks_ids();
foreach ($album_groups as $a_id) {
$art = new Art($a_id, $object_type);
$art->insert($image, $mime);
}
} else {
$art = new Art($object_id, $object_type);
$art->insert($image, $mime);
}
header("Location:" . $burl);
break;
}
UI::show_footer();

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -21,7 +21,16 @@
*/ */
if (!defined('NO_SESSION')) { if (!defined('NO_SESSION')) {
require_once 'lib/init.php'; if (isset($_REQUEST['ssid'])) {
define('NO_SESSION', 1);
require_once 'lib/init.php';
if (!Session::exists('stream', $_REQUEST['ssid'])) {
UI::access_denied();
exit;
}
} else {
require_once 'lib/init.php';
}
} }
ob_end_clean(); ob_end_clean();
@ -35,72 +44,78 @@ if (!defined('NO_SESSION') && !Access::check_function('batch_download')) {
set_time_limit(0); set_time_limit(0);
$media_ids = array(); $media_ids = array();
$name = "Unknown.zip"; $default_name = "Unknown.zip";
$object_type = scrub_in($_REQUEST['action']);
$name = $default_name;
switch ($_REQUEST['action']) { if ($object_type == 'browse') {
case 'tmp_playlist': $object_type = $_REQUEST['type'];
$media_ids = $GLOBALS['user']->playlist->get_items(); }
$name = $GLOBALS['user']->username . ' - Playlist';
break; if (!check_can_zip($object_type)) {
case 'playlist': debug_event('batch', 'Object type `' . $object_type . '` is not allowed to be zipped.', 1);
$playlist = new Playlist($_REQUEST['id']); UI::access_denied();
$media_ids = $playlist->get_songs(); exit;
$name = $playlist->name; }
break;
case 'smartplaylist': if (Core::is_playable_item($_REQUEST['action'])) {
$search = new Search('song', $_REQUEST['id']); $id = $_REQUEST['id'];
$sql = $search->to_sql(); if (!is_array($id)) {
$sql = $sql['base'] . ' ' . $sql['table_sql'] . ' WHERE ' . $id = array($id);
$sql['where_sql']; }
$db_results = Dba::read($sql); $media_ids = array();
while ($row = Dba::fetch_assoc($db_results)) { foreach ($id as $i) {
$media_ids[] = $row['id']; $libitem = new $object_type($i);
if ($libitem->id) {
$libitem->format();
$name = $libitem->get_fullname();
$media_ids = array_merge($media_ids, $libitem->get_medias());
} }
$name = $search->name; }
break; } else {
case 'album': switch ($_REQUEST['action']) {
foreach ($_REQUEST['id'] as $a) { case 'tmp_playlist':
$album = new Album($a); $media_ids = $GLOBALS['user']->playlist->get_items();
if (empty($name)) { $name = $GLOBALS['user']->username . ' - Playlist';
$name = $album->name; break;
} case 'browse':
$asongs = $album->get_songs(); $id = intval(scrub_in($_REQUEST['browse_id']));
foreach ($asongs as $song_id) { $browse = new Browse($id);
$media_ids[] = $song_id; $browse_media_ids = $browse->get_saved();
} foreach ($browse_media_ids as $media_id) {
} switch ($object_type) {
break; case 'album':
case 'artist': $album = new Album($media_id);
$artist = new Artist($_REQUEST['id']); $media_ids = array_merge($media_ids, $album->get_songs());
$media_ids = $artist->get_songs(); break;
$name = $artist->name; case 'song':
break; $media_ids[] = $media_id;
case 'browse': break;
$id = scrub_in($_REQUEST['browse_id']); case 'video':
$browse = new Browse($id); $media_ids[] = array('object_type' => 'Video', 'object_id' => $media_id);
$browse_media_ids = $browse->get_saved(); break;
foreach ($browse_media_ids as $media_id) { } // switch on type
switch ($_REQUEST['type']) { } // foreach media_id
case 'album': $name = 'Batch-' . date("dmY",time());
$album = new Album($media_id); default:
$media_ids = array_merge($media_ids, $album->get_songs()); // Rien a faire
break; break;
case 'song': } // action switch
$media_ids[] = $media_id; }
break;
case 'video': if (!User::stream_control($media_ids)) {
$media_ids[] = array('Video', $media_id); debug_event('UI::access_denied', 'Stream control failed for user ' . $GLOBALS['user']->username, '3');
break; UI::access_denied();
} // switch on type exit;
} // foreach media_id }
$name = 'Batch-' . date("dmY",time());
default: // Write/close session data to release session lock for this script.
// Rien a faire // This to allow other pages from the same session to be processed
break; // Do NOT change any session variable after this call
} // action switch session_write_close();
// Take whatever we've got and send the zip // Take whatever we've got and send the zip
$song_files = get_song_files($media_ids); $song_files = get_media_files($media_ids);
if (is_array($song_files['0'])) { if (is_array($song_files['0'])) {
set_memory_limit($song_files['1']+32); set_memory_limit($song_files['1']+32);
send_zip($name,$song_files['0']); send_zip($name,$song_files['0']);

View file

@ -1,2 +1,10 @@
Order deny,allow # Apache 2.4
Deny from all <IfModule mod_authz_core.c>
Require all denied
</IfModule>
# Apache 2.2
<IfModule mod_access.c>
Order deny,allow
Deny from all
</IfModule>

45
sources/bin/broadcast.inc Normal file
View file

@ -0,0 +1,45 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
define('NO_SESSION','1');
define('CLI', 1);
$path = dirname(__FILE__);
$prefix = realpath($path . '/../');
require_once $prefix . '/lib/init.php';
ob_end_flush();
echo T_("Starting broadcasts...") . "\n";
if (AmpConfig::get('upnp_backend')) {
echo T_("UPnP broadcast... ");
Upnp_Api::sddpSend();
echo T_("Done.") . "\n";
} else {
echo T_("UPnP backend disabled. Broadcast skipped.") . "\n";
}
ob_end_flush();
echo "\n";
?>

View file

@ -0,0 +1,48 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
define('NO_SESSION','1');
$path = dirname(__FILE__);
$prefix = realpath($path . '/../');
require_once $prefix . '/lib/init.php';
// Turn off output buffering we don't need it for a command line script
ob_end_clean();
$sql = "SELECT `image`,`id` FROM `image`";
$db_results = Dba::read($sql);
$results = array();
while ($row = Dba::fetch_assoc($db_results)) {
$source = $row['image'];
$id = $row['id'];
$dimensions = Core::image_dimensions($source);
if ($dimensions) {
$width = intval($dimensions['width']);
$height = intval($dimensions['height']);
$sql = "Update `image` SET `width`=". $width . ",`height`=".$height." WHERE `id`='".$id."'";
Dba::write($sql);
}
}
?>

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -29,39 +29,49 @@ require_once $prefix . '/lib/init.php';
ob_end_flush(); ob_end_flush();
$catclean = 0; //All off by default $tmpmemlimoff = 0; //All off by default
$catclean = 0;
$catverify = 0; $catverify = 0;
$catadd = 0; $catadd = 0;
$artadd = 0; $artadd = 0;
$plimp = 0; $plimp = 0;
$optimizetables = 0;
if (count($_SERVER['argv']) == 1) { if (count($_SERVER['argv']) == 1) {
$operations_string = "\n\t". T_('- All Catalog Operations'); $operations_string = "\n\t- ". T_('Doing all catalog operations');
} }
if (count($_SERVER['argv']) > 1) { if (count($_SERVER['argv']) > 1) {
for ($x = 1; $x < count($_SERVER['argv']); $x++) { for ($x = 1; $x < count($_SERVER['argv']); $x++) {
if ($_SERVER['argv'][$x] == "-c") { if ($_SERVER['argv'][$x] == "-m") {
$operations_string .= "\n\t" . T_('- Catalog Clean'); $operations_string .= "\n\t- " . T_('Temporary deactivate PHP memory limit');
$tmpmemlimoff = 1;
}
elseif ($_SERVER['argv'][$x] == "-c") {
$operations_string .= "\n\t- " . T_('Cleaning catalog/s');
$catclean = 1; $catclean = 1;
} }
elseif ($_SERVER['argv'][$x] == "-v") { elseif ($_SERVER['argv'][$x] == "-v") {
$operations_string .= "\n\t" . T_('- Catalog Verify'); $operations_string .= "\n\t- " . T_('Verifying catalog/s');
$catverify = 1; $catverify = 1;
} }
elseif ($_SERVER['argv'][$x] == "-a") { elseif ($_SERVER['argv'][$x] == "-a") {
$operations_string .= "\n\t" . T_('- Catalog Add'); $operations_string .= "\n\t- " . T_('Adding new media to catalog/s');
$catadd = 1; $catadd = 1;
} }
elseif ($_SERVER['argv'][$x] == "-g") { elseif ($_SERVER['argv'][$x] == "-g") {
$operations_string .= "\n\t" . T_('- Catalog Art Gather'); $operations_string .= "\n\t- " . T_('Gathering new media art');
$artadd = 1; $artadd = 1;
} }
elseif ($_SERVER['argv'][$x] == "-i") { elseif ($_SERVER['argv'][$x] == "-i") {
$operations_string .= "\n\t" . T_('- Playlist Import'); $operations_string .= "\n\t- " . T_('Importing playlist/s');
$plimp = 1; $plimp = 1;
} }
elseif ($_SERVER['argv'][$x] == "-o") {
$operations_string .= "\n\t- " . T_('Database table optimization');
$optimizetables = 1;
}
else { else {
if ($where) $where .= " OR "; if ($where) $where .= " OR ";
$where .= "name LIKE '%" . Dba::escape(preg_replace("/[^a-z0-9\. -]/i", "", $_SERVER['argv'][$x])) . "%'"; $where .= "name LIKE '%" . Dba::escape(preg_replace("/[^a-z0-9\. -]/i", "", $_SERVER['argv'][$x])) . "%'";
@ -70,19 +80,43 @@ if (count($_SERVER['argv']) > 1) {
} }
if (count($_SERVER['argv']) != 1 AND $artadd != 1 && $catclean != 1 && $catverify != 1 && $catadd != 1) { if (count($_SERVER['argv']) != 1 AND $artadd != 1 && $catclean != 1 && $catverify != 1 && $catadd != 1) {
usage(); usage();
exit; exit;
} }
if ($artadd == 0 && $catclean == 0 && $catverify == 0 && $catadd == 0) { //didn't pass any clean/verify/add arguments if ($catclean == 0 && $catverify == 0 && $catadd == 0 && $artadd == 0 && $optimizetables == 0) { //didn't pass any clean/verify/add arguments
$catclean = 1; //set them all to on $catclean = 1; //set them all to on
$catverify = 1; $catverify = 1;
$catadd = 1; $catadd = 1;
$artadd = 1; $artadd = 1;
$optimizetables = 1;
}
echo "\n----------------------------------------------------------\n";
echo T_("Starting catalog operations...") . $operations_string . "\n";
echo "----------------------------------------------------------\n\n";
// -------- Options before the catalog actions loop
if ($tmpmemlimoff == 1) {
// Temporarily deactivate PHP memory limit
echo "\033[31m- " . T_("Deactivated PHP memory limit") . " -\033[0m\n";
ini_set('memory_limit','-1');
echo "------------------\n\n";
} }
echo T_("Starting Catalog Operations...") . $operations_string . "\n"; $options = array(); // for $catadd
if ($artadd == 1) {
echo "- " . T_("Gathering art") . " - \n";
$options['gather_art'] = true;
} else {
$options['gather_art'] = false;
}
if ($plimp == 1) {
echo "- " . T_("Parsing playlists") . " - \n";
$options['parse_playlist'] = true;
} else {
$options['parse_playlist'] = false;
}
// --------
if ($where) $where = "($where) AND catalog_type='local'"; if ($where) $where = "($where) AND catalog_type='local'";
else $where = "catalog_type='local'"; else $where = "catalog_type='local'";
$sql = "SELECT id FROM catalog"; $sql = "SELECT id FROM catalog";
@ -94,48 +128,46 @@ ob_start("ob_html_strip",'1024',true);
while ($row = Dba::fetch_row($db_results)) { while ($row = Dba::fetch_row($db_results)) {
$catalog = Catalog::create_from_id($row['0']); $catalog = Catalog::create_from_id($row['0']);
printf(T_('Reading: %s'), $catalog->name); printf(T_('Reading catalog: %s'), $catalog->name);
ob_flush(); ob_flush();
echo "\n"; echo "\n";
if ($catclean == 1) { if ($catclean == 1) {
// Clean out dead files // Clean out dead files
echo T_("- Starting Clean - "); echo "- " . T_("Start cleaning orphaned media entries") . " - \n";
echo "\n"; echo "\n";
$catalog->clean_catalog(); $catalog->clean_catalog();
echo "------------------\n\n"; echo "------------------\n\n";
} }
if ($catverify == 1) { if ($catverify == 1) {
// Verify Existing // Verify Existing
echo T_("- Starting Verify - "); echo "- " . T_("Start verifying media related to catalog entries") . " - \n";
echo "\n"; echo "\n";
$catalog->verify_catalog($row['0']); $catalog->verify_catalog($row['0']);
echo "-------------------\n\n"; echo "-------------------\n\n";
} }
if ($catadd == 1) { if ($catadd == 1) {
// Look for new files // Look for new files
echo T_("- Starting Add - "); echo "- " . T_("Start adding new media") . " - \n";
echo "\n"; echo "\n";
$options = array();
if ($artadd == 1) {
$options['gather_art'] = true;
}
if ($plimp == 1) {
$options['parse_playlist'] = true;
}
$catalog->add_to_catalog($options); $catalog->add_to_catalog($options);
echo "----------------\n\n"; echo "----------------\n\n";
} elseif ($artadd == 1) { }
// Look for album art elseif ($artadd == 1) {
echo T_('Starting Album Art Search'); // Look for media art
echo "- " . T_('Start searching new media art') . " - \n";
echo "\n"; echo "\n";
$catalog->gather_art(); $catalog->gather_art();
echo "----------------\n\n"; echo "----------------\n\n";
} }
} }
if ($optimizetables == 1) {
Dba::optimize_tables(); // Optimize Database Tables
echo "- " . T_('Optimizing database tables') . " - \n";
echo "\n";
Dba::optimize_tables();
echo "------------------\n\n";
}
ob_end_flush(); ob_end_flush();
echo "\n"; echo "\n";
@ -154,22 +186,37 @@ function ob_html_strip($string) {
} // ob_html_strip } // ob_html_strip
function usage() { function usage() {
echo T_("- Catalog Update -");
echo "\n"; echo "\n";
echo T_("Usage: catalog_update.inc [CATALOG NAME] [-c|-v|-a|-g|-t|-i]"); echo "----------------------------------------------------------\n\t\t";
echo "\n\t"; echo T_("- Catalog Update Help -");
echo T_("Default behavior is to do all except playlist import"); echo "\n\033[32m";
echo T_("Usage: catalog_update.inc [CATALOG NAME] [-m|-c|-v|-a|-g|-i|-o]") . "\033[0m (\033[31m!\033[0m)";
echo "\033[0m\n";
echo "----------------------------------------------------------";
echo "\n";
echo T_("Default behavior is to do all except temporarily deactivate the php memory limit");
echo "\n";
echo "----------------------------------------------------------";
echo "\n-m\t";
echo T_('Temporarily deactivates PHP memory limit.') . " (\033[31m1\033[0m)";
echo "\n-c\t"; echo "\n-c\t";
echo T_('Clean Catalogs'); echo T_('Cleans catalogs from orphaned entries.');
echo "\n-v\t"; echo "\n-v\t";
echo T_('Verify Catalogs'); echo T_('Verifies catalog entries and updates them if related files have new information.');
echo "\n-a\t"; echo "\n-a\t";
echo T_('Add to Catalogs'); echo T_('Adds new media to catalogs.');
echo "\n-i\t";
echo T_('Import Playlists');
echo "\n-g\t"; echo "\n-g\t";
echo T_('Gather Art'); echo T_('Gathers media Art.');
echo "\n-i\t";
echo T_('Imports playlists.');
echo "\n-o\t";
echo T_('Optimizes Database Tables.') . " (\033[31m2\033[0m)";
echo "\n"; echo "\n";
echo "----------------------------------------------------------\033[31m\n";
echo "1. " . T_('Use this option at your own risk! Your system could crash or become unresponsive due to huge memory consumption!') . "\n";
echo "2. " . T_('Depending on your systems performance, this option could need a long time to finish and extremely slow down other database processes if you have big catalogs!') . "\n";
echo "! " . T_('The switches [-m|-i|-o] can only be used, if one of the other switches [-c|-v|-a|-g] is used.');
echo "\033[0m\n";
echo "----------------------------------------------------------"; echo "----------------------------------------------------------";
echo "\n"; echo "\n";
} }

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -23,6 +23,8 @@
define('NO_SESSION','1'); define('NO_SESSION','1');
define('CLI', 1); define('CLI', 1);
$chunk_buffer = '';
$nb_chunks_remainder = 0;
$path = dirname(__FILE__); $path = dirname(__FILE__);
$prefix = realpath($path . '/../'); $prefix = realpath($path . '/../');
require_once $prefix . '/lib/init.php'; require_once $prefix . '/lib/init.php';
@ -106,7 +108,7 @@ echo T_("Listening on ") . $address . ':' . $port . "\n";
$stream_clients = array(); $stream_clients = array();
$client_socks = array(); $client_socks = array();
$last_stream = 0; $last_stream = microtime(true);
while(true) while(true)
{ {
//prepare readable sockets //prepare readable sockets
@ -114,7 +116,6 @@ while(true)
if (count($client_socks) < $channel->max_listeners) { if (count($client_socks) < $channel->max_listeners) {
$read_socks[] = $server; $read_socks[] = $server;
} }
//echo "b\n";ob_flush(); //echo "b\n";ob_flush();
//start reading and use a large timeout //start reading and use a large timeout
if(stream_select ( $read_socks, $write, $except, 1)) if(stream_select ( $read_socks, $write, $except, 1))
@ -141,280 +142,112 @@ while(true)
// Get new message from existing client // Get new message from existing client
foreach($read_socks as $sock) foreach($read_socks as $sock)
{ {
$data = fread($sock, 1024);
if(!$data)
{
client_disconnect($channel, $client_socks, $stream_clients, $sock);
continue;
}
$headers = explode("\n", $data);
if (count($headers) > 0) {
$cmd = explode(" ", $headers[0]);
if ($cmd['0'] == 'GET') {
switch ($cmd['1']) {
case '/stream.' . $channel->stream_type:
$options = array(
'socket' => $sock,
'length' => 0
);
for ($i = 1; $i < count($headers); $i++) {
$headerpart = explode(":", $headers[$i], 2);
$header = strtolower(trim($headerpart[0]));
$value = trim($headerpart[1]);
switch ($header) {
case 'icy-metadata':
$options['metadata'] = ($value == '1');
$options['metadata_lastsent'] = 0;
$options['metadata_lastsong'] = 0;
break;
}
}
// Stream request
if ($options['metadata']) {
//fwrite($sock, "ICY 200 OK\r\n");
fwrite($sock, "HTTP/1.0 200 OK\r\n");
} else {
fwrite($sock, "HTTP/1.1 200 OK\r\n");
fwrite($sock, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
}
fwrite($sock, "Content-Type: " . Song::type_to_mime($transcode_to) . "\r\n");
fwrite($sock, "Accept-Ranges: none\r\n");
$genre = $channel->get_genre();
// Send Shoutcast metadata on demand
if ($options['metadata']) {
fwrite($sock, "icy-notice1: " . AmpConfig::get('title') . "\r\n");
fwrite($sock, "icy-name: " . $channel->name . "\r\n");
if (!empty($genre)) {
fwrite($sock, "icy-genre: " . $genre . "\r\n");
}
fwrite($sock, "icy-url: " . $channel->url . "\r\n");
fwrite($sock, "icy-pub: " . ($channel->is_private) ? '0' : '1' . "\r\n");
if ($channel->bitrate) {
fwrite($sock, "icy-br: " . strval($channel->bitrate) . "\r\n");
}
fwrite($sock, "icy-metaint: " . strval($metadata_interval) . "\r\n");
}
// Send additional Icecast metadata
fwrite($sock, "x-audiocast-server-url: " . $channel->url . "\r\n");
fwrite($sock, "x-audiocast-name: " . $channel->name . "\r\n");
fwrite($sock, "x-audiocast-description: " . $channel->description . "\r\n");
fwrite($sock, "x-audiocast-url: " . $channel->url . "\r\n");
if (!empty($genre)) {
fwrite($sock, "x-audiocast-genre: " . $genre . "\r\n");
}
fwrite($sock, "x-audiocast-bitrate: " . strval($channel->bitrate) . "\r\n");
fwrite($sock, "x-audiocast-public: " . (($channel->is_private) ? "0" : "1") . "\r\n");
fwrite($sock, "\r\n");
// Add to stream clients list
$key = array_search($sock, $read_socks);
$stream_clients[$key] = $options;
break;
case '/':
case '/status.xsl':
// Stream request
fwrite($sock, "HTTP/1.0 200 OK\r\n");
fwrite($sock, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
fwrite($sock, "Content-Type: text/html\r\n");
fwrite($sock, "\r\n");
// Create xsl structure
// Header
$xsl = "";
$xsl .= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" . "\n";
$xsl .= "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" . "\n";
$xsl .= "<html xmlns=\"http://www.w3.org/1999/xhtml\">" . "\n";
$xsl .= "<head>" . "\n";
$xsl .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" . "\n";
$xsl .= "<title>Icecast Streaming Media Server - Ampache</title>" . "\n";
$xsl .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" . "\n";
$xsl .= "</head>" . "\n";
$xsl .= "<body>" . "\n";
$xsl .= "<div class=\"main\">" . "\n";
// Content
$xsl .= "<div class=\"roundcont\">" . "\n";
$xsl .= "<div class=\"roundtop\">" . "\n";
$xsl .= "<img src=\"images/corner_topleft.jpg\" class=\"corner\" style=\"display: none\" alt=\"\" />" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<div class=\"newscontent\">" . "\n";
$xsl .= "<div class=\"streamheader\">" . "\n";
$xsl .= "<table cellspacing=\"0\" cellpadding=\"0\">" . "\n";
$xsl .= "<colgroup align=\"left\"></colgroup>" . "\n";
$xsl .= "<colgroup align=\"right\" width=\"300\"></colgroup>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td><h3>Mount Point /stream." . $channel->stream_type . "</h3></td>" . "\n";
$xsl .= "<td align=\"right\">" . "\n";
$xsl .= "<a href=\"stream.". $channel->stream_type .".m3u\">M3U</a>" . "\n";
$xsl .= "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "</table>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<table border=\"0\" cellpadding=\"4\">" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream Title:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->name . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream Description:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->description . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Content Type:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . Song::type_to_mime($channel->stream_type) . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Mount Start:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . date("c", $channel->start_date) . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Bitrate:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->bitrate . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Current Listeners:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->listeners . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Peak Listeners:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->peak_listeners . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$genre = $channel->get_genre();
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream Genre:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $genre . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream URL:</td>" . "\n";
$xsl .= "<td class=\"streamdata\"><a href=\"" . $channel->url . "\" target=\"_blank\">" . $channel->url . "</a></td>" . "\n";
$xsl .= "</tr>" . "\n";
$currentsong = "";
if ($channel->media) {
$currentsong = $channel->media->f_artist . " - " . $channel->media->f_title;
}
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Current Song:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $currentsong . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "</table>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<div class=\"roundbottom\">" . "\n";
$xsl .= "<img src=\"images/corner_bottomleft.jpg\" class=\"corner\" style=\"display: none\" alt=\"\" />" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<br /><br />" . "\n";
// Footer
$xsl .= "<div class=\"poster\">" . "\n";
$xsl .= "Support Icecast development at <a target=\"_blank\" href=\"http://www.icecast.org\">www.icecast.org</a>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "</body>" . "\n";
$xsl .= "</html>" . "\n";
fwrite($sock, $xsl);
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
case '/style.css':
case '/favicon.ico':
case '/images/corner_bottomleft.jpg':
case '/images/corner_bottomright.jpg':
case '/images/corner_topleft.jpg':
case '/images/corner_topright.jpg':
case '/images/icecast.png':
case '/images/key.png':
case '/images/tunein.png':
// Get read file data
$fpath = AmpConfig::get('prefix') . '/channel' . $cmd['1'];
$pinfo = pathinfo($fpath);
$content_type = 'text/html';
switch ($pinfo['extension']) {
case 'css':
$content_type = "text/css";
break;
case 'jpg':
$content_type = "image/jpeg";
break;
case 'png':
$content_type = "image/png";
break;
case 'ico':
$content_type = "image/vnd.microsoft.icon";
break;
}
fwrite($sock, "HTTP/1.0 200 OK\r\n");
fwrite($sock, "Content-Type: " . $content_type . "\r\n");
$fdata = file_get_contents($fpath);
fwrite($sock, "Content-Length: " . strlen($fdata) . "\r\n");
fwrite($sock, "\r\n");
fwrite($sock, $fdata);
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
case '/stream.' . $channel->stream_type . '.m3u':
fwrite($sock, "HTTP/1.0 200 OK\r\n");
fwrite($sock, "Cache-control: public\r\n");
fwrite($sock, "Content-Disposition: filename=stream." . $channel->stream_type . ".m3u\r\n");
fwrite($sock, "Content-Type: audio/x-mpegurl\r\n");
fwrite($sock, "\r\n");
fwrite($sock, $channel->get_stream_url() . "\n");
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
default:
debug_event('channel', 'Unknown request. Closing connection.', '3');
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
}
}
}
// Handle data parse // Handle data parse
http_serve($channel, $client_socks, $stream_clients, $read_socks, $sock);
} }
} }
if ($channel->bitrate) { if ($channel->bitrate) {
$time_offset = microtime(true) - $last_stream; $time_offset = microtime(true) - $last_stream;
//$mtime = ($last_stream > 0 && $time_offset < 1000000) ? $time_offset : 1;
$mtime = 1; //debug_event('channel', 'time_offset : '. $time_offset, '5');
if ($last_stream > 0 && $time_offset < 1) { //debug_event('channel', 'last_stream: '.$last_stream, '5');
usleep(1000000 - ($time_offset * 1000000));
} elseif ($last_stream > 0) { if ($time_offset < 1)
//$mtime = $time_offset; usleep(1000000 - ($time_offset * 1000000)); // always at least 1 second between cycles
$last_stream = microtime(true);
$mtime = ($time_offset > 1) ? $time_offset : 1;
$nb_chunks = ceil(($mtime * ($channel->bitrate+1/100*$channel->bitrate) * 1000 / 8) / $channel->chunk_size); // channel->bitrate+1% ... leave some headroom for metadata / headers
// we only send full blocks, save remainder and apply when appropriate: allows more granular/arbitrary average bitrates
if ($nb_chunks - ($mtime * ($channel->bitrate+1/100*$channel->bitrate) * 1000 / 8 / $channel->chunk_size) > 0)
$nb_chunks_remainder += $nb_chunks - ($mtime * $channel->bitrate * 1000 / 8 / $channel->chunk_size);
if ($nb_chunks >= 1 && $nb_chunks_remainder >= 1){
$nb_chunks -= 1;
$nb_chunks_remainder -= 1;
//debug_event('channel', 'REMAINDER: '.$nb_chunks_remainder, '5');
} }
$nb_chunks = ceil(($mtime * $channel->bitrate * 1000) / 4096); //debug_event('channel', 'mtime '.$mtime, '5');
//debug_event('channel', 'nb_chunks: '.$nb_chunks, '5');
} else { } else {
$nb_chunks = 1; $nb_chunks = 1;
} }
// Get multiple chunks according to bitrate to return enough data per second (because sleep with socket select) // Get multiple chunks according to bitrate to return enough data per second (because sleep with socket select)
for ($c = 0; $c < $nb_chunks; $c++) { for ($c = 0; $c < $nb_chunks; $c++) {
$chunk = $channel->get_chunk(); $chunk = $channel->get_chunk();
$chunklen = strlen($chunk); $chunklen = strlen($chunk);
$chunk_buffer .= $chunk;
//buffer maintenance
while (strlen($chunk_buffer) > (15 * $nb_chunks * $channel->chunk_size) ){ // buffer 15 seconds
if (strtolower($channel->stream_type) == "ogg" && strtohex(substr($chunk_buffer, 0, 4)) == "4F676753") { //maintain ogg chunk alignment --- "4F676753" == "OggS"
// read OggS segment length
$hex = strtohex(substr($chunk_buffer, 0, 27));
$ogg_nr_of_segments = hexdec(substr($hex, 26*2, 2));
$hex .= strtohex(substr($chunk_buffer, 27, $ogg_nr_of_segments));
$ogg_sum_segm_laces = 0;
for($segm = 0; $segm < $ogg_nr_of_segments; $segm++){
$ogg_sum_segm_laces += hexdec(substr($hex, 27*2 + $segm*2, 2));
}
//$naive = strpos(substr($chunk_buffer, 4), 'OggS') + 4; // naive search for next header
//remove 1 whole OggS chunk
$chunk_buffer = substr($chunk_buffer, 27 + $ogg_nr_of_segments + $ogg_sum_segm_laces);
//debug_event('channel', '$new chunk buffer : '.substr($chunk_buffer,0,300) . ' $hex: '.strtohex(substr($chunk_buffer,0,600)) . ' $ogg_nr_of_segments: ' .$ogg_nr_of_segments . ' bytes cut off: '.(27 + $ogg_nr_of_segments + $ogg_sum_segm_laces) . ' naive: ' .$naive, '5');
} elseif (strtolower($channel->stream_type) == "ogg") {
debug_event('channel', 'Ogg alignament broken! Trying repair...', '5');
$manual_search = strpos($chunk_buffer, 'OggS');
$chunk_buffer = substr($chunk_buffer, $manual_search);
} else { // no chunk alignment required
$chunk_buffer = substr($chunk_buffer, $chunklen);
}
//debug_event('channel', 'remvd chunk from buffer ', '5');
}
if ($chunklen > 0) { if ($chunklen > 0) {
foreach($stream_clients as $key => $client) foreach($stream_clients as $key => $client)
{ {
$sock = $client['socket']; $sock = $client['socket'];
$clchunk = $chunk;
if(!is_resource($sock)) { if(!is_resource($sock)) {
client_disconnect($channel, $client_socks, $stream_clients, $sock); client_disconnect($channel, $client_socks, $stream_clients, $sock);
continue; continue;
} }
$clchunk = $chunk; if ($client['isnew'] == 1){
$client['isnew'] = 0;
//fwrite($sock, $channel->header_chunk);
//debug_event('channel', 'IS NEW' . $channel->header_chunk, '5');
$clchunk_buffer = $channel->header_chunk . $chunk_buffer;
if ($client['metadata']){ //stub
//if (strtolower($channel->stream_type) == "ogg")
while(strlen($clchunk_buffer) > $metadata_interval){
fwrite($sock, substr($clchunk_buffer, 0, $metadata_interval) . chr(0x00));
$clchunk_buffer = substr($clchunk_buffer, $metadata_interval);
}
fwrite($sock, $clchunk_buffer);
$client['metadata_lastsent'] = 0;
$client['length'] += strlen($clchunk_buffer);
} else {
//fwrite($sock, $channel->header_chunk);
$buffer_bytes_written = fwrite($sock, $clchunk_buffer);
while ($buffer_bytes_written != strlen($clchunk_buffer)){
debug_event('channel', 'I HERPED WHEN I SHOULD HAVE DERPED!', '5');
//debug_event('channel', 'chunk_buffer bytes written:' .$buffer_bytes_written .'strlen $chunk_buffer: '.strlen($chunk_buffer), '5');
$clchunk_buffer = substr($clchunk_buffer, $buffer_bytes_written);
$buffer_bytes_written = fwrite($sock, $clchunk_buffer);
}
}
$stream_clients[$key] = $client;
continue;
}
// Check if we need to insert metadata information // Check if we need to insert metadata information
if ($client['metadata']) { if ($client['metadata']) {
$chkmdlen = ($client['length'] + $chunklen) - $client['metadata_lastsent']; $chkmdlen = ($client['length'] + $chunklen) - $client['metadata_lastsent'];
@ -437,20 +270,19 @@ while(true)
$clchunk = substr($chunk, $subpos); $clchunk = substr($chunk, $subpos);
} }
} }
if (strlen($clchunk) > 0) { if (strlen($clchunk) > 0) {
fwrite($sock, $clchunk); fwrite($sock, $clchunk);
$client['length'] += strlen($clchunk); $client['length'] += strlen($clchunk);
} }
$stream_clients[$key] = $client; $stream_clients[$key] = $client;
//debug_event('channel', 'Client stream current length: ' . $client['length'], '5'); //debug_event('channel', 'Client stream current length: ' . $client['length'], '5');
} }
} else { } else {
$channel->update_listeners(0); $channel->update_listeners(0);
debug_event('channel', 'No more data, stream ended.', 5);
die('No more data, stream ended.'); die('No more data, stream ended.');
} }
$last_stream = microtime(true);
} }
} }
@ -486,4 +318,261 @@ function usage()
echo "\n"; echo "\n";
} }
function http_serve($channel, &$client_socks, &$stream_clients, &$read_socks, $sock)
{
$data = fread($sock, 1024);
if(!$data)
{
client_disconnect($channel, $client_socks, $stream_clients, $sock);
return;
}
$headers = explode("\n", $data);
if (count($headers) > 0) {
$cmd = explode(" ", $headers[0]);
if ($cmd['0'] == 'GET') {
switch ($cmd['1']) {
case '/stream.' . $channel->stream_type:
$options = array(
'socket' => $sock,
'length' => 0,
'isnew' => 1
);
//debug_event('channel', 'HTTP HEADERS: '.$data,'5');
for ($i = 1; $i < count($headers); $i++) {
$headerpart = explode(":", $headers[$i], 2);
$header = strtolower(trim($headerpart[0]));
$value = trim($headerpart[1]);
switch ($header) {
case 'icy-metadata':
$options['metadata'] = ($value == '1');
$options['metadata_lastsent'] = 0;
$options['metadata_lastsong'] = 0;
break;
}
}
// Stream request
if ($options['metadata']) {
//$http = "ICY 200 OK\r\n");
$http = "HTTP/1.0 200 OK\r\n";
} else {
$http = "HTTP/1.1 200 OK\r\n";
$http .= "Cache-Control: no-store, no-cache, must-revalidate\r\n";
}
$http .= "Content-Type: " . Song::type_to_mime($channel->stream_type) . "\r\n";
$http .= "Accept-Ranges: none\r\n";
$genre = $channel->get_genre();
// Send Shoutcast metadata on demand
//if ($options['metadata']) {
$http .= "icy-notice1: " . AmpConfig::get('site_title') . "\r\n";
$http .= "icy-name: " . $channel->name . "\r\n";
if (!empty($genre)) {
$http .= "icy-genre: " . $genre . "\r\n";
}
$http .= "icy-url: " . $channel->url . "\r\n";
$http .= "icy-pub: " . (($channel->is_private) ? "0" : "1") . "\r\n";
if ($channel->bitrate) {
$http .= "icy-br: " . strval($channel->bitrate) . "\r\n";
}
global $metadata_interval;
$http .= "icy-metaint: " . strval($metadata_interval) . "\r\n";
//}
// Send additional Icecast metadata
$http .= "x-audiocast-server-url: " . $channel->url . "\r\n";
$http .= "x-audiocast-name: " . $channel->name . "\r\n";
$http .= "x-audiocast-description: " . $channel->description . "\r\n";
$http .= "x-audiocast-url: " . $channel->url . "\r\n";
if (!empty($genre)) {
$http .= "x-audiocast-genre: " . $genre . "\r\n";
}
$http .= "x-audiocast-bitrate: " . strval($channel->bitrate) . "\r\n";
$http .= "x-audiocast-public: " . (($channel->is_private) ? "0" : "1") . "\r\n";
$http .= "\r\n";
fwrite($sock, $http);
// Add to stream clients list
$key = array_search($sock, $read_socks);
$stream_clients[$key] = $options;
break;
case '/':
case '/status.xsl':
// Stream request
fwrite($sock, "HTTP/1.0 200 OK\r\n");
fwrite($sock, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
fwrite($sock, "Content-Type: text/html\r\n");
fwrite($sock, "\r\n");
// Create xsl structure
// Header
$xsl = "";
$xsl .= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" . "\n";
$xsl .= "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" . "\n";
$xsl .= "<html xmlns=\"http://www.w3.org/1999/xhtml\">" . "\n";
$xsl .= "<head>" . "\n";
$xsl .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" . "\n";
$xsl .= "<title>Icecast Streaming Media Server - Ampache</title>" . "\n";
$xsl .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" . "\n";
$xsl .= "</head>" . "\n";
$xsl .= "<body>" . "\n";
$xsl .= "<div class=\"main\">" . "\n";
// Content
$xsl .= "<div class=\"roundcont\">" . "\n";
$xsl .= "<div class=\"roundtop\">" . "\n";
$xsl .= "<img src=\"images/corner_topleft.jpg\" class=\"corner\" style=\"display: none\" alt=\"\" />" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<div class=\"newscontent\">" . "\n";
$xsl .= "<div class=\"streamheader\">" . "\n";
$xsl .= "<table cellspacing=\"0\" cellpadding=\"0\">" . "\n";
$xsl .= "<colgroup align=\"left\"></colgroup>" . "\n";
$xsl .= "<colgroup align=\"right\" width=\"300\"></colgroup>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td><h3>Mount Point /stream." . $channel->stream_type . "</h3></td>" . "\n";
$xsl .= "<td align=\"right\">" . "\n";
$xsl .= "<a href=\"stream.". $channel->stream_type .".m3u\">M3U</a>" . "\n";
$xsl .= "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "</table>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<table border=\"0\" cellpadding=\"4\">" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream Title:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->name . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream Description:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->description . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Content Type:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . Song::type_to_mime($channel->stream_type) . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Mount Start:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . date("c", $channel->start_date) . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Bitrate:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->bitrate . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Current Listeners:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->listeners . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Peak Listeners:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $channel->peak_listeners . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$genre = $channel->get_genre();
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream Genre:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $genre . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Stream URL:</td>" . "\n";
$xsl .= "<td class=\"streamdata\"><a href=\"" . $channel->url . "\" target=\"_blank\">" . $channel->url . "</a></td>" . "\n";
$xsl .= "</tr>" . "\n";
$currentsong = "";
if ($channel->media) {
$currentsong = $channel->media->f_artist . " - " . $channel->media->f_title;
}
$xsl .= "<tr>" . "\n";
$xsl .= "<td>Current Song:</td>" . "\n";
$xsl .= "<td class=\"streamdata\">" . $currentsong . "</td>" . "\n";
$xsl .= "</tr>" . "\n";
$xsl .= "</table>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<div class=\"roundbottom\">" . "\n";
$xsl .= "<img src=\"images/corner_bottomleft.jpg\" class=\"corner\" style=\"display: none\" alt=\"\" />" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "<br /><br />" . "\n";
// Footer
$xsl .= "<div class=\"poster\">" . "\n";
$xsl .= "Support Ampache at <a target=\"_blank\" href=\"http://www.ampache.org\">www.ampache.org</a>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "</div>" . "\n";
$xsl .= "</body>" . "\n";
$xsl .= "</html>" . "\n";
fwrite($sock, $xsl);
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
case '/style.css':
case '/favicon.ico':
case '/images/corner_bottomleft.jpg':
case '/images/corner_bottomright.jpg':
case '/images/corner_topleft.jpg':
case '/images/corner_topright.jpg':
case '/images/icecast.png':
case '/images/key.png':
case '/images/tunein.png':
// Get read file data
$fpath = AmpConfig::get('prefix') . '/channel' . $cmd['1'];
$pinfo = pathinfo($fpath);
$content_type = 'text/html';
switch ($pinfo['extension']) {
case 'css':
$content_type = "text/css";
break;
case 'jpg':
$content_type = "image/jpeg";
break;
case 'png':
$content_type = "image/png";
break;
case 'ico':
$content_type = "image/vnd.microsoft.icon";
break;
}
fwrite($sock, "HTTP/1.0 200 OK\r\n");
fwrite($sock, "Content-Type: " . $content_type . "\r\n");
$fdata = file_get_contents($fpath);
fwrite($sock, "Content-Length: " . strlen($fdata) . "\r\n");
fwrite($sock, "\r\n");
fwrite($sock, $fdata);
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
case '/stream.' . $channel->stream_type . '.m3u':
fwrite($sock, "HTTP/1.0 200 OK\r\n");
fwrite($sock, "Cache-control: public\r\n");
fwrite($sock, "Content-Disposition: filename=stream." . $channel->stream_type . ".m3u\r\n");
fwrite($sock, "Content-Type: audio/x-mpegurl\r\n");
fwrite($sock, "\r\n");
fwrite($sock, $channel->get_stream_url() . "\n");
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
default:
debug_event('channel', 'Unknown request. Closing connection.', '3');
fclose($sock);
unset($client_socks[array_search($sock, $client_socks)]);
break;
}
}
}
}
function strtohex($x) {
$s='';
foreach(str_split($x) as $c) $s.=sprintf("%02X",ord($c));
return($s);
}
?> ?>

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -75,7 +75,7 @@ while ($row = Dba::fetch_assoc($db_results)) {
} // end of the catalogs } // end of the catalogs
echo T_('Finished checking filenames for valid chacters'); echo T_('Finished checking file names for valid characters');
echo "\n"; echo "\n";
/************************************************** /**************************************************
@ -191,13 +191,13 @@ function charset_rename_file($full_file,$translated_filename) {
$results = copy($full_file,$translated_filename); $results = copy($full_file,$translated_filename);
if (!$results) { if (!$results) {
echo T_('Error: Copy Failed, not deleteing old file'); echo T_('Error: Copy Failed, not deleting old file');
echo "\n"; echo "\n";
return false; return false;
} }
$old_sum = filesize($full_file); $old_sum = Core::get_filesize($full_file);
$new_sum = filesize($translated_filename); $new_sum = Core::get_filesize($translated_filename);
if ($old_sum != $new_sum OR !$new_sum) { if ($old_sum != $new_sum OR !$new_sum) {
printf (T_('Error: Size Inconsistency, not deleting %s'), $full_file); printf (T_('Error: Size Inconsistency, not deleting %s'), $full_file);

View file

@ -1 +0,0 @@
Deny from all

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -53,7 +53,7 @@ $catalog = Catalog::create_from_id($results['id']);
$dir_pattern = $catalog->sort_pattern; $dir_pattern = $catalog->sort_pattern;
$file_pattern = $catalog->rename_pattern; $file_pattern = $catalog->rename_pattern;
$info = new vainfo($filename, '', '', '', $dir_pattern, $file_pattern); $info = new vainfo($filename, array('music'), '', '', '', $dir_pattern, $file_pattern);
if(isset($dir_pattern) || isset($file_pattern)) { if(isset($dir_pattern) || isset($file_pattern)) {
printf(T_('Using: %s AND %s for file pattern matching'), $dir_pattern, $file_pattern); printf(T_('Using: %s AND %s for file pattern matching'), $dir_pattern, $file_pattern);
print "\n"; print "\n";

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -65,7 +65,6 @@ while ($r = Dba::fetch_row($db_results)) {
foreach ($songs as $song) { foreach ($songs as $song) {
/* Find this poor song a home */ /* Find this poor song a home */
$song->format(); $song->format();
$song->format_pattern();
$directory = sort_find_home($song,$catalog->sort_pattern,$catalog->path); $directory = sort_find_home($song,$catalog->sort_pattern,$catalog->path);
$filename = $song->f_file; $filename = $song->f_file;
$fullpath = $directory . "/" . $filename; $fullpath = $directory . "/" . $filename;
@ -268,12 +267,12 @@ function sort_move_file($song,$fullname) {
/* Look for the folder art and copy that as well */ /* Look for the folder art and copy that as well */
if (!AmpConfig::get('album_art_preferred_filename') OR strstr(AmpConfig::get('album_art_preferred_filename'),"%")) { if (!AmpConfig::get('album_art_preferred_filename') OR strstr(AmpConfig::get('album_art_preferred_filename'),"%")) {
$folder_art = $directory . '/folder.jpg'; $folder_art = $directory . DIRECTORY_SEPARATOR . 'folder.jpg';
$old_art = $old_dir . '/folder.jpg'; $old_art = $old_dir . DIRECTORY_SEPARATOR . 'folder.jpg';
} }
else { else {
$folder_art = $directory . "/" . sort_clean_name(AmpConfig::get('album_art_preferred_filename')); $folder_art = $directory . DIRECTORY_SEPARATOR . sort_clean_name(AmpConfig::get('album_art_preferred_filename'));
$old_art = $old_dir . "/" . sort_clean_name(AmpConfig::get('album_art_preferred_filename')); $old_art = $old_dir . DIRECTORY_SEPARATOR . sort_clean_name(AmpConfig::get('album_art_preferred_filename'));
} }
debug_event('copy_art','Copied ' . $old_art . ' to ' . $folder_art,'5'); debug_event('copy_art','Copied ' . $old_art . ' to ' . $folder_art,'5');
@ -282,8 +281,8 @@ function sort_move_file($song,$fullname) {
if (!$results) { printf (T_('Error: Unable to copy file to %s'), $fullname); echo "\n"; return false; } if (!$results) { printf (T_('Error: Unable to copy file to %s'), $fullname); echo "\n"; return false; }
/* Check the filesize */ /* Check the filesize */
$new_sum = filesize($fullname); $new_sum = Core::get_filesize($fullname);
$old_sum = filesize($song->file); $old_sum = Core::get_filesize($song->file);
if ($new_sum != $old_sum OR !$new_sum) { if ($new_sum != $old_sum OR !$new_sum) {
printf (T_('Error: Size Inconsistency, not deleting %s'), $song->file); printf (T_('Error: Size Inconsistency, not deleting %s'), $song->file);

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -35,7 +35,7 @@ else {
// Make sure the output dir is valid and writeable // Make sure the output dir is valid and writeable
if (!is_writeable($dirname)) { if (!is_writeable($dirname)) {
printf (T_('Error: Directory %s not writeable'), $dirname); printf (T_('Error: Directory %s is not writable'), $dirname);
echo "\n"; echo "\n";
} }

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -22,12 +22,16 @@
require_once 'lib/init.php'; require_once 'lib/init.php';
if (!AmpConfig::get('broadcast')) {
UI::access_denied();
exit;
}
UI::show_header(); UI::show_header();
/* Switch on the action passed in */ /* Switch on the action passed in */
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'show_delete': case 'show_delete':
UI::show_header();
$id = $_REQUEST['id']; $id = $_REQUEST['id'];
$next_url = AmpConfig::get('web_path') . '/broadcast.php?action=delete&id=' . scrub_out($id); $next_url = AmpConfig::get('web_path') . '/broadcast.php?action=delete&id=' . scrub_out($id);
@ -40,7 +44,6 @@ switch ($_REQUEST['action']) {
exit; exit;
} }
UI::show_header();
$id = $_REQUEST['id']; $id = $_REQUEST['id'];
$broadcast = new Broadcast($id); $broadcast = new Broadcast($id);
if ($broadcast->delete()) { if ($broadcast->delete()) {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -49,6 +49,14 @@ switch ($_REQUEST['action']) {
case 'song': case 'song':
case 'channel': case 'channel':
case 'broadcast': case 'broadcast':
case 'tvshow':
case 'tvshow_season':
case 'tvshow_episode':
case 'movie':
case 'clip':
case 'personal_video':
case 'label':
case 'pvmsg':
$browse->set_type($_REQUEST['action']); $browse->set_type($_REQUEST['action']);
$browse->set_simple_browse(true); $browse->set_simple_browse(true);
break; break;
@ -56,6 +64,9 @@ switch ($_REQUEST['action']) {
UI::show_header(); UI::show_header();
// Browser is able to save page on current session. Only applied to main menus.
$browse->set_update_session(true);
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'file': case 'file':
break; break;
@ -65,20 +76,22 @@ switch ($_REQUEST['action']) {
$browse->set_filter('catalog_enabled', '1'); $browse->set_filter('catalog_enabled', '1');
} }
$browse->set_sort('name','ASC'); $browse->set_sort('name','ASC');
$browse->update_browse_from_session(); // Update current index depending on what is in session.
$browse->show_objects(); $browse->show_objects();
break; break;
case 'tag': case 'tag':
//FIXME: This whole thing is ugly, even though it works. //FIXME: This whole thing is ugly, even though it works.
$browse->set_sort('count','ASC'); $browse->set_sort('count','ASC');
// This one's a doozy // This one's a doozy
$browse_type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'song';
$browse->set_simple_browse(false); $browse->set_simple_browse(false);
$browse->save_objects(Tag::get_tags(/*AmpConfig::get('offset_limit')*/)); // Should add a pager? $browse->save_objects(Tag::get_tags($browse_type, 0, 'name')); // Should add a pager?
$object_ids = $browse->get_saved(); $object_ids = $browse->get_saved();
$keys = array_keys($object_ids); $keys = array_keys($object_ids);
Tag::build_cache($keys); Tag::build_cache($keys);
UI::show_box_top(T_('Tag Cloud'), 'box box_tag_cloud'); UI::show_box_top(T_('Tag Cloud'), 'box box_tag_cloud');
$browse2 = new Browse(); $browse2 = new Browse();
$browse2->set_type('song'); $browse2->set_type($browse_type);
$browse2->store(); $browse2->store();
require_once AmpConfig::get('prefix') . '/templates/show_tagcloud.inc.php'; require_once AmpConfig::get('prefix') . '/templates/show_tagcloud.inc.php';
UI::show_box_bottom(); UI::show_box_bottom();
@ -91,6 +104,7 @@ switch ($_REQUEST['action']) {
$browse->set_filter('catalog_enabled', '1'); $browse->set_filter('catalog_enabled', '1');
} }
$browse->set_sort('name','ASC'); $browse->set_sort('name','ASC');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'song': case 'song':
@ -99,6 +113,7 @@ switch ($_REQUEST['action']) {
$browse->set_filter('catalog_enabled', '1'); $browse->set_filter('catalog_enabled', '1');
} }
$browse->set_sort('title','ASC'); $browse->set_sort('title','ASC');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'live_stream': case 'live_stream':
@ -106,6 +121,7 @@ switch ($_REQUEST['action']) {
$browse->set_filter('catalog_enabled', '1'); $browse->set_filter('catalog_enabled', '1');
} }
$browse->set_sort('name','ASC'); $browse->set_sort('name','ASC');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'catalog': case 'catalog':
@ -114,19 +130,23 @@ switch ($_REQUEST['action']) {
case 'playlist': case 'playlist':
$browse->set_sort('type','ASC'); $browse->set_sort('type','ASC');
$browse->set_filter('playlist_type','1'); $browse->set_filter('playlist_type','1');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'smartplaylist': case 'smartplaylist':
$browse->set_sort('type', 'ASC'); $browse->set_sort('type', 'ASC');
$browse->set_filter('playlist_type','1'); $browse->set_filter('playlist_type','1');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'channel': case 'channel':
$browse->set_sort('id', 'ASC'); $browse->set_sort('id', 'ASC');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'broadcast': case 'broadcast':
$browse->set_sort('id', 'ASC'); $browse->set_sort('id', 'ASC');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'video': case 'video':
@ -134,8 +154,54 @@ switch ($_REQUEST['action']) {
$browse->set_filter('catalog_enabled', '1'); $browse->set_filter('catalog_enabled', '1');
} }
$browse->set_sort('title','ASC'); $browse->set_sort('title','ASC');
$browse->update_browse_from_session();
$browse->show_objects(); $browse->show_objects();
break; break;
case 'tvshow':
if (AmpConfig::get('catalog_disable')) {
$browse->set_filter('catalog_enabled', '1');
}
$browse->set_sort('name','ASC');
$browse->update_browse_from_session();
$browse->show_objects();
break;
case 'tvshow_season':
if (AmpConfig::get('catalog_disable')) {
$browse->set_filter('catalog_enabled', '1');
}
$browse->set_sort('season_number','ASC');
$browse->update_browse_from_session();
$browse->show_objects();
break;
case 'tvshow_episode':
case 'movie':
case 'clip':
case 'personal_video':
if (AmpConfig::get('catalog_disable')) {
$browse->set_filter('catalog_enabled', '1');
}
$browse->update_browse_from_session();
$browse->show_objects();
break;
case 'label':
if (AmpConfig::get('catalog_disable')) {
$browse->set_filter('catalog_enabled', '1');
}
$browse->set_sort('name','ASC');
$browse->update_browse_from_session();
$browse->show_objects();
break;
case 'pvmsg':
$browse->set_sort('creation_date','DESC');
$folder = $_REQUEST['folder'];
if ($folder === "sent") {
$browse->set_filter('user', $GLOBALS['user']->id);
} else {
$browse->set_filter('to_user', $GLOBALS['user']->id);
}
$browse->update_browse_from_session();
$browse->show_objects();
break;
default: default:
break; break;

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -22,13 +22,16 @@
require_once 'lib/init.php'; require_once 'lib/init.php';
if (!AmpConfig::get('channel')) {
UI::access_denied();
exit;
}
UI::show_header(); UI::show_header();
/* Switch on the action passed in */ /* Switch on the action passed in */
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'show_create': case 'show_create':
UI::show_header();
$type = Channel::format_type($_REQUEST['type']); $type = Channel::format_type($_REQUEST['type']);
if (!empty($type) && !empty($_REQUEST['id'])) { if (!empty($type) && !empty($_REQUEST['id'])) {
$object = new $type($_REQUEST['id']); $object = new $type($_REQUEST['id']);
@ -50,7 +53,6 @@ switch ($_REQUEST['action']) {
exit; exit;
} }
UI::show_header();
$created = Channel::create($_REQUEST['name'], $_REQUEST['description'], $_REQUEST['url'], $_REQUEST['type'], $_REQUEST['id'], $_REQUEST['interface'], $_REQUEST['port'], $_REQUEST['admin_password'], $_REQUEST['private'] ?: 0, $_REQUEST['max_listeners'], $_REQUEST['random'] ?: 0, $_REQUEST['loop'] ?: 0, $_REQUEST['stream_type'], $_REQUEST['bitrate']); $created = Channel::create($_REQUEST['name'], $_REQUEST['description'], $_REQUEST['url'], $_REQUEST['type'], $_REQUEST['id'], $_REQUEST['interface'], $_REQUEST['port'], $_REQUEST['admin_password'], $_REQUEST['private'] ?: 0, $_REQUEST['max_listeners'], $_REQUEST['random'] ?: 0, $_REQUEST['loop'] ?: 0, $_REQUEST['stream_type'], $_REQUEST['bitrate']);
if (!$created) { if (!$created) {
@ -62,7 +64,6 @@ switch ($_REQUEST['action']) {
UI::show_footer(); UI::show_footer();
exit; exit;
case 'show_delete': case 'show_delete':
UI::show_header();
$id = $_REQUEST['id']; $id = $_REQUEST['id'];
$next_url = AmpConfig::get('web_path') . '/channel.php?action=delete&id=' . scrub_out($id); $next_url = AmpConfig::get('web_path') . '/channel.php?action=delete&id=' . scrub_out($id);
@ -75,7 +76,6 @@ switch ($_REQUEST['action']) {
exit; exit;
} }
UI::show_header();
$id = $_REQUEST['id']; $id = $_REQUEST['id'];
$channel = new Channel($id); $channel = new Channel($id);
if ($channel->delete()) { if ($channel->delete()) {

View file

@ -2,5 +2,5 @@
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-s RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^([0-9]+)/(.*)$ index.php?channel=$1&target=$2 [PT,L,QSA] RewriteRule ^([0-9]+)/(.*)$ /channel/index.php?channel=$1&target=$2 [PT,L,QSA]
</IfModule> </IfModule>

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -76,10 +76,6 @@ html, body {
margin-bottom: 10px; margin-bottom: 10px;
background: url(images/icecast.png) no-repeat left center; background: url(images/icecast.png) no-repeat left center;
} }
.main iframe {
width: 100%;
border: 0;
}
.news { .news {
font-family: Verdana, sans-serif; font-family: Verdana, sans-serif;
text-decoration: none; text-decoration: none;

View file

@ -1 +0,0 @@
ampache.cfg.php

View file

@ -1,2 +1,10 @@
Order deny,allow # Apache 2.4
Deny from all <IfModule mod_authz_core.c>
Require all denied
</IfModule>
# Apache 2.2
<IfModule mod_access.c>
Order deny,allow
Deny from all
</IfModule>

View file

@ -7,19 +7,19 @@
; if this config file is up to date ; if this config file is up to date
; this is compared against a value hard-coded ; this is compared against a value hard-coded
; into the init script ; into the init script
config_version = 16 config_version = 29
;################### ;###################
; Path Vars # ; Path Vars #
;################### ;###################
; The http host of your server. ; The public http host of your server.
; If not set, retrieved automatically from client request. ; If not set, retrieved automatically from client request.
; This setting is required for WebSocket server ; This setting is required for WebSocket server
; DEFAULT: "" ; DEFAULT: ""
;http_host = "localhost" ;http_host = "localhost"
; The path to your ampache install ; The public path to your ampache install
; Do not put a trailing / on this path ; Do not put a trailing / on this path
; For example if your site is located at http://localhost ; For example if your site is located at http://localhost
; than you do not need to enter anything for the web_path ; than you do not need to enter anything for the web_path
@ -28,11 +28,17 @@ config_version = 16
; DEFAULT: "" ; DEFAULT: ""
;web_path = "" ;web_path = ""
; The local http url of your server.
; If not set, retrieved automatically from server information.
; DEFAULT: ""
;local_web_path = "http://localhost/ampache"
;############################## ;##############################
; Session and Login Variables # ; Session and Login Variables #
;############################## ;##############################
; Hostname of your database ; Hostname of your database
; For socket authentication, set the path to socket file (e.g. /var/run/mysqld/mysqld.sock)
; DEFAULT: localhost ; DEFAULT: localhost
database_hostname = localhost database_hostname = localhost
@ -50,10 +56,14 @@ database_username = username
; Password for your ampache database, this can not be blank ; Password for your ampache database, this can not be blank
; this is a 'forced' security precaution, the default value ; this is a 'forced' security precaution, the default value
; will not work ; will not work (except if using socket authentication)
; DEFAULT: "" ; DEFAULT: ""
database_password = password database_password = password
; Cryptographic secret
; This MUST BE changed with your own secret key. Ampache-specific, just pick any random string you want.
secret_key = "abcdefghijklmnoprqstuvwyz0123456"
; Length that a session will last expressed in seconds. Default is ; Length that a session will last expressed in seconds. Default is
; one hour. ; one hour.
; DEFAULT: 3600 ; DEFAULT: 3600
@ -66,11 +76,11 @@ session_length = 3600
stream_length = 7200 stream_length = 7200
; This length defines how long a 'remember me' session and cookie will ; This length defines how long a 'remember me' session and cookie will
; last, the default is 7200, same as length. It is up to the administrator ; last, the default is 86400, same as length. It is up to the administrator
; of the box to increase this, for reference 86400 = 1 day ; of the box to increase this, for reference 86400 = 1 day,
; 604800 = 1 week and 2419200 = 1 month ; 604800 = 1 week, and 2419200 = 1 month
; DEFAULT: 86400 ; DEFAULT: 604800
remember_length = 86400 remember_length = 604800
; Name of the Session/Cookie that will sent to the browser ; Name of the Session/Cookie that will sent to the browser
; default should be fine ; default should be fine
@ -120,15 +130,15 @@ auth_methods = "mysql"
; This defines which file types Ampache will attempt to catalog ; This defines which file types Ampache will attempt to catalog
; You can specify any file extension you want in here separating them ; You can specify any file extension you want in here separating them
; with a | ; with a |
; DEFAULT: mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv ; DEFAULT: mp3|mpc|m4p|m4a|aac|ogg|oga|wav|aif|aiff|rm|wma|asf|flac|opus|spx|ra|ape|shn|wv
catalog_file_pattern = "mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv" catalog_file_pattern = "mp3|mpc|m4p|m4a|aac|ogg|oga|wav|aif|aiff|rm|wma|asf|flac|opus|spx|ra|ape|shn|wv"
; Video Pattern ; Video Pattern
; This defines which video file types Ampache will attempt to catalog ; This defines which video file types Ampache will attempt to catalog
; You can specify any file extension you want in here seperating them with ; You can specify any file extension you want in here seperating them with
; a | but ampache may not be able to parse them ; a | but ampache may not be able to parse them
; DEAFULT: avi|mpg|flv|m4v|webm ; DEAFULT: avi|mpg|mpeg|flv|m4v|mp4|webm|mkv|wmv|ogv|mov|divx|m2ts
catalog_video_pattern = "avi|mpg|flv|m4v|webm" catalog_video_pattern = "avi|mpg|mpeg|flv|m4v|mp4|webm|mkv|wmv|ogv|mov|divx|m2ts"
; Playlist Pattern ; Playlist Pattern
; This defines which playlist types Ampache will attempt to catalog ; This defines which playlist types Ampache will attempt to catalog
@ -208,12 +218,13 @@ require_localnet_session = "true"
; DEFAULT: false ; DEFAULT: false
;allow_zip_download = "false" ;allow_zip_download = "false"
; File Zip Download Allow Zip Types
; This settings tells Ampache to attempt to save the zip file ; This setting allows/disallows zip download of specific object types
; to the filesystem instead of creating it in memory, you must ; If empty, all supported object types can be zipped.
; also set tmp_dir_path in order for this to work ; Otherwise, only the given object list can be zipped.
; DEFAULT: false ; POSSIBLE VALUES: artist, album, playlist, search, tmp_playlist
;file_zip_download = "false" ; DEFAULT: none
;allow_zip_types = "album"
; File Zip Comment ; File Zip Comment
; This is an optional configuration option that adds a comment ; This is an optional configuration option that adds a comment
@ -234,7 +245,7 @@ require_localnet_session = "true"
;waveform_color = "#FF0000" ;waveform_color = "#FF0000"
; Temporary Directory Path ; Temporary Directory Path
; If File Zip Download or Waveform is enabled this must be set to tell ; If Waveform is enabled this must be set to tell
; Ampache which directory to save the temporary file to. Do not put a ; Ampache which directory to save the temporary file to. Do not put a
; trailing slash or this will not work. ; trailing slash or this will not work.
; DEFAULT: false ; DEFAULT: false
@ -261,13 +272,52 @@ getid3_tag_order = "id3v2,id3v1,vorbiscomment,quicktime,matroska,ape,asf,avi,mpe
; DEFAULT: false ; DEFAULT: false
;getid3_detect_id3v2_encoding = "false" ;getid3_detect_id3v2_encoding = "false"
; This determines if file metadata should be write back to files
; as id3 metadata when updated.
; DEFAULT: false
;write_id3 = "false"
; This determines if album art should be write back to files
; as id3 metadata when updated.
; DEFAULT: false
;write_id3_art = "false"
; This determines if catalog manager users can delete medias from disk.
; DEFAULT: false
;delete_from_disk = "false"
; This determines the order in which metadata sources are used (and in the ; This determines the order in which metadata sources are used (and in the
; case of plugins, checked) ; case of plugins, checked)
; POSSIBLE VALUES (builtins): filename and getID3 ; POSSIBLE VALUES (builtins): filename and getID3
; POSSIBLE VALUES (plugins): MusicBrainz, plus any others you've installed. ; POSSIBLE VALUES (plugins): MusicBrainz,TheAudioDb, plus any others you've installed.
; DEFAULT: getID3 filename ; DEFAULT: getID3 filename
metadata_order = "getID3,filename" metadata_order = "getID3,filename"
; This determines the order in which metadata sources are used (and in the
; case of plugins, checked) for video files
; POSSIBLE VALUES (builtins): filename and getID3
; POSSIBLE VALUES (plugins): Tvdb,Tmdb,Omdb, plus any others you've installed.
; DEFAULT: filename getID3
metadata_order_video = "filename,getID3"
; This determines if extended metadata grabbed from external services should be deferred.
; If enabled, extended metadata is retrieved when browsing the library item.
; If disabled, extended metadata is retrieved at catalog update.
; Today, only Artist information (summary, place formed, ...) can be deferred.
; DEFAULT: true
deferred_ext_metadata = "true"
; Some taggers use delimiters other than \0 for fields
; This list specifies possible delimiters additional to \0
; This setting takes a regex pattern.
; DEFAULT: // / \ | , ;
additional_genre_delimiters = "[/]{2}|[/|\\\\|\|,|;]"
; This determines if a preview image should be retrieved from video files
; It requires encode_get_image transcode settings.
; DEFAULT: false
;generate_video_preview = "true"
; Un comment if don't want ampache to follow symlinks ; Un comment if don't want ampache to follow symlinks
; DEFAULT: false ; DEFAULT: false
;no_symlinks = "false" ;no_symlinks = "false"
@ -284,10 +334,10 @@ use_auth = "true"
; If use_auth is set to false then this option is used ; If use_auth is set to false then this option is used
; to determine the permission level of the 'default' users ; to determine the permission level of the 'default' users
; default is administrator. This setting only takes affect ; default is administrator. This setting only takes affect
; if use_auth if false ; if use_auth is false
; POSSIBLE VALUES: user, admin, manager, guest ; POSSIBLE VALUES: user, admin, manager, guest
; DEFAULT: admin ; DEFAULT: guest
default_auth_level = "admin" default_auth_level = "guest"
; 5 Star Ratings ; 5 Star Ratings
; This allows ratings for almost any object in ampache ; This allows ratings for almost any object in ampache
@ -314,10 +364,10 @@ directplay = "true"
; DEFAULT: true ; DEFAULT: true
sociable = "true" sociable = "true"
; Notify ; License
; This turns on / off all Ampache notifications ; This turns on / off all licensing features on Ampache
; DEFAULT: true ; DEFAULT: false
notify = "true" ;licensing = "false"
; This options will turn on/off Demo Mode ; This options will turn on/off Demo Mode
; If Demo mode is on you can not play songs or update your catalog ; If Demo mode is on you can not play songs or update your catalog
@ -332,7 +382,7 @@ notify = "true"
; requirments on larger catalogs. If you have the memory this can create ; requirments on larger catalogs. If you have the memory this can create
; a 2-3x speed improvement. ; a 2-3x speed improvement.
; DEFAULT: false ; DEFAULT: false
;memory_cache = false ;memory_cache = "false"
; Memory Limit ; Memory Limit
; This defines the "Min" memory limit for PHP if your php.ini ; This defines the "Min" memory limit for PHP if your php.ini
@ -349,6 +399,42 @@ notify = "true"
; DEFAULT: folder.jpg ; DEFAULT: folder.jpg
;album_art_preferred_filename = "folder.jpg" ;album_art_preferred_filename = "folder.jpg"
; Album Art Store on Disk
; This defines if arts should be stored on disk instead of database.
; DEFAULT: false
;album_art_store_disk = "false"
; Local Metadata Directory
; This define a local metadata directory with write access where to store
; heavy data if enabled (album arts, ...)
; DEFAULT: none
;local_metadata_dir = "/metadata"
; Maximal upload size
; Specify the maximal allowed upload size for images, in bytes.
; DEFAULT: 1048576
;max_upload_size = 1048576
; Album Art Minimum Width
; Specify the minimum width for arts (in pixel).
; DEFAULT: none
;album_art_min_width = 100
; Album Art Maximum Width
; Specify the maximum width for arts (in pixel).
; DEFAULT: none
;album_art_max_width = 1024
; Album Art Minimum Height
; Specify the minimum height for arts (in pixel).
; DEFAULT: none
;album_art_min_height = 100
; Album Art Maximum Height
; Specify the maximum height for arts (in pixel).
; DEFAULT: none
;album_art_max_height = 1024
; Resize Images * Requires PHP-GD * ; Resize Images * Requires PHP-GD *
; Set this to true if you want Ampache to resize the Album ; Set this to true if you want Ampache to resize the Album
; art on the fly, this increases load time and CPU usage ; art on the fly, this increases load time and CPU usage
@ -357,25 +443,23 @@ notify = "true"
; DEFAULT: false ; DEFAULT: false
;resize_images = "false" ;resize_images = "false"
; Statistical Graphs * Requires PHP-GD *
; Set this to true if you want Ampache to generate statistical
; graphs on usages / users.
; DEFAULT: false
;statistical_graphs = "false"
; Art Gather Order ; Art Gather Order
; Simply arrange the following in the order you would like ; Simply arrange the following in the order you would like
; ampache to search. If you want to disable one of the search ; ampache to search. If you want to disable one of the search
; methods simply leave it out. DB should be left as the first ; methods simply leave it out. DB should be left as the first
; method unless you want it to overwrite what's already in the ; method unless you want it to overwrite what's already in the
; database ; database
; POSSIBLE VALUES: db tags folder amazon lastfm musicbrainz google ; POSSIBLE VALUES (builtins): db tags folder lastfm musicbrainz google
; POSSIBLE VALUES (plugins): Amazon,TheAudioDb,Tmdb,Omdb,Flickr
; DEFAULT: db,tags,folder,musicbrainz,lastfm,google ; DEFAULT: db,tags,folder,musicbrainz,lastfm,google
art_order = "db,tags,folder,musicbrainz,lastfm,google" art_order = "db,tags,folder,musicbrainz,lastfm,google"
; Amazon Developer Key
; These are needed in order to actually use the amazon album art
; Your public key is your 'Access Key ID'
; Your private key is your 'Secret Access Key'
; DEFAULT: false
;amazon_developer_public_key = ""
;amazon_developer_private_key = ""
;amazon_developer_associate_tag = ""
; Recommendations ; Recommendations
; Set this to true to enable display of similar artists or albums ; Set this to true to enable display of similar artists or albums
; while browsing. Requires Last.FM. ; while browsing. Requires Last.FM.
@ -390,14 +474,14 @@ art_order = "db,tags,folder,musicbrainz,lastfm,google"
; Last.FM API Key ; Last.FM API Key
; Set this to your Last.FM api key to actually use Last.FM for ; Set this to your Last.FM api key to actually use Last.FM for
; recommendations. ; recommendations and metadata.
;lastfm_api_key = "" lastfm_api_key = "d5df942424c71b754e54ce1832505ae2"
; Wanted ; Wanted
; Set this to true to enable display missing albums and the ; Set this to true to enable display missing albums and the
; possibility for users to mark it as wanted. ; possibility for users to mark it as wanted.
; DEFAULT: false ; DEFAULT: false
;wanted = "false" wanted = "true"
; Wanted types ; Wanted types
; Set the allowed types of wanted releases (album,compilation,single,ep,live,remix,promotion,official) ; Set the allowed types of wanted releases (album,compilation,single,ep,live,remix,promotion,official)
@ -413,43 +497,34 @@ wanted_types = "album,official"
; EchoNest provides several music services. Currently used for missing song 30 seconds preview. ; EchoNest provides several music services. Currently used for missing song 30 seconds preview.
;echonest_api_key = "" ;echonest_api_key = ""
; Labels
; Use labels to browse artists per label membership.
; DEFAULT: false
;label = "false"
; Broadcasts ; Broadcasts
; Allow users to broadcast music. ; Allow users to broadcast music.
; This feature requires advanced server configuration, please take a look on the wiki for more information. ; This feature requires advanced server configuration, please take a look on the wiki for more information.
; DEFAULT: false ; DEFAULT: false
;broadcast = "false" ;broadcast = "false"
; Channels
; Set this to true to enable channels and the
; possibility for users to create channels from playlists
; DEFAULT: true
channel = "true"
; Live Streams
; Set this to true to enable live streams (radio) and the
; possibility for users to add new live streams.
; DEFAULT: true
live_stream = "true"
; Web Socket address ; Web Socket address
; Declare the web socket server address ; Declare the web socket server address
; DEFAULT: determined automatically ; DEFAULT: determined automatically
;websocket_address = "ws://localhost:8100" ;websocket_address = "ws://localhost:8100"
; Amazon base urls
; An array of Amazon sites to search.
; NOTE: This will search each of these sites in turn so don't expect it
; to be lightning fast!
; It is strongly recommended that only one of these is selected at any
; one time
; POSSIBLE VALUES:
; http://webservices.amazon.com
; http://webservices.amazon.co.uk
; http://webservices.amazon.de
; http://webservices.amazon.co.jp
; http://webservices.amazon.fr
; http://webservices.amazon.ca
; Default: http://webservices.amazon.com
amazon_base_urls = "http://webservices.amazon.com"
; max_amazon_results_pages
; The maximum number of results pages to pull from EACH amazon site
; NOTE: The art search pages through the results returned by your search
; up to this number of pages. As with the base_urls above, this is going
; to take more time, the more pages you ask it to process.
; Of course a good search will return only a few matches anyway.
; It is strongly recommended that you do _not_ change this value
; DEFAULT: 1 page (10 items)
max_amazon_results_pages = 1
; Debug ; Debug
; If this is enabled Ampache will write debugging information to the log file ; If this is enabled Ampache will write debugging information to the log file
; DEFAULT: false ; DEFAULT: false
@ -502,6 +577,13 @@ site_charset = UTF-8
; Possible Values: Int > 5 ; Possible Values: Int > 5
refresh_limit = "60" refresh_limit = "60"
; Footer Statistics
; This defines whether statistics (Queries, Cache Hits, Load Time)
; are shown in the page footer.
; DEFAULT: true
; Possible values: true, false
show_footer_statistics = "true"
;######################################################### ;#########################################################
; Custom actions (optional) # ; Custom actions (optional) #
;######################################################### ;#########################################################
@ -531,7 +613,7 @@ refresh_limit = "60"
; For OpenLDAP use "uid" ; For OpenLDAP use "uid"
; For Microsoft Active Directory (MAD) use "sAMAccountName" ; For Microsoft Active Directory (MAD) use "sAMAccountName"
; DEFAULT: null ; DEFAULT: null
; ldap_filter = "sAMAccountName" ;ldap_filter = "(sAMAccountName=%v)"
; LDAP objectclass (required) ; LDAP objectclass (required)
; OpanLDAP objectclass = "*" ; OpanLDAP objectclass = "*"
@ -616,7 +698,7 @@ refresh_limit = "60"
;auto_user = "guest" ;auto_user = "guest"
; This will display the user agreement when registering ; This will display the user agreement when registering
; For agreement text, edit templates/user_agreement.php ; For agreement text, edit config/registration_agreement.php
; User will need to accept the agreement before they can register ; User will need to accept the agreement before they can register
; DEFAULT: false ; DEFAULT: false
;user_agreement = "false" ;user_agreement = "false"
@ -625,6 +707,24 @@ refresh_limit = "60"
; DEFAULT: false ; DEFAULT: false
;user_no_email_confirm = "false" ;user_no_email_confirm = "false"
; This will display the cookie disclaimer (EU Cookie Law)
; DEFAULT: false
;cookie_disclaimer = "false"
; The fields that will be shown on Registration page
; If a user wants to register.
; Username and email fields are forced.
; POSSIBLE VALUES: fullname,website,state,city
; DEFAULT: "fullname,website"
registration_display_fields = "fullname,website"
; The fields that will be mandatory
; This controls which fields are mandatory for registration.
; Username and email fields are forced mandatory.
; POSSIBLE VALUES: fullname,website,state,city
; DEFAULT: fullname
registration_mandatory_fields = "fullname"
;######################################################## ;########################################################
; These options control the dynamic downsampling based # ; These options control the dynamic downsampling based #
; on current usage # ; on current usage #
@ -662,25 +762,64 @@ refresh_limit = "60"
; (e.g. if you store everything in FLAC, but don't want to ever stream that.) ; (e.g. if you store everything in FLAC, but don't want to ever stream that.)
; transcode_TYPE = {allowed|required|false} ; transcode_TYPE = {allowed|required|false}
; DEFAULT: false ; DEFAULT: false
;;; Audio
;transcode_m4a = allowed ;transcode_m4a = allowed
;transcode_flac = required ;transcode_flac = required
;transcode_mpc = required ;transcode_mpc = required
;transcode_ogg = required ;transcode_ogg = required
;transcode_oga = required
;transcode_wav = required ;transcode_wav = required
;transcode_wma = required
;transcode_aif = required
;transcode_aiff = required
;transcode_ape = required
;transcode_shn = required
;transcode_mp3 = allowed ;transcode_mp3 = allowed
;;; Video
;transcode_avi = allowed
;transcode_mkv = allowed
;transcode_mpg = allowed
;transcode_mpeg = allowed
;transcode_m4v = allowed
;transcode_mp4 = allowed
;transcode_mov = allowed
;transcode_wmv = allowed
;transcode_ogv = allowed
;transcode_divx = allowed
;transcode_m2ts = allowed
;transcode_webm = allowed
; Default output format ; Default audio output format
; DEFAULT: none ; DEFAULT: none
;encode_target = mp3 ;encode_target = mp3
; Default video output format
; DEFAULT: none
;encode_video_target = webm
; Override the default output format on a per-type basis ; Override the default output format on a per-type basis
; encode_target_TYPE = TYPE ; encode_target_TYPE = TYPE
; DEFAULT: none ; DEFAULT: none
;encode_target_flac = ogg ;encode_target_flac = ogg
; Override the default TYPE transcoding behavior on a per-player basis
; transcode_player_PLAYER_TYPE = TYPE
; Valid PLAYER is: webplayer, api
; DEFAULT: none
;transcode_player_webplayer_m4a = required
;transcode_player_webplayer_flac = required
;transcode_player_webplayer_mpc = required
; Override the default output format on a per-player basis
; encode_player_PLAYER_target = TYPE
; Valid PLAYER is: webplayer, api
; DEFAULT: none
;encode_player_webplayer_target = mp3
;encode_player_api_target = mp3
; Allow clients to override transcode settings (output type, bitrate, codec ...) ; Allow clients to override transcode settings (output type, bitrate, codec ...)
; DEFAULT: true ; DEFAULT: true
transcode_player_customize = true transcode_player_customize = "true"
; Command configuration. Substitutions will be made as follows: ; Command configuration. Substitutions will be made as follows:
; %FILE% => filename ; %FILE% => filename
@ -694,9 +833,12 @@ transcode_player_customize = true
; equivalent to the old default, but if you find that necessary you should be ; equivalent to the old default, but if you find that necessary you should be
; clever enough to figure out how on your own. ; clever enough to figure out how on your own.
; DEFAULT: none ; DEFAULT: none
;transcode_cmd = "ffmpeg -i %FILE%" ;transcode_cmd = "ffmpeg"
;transcode_cmd = "avconv -i %FILE%" ;transcode_cmd = "avconv"
;transcode_cmd = "/usr/bin/neatokeen %FILE%" ;transcode_cmd = "/usr/bin/neatokeen"
; Transcode input file argument
transcode_input = "-i %FILE%"
; Specific transcode commands ; Specific transcode commands
; It shouldn't be necessary in most cases, but you can override the transcode ; It shouldn't be necessary in most cases, but you can override the transcode
@ -710,10 +852,26 @@ transcode_player_customize = true
; For each output format, you should provide the necessary arguments for ; For each output format, you should provide the necessary arguments for
; your transcode_cmd. ; your transcode_cmd.
; encode_args_TYPE = TRANSCODE_CMD_ARGS ; encode_args_TYPE = TRANSCODE_CMD_ARGS
;encode_args_mp3 = "-vn -b:a %SAMPLE%K -c:a libmp3lame -f mp3 pipe:1" encode_args_mp3 = "-vn -b:a %SAMPLE%K -c:a libmp3lame -f mp3 pipe:1"
;encode_args_ogg = "-vn -b:a %SAMPLE%K -c:a libvorbis -f ogg pipe:1" encode_args_ogg = "-vn -b:a %SAMPLE%K -c:a libvorbis -f ogg pipe:1"
;encode_args_m4a = "-vn -b:a %SAMPLE%K -c:a libfdk_aac -f adts pipe:1" encode_args_m4a = "-vn -b:a %SAMPLE%K -c:a libfdk_aac -f adts pipe:1"
;encode_args_wav = "-vn -b:a %SAMPLE%K -c:a pcm_s16le -f wav pipe:1" encode_args_wav = "-vn -b:a %SAMPLE%K -c:a pcm_s16le -f wav pipe:1"
encode_args_flv = "-b:a %SAMPLE%K -ar 44100 -ac 2 -v 0 -f flv -c:v libx264 -preset superfast -threads 0 pipe:1"
encode_args_webm = "-q %QUALITY% -f webm -c:v libvpx -maxrate %MAXBITRATE%k -preset superfast -threads 0 pipe:1"
encode_args_ts = "-q %QUALITY% -s %RESOLUTION% -f mpegts -c:v libx264 -c:a libmp3lame -maxrate %MAXBITRATE%k -preset superfast -threads 0 pipe:1"
; Encoding arguments to retrieve an image from a single frame
encode_get_image = "-ss %TIME% -f image2 -vframes 1 pipe:1"
; Encoding argument to encrust subtitle
encode_srt = "-vf \"subtitles='%SRTFILE%'\""
; Encode segment frame argument
encode_ss_frame = "-ss %TIME%"
; Encode segment duration argument
encode_ss_duration = "-t %DURATION%"
;###################################################### ;######################################################
; these options allow you to configure your rss-feed ; these options allow you to configure your rss-feed
@ -721,7 +879,7 @@ transcode_player_customize = true
; song is the information in the feed. can be multiple items. ; song is the information in the feed. can be multiple items.
; use_rss = false (values true | false) ; use_rss = false (values true | false)
;DEFAULT: use_rss = false ;DEFAULT: use_rss = false
;use_rss = false ;use_rss = "false"
;##################################################### ;#####################################################
;############################# ;#############################
@ -737,7 +895,7 @@ transcode_player_customize = true
; If Ampache is behind an https reverse proxy, force use HTTPS protocol. ; If Ampache is behind an https reverse proxy, force use HTTPS protocol.
;Default: false ;Default: false
;force_ssl = true ;force_ssl = "true"
;############################# ;#############################
; Mail Settings # ; Mail Settings #
@ -796,7 +954,7 @@ transcode_player_customize = true
;Enable SMTP authentication ;Enable SMTP authentication
;DEFAULT: false ;DEFAULT: false
;mail_auth = true ;mail_auth = "true"
;SMTP Username ;SMTP Username
;your mail auth username. ;your mail auth username.

View file

@ -0,0 +1,29 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
require_once 'lib/init.php';
UI::show_header();
require_once AmpConfig::get('prefix') . '/templates/cookie_disclaimer.inc.php';
UI::show_footer();

6
sources/daap/.htaccess Normal file
View file

@ -0,0 +1,6 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^(.+)$ /index.php?action=$1 [PT,L,QSA]
</IfModule>

67
sources/daap/index.php Normal file
View file

@ -0,0 +1,67 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
define('NO_SESSION','1');
require_once '../lib/init.php';
if (!AmpConfig::get('daap_backend')) {
echo "Disabled.";
exit;
}
$action = $_GET['action'];
$headers = apache_request_headers();
//$daapAccessIndex = $headers['Client-DAAP-Access-Index'];
//$daapVersion = $headers['Client-DAAP-Version'];
//$daapValidation = $headers['Client-DAAP-Validation']; // That's header hash, we don't care about it (only required by iTunes >= 7.0)
debug_event('daap', 'Request headers: '. print_r($headers, true), '5');
// Get the list of possible methods for the Plex API
$methods = get_class_methods('daap_api');
// Define list of internal functions that should be skipped
$internal_functions = array('apiOutput', 'create_dictionary', 'createError', 'output_body', 'output_header', 'follow_stream');
Daap_Api::create_dictionary();
$params = array_filter(explode('/', $action), 'strlen');
if (count($params) > 0) {
// Recurse through them and see if we're calling one of them
for ($i = count($params); $i > 0; $i--) {
$act = strtolower(implode('_', array_slice($params, 0, $i)));
$act = str_replace("-", "_", $act);
foreach ($methods as $method) {
if (in_array($method, $internal_functions)) { continue; }
// If the method is the same as the action being called
// Then let's call this function!
if ($act == $method) {
call_user_func(array('daap_api', $method), array_slice($params, $i, count($params) - $i));
// We only allow a single function to be called, and we assume it's cleaned up!
exit();
}
} // end foreach methods in API
}
}
Daap_Api::createError(404);

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2

View file

@ -23,3 +23,11 @@ Acknowledgements
* Ben Shields * Ben Shields
* Afterster * Afterster
* SUTJael * SUTJael
* Psy-Virus
* John Moore (jcwmoore)
* René Bigler (Razrael)
* Kaivo
* Ernest Wagner (wagnered)
* lotan
* brownl
* Deathcow

View file

@ -1,7 +1,207 @@
CHANGELOG CHANGELOG
========= =========
3.7 3.8.0
----------
- Added Portuguese (Brasil) language (thanks Ione Souza Junior)
- Updated PHPMailer version to 5.2.10
- Fixed user stats clear
- Added user, followers and last shouts XML API functions
- Fixed transcoded process end on some systems (thanks nan4k7)
- Added ogg channel streaming support (thanks Deathcow)
- Fixed sql connection close before stream (thanks fufroma)
- Added support for several ldap filters (thanks T-Rock)
- Fixed 'Add to existing playlist' button on web player (thanks RyanCopley)
- Added 'add to existing playlist' link on album page (thanks RyanCopley)
- Added option to hide user fullname from other users
- Added playlist track information in Apache XML API (thanks RyanCopley)
- Fixed playlist remove song in Apache XML API (thanks RyanCopley)
- Fixed SubSonic API ifModifiedSince information
- Added Podcast links to albums / artists
- Added Piwik and Google Analytics plugins
- Added Apache 2.4 access control declaration in htaccess files
- Fixed performance issues on user preferences
- Added artist search by year and place
- Fixed search by comment (thanks malkavi)
- Added Paypal and Flattr plugins
- Added .maintenance page
- Fixed captcha
- Added private messages between users
- Fixed SubSonic API rating information on albums and songs
- Added latest artists and shouts RSS feeds
- Fixed tag cloud ordering
- Added Label entities associated to artists / users
- Added WebDAV backend
- Fixed SubSonic API requests with musicFolderId parameter (thanks dhsc19)
- Added footer text edition setting
- Added uploaded artist list on user page
- Added custom Ampache login logo and favicon support
- Added edition support on shared objects (thanks dhsc19)
- Fixed share feature on videos (thanks RobertoCarlo)
- Removed album year display from album name if unset
- Fixed Subsonic API Album/Artist song's link (thanks dhsc19 and daneren2005)
- Added mysql database socket authentication support on web setup (thanks AsavarTzeth)
- Fixed artist art url for mobile use (thanks dhsc19)
- Added Shoutbox home plugin
- Added catalog favorites home plugin
- Fixed search by rating (thanks iamnumbersix)
- Added UPnP localplay (thanks SeregaPru)
- Changed preferences to return the global value if preference is missing for the searched user
- Fixed special chars in songs names and tags (thanks SeregaPru)
- Fixed Subsonic API playlist edition/delation (thanks dhsc19)
- Fixed integer default value in Apache XML API
- Fixed image thumb on webplayer and search preview (thanks RobertoCarlo and eephyne)
- Fixed proxy setting on all external http requests (thanks brendankearney)
- Added QRCode view of user API key
- Fixed http status code on Subsonic API streams when using curl (thanks nicklan)
- Added Server-Sent Events on catalog actions
- Added option to enable/disable channel and live stream features
- Removed official PHP 5.3 support
- Added option to show/hide footer statistics (thanks brownl)
- Added delete from disk option on user uploaded files
- Added installation type and players helper at installation process
- Added tv_episode tag on quicktime files (thanks wagnered)
- Added new option to disable deferred extended metadata, e.g. artist details
- Added Subsonic API getAvatar function
- Fixed unsynced lyrics tags
- Fixed ldap_filter setting deactivation on ampache.cfg.php update (thanks Rouzax)
- Added Subsonic API similar artists & songs functions
- Added Subsonic API getLyrics function
- Fixed disk number and album artist metadata on quicktime files (thanks JoeDat)
- Fixed Ampache API playlist_add_song function
- Added ability to store images on disk
- Added new setting to define album art min and max width/height
- Fixed Subsonic API getAlbum returned artist id on songs
- Fixed Subsonic API cover art when PHP-GD unavailable
- Fixed localplay playlist refresh on volume changes (thanks essagl)
- Fixed web player equalizer option if visualizer is not enabled (thanks brownl)
- Fixed asx file mime type (thanks thinca)
- Added song genre parsing options (thanks Razrael and lotan)
- Added sort on languages list (thanks brownl)
- Added placeholder text to search box (thanks brownl)
- Added web player Play Next feature (thanks tan-ce)
- Fixed Plex backend administration page uri (thanks a9k)
- Fixed expired shared objects clean (thanks eephyne)
- Added missing artist search results (thanks bliptec)
- Fixed song genre id parsing (thanks lotan)
- Added Scrobble method to Subsonic API
- Added an option to add tags to child without overwriting
- Added image dimension info to image tables (thanks tsquare66)
- Replaced ArchiveLib by StreamZip-PHP to avoid temporary zip file
- Added Year field in song details and edition
- Added Subsonic API create/delete user, jukebox control and search auto suggestion
- Added few optional install tests
- Improved Share features with modal dialog choices
- Added new action on playlists to remove duplicates
- Fixed playlist addition to another playlist (thanks kszulc)
- Fixed Various Artist link on album page (thanks Jucgshu)
- Added session_destroy call when a session should be destroyed
- Added HTML5 ReplayGain track feature
- Added display and mandatory user registration fields settings
- Added .htaccess IfModule mod_access.c directives
- Fixed SmartPlayer results per user (thanks nakinigit)
- Fixed XSS vulnerability CVE-2014-8620 (thanks g0blin)
- Fixed playlist import setting on catalog update to be disabled by default (thanks DaPike)
- Added ability to browse my tags other library items than songs
- Added Stream Control plugins
- Added transcode settings per player type
- Added ability to write directly the new configuration file when it version changed
- Added `quick play url` to have permanent authenticated stream link without session
- Fixed unresponsive website on batch download (thanks Rouzax)
- Added batch download item granularity
- Fixed 'guest' user site rendering
- Added Aurora.js support in webplayer
- Added Google Maps geolocation analyze plugin
- Added statistical graphs
- Added user geolocation
- Added 'Missing Artist' search
- Fixed Ampache installation with FastCGI
- Added a new RSS Feed plugin
- Added a new 'display home' plugin type
- Added Favorite and Rating features to playlists
- Added user feedback near mouse cursor on democratic votes
- Changed header page position to be fixed
- Added external links on song page details
- Fixed Subsonic API getAlbumList2 byGenre and byYear order (thanks rrjk)
- Added html5 desktop notification
- Added album group order setting
- Fixed unwanted album merge when one of the album doesn't have mbid
- Changed video player to go outside the footer
- Added ip address in authentication failure for fail2ban scripts (thanks popindavibe)
- Added parameter to hide directplay button if number of items is above a limit
- Added Tag split (thanks jcwmoore)
- Fixed album/artist arts and stats migration on rename (thanks jcwmoore)
- Fixed get lyrics from files (thanks apastuszak)
- Fixed verify local catalog (thanks JoeDat)
- Removed Twitter code
- Added optional cookie disclaimer for the EU Cookie Law
- Replaced catalog action links to action dropdown list (thanks Psy-Virus)
- Fixed `remember me` feature (thanks ainola)
- Added email when registered user must be enabled by administrators
- Fixed local catalog clean on Windows (thanks Rouzax)
- Added Subsonic API maxBitRate parameter support (thanks philipl)
- Fixed SubSonic API special characters encode (thanks nan4k7)
- Added Beets local and remote catalog support (thanks Razrael)
- Fixed XML error code returned with invalid Ampache API handshake (thanks funkygaddafi)
- Replaced iframe to Ajax dynamic page loading
- Changed `Albums of the moment` to not necessarily have a cover
- Added Plex backend items edition support
- Added hls stream support
- Added X-Content-Duration header support on streams
- Removed Toogle Art from artist page
- Fixed track numbers when removing a song from playlist (thanks stonie08)
- Added Plex backend playlist support
- Added gather art from video files (thanks wagnered)
- Added Plex backend movie / tvshow support
- Added release group on albums
- Added Smart Playlist songs list
- Added zlib test
- Removed old Ampache themes
- Fixed SubSonic API lastModified element (thanks bikkuri10)
- Disabled `beautiful url` on XML-API for retro-compatibility
- Fixed image resource allocation (thanks greengeek1)
- Added setting to write id3 metadata to files (thanks tsquare66)
- Added check for large files manipulation
- Added video subtitle support
- Fixed Google arts to use real arts and not the small size preview
- Added Tmdb metadata plugin
- Added Omdb metadata plugin
- Added Music Clips, Movies and TV Shows support
- Added media type information on catalog
- Fixed get SmartPlaylist in XML-API (thanks opencrf)
- Added beautiful url on arts
- Improved browse list header (thanks Psy-Virus)
- Fixed user online/offline information on Reborn theme (thanks thorsforge)
- Added UPnP backend (thanks SeregaPru)
- Added DAAP backend
- Added sort options on playlists (thanks Shdwdrgn)
- Fixed XML-API tag information (thanks jcwmoore)
- Fixed multiple broadcast play (thanks uk3gaus)
- Added SmartPlaylists to Subsonic API
- Added limit option on SmartPlaylists
- Added random option on SmartPlaylists
- Added 'item count' on browse
- Added direct typed links on items tags
- Fixed SubSonic API compatibility with few players requesting information on library -1
- Added license information on songs
- Added upload feature on web interface
- Added albumartist information on songs (thanks tsquare66)
- Fixed errors on sql table exists check
- Fixed play/pause on broadcasts (thanks uk3gaus)
- Added donation button
- Added democratic page automatic refresh
- Fixed distinct random albums
- Added collapsing menu (thanks Kaivo)
- Added 'save to playlist' feature on web player (thanks Kaivo)
- Added tag merge feature
- Fixed democratic vote with automatic logins (thanks M4DM4NZ)
- Added git pull update from web interface for development versions
- Fixed http-rang requests on streaming (thanks thejk)
- Improved installation process
- Improved French translation (thanks arnaudbey)
- Improved German translation (thanks Psy-Virus and meandor)
3.7.0
---------- ----------
- Added Scrutinizer analyze - Added Scrutinizer analyze
- Fixed playlist play with disabled songs (reported by stebe) - Fixed playlist play with disabled songs (reported by stebe)

View file

@ -27,9 +27,15 @@ should be implemented as a public method:
get_metadata(Array $metadata) get_metadata(Array $metadata)
The passed array contains the best metadata we've got. The passed array contains the best metadata we've got.
save_rating(Rating $rating, int $new_value) save_rating(Rating $rating, int $new_value)
save_songplay(Song $song) save_mediaplay(Media $media)
get_lyrics(Song $song) get_lyrics(Song $song)
process_wanted(Wanted $wanted) process_wanted(Wanted $wanted)
shortener(string $url) shortener(string $url)
get_photos(string $search) get_photos(string $search)
gather_arts(string $type, array $options, int $limit)
get_song_preview(string $track_mbid, string $artist_name, string $title)
stream_song_preview(string $file)
display_home()
external_share(string $url, string $text)
display_user_field(library_item $libitem = null)
display_on_footer

69
sources/graph.php Normal file
View file

@ -0,0 +1,69 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
// This file is a little weird it needs to allow API session
// this needs to be done a little better, but for now... eah
define('NO_SESSION','1');
require_once 'lib/init.php';
// Check to see if they've got an interface session or a valid API session, if not GTFO
if (!Session::exists('interface', $_COOKIE[AmpConfig::get('session_name')]) && !Session::exists('api', $_REQUEST['auth'])) {
debug_event('graph', 'Access denied, checked cookie session:' . $_COOKIE[AmpConfig::get('session_name')] . ' and auth:' . $_REQUEST['auth'], 1);
exit;
}
if (!AmpConfig::get('statistical_graphs')) {
debug_event('graph', 'Access denied, statistical graph disabled.', 1);
exit;
}
$type = $_REQUEST['type'];
$user_id = intval($_REQUEST['user_id']);
$object_type = (string) scrub_in($_REQUEST['object_type']);
if (!Core::is_library_item($object_type)) {
$object_type = null;
}
$object_id = intval($_REQUEST['object_id']);
$start_date = scrub_in($_REQUEST['start_date']);
$end_date = scrub_in($_REQUEST['end_date']);
$zoom = (string) scrub_in($_REQUEST['zoom']);
$width = intval($_REQUEST['width']);
$height = intval($_REQUEST['height']);
$graph = new Graph();
switch ($type) {
case 'user_hits':
$graph->render_user_hits($user_id, $object_type, $object_id, $start_date, $end_date, $zoom, $width, $height);
break;
case 'user_bandwidth':
$graph->render_user_bandwidth($user_id, $object_type, $object_id, $start_date, $end_date, $zoom, $width, $height);
break;
case 'catalog_files':
$graph->render_catalog_files($user_id, $object_type, $object_id, $start_date, $end_date, $zoom, $width, $height);
break;
case 'catalog_size':
$graph->render_catalog_size($user_id, $object_type, $object_id, $start_date, $end_date, $zoom, $width, $height);
break;
}

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -32,10 +32,12 @@
define('NO_SESSION','1'); define('NO_SESSION','1');
require_once 'lib/init.php'; require_once 'lib/init.php';
// Check to see if they've got an interface session or a valid API session, if not GTFO if (AmpConfig::get('use_auth') && AmpConfig::get('require_session')) {
if (!Session::exists('interface', $_COOKIE[AmpConfig::get('session_name')]) && !Session::exists('api', $_REQUEST['auth'])) { // Check to see if they've got an interface session or a valid API session, if not GTFO
debug_event('image','Access denied, checked cookie session:' . $_COOKIE[AmpConfig::get('session_name')] . ' and auth:' . $_REQUEST['auth'], 1); if (!Session::exists('interface', $_COOKIE[AmpConfig::get('session_name')]) && !Session::exists('api', $_REQUEST['auth'])) {
exit; debug_event('image','Access denied, checked cookie session:' . $_COOKIE[AmpConfig::get('session_name')] . ' and auth:' . $_REQUEST['auth'], 1);
exit;
}
} }
// If we aren't resizing just trash thumb // If we aren't resizing just trash thumb
@ -46,44 +48,18 @@ if (!isset($_GET['object_type'])) {
$_GET['object_type'] = 'album'; $_GET['object_type'] = 'album';
} }
$type = Art::validate_type($_GET['object_type']); $type = $_GET['object_type'];
if (!Core::is_library_item($type))
exit;
/* Decide what size this image is */ /* Decide what size this image is */
switch ($_GET['thumb']) { $size = Art::get_thumb_size($_GET['thumb']);
case '1': $kind = isset($_GET['kind']) ? $_GET['kind'] : 'default';
/* This is used by the now_playing stuff */
$size['height'] = '75';
$size['width'] = '75';
break;
case '2':
$size['height'] = '128';
$size['width'] = '128';
break;
case '3':
/* This is used by the flash player */
$size['height'] = '80';
$size['width'] = '80';
break;
case '4':
/* Web Player size */
$size['height'] = 200;
$size['width'] = 200; // 200px width, set via CSS
break;
case '5':
/* Web Player size */
$size['height'] = 32;
$size['width'] = 32;
break;
default:
$size['height'] = '275';
$size['width'] = '275';
if (!isset($_GET['thumb'])) { $return_raw = true; }
break;
} // define size based on thumbnail
$image = ''; $image = '';
$mime = ''; $mime = '';
$filename = ''; $filename = '';
$etag = '';
$typeManaged = false; $typeManaged = false;
if (isset($_GET['type'])) { if (isset($_GET['type'])) {
switch ($_GET['type']) { switch ($_GET['type']) {
@ -102,20 +78,47 @@ if (isset($_GET['type'])) {
} }
} }
if (!$typeManaged) { if (!$typeManaged) {
$media = new $type($_GET['id']); $item = new $type($_GET['object_id']);
$filename = $media->name; $filename = $item->name ?: $item->title;
$art = new Art($media->id,$type); $art = new Art($item->id, $type, $kind);
$art->get_db(); $art->get_db();
$etag = $art->id;
// That means the client has a cached version of the image
$reqheaders = getallheaders();
if (isset($reqheaders['If-Modified-Since']) && isset($reqheaders['If-None-Match'])) {
$ccontrol = $reqheaders['Cache-Control'];
if ($ccontrol != 'no-cache') {
$cetagf = explode('-', $reqheaders['If-None-Match']);
$cetag = $cetagf[0];
// Same image than the cached one? Use the cache.
if ($cetag == $etag) {
header('HTTP/1.1 304 Not Modified');
exit;
}
}
}
if (!$art->raw_mime) { if (!$art->raw_mime) {
$mime = 'image/jpeg'; $defaultimg = AmpConfig::get('prefix') . AmpConfig::get('theme_path') . '/images/';
$image = file_get_contents(AmpConfig::get('prefix') . switch ($type) {
AmpConfig::get('theme_path') . case 'video':
'/images/blankalbum.jpg'); case 'tvshow':
case 'tvshow_season':
$mime = 'image/png';
$defaultimg .= "blankmovie.png";
break;
default:
$mime = 'image/jpeg';
$defaultimg .= "blankalbum.jpg";
break;
}
$image = file_get_contents($defaultimg);
} else { } else {
if ($_GET['thumb']) { if ($_GET['thumb']) {
$thumb_data = $art->get_thumb($size); $thumb_data = $art->get_thumb($size);
$etag .= '-' . $_GET['thumb'];
} }
$mime = isset($thumb_data['thumb_mime']) ? $thumb_data['thumb_mime'] : $art->raw_mime; $mime = isset($thumb_data['thumb_mime']) ? $thumb_data['thumb_mime'] : $art->raw_mime;
@ -129,7 +132,11 @@ if (!empty($image)) {
// Send the headers and output the image // Send the headers and output the image
$browser = new Horde_Browser(); $browser = new Horde_Browser();
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + 604800)); if (!empty($etag)) {
header('ETag: ' . $etag);
header('Cache-Control: private');
header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', time()));
}
$browser->downloadHeaders($filename, $mime, true); $browser->downloadHeaders($filename, $mime, true);
echo $image; echo $image;
} }

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -22,12 +22,6 @@
require_once 'lib/init.php'; require_once 'lib/init.php';
if (AmpConfig::get('iframes')) {
if (!isset($_GET['framed'])) {
UI::show_mainframes();
exit;
}
}
UI::show_header(); UI::show_header();
$action = isset($_REQUEST['action']) ? scrub_in($_REQUEST['action']) : null; $action = isset($_REQUEST['action']) ? scrub_in($_REQUEST['action']) : null;
@ -42,7 +36,7 @@ $_SESSION['catalog'] = 0;
* refresh_javascript include. Must be greater then 5, I'm not * refresh_javascript include. Must be greater then 5, I'm not
* going to let them break their servers * going to let them break their servers
*/ */
if (AmpConfig::get('refresh_limit') > 5) { if (AmpConfig::get('refresh_limit') > 5 && AmpConfig::get('home_now_playing')) {
$refresh_limit = AmpConfig::get('refresh_limit'); $refresh_limit = AmpConfig::get('refresh_limit');
$ajax_url = '?page=index&action=reloadnp'; $ajax_url = '?page=index&action=reloadnp';
require_once AmpConfig::get('prefix') . '/templates/javascript_refresh.inc.php'; require_once AmpConfig::get('prefix') . '/templates/javascript_refresh.inc.php';

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -37,6 +37,7 @@ define('INSTALL', 1);
$htaccess_play_file = AmpConfig::get('prefix') . '/play/.htaccess'; $htaccess_play_file = AmpConfig::get('prefix') . '/play/.htaccess';
$htaccess_rest_file = AmpConfig::get('prefix') . '/rest/.htaccess'; $htaccess_rest_file = AmpConfig::get('prefix') . '/rest/.htaccess';
$htaccess_channel_file = AmpConfig::get('prefix') . '/channel/.htaccess';
// Clean up incoming variables // Clean up incoming variables
$web_path = scrub_in($_REQUEST['web_path']); $web_path = scrub_in($_REQUEST['web_path']);
@ -65,6 +66,20 @@ if (isset($_REQUEST['transcode_template'])) {
install_config_transcode_mode($mode); install_config_transcode_mode($mode);
} }
if (isset($_REQUEST['usecase'])) {
$case = $_REQUEST['usecase'];
if (Dba::check_database()) {
install_config_use_case($case);
}
}
if (isset($_REQUEST['backends'])) {
$backends = $_REQUEST['backends'];
if (Dba::check_database()) {
install_config_backends($backends);
}
}
// Charset and gettext setup // Charset and gettext setup
$htmllang = $_REQUEST['htmllang']; $htmllang = $_REQUEST['htmllang'];
$charset = $_REQUEST['charset']; $charset = $_REQUEST['charset'];
@ -89,7 +104,7 @@ load_gettext();
header ('Content-Type: text/html; charset=' . AmpConfig::get('site_charset')); header ('Content-Type: text/html; charset=' . AmpConfig::get('site_charset'));
// Correct potential \ or / in the dirname // Correct potential \ or / in the dirname
$safe_dirname = rtrim(dirname($_SERVER['PHP_SELF']),"/\\"); $safe_dirname = get_web_path();
$web_path = $http_type . $_SERVER['HTTP_HOST'] . $safe_dirname; $web_path = $http_type . $_SERVER['HTTP_HOST'] . $safe_dirname;
@ -119,29 +134,54 @@ switch ($_REQUEST['action']) {
// Now that it's inserted save the lang preference // Now that it's inserted save the lang preference
Preference::update('lang', '-1', AmpConfig::get('lang')); Preference::update('lang', '-1', AmpConfig::get('lang'));
header ('Location: ' . $web_path . "/install.php?action=show_create_config&local_db=$database&local_host=$hostname&local_port=$port&htmllang=$htmllang&charset=$charset");
break;
case 'create_config':
$download = (!isset($_POST['write']));
$download_htaccess_rest = (isset($_POST['download_htaccess_rest']));
$download_htaccess_play = (isset($_POST['download_htaccess_play']));
$write_htaccess_rest = (isset($_POST['write_htaccess_rest']));
$write_htaccess_play = (isset($_POST['write_htaccess_play']));
if ($write_htaccess_rest || $download_htaccess_rest) {
$created_config = install_rewrite_rules($htaccess_rest_file, $_POST['web_path'], $download_htaccess_rest);
} elseif ($write_htaccess_play || $download_htaccess_play) {
$created_config = install_rewrite_rules($htaccess_play_file, $_POST['web_path'], $download_htaccess_play);
} else {
$created_config = install_create_config($download);
}
require_once 'templates/show_install_config.inc.php';
break;
case 'show_create_config': case 'show_create_config':
require_once 'templates/show_install_config.inc.php'; require_once 'templates/show_install_config.inc.php';
break; break;
case 'create_config':
$all = (isset($_POST['create_all']));
$skip = (isset($_POST['skip_config']));
if (!$skip) {
$write = (isset($_POST['write']));
$download = (isset($_POST['download']));
$download_htaccess_channel = (isset($_POST['download_htaccess_channel']));
$download_htaccess_rest = (isset($_POST['download_htaccess_rest']));
$download_htaccess_play = (isset($_POST['download_htaccess_play']));
$write_htaccess_channel = (isset($_POST['write_htaccess_channel']));
$write_htaccess_rest = (isset($_POST['write_htaccess_rest']));
$write_htaccess_play = (isset($_POST['write_htaccess_play']));
$created_config = true;
if ($write_htaccess_channel || $download_htaccess_channel || $all) {
$created_config = $created_config && install_rewrite_rules($htaccess_channel_file, $_POST['web_path'], $download_htaccess_channel);
}
if ($write_htaccess_rest || $download_htaccess_rest || $all) {
$created_config = $created_config && install_rewrite_rules($htaccess_rest_file, $_POST['web_path'], $download_htaccess_rest);
}
if ($write_htaccess_play || $download_htaccess_play || $all) {
$created_config = $created_config && install_rewrite_rules($htaccess_play_file, $_POST['web_path'], $download_htaccess_play);
}
if ($write || $download || $all) {
$created_config = $created_config && install_create_config($download);
}
}
case 'show_create_account':
$results = parse_ini_file($configfile);
if (!isset($created_config)) $created_config = true;
/* Make sure we've got a valid config file */
if (!check_config_values($results) || !$created_config) {
Error::add('general', T_('Error: Config files not found or unreadable'));
require_once AmpConfig::get('prefix') . '/templates/show_install_config.inc.php';
break;
}
// Don't try to add administrator user on existing database
if (install_check_status($configfile)) {
require_once AmpConfig::get('prefix') . '/templates/show_install_account.inc.php';
} else {
header ("Location: " . $web_path . '/login.php');
}
break;
case 'create_account': case 'create_account':
$results = parse_ini_file($configfile); $results = parse_ini_file($configfile);
AmpConfig::set_by_array($results, true); AmpConfig::set_by_array($results, true);
@ -153,19 +193,13 @@ switch ($_REQUEST['action']) {
break; break;
} }
header ("Location: " . $web_path . '/login.php'); // Automatically log-in the newly created user
break; Session::create_cookie();
case 'show_create_account': Session::create(array('type' => 'mysql', 'username' => $username));
$results = parse_ini_file($configfile); $_SESSION['userdata']['username'] = $username;
Session::check();
/* Make sure we've got a valid config file */ header ("Location: " . $web_path . '/index.php');
if (!check_config_values($results)) {
Error::add('general', T_('Error: Config file not found or unreadable'));
require_once AmpConfig::get('prefix') . '/templates/show_install_config.inc.php';
break;
}
require_once AmpConfig::get('prefix') . '/templates/show_install_account.inc.php';
break; break;
case 'init': case 'init':
require_once 'templates/show_install.inc.php'; require_once 'templates/show_install.inc.php';

111
sources/labels.php Normal file
View file

@ -0,0 +1,111 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
require_once 'lib/init.php';
UI::show_header();
// Switch on the incomming action
switch ($_REQUEST['action']) {
case 'delete':
if (AmpConfig::get('demo_mode')) { break; }
$label_id = scrub_in($_REQUEST['label_id']);
show_confirmation(
T_('Label Deletion'),
T_('Are you sure you want to permanently delete this label?'),
AmpConfig::get('web_path')."/labels.php?action=confirm_delete&label_id=" . $label_id,
1,
'delete_label'
);
break;
case 'confirm_delete':
if (AmpConfig::get('demo_mode')) { break; }
$label = new Label($_REQUEST['label_id']);
if (!Catalog::can_remove($label)) {
debug_event('label', 'Unauthorized to remove the label `.' . $label->id . '`.', 1);
UI::access_denied();
exit;
}
if ($label->remove()) {
show_confirmation(T_('Label Deletion'), T_('Label has been deleted.'), AmpConfig::get('web_path'));
} else {
show_confirmation(T_('Label Deletion'), T_('Cannot delete this label.'), AmpConfig::get('web_path'));
}
break;
case 'add_label':
// Must be at least a content manager or edit upload enabled
if (!Access::check('interface','50') && !AmpConfig::get('upload_allow_edit')) {
UI::access_denied();
exit;
}
if (!Core::form_verify('add_label','post')) {
UI::access_denied();
exit;
}
// Remove unauthorized defined values from here
if (isset($_POST['user'])) {
unset($_POST['user']);
}
if (isset($_POST['creation_date'])) {
unset($_POST['creation_date']);
}
$label_id = Label::create($_POST);
if (!$label_id) {
require_once AmpConfig::get('prefix') . '/templates/show_add_label.inc.php';
} else {
$body = T_('Label Added');
$title = '';
show_confirmation($title, $body, AmpConfig::get('web_path') . '/browse.php?action=label');
}
break;
case 'show':
$label_id = intval($_REQUEST['label']);
if (!$label_id) {
if (!empty($_REQUEST['name'])) {
$label_id = Label::lookup($_REQUEST);
}
}
if ($label_id > 0) {
$label = new Label($label_id);
$label->format();
$object_ids = $label->get_artists();
$object_type = 'artist';
require_once AmpConfig::get('prefix') . '/templates/show_label.inc.php';
UI::show_footer();
exit;
}
case 'show_add_label':
if (Access::check('interface','50') || AmpConfig::get('upload_allow_edit')) {
require_once AmpConfig::get('prefix') . '/templates/show_add_label.inc.php';
} else {
echo T_('Label cannot be found.');
}
break;
} // end switch
UI::show_footer();

View file

@ -1,2 +1,10 @@
Order deny,allow # Apache 2.4
Deny from all <IfModule mod_authz_core.c>
Require all denied
</IfModule>
# Apache 2.2
<IfModule mod_access.c>
Order deny,allow
Deny from all
</IfModule>

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -21,93 +21,97 @@
*/ */
/** /**
* get_song_files * get_media_files
* *
* Takes an array of song ids and returns an array of the actual filenames * Takes an array of media ids and returns an array of the actual filenames
* *
* @param array $media_ids Media IDs. * @param array $media_ids Media IDs.
*/ */
function get_song_files($media_ids) function get_media_files($media_ids)
{ {
$media_files = array(); $media_files = array();
$total_size = 0; $total_size = 0;
foreach ($media_ids as $element) { foreach ($media_ids as $element) {
if (is_array($element)) { if (is_array($element)) {
$type = array_shift($element); if (isset($element['object_type'])) {
$media = new $type(array_shift($element)); $type = $element['object_type'];
$id = $element['object_id'];
} else {
$type = array_shift($element);
$id = array_shift($element);
}
$media = new $type($id);
} else { } else {
$media = new Song($element); $media = new Song($element);
} }
if ($media->enabled) { if ($media->enabled) {
$total_size += sprintf("%.2f",($media->size/1048576));
$media->format(); $media->format();
$dirname = $media->f_album_full; $total_size += sprintf("%.2f",($media->size/1048576));
//debug_event('batch.lib.php', 'Songs file {'.$media->file.'}...', '5'); $dirname = '';
$parent = $media->get_parent();
if ($parent != null) {
$pobj = new $parent['object_type']($parent['object_id']);
$pobj->format();
$dirname = $pobj->get_fullname();
}
if (!array_key_exists($dirname, $media_files)) { if (!array_key_exists($dirname, $media_files)) {
$media_files[$dirname] = array(); $media_files[$dirname] = array();
} }
array_push($media_files[$dirname], $media->file); array_push($media_files[$dirname], Core::conv_lc_file($media->file));
} }
} }
return array($media_files, $total_size); return array($media_files, $total_size);
} //get_song_files } //get_media_files
/** /**
* send_zip * send_zip
* *
* takes array of full paths to songs * takes array of full paths to medias
* zips them and sends them * zips them and sends them
* *
* @param string $name name of the zip file to be created * @param string $name name of the zip file to be created
* @param array $song_files array of full paths to songs to zip create w/ call to get_song_files * @param array $media_files array of full paths to medias to zip create w/ call to get_media_files
*/ */
function send_zip($name, $song_files) function send_zip($name, $media_files)
{ {
// Check if they want to save it to a file, if so then make sure they've
// got a defined path as well and that it's writable.
$basedir = '';
if (AmpConfig::get('file_zip_download') && AmpConfig::get('tmp_dir_path')) {
// Check writeable
if (!is_writable(AmpConfig::get('tmp_dir_path'))) {
$in_memory = '1';
debug_event('Error','File Zip Path:' . AmpConfig::get('tmp_dir_path') . ' is not writable','1');
} else {
$in_memory = '0';
$basedir = AmpConfig::get('tmp_dir_path');
}
} else {
$in_memory = '1';
} // if file downloads
/* Require needed library */ /* Require needed library */
require_once AmpConfig::get('prefix') . '/modules/archive/archive.lib.php'; require_once AmpConfig::get('prefix') . '/modules/ZipStream/ZipStream.php';
$arc = new zip_file($name . ".zip" ); $arc = new ZipStream\ZipStream($name . ".zip" );
$options = array( $options = array(
'inmemory' => $in_memory, // create archive in memory
'basedir' => $basedir,
'storepaths' => 0, // only store file name, not full path
'level' => 0, // no compression
'comment' => AmpConfig::get('file_zip_comment'), 'comment' => AmpConfig::get('file_zip_comment'),
'type' => "zip"
); );
$arc->set_options( $options ); foreach ($media_files as $dir => $files) {
foreach ($song_files as $dir => $files) { foreach ($files as $file) {
$arc->add_files($files, $dir); $arc->addFileFromPath($dir . "/" . basename($file), $file, $options);
}
} }
if (count($arc->error)) { $arc->finish();
debug_event('archive',"Error: unable to add songs",'3');
return false;
} // if failed to add songs
if (!$arc->create_archive()) {
debug_event('archive',"Error: unable to create archive",'3');
return false;
} // if failed to create archive
$arc->download_file();
} // send_zip } // send_zip
/**
* check_can_zip
*
* Check that an object type is allowed to be zipped.
*
* @param string $object_type
*/
function check_can_zip($object_type)
{
$allowed = true;
if (AmpConfig::get('allow_zip_types')) {
$allowed = false;
$allowed_types = explode(',', AmpConfig::get('allow_zip_types'));
foreach ($allowed_types as $atype) {
if (trim($atype) == $object_type) {
$allowed = true;
break;
}
}
}
return $allowed;
}

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -30,27 +30,68 @@
class Access class Access
{ {
// Variables from DB // Variables from DB
/**
* @var int $id
*/
public $id; public $id;
/**
* @var string $name
*/
public $name; public $name;
/**
* @var string $start
*/
public $start; public $start;
/**
* @var string $end
*/
public $end; public $end;
/**
* @var int $level
*/
public $level; public $level;
/**
* @var int $user
*/
public $user; public $user;
/**
* @var string $type
*/
public $type; public $type;
/**
* @var boolean $enabled
*/
public $enabled; public $enabled;
/**
* @var string $f_start
*/
public $f_start; public $f_start;
/**
* @var string $f_end
*/
public $f_end; public $f_end;
/**
* @var string $f_user
*/
public $f_user; public $f_user;
/**
* @var string $f_level
*/
public $f_level; public $f_level;
/**
* @var string $f_type
*/
public $f_type; public $f_type;
/** /**
* constructor * constructor
* *
* Takes an ID of the access_id dealie :) * Takes an ID of the access_id dealie :)
* @param int|null $access_id
*/ */
public function __construct($access_id = '') public function __construct($access_id = null)
{ {
if (!$access_id) { return false; } if (!$access_id) { return false; }
@ -69,6 +110,7 @@ class Access
* _get_info * _get_info
* *
* Gets the vars for $this out of the database. * Gets the vars for $this out of the database.
* @return array
*/ */
private function _get_info() private function _get_info()
{ {
@ -100,6 +142,9 @@ class Access
* _verify_range * _verify_range
* *
* This outputs an error if the IP range is bad. * This outputs an error if the IP range is bad.
* @param string $startp
* @param string $endp
* @return boolean
*/ */
private static function _verify_range($startp, $endp) private static function _verify_range($startp, $endp)
{ {
@ -128,8 +173,10 @@ class Access
* *
* This function takes a named array as a datasource and updates the current * This function takes a named array as a datasource and updates the current
* access list entry. * access list entry.
* @param array $data
* @return boolean
*/ */
public function update($data) public function update(array $data)
{ {
if (!self::_verify_range($data['start'], $data['end'])) { if (!self::_verify_range($data['start'], $data['end'])) {
return false; return false;
@ -156,8 +203,10 @@ class Access
* *
* This takes a keyed array of data and trys to insert it as a * This takes a keyed array of data and trys to insert it as a
* new ACL entry * new ACL entry
* @param array $data
* @return boolean
*/ */
public static function create($data) public static function create(array $data)
{ {
if (!self::_verify_range($data['start'], $data['end'])) { if (!self::_verify_range($data['start'], $data['end'])) {
return false; return false;
@ -191,8 +240,10 @@ class Access
* *
* This sees if the ACL that we've specified already exists in order to * This sees if the ACL that we've specified already exists in order to
* prevent duplicates. The name is ignored. * prevent duplicates. The name is ignored.
* @param array $data
* @return boolean
*/ */
public static function exists($data) public static function exists(array $data)
{ {
$start = inet_pton($data['start']); $start = inet_pton($data['start']);
$end = inet_pton($data['end']); $end = inet_pton($data['end']);
@ -214,6 +265,7 @@ class Access
* delete * delete
* *
* deletes the specified access_list entry * deletes the specified access_list entry
* @param int $id
*/ */
public static function delete($id) public static function delete($id)
{ {
@ -224,24 +276,26 @@ class Access
* check_function * check_function
* *
* This checks if specific functionality is enabled. * This checks if specific functionality is enabled.
* @param string $type
* @return boolean
*/ */
public static function check_function($type) public static function check_function($type)
{ {
switch ($type) { switch ($type) {
case 'download': case 'download':
return AmpConfig::get('download'); return make_bool(AmpConfig::get('download'));
case 'batch_download': case 'batch_download':
if (!function_exists('gzcompress')) { if (!function_exists('gzcompress')) {
debug_event('access', 'ZLIB extension not loaded, batch download disabled', 3); debug_event('access', 'ZLIB extension not loaded, batch download disabled', 3);
return false; return false;
} }
if (AmpConfig::get('allow_zip_download') AND $GLOBALS['user']->has_access('25')) { if (AmpConfig::get('allow_zip_download') AND $GLOBALS['user']->has_access('5')) {
return AmpConfig::get('download'); return make_bool(AmpConfig::get('download'));
} }
break; break;
default:
return false;
} }
return false;
} }
/** /**
@ -249,6 +303,11 @@ class Access
* *
* This takes a type, ip, user, level and key and then returns whether they * This takes a type, ip, user, level and key and then returns whether they
* are allowed. The IP is passed as a dotted quad. * are allowed. The IP is passed as a dotted quad.
* @param string $type
* @param int|string $user
* @param int $level
* @param string $ip
* @return boolean
*/ */
public static function check_network($type, $user, $level, $ip=null) public static function check_network($type, $user, $level, $ip=null)
{ {
@ -313,8 +372,12 @@ class Access
* *
* Everything uses the global 0,5,25,50,75,100 stuff. GLOBALS['user'] is * Everything uses the global 0,5,25,50,75,100 stuff. GLOBALS['user'] is
* always used. * always used.
* @param string $type
* @param int $level
* @param int|null $user
* @return boolean
*/ */
public static function check($type, $level) public static function check($type, $level, $user_id=null)
{ {
if (AmpConfig::get('demo_mode')) { if (AmpConfig::get('demo_mode')) {
return true; return true;
@ -323,6 +386,10 @@ class Access
return true; return true;
} }
$user = $GLOBALS['user'];
if ($user_id) {
$user = new User($user_id);
}
$level = intval($level); $level = intval($level);
// Switch on the type // Switch on the type
@ -330,10 +397,10 @@ class Access
case 'localplay': case 'localplay':
// Check their localplay_level // Check their localplay_level
return (AmpConfig::get('localplay_level') >= $level return (AmpConfig::get('localplay_level') >= $level
|| $GLOBALS['user']->access >= 100); || $user->access >= 100);
case 'interface': case 'interface':
// Check their standard user level // Check their standard user level
return ($GLOBALS['user']->access >= $level); return ($user->access >= $level);
default: default:
return false; return false;
} }
@ -344,6 +411,8 @@ class Access
* *
* This validates the specified type; it will always return a valid type, * This validates the specified type; it will always return a valid type,
* even if you pass in an invalid one. * even if you pass in an invalid one.
* @param string $type
* @return string
*/ */
public static function validate_type($type) public static function validate_type($type)
{ {
@ -360,6 +429,7 @@ class Access
/** /**
* get_access_lists * get_access_lists
* returns a full listing of all access rules on this server * returns a full listing of all access rules on this server
* @return array
*/ */
public static function get_access_lists() public static function get_access_lists()
{ {
@ -380,6 +450,7 @@ class Access
* get_level_name * get_level_name
* *
* take the int level and return a named level * take the int level and return a named level
* @return string
*/ */
public function get_level_name() public function get_level_name()
{ {
@ -401,6 +472,7 @@ class Access
* get_user_name * get_user_name
* *
* Return a name for the users covered by this ACL. * Return a name for the users covered by this ACL.
* @return string
*/ */
public function get_user_name() public function get_user_name()
{ {
@ -414,6 +486,7 @@ class Access
* get_type_name * get_type_name
* *
* This function returns the pretty name for our current type. * This function returns the pretty name for our current type.
* @return string
*/ */
public function get_type_name() public function get_type_name()
{ {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -31,6 +31,7 @@
class Ajax class Ajax
{ {
private static $include_override; private static $include_override;
private static $counter = 0;
/** /**
* constructor * constructor
@ -46,6 +47,11 @@ class Ajax
* observe * observe
* This returns a string with the correct and full ajax 'observe' stuff * This returns a string with the correct and full ajax 'observe' stuff
* from jQuery * from jQuery
* @param string $source
* @param string $method
* @param string $action
* @param string $confirm
* @return string
*/ */
public static function observe($source, $method, $action, $confirm='') public static function observe($source, $method, $action, $confirm='')
{ {
@ -59,10 +65,15 @@ class Ajax
$observe = "<script type=\"text/javascript\">"; $observe = "<script type=\"text/javascript\">";
$methodact = (($method == 'click') ? "update_action();" : ""); $methodact = (($method == 'click') ? "update_action();" : "");
if (!empty($confirm)) { if (AmpConfig::get('ajax_load') && $method == 'load') {
$observe .= "$(".$source_txt.").on('".$method."', function(){ ".$methodact." if (confirm(\"".$confirm."\")) { ".$action." }});"; $source_txt = "$( document ).ready(";
} else { } else {
$observe .= "$(".$source_txt.").on('".$method."', function(){ ".$methodact." ".$action.";});"; $source_txt = "$(".$source_txt.").on('".$method."', ";
}
if (!empty($confirm)) {
$observe .= $source_txt . "function(){ ".$methodact." if (confirm(\"".$confirm."\")) { ".$action." }});";
} else {
$observe .= $source_txt . "function(){ ".$methodact." ".$action.";});";
} }
$observe .= "</script>"; $observe .= "</script>";
@ -73,6 +84,8 @@ class Ajax
/** /**
* url * url
* This takes a string and makes an URL * This takes a string and makes an URL
* @param string $action
* @return string
*/ */
public static function url($action) public static function url($action)
{ {
@ -83,6 +96,10 @@ class Ajax
* action * action
* This takes the action, the source and the post (if passed) and * This takes the action, the source and the post (if passed) and
* generates the full ajax link * generates the full ajax link
* @param string $action
* @param string $source
* @param string $post
* @return string
*/ */
public static function action($action, $source, $post='') public static function action($action, $source, $post='')
{ {
@ -110,6 +127,14 @@ class Ajax
* button * button
* This prints out an img of the specified icon with the specified alt * This prints out an img of the specified icon with the specified alt
* text and then sets up the required ajax for it. * text and then sets up the required ajax for it.
* @param string $action
* @param string $icon
* @param string $alt
* @param string $source
* @param string $post
* @param string $class
* @param string $confirm
* @return string
*/ */
public static function button($action, $icon, $alt, $source='', $post='', $class='', $confirm='') public static function button($action, $icon, $alt, $source='', $post='', $class='', $confirm='')
{ {
@ -138,24 +163,35 @@ class Ajax
* text * text
* This prints out the specified text as a link and sets up the required * This prints out the specified text as a link and sets up the required
* ajax for the link so it works correctly * ajax for the link so it works correctly
* @param string $action
* @param string $text
* @param string $source
* @param string $post
* @param string $class
* @return string
*/ */
public static function text($action, $text, $source, $post='', $class='') public static function text($action, $text, $source, $post='', $class='')
{ {
// Avoid duplicate id // Temporary workaround to avoid sorting on custom base requests
$source .= '_' . time(); if (!defined("NO_BROWSE_SORTING") || strpos($source, "sort_") === false) {
// Avoid duplicate id
$source .= '_' . time() . '_' . self::$counter++;
// Format the string we wanna use // Format the string we wanna use
$ajax_string = self::action($action, $source, $post); $ajax_string = self::action($action, $source, $post);
// If they passed a span class // If they passed a span class
if ($class) { if ($class) {
$class = ' class="' . $class . '"'; $class = ' class="' . $class . '"';
}
$string = "<a href=\"javascript:void(0);\" id=\"$source\" $class>$text</a>\n";
$string .= self::observe($source, 'click', $ajax_string);
} else {
$string = $text;
} }
$string = "<a href=\"javascript:void(0);\" id=\"$source\" $class>$text</a>\n";
$string .= self::observe($source, 'click', $ajax_string);
return $string; return $string;
} // text } // text
@ -163,6 +199,7 @@ class Ajax
/** /**
* run * run
* This runs the specified action no questions asked * This runs the specified action no questions asked
* @param string $action
*/ */
public static function run($action) public static function run($action)
{ {
@ -176,6 +213,7 @@ class Ajax
* set_include_override * set_include_override
* This sets the including div override, used only one place. Kind of a * This sets the including div override, used only one place. Kind of a
* hack. * hack.
* @param bool $value
*/ */
public static function set_include_override($value) public static function set_include_override($value)
{ {
@ -187,6 +225,8 @@ class Ajax
* start_container * start_container
* This checks to see if we're AJAXin'. If we aren't then it echoes out * This checks to see if we're AJAXin'. If we aren't then it echoes out
* the html needed to start a container that can be replaced by Ajax. * the html needed to start a container that can be replaced by Ajax.
* @param string $name
* @param string $class
*/ */
public static function start_container($name, $class = '') public static function start_container($name, $class = '')
{ {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -28,39 +28,153 @@
* it is related to the album table in the database. * it is related to the album table in the database.
* *
*/ */
class Album extends database_object class Album extends database_object implements library_item
{ {
/* Variables from DB */ /* Variables from DB */
public $id;
public $name;
public $disk;
public $year;
public $prefix;
public $mbid; // MusicBrainz ID
/**
* @var int $id
*/
public $id;
/**
* @var string $name
*/
public $name;
/**
* @var int $album_artist
*/
public $album_artist;
/**
* @var int $disk
*/
public $disk;
/**
* @var int $year
*/
public $year;
/**
* @var string $prefix
*/
public $prefix;
/**
* @var string $mbid
*/
public $mbid; // MusicBrainz ID
/**
* @var string $mbid_group
*/
public $mbid_group; // MusicBrainz Release Group ID
/**
* @var string $release_type
*/
public $release_type;
/**
* @var int $catalog_id
*/
public $catalog_id;
/**
* @var int $song_count
*/
public $song_count; public $song_count;
/**
* @var string $artist_prefix
*/
public $artist_prefix; public $artist_prefix;
/**
* @var string $artist_name
*/
public $artist_name; public $artist_name;
/**
* @var int $artist_id
*/
public $artist_id; public $artist_id;
/**
* @var array $tags
*/
public $tags; public $tags;
/**
* @var string $full_name
*/
public $full_name; // Prefix + Name, generated public $full_name; // Prefix + Name, generated
/**
* @var int $artist_count
*/
public $artist_count; public $artist_count;
/**
* @var string $f_artist_name
*/
public $f_artist_name; public $f_artist_name;
/**
* @var string $f_artist_link
*/
public $f_artist_link; public $f_artist_link;
/**
* @var string $f_artist
*/
public $f_artist; public $f_artist;
/**
* @var string $album_artist_name
*/
public $album_artist_name;
/**
* @var string $f_album_artist_name
*/
public $f_album_artist_name;
/**
* @var string $f_album_artist_link
*/
public $f_album_artist_link;
/**
* @var string $f_name
*/
public $f_name; public $f_name;
public $f_name_link; /**
public $f_link_src; * @var string $link
*/
public $link;
/**
* @var string $f_link
*/
public $f_link; public $f_link;
/**
* @var string $f_tags
*/
public $f_tags; public $f_tags;
/**
* @var string $f_year
*/
public $f_year;
/**
* @var string $f_title
*/
public $f_title; public $f_title;
/**
* @var string $f_release_type
*/
public $f_release_type;
// cached information // cached information
/**
* @var boolean $_fake
*/
public $_fake; public $_fake;
/**
* @var array $_songs
*/
public $_songs = array(); public $_songs = array();
/**
* @var array $_mapcache
*/
private static $_mapcache = array(); private static $_mapcache = array();
/**
* @var array $album_suite
*/
public $album_suite = array(); public $album_suite = array();
/**
* @var boolean $allow_group_disks
*/
public $allow_group_disks = false; public $allow_group_disks = false;
/** /**
@ -69,8 +183,9 @@ class Album extends database_object
* to this album from the database it does not * to this album from the database it does not
* pull the album or thumb art by default or * pull the album or thumb art by default or
* get any of the counts. * get any of the counts.
* @param int|null $id
*/ */
public function __construct($id='') public function __construct($id=null)
{ {
if (!$id) { return false; } if (!$id) { return false; }
@ -98,8 +213,10 @@ class Album extends database_object
* construct_from_array * construct_from_array
* This is often used by the metadata class, it fills out an album object from a * This is often used by the metadata class, it fills out an album object from a
* named array, _fake is set to true * named array, _fake is set to true
* @param array $data
* @return Album
*/ */
public static function construct_from_array($data) public static function construct_from_array(array $data)
{ {
$album = new Album(0); $album = new Album(0);
foreach ($data as $key=>$value) { foreach ($data as $key=>$value) {
@ -126,8 +243,10 @@ class Album extends database_object
* build_cache * build_cache
* This takes an array of object ids and caches all of their information * This takes an array of object ids and caches all of their information
* with a single query * with a single query
* @param array $ids
* @return boolean
*/ */
public static function build_cache($ids) public static function build_cache(array $ids)
{ {
// Nothing to do if they pass us nothing // Nothing to do if they pass us nothing
if (!is_array($ids) OR !count($ids)) { if (!is_array($ids) OR !count($ids)) {
@ -140,7 +259,7 @@ class Album extends database_object
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
parent::add_to_cache('album',$row['id'],$row); parent::add_to_cache('album', $row['id'], $row);
} }
return true; return true;
@ -151,9 +270,14 @@ class Album extends database_object
* _get_extra_info * _get_extra_info
* This pulls the extra information from our tables, this is a 3 table join, which is why we don't normally * This pulls the extra information from our tables, this is a 3 table join, which is why we don't normally
* do it * do it
* @return array
*/ */
private function _get_extra_info() private function _get_extra_info($limit_threshold = '')
{ {
if (!$this->id) {
return array();
}
if (parent::is_cached('album_extra', $this->id)) { if (parent::is_cached('album_extra', $this->id)) {
return parent::get_from_cache('album_extra', $this->id); return parent::get_from_cache('album_extra', $this->id);
} }
@ -203,7 +327,7 @@ class Album extends database_object
$results['has_thumb'] = make_bool($art->thumb); $results['has_thumb'] = make_bool($art->thumb);
if (AmpConfig::get('show_played_times')) { if (AmpConfig::get('show_played_times')) {
$results['object_cnt'] = Stats::get_object_count('album', $this->id); $results['object_cnt'] = Stats::get_object_count('album', $this->id, $limit_threshold);
} }
parent::add_to_cache('album_extra', $this->id, $results); parent::add_to_cache('album_extra', $this->id, $results);
@ -212,18 +336,55 @@ class Album extends database_object
} // _get_extra_info } // _get_extra_info
public function can_edit($user = null)
{
if (!$user) {
$user = $GLOBALS['user']->id;
}
if (!$user)
return false;
if ($this->user !== null && $user == $this->user)
return true;
if (Access::check('interface', 50, $user))
return true;
if (!$this->album_artist)
return false;
if (!AmpConfig::get('upload_allow_edit'))
return false;
$owner = $this->get_user_owner();
return ($owner && $owner === $user);
}
/** /**
* check * check
* *
* Searches for an album; if none is found, insert a new one. * Searches for an album; if none is found, insert a new one.
* @param string $name
* @param int $year
* @param int $disk
* @param string $mbid
* @param string $mbid_group
* @param string $album_artist
* @param string $release_type
* @param boolean $readonly
* @return int|null
*/ */
public static function check($name, $year = 0, $disk = 0, $mbid = null, $readonly = false) public static function check($name, $year = 0, $disk = 0, $mbid = null, $mbid_group = null, $album_artist = null, $release_type = null, $readonly = false)
{ {
if ($mbid == '') $mbid = null;
$trimmed = Catalog::trim_prefix(trim($name)); $trimmed = Catalog::trim_prefix(trim($name));
$name = $trimmed['string']; $name = $trimmed['string'];
$prefix = $trimmed['prefix']; $prefix = $trimmed['prefix'];
$album_artist = intval($album_artist);
$album_artist = ($album_artist <= 0) ? null : $album_artist;
$mbid = empty($mbid) ? null : $mbid;
$mbid_group = empty($mbid_group) ? null : $mbid_group;
$release_type = empty($release_type) ? null : $release_type;
// Not even sure if these can be negative, but better safe than llama. // Not even sure if these can be negative, but better safe than llama.
$year = abs(intval($year)); $year = abs(intval($year));
@ -233,35 +394,36 @@ class Album extends database_object
$name = T_('Unknown (Orphaned)'); $name = T_('Unknown (Orphaned)');
$year = 0; $year = 0;
$disk = 0; $disk = 0;
$album_artist = null;
}
if (isset(self::$_mapcache[$name][$disk][$mbid][$album_artist])) {
return self::$_mapcache[$name][$disk][$mbid][$album_artist];
} }
if (isset(self::$_mapcache[$name][$year][$disk][$mbid])) { $sql = 'SELECT `album`.`id` FROM `album` WHERE `album`.`name` = ? AND `album`.`disk` = ? ';
return self::$_mapcache[$name][$year][$disk][$mbid]; $params = array($name, $disk);
}
$sql = 'SELECT `id` FROM `album` WHERE `name` = ? AND `disk` = ? AND `year` = ? AND `mbid` ';
$params = array($name, $disk, $year);
if ($mbid) { if ($mbid) {
$sql .= '= ? '; $sql .= 'AND `album`.`mbid` = ? ';
$params[] = $mbid; $params[] = $mbid;
} else { } else {
$sql .= 'IS NULL '; $sql .= 'AND `album`.`mbid` IS NULL ';
}
if ($prefix) {
$sql .= 'AND `album`.`prefix` = ? ';
$params[] = $prefix;
} }
$sql .= 'AND `prefix` '; if ($album_artist) {
if ($prefix) { $sql .= 'AND `album`.`album_artist` = ? ';
$sql .= '= ?'; $params[] = $album_artist;
$params[] = $prefix;
} else {
$sql .= 'IS NULL';
} }
$db_results = Dba::read($sql, $params); $db_results = Dba::read($sql, $params);
if ($row = Dba::fetch_assoc($db_results)) { if ($row = Dba::fetch_assoc($db_results)) {
$id = $row['id']; $id = $row['id'];
self::$_mapcache[$name][$year][$disk][$mbid] = $id; self::$_mapcache[$name][$disk][$mbid][$album_artist] = $id;
return $id; return $id;
} }
@ -269,9 +431,9 @@ class Album extends database_object
return null; return null;
} }
$sql = 'INSERT INTO `album` (`name`, `prefix`, `year`, `disk`, `mbid`) VALUES (?, ?, ?, ?, ?)'; $sql = 'INSERT INTO `album` (`name`, `prefix`, `year`, `disk`, `mbid`, `mbid_group`, `release_type`, `album_artist`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)';
$db_results = Dba::write($sql, array($name, $prefix, $year, $disk, $mbid)); $db_results = Dba::write($sql, array($name, $prefix, $year, $disk, $mbid, $mbid_group, $release_type, $album_artist));
if (!$db_results) { if (!$db_results) {
return null; return null;
} }
@ -287,7 +449,7 @@ class Album extends database_object
} }
} }
self::$_mapcache[$name][$year][$disk][$mbid] = $id; self::$_mapcache[$name][$disk][$mbid][$album_artist] = $id;
return $id; return $id;
} }
@ -296,6 +458,9 @@ class Album extends database_object
* gets the songs for this album takes an optional limit * gets the songs for this album takes an optional limit
* and an optional artist, if artist is passed it only gets * and an optional artist, if artist is passed it only gets
* songs with this album + specified artist * songs with this album + specified artist
* @param int $limit
* @param string $artist
* @return int[]
*/ */
public function get_songs($limit = 0,$artist='') public function get_songs($limit = 0,$artist='')
{ {
@ -331,6 +496,8 @@ class Album extends database_object
/** /**
* get_http_album_query_ids * get_http_album_query_ids
* return the html album parameters with all album suite ids * return the html album parameters with all album suite ids
* @param string $url_param_name
* @return string
*/ */
public function get_http_album_query_ids($url_param_name) public function get_http_album_query_ids($url_param_name)
{ {
@ -346,6 +513,7 @@ class Album extends database_object
/** /**
* get_group_disks_ids * get_group_disks_ids
* return all album suite ids or current album if no albums * return all album suite ids or current album if no albums
* @return int[]
*/ */
public function get_group_disks_ids() public function get_group_disks_ids()
{ {
@ -360,14 +528,16 @@ class Album extends database_object
/** /**
* get_album_suite * get_album_suite
* gets the album ids with the same musicbrainz identifier * gets the album ids with the same musicbrainz identifier
* @param int $catalog
* return int[]
*/ */
public function get_album_suite($catalog = '') public function get_album_suite($catalog = 0)
{ {
$results = array(); $results = array();
$catalog_where = ""; $catalog_where = "";
$catalog_join = "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog`"; $catalog_join = "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog`";
if (!empty($catalog)) { if ($catalog) {
$catalog_where .= " AND `catalog`.`id` = '$catalog'"; $catalog_where .= " AND `catalog`.`id` = '$catalog'";
} }
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
@ -390,6 +560,8 @@ class Album extends database_object
/** /**
* has_track * has_track
* This checks to see if this album has a track of the specified title * This checks to see if this album has a track of the specified title
* @param string $title
* @return array
*/ */
public function has_track($title) public function has_track($title)
{ {
@ -402,39 +574,69 @@ class Album extends database_object
} // has_track } // has_track
/**
* get_addtime_first_song
* Get the add date of first added song.
* @return int
*/
public function get_addtime_first_song()
{
$time = 0;
$sql = "SELECT MIN(`addition_time`) FROM `song` WHERE `album` = ?";
$db_results = Dba::read($sql, array($this->id));
if ($data = Dba::fetch_row($db_results)) {
$time = $data[0];
}
return $time;
}
/** /**
* format * format
* This is the format function for this object. It sets cleaned up * This is the format function for this object. It sets cleaned up
* album information with the base required * album information with the base required
* f_link, f_name * f_link, f_name
*/ */
public function format() public function format($details = true, $limit_threshold = '')
{ {
$web_path = AmpConfig::get('web_path'); $web_path = AmpConfig::get('web_path');
/* Pull the advanced information */ if ($details) {
$data = $this->_get_extra_info(); /* Pull the advanced information */
foreach ($data as $key=>$value) { $this->$key = $value; } $data = $this->_get_extra_info($limit_threshold);
foreach ($data as $key=>$value) { $this->$key = $value; }
if ($this->album_artist) {
$Album_artist = new Artist($this->album_artist);
$Album_artist->format();
$this->album_artist_name = $Album_artist->name;
$this->f_album_artist_name = $Album_artist->f_name;
$this->f_album_artist_link = "<a href=\"" . $web_path . "/artists.php?action=show&artist=" . $this->album_artist . "\" title=\"" . scrub_out($this->album_artist_name) . "\">" . $this->f_album_artist_name . "</a>";
}
$this->tags = Tag::get_top_tags('album', $this->id);
$this->f_tags = Tag::get_display($this->tags, true, 'album');
}
/* Truncate the string if it's to long */ /* Truncate the string if it's to long */
$this->f_name = $this->full_name; $this->f_name = $this->full_name;
$this->f_link_src = $web_path . '/albums.php?action=show&album=' . scrub_out($this->id); $this->link = $web_path . '/albums.php?action=show&album=' . scrub_out($this->id);
$this->f_name_link = "<a href=\"" . $this->f_link_src . "\" title=\"" . scrub_out($this->full_name) . "\">" . scrub_out($this->f_name); $this->f_link = "<a href=\"" . $this->link . "\" title=\"" . scrub_out($this->full_name) . "\">" . scrub_out($this->f_name);
// Looking if we need to combine or display disks // Looking if we need to combine or display disks
if ($this->disk && (!$this->allow_group_disks || ($this->allow_group_disks && !AmpConfig::get('album_group')))) { if ($this->disk && (!$this->allow_group_disks || ($this->allow_group_disks && !AmpConfig::get('album_group')))) {
$this->f_name_link .= " <span class=\"discnb\">[" . T_('Disk') . " " . $this->disk . "]</span>"; $this->f_link .= " <span class=\"discnb\">[" . T_('Disk') . " " . $this->disk . "]</span>";
} }
$this->f_name_link .="</a>"; $this->f_link .="</a>";
$this->f_link = $this->f_name_link;
$this->f_title = $this->full_name; $this->f_title = $this->full_name;
if ($this->artist_count == '1') { if ($this->artist_count == '1') {
$artist = trim(trim($this->artist_prefix) . ' ' . trim($this->artist_name)); $artist = trim(trim($this->artist_prefix) . ' ' . trim($this->artist_name));
$this->f_artist_name = $artist; $this->f_artist_name = $artist;
$this->f_artist_link = "<a href=\"$web_path/artists.php?action=show&amp;artist=" . $this->artist_id . "\" title=\"" . scrub_out($this->artist_name) . "\">" . $artist . "</a>"; $this->f_artist_link = "<a href=\"$web_path/artists.php?action=show&artist=" . $this->artist_id . "\" title=\"" . scrub_out($this->artist_name) . "\">" . $artist . "</a>";
$this->f_artist = $artist; $this->f_artist = $artist;
} else { } else {
$this->f_artist_link = "<span title=\"$this->artist_count " . T_('Artists') . "\">" . T_('Various') . "</span>"; $this->f_artist_link = "<span title=\"$this->artist_count " . T_('Artists') . "\">" . T_('Various') . "</span>";
@ -442,18 +644,180 @@ class Album extends database_object
$this->f_artist_name = $this->f_artist; $this->f_artist_name = $this->f_artist;
} }
if ($this->year == '0') { if (!$this->year) {
$this->year = "N/A"; $this->f_year = "N/A";
} }
$this->tags = Tag::get_top_tags('album', $this->id); $this->f_release_type = ucwords($this->release_type);
$this->f_tags = Tag::get_display($this->tags);
} // format } // format
/**
* Get item keywords for metadata searches.
* @return array
*/
public function get_keywords()
{
$keywords = array();
$keywords['mb_albumid'] = array('important' => false,
'label' => T_('Album MusicBrainzID'),
'value' => $this->mbid);
$keywords['mb_albumid_group'] = array('important' => false,
'label' => T_('Release Group MusicBrainzID'),
'value' => $this->mbid_group);
$keywords['artist'] = array('important' => true,
'label' => T_('Artist'),
'value' => (($this->artist_count < 2) ? $this->f_artist_name : ''));
$keywords['album'] = array('important' => true,
'label' => T_('Album'),
'value' => $this->f_name);
return $keywords;
}
/**
* Get item fullname.
* @return string
*/
public function get_fullname()
{
return $this->f_name;
}
/**
* Get parent item description.
* @return array|null
*/
public function get_parent()
{
if ($this->artist_count == 1) {
return array('object_type' => 'artist', 'object_id' => $this->artist_id);
}
return null;
}
/**
* Get item childrens.
* @return array
*/
public function get_childrens()
{
return $this->get_medias();
}
/**
* Search for item childrens.
* @param string $name
* @return array
*/
public function search_childrens($name)
{
$search['type'] = "song";
$search['rule_0_input'] = $name;
$search['rule_0_operator'] = 4;
$search['rule_0'] = "title";
$search['rule_1_input'] = $this->name;
$search['rule_1_operator'] = 4;
$search['rule_1'] = "album";
$search['rule_2_input'] = $this->album_artist_name;
$search['rule_2_operator'] = 4;
$search['rule_2'] = "artist";
$songs = Search::run($search);
$childrens = array();
foreach ($songs as $song) {
$childrens[] = array(
'object_type' => 'song',
'object_id' => $song
);
}
return $childrens;
}
/**
* Get all childrens and sub-childrens medias.
* @param string $filter_type
* @return array
*/
public function get_medias($filter_type = null)
{
$medias = array();
if (!$filter_type || $filter_type == 'song') {
$songs = $this->get_songs();
foreach ($songs as $song_id) {
$medias[] = array(
'object_type' => 'song',
'object_id' => $song_id
);
}
}
return $medias;
}
/**
* get_catalogs
*
* Get all catalog ids related to this item.
* @return int[]
*/
public function get_catalogs()
{
return array($this->catalog_id);
}
/**
* Get item's owner.
* @return int|null
*/
public function get_user_owner()
{
if (!$this->album_artist)
return null;
$artist = new Artist($this->album_artist);
return $artist->get_user_owner();
}
/**
* Get default art kind for this item.
* @return string
*/
public function get_default_art_kind()
{
return 'default';
}
public function get_description()
{
// Album description is not supported yet, always return artist description
$artist = new Artist($this->artist_id);
return $artist->get_description();
}
public function display_art($thumb = 2)
{
$id = null;
$type = null;
if (Art::has_db($this->id, 'album')) {
$id = $this->id;
$type = 'album';
} else if (Art::has_db($this->artist_id, 'artist')) {
$id = $this->artist_id;
$type = 'artist';
}
if ($id !== null && $type !== null) {
Art::display($type, $id, $this->get_fullname(), $thumb, $this->link);
}
}
/** /**
* get_random_songs * get_random_songs
* gets a random number, and a random assortment of songs from this album * gets a random number, and a random assortment of songs from this album
* @return int[]
*/ */
public function get_random_songs() public function get_random_songs()
{ {
@ -481,17 +845,27 @@ class Album extends database_object
* update * update
* This function takes a key'd array of data and updates this object * This function takes a key'd array of data and updates this object
* as needed * as needed
* @param array $data
* @return int
*/ */
public function update($data) public function update(array $data)
{ {
$year = $data['year']; $year = isset($data['year']) ? $data['year'] : $this->year;
$artist = $data['artist']; $artist = isset($data['artist']) ? intval($data['artist']) : $this->artist_id;
$name = $data['name']; $album_artist = isset($data['album_artist']) ? intval($data['album_artist']) : $this->album_artist;
$disk = $data['disk']; $name = isset($data['name']) ? $data['name'] : $this->name;
$mbid = $data['mbid']; $disk = isset($data['disk']) ? $data['disk']: $this->disk;
$mbid = isset($data['mbid']) ? $data['mbid'] : $this->mbid;
$mbid_group = isset($data['mbid_group']) ? $data['mbid_group'] : $this->mbid_group;
$release_type = isset($data['release_type']) ? $data['release_type'] : $this->release_type;
$current_id = $this->id; $current_id = $this->id;
if (!empty($data['album_artist_name'])) {
// Need to create new artist according the name
$album_artist = Artist::check($data['album_artist_name']);
}
$updated = false; $updated = false;
$songs = null; $songs = null;
if ($artist != $this->artist_id AND $artist) { if ($artist != $this->artist_id AND $artist) {
@ -504,17 +878,31 @@ class Album extends database_object
Artist::gc(); Artist::gc();
} }
$album_id = self::check($name, $year, $disk, $mbid); $album_id = self::check($name, $year, $disk, $mbid, $mbid_group, $album_artist, $release_type);
if ($album_id != $this->id) { if ($album_id != $this->id) {
if (!is_array($songs)) { $songs = $this->get_songs(); } if (!is_array($songs)) { $songs = $this->get_songs(); }
foreach ($songs as $song_id) { foreach ($songs as $song_id) {
Song::update_album($album_id,$song_id); Song::update_album($album_id,$song_id);
Song::update_year($year,$song_id); Song::update_year($year,$song_id);
Song::write_id3_for_song($song_id);
} }
$current_id = $album_id; $current_id = $album_id;
$updated = true; $updated = true;
Stats::migrate('album', $this->id, $album_id);
Art::migrate('album', $this->id, $album_id);
self::gc(); self::gc();
} else {
Album::update_year($year, $album_id);
Album::update_mbid_group($mbid_group, $album_id);
Album::update_release_type($release_type, $album_id);
} }
$this->year = $year;
$this->mbid_group = $mbid_group;
$this->release_type = $release_type;
$this->name = $name;
$this->disk = $disk;
$this->mbid = $mbid;
$this->album_artist = $album_artist;
if ($updated && is_array($songs)) { if ($updated && is_array($songs)) {
foreach ($songs as $song_id) { foreach ($songs as $song_id) {
@ -525,11 +913,19 @@ class Album extends database_object
Userflag::gc(); Userflag::gc();
} // if updated } // if updated
$override_songs = false; $override_childs = false;
if ($data['apply_childs'] == 'checked') { if ($data['overwrite_childs'] == 'checked') {
$override_songs = true; $override_childs = true;
}
$add_to_childs = false;
if ($data['add_to_childs'] == 'checked') {
$add_to_childs = true;
}
if (isset($data['edit_tags'])) {
$this->update_tags($data['edit_tags'], $override_childs, $add_to_childs, $current_id, true);
} }
$this->update_tags($data['edit_tags'], $override_songs, $current_id);
return $current_id; return $current_id;
@ -539,27 +935,106 @@ class Album extends database_object
* update_tags * update_tags
* *
* Update tags of albums and/or songs * Update tags of albums and/or songs
* @param string $tags_comma
* @param boolean $override_childs
* @param boolean $add_to_childs
* @param int|null $current_id
*/ */
public function update_tags($tags_comma, $override_songs, $current_id = null) public function update_tags($tags_comma, $override_childs, $add_to_childs, $current_id = null, $force_update = false)
{ {
if ($current_id == null) { if ($current_id == null) {
$current_id = $this->id; $current_id = $this->id;
} }
Tag::update_tag_list($tags_comma, 'album', $current_id); // When current_id not empty we force to overwrite current object
Tag::update_tag_list($tags_comma, 'album', $current_id, $force_update ? true : $override_childs);
if ($override_songs) { if ($override_childs || $add_to_childs) {
$songs = $this->get_songs(); $songs = $this->get_songs();
foreach ($songs as $song_id) { foreach ($songs as $song_id) {
Tag::update_tag_list($tags_comma, 'song', $song_id); Tag::update_tag_list($tags_comma, 'song', $song_id, $override_childs);
} }
} }
} }
public function remove_from_disk()
{
$deleted = true;
$song_ids = $this->get_songs();
foreach ($song_ids as $id) {
$song = new Song($id);
$deleted = $song->remove_from_disk();
if (!$deleted) {
debug_event('album', 'Error when deleting the song `' . $id .'`.', 1);
break;
}
}
if ($deleted) {
$sql = "DELETE FROM `album` WHERE `id` = ?";
$deleted = Dba::write($sql, array($this->id));
if ($deleted) {
Art::gc('album', $this->id);
Userflag::gc('album', $this->id);
Rating::gc('album', $this->id);
Shoutbox::gc('album', $this->id);
}
}
return $deleted;
}
/**
* Update album year.
* @param int $year
* @param int $album_id
*/
public static function update_year($year, $album_id)
{
self::update_field('year', $year, $album_id);
}
/**
* Update album mbid group.
* @param string $mbid_group
* @param int $album_id
*/
public static function update_mbid_group($mbid_group, $album_id)
{
$mbid_group = (!empty($mbid_group)) ? $mbid_group : null;
self::update_field('mbid_group', $mbid_group, $album_id);
}
/**
* Update album release type.
* @param string $release_type
* @param int $album_id
*/
public static function update_release_type($release_type, $album_id)
{
$release_type = (!empty($release_type)) ? $release_type : null;
self::update_field('release_type', $release_type, $album_id);
}
/**
* Update an album field.
* @param string $field
* @param int $album_id
* @return boolean
*/
private static function update_field($field, $value, $album_id)
{
$sql = "UPDATE `album` SET `" . $field . "` = ? WHERE `id` = ?";
return Dba::write($sql, array($value, $album_id));
}
/** /**
* get_random * get_random
* *
* This returns a number of random albums. * This returns a number of random albums.
* @param int $count
* @param boolean $with_art
* @return int[]
*/ */
public static function get_random($count = 1, $with_art = false) public static function get_random($count = 1, $with_art = false)
{ {
@ -569,7 +1044,7 @@ class Album extends database_object
$count = 1; $count = 1;
} }
$sql = "SELECT `album`.`id` FROM `album` " . $sql = "SELECT DISTINCT `album`.`id` FROM `album` " .
"LEFT JOIN `song` ON `song`.`album` = `album`.`id` "; "LEFT JOIN `song` ON `song`.`album` = `album`.`id` ";
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
$sql .= "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` "; $sql .= "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` ";

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -27,6 +27,9 @@
*/ */
class Ampache_RSS class Ampache_RSS
{ {
/**
* @var string $type
*/
private $type; private $type;
public $data; public $data;
@ -44,33 +47,56 @@ class Ampache_RSS
* get_xml * get_xml
* This returns the xmldocument for the current rss type, it calls a sub function that gathers the data * This returns the xmldocument for the current rss type, it calls a sub function that gathers the data
* and then uses the xmlDATA class to build the document * and then uses the xmlDATA class to build the document
* @return string
*/ */
public function get_xml() public function get_xml($params = null)
{ {
// Function call name if ($this->type === "podcast") {
$data_function = 'load_' . $this->type; if ($params != null && is_array($params)) {
$pub_date_function = 'pubdate_' . $this->type; $object_type = $params['object_type'];
$object_id = $params['object_id'];
if (Core::is_library_item($object_type)) {
$libitem = new $object_type($object_id);
if ($libitem->id) {
$libitem->format();
return XML_Data::podcast($libitem);
}
}
}
} else {
// Function call name
$data_function = 'load_' . $this->type;
$pub_date_function = 'pubdate_' . $this->type;
$data = call_user_func(array('Ampache_RSS',$data_function)); $data = call_user_func(array('Ampache_RSS',$data_function));
$pub_date = call_user_func(array('Ampache_RSS',$pub_date_function)); $pub_date = null;
if (method_exists('Ampache_RSS', $data_function)) {
$pub_date = call_user_func(array('Ampache_RSS',$pub_date_function));
}
XML_Data::set_type('rss'); XML_Data::set_type('rss');
$xml_document = XML_Data::rss_feed($data,$this->get_title(),$this->get_description(),$pub_date); $xml_document = XML_Data::rss_feed($data,$this->get_title(),$this->get_description(),$pub_date);
return $xml_document; return $xml_document;
}
return null;
} // get_xml } // get_xml
/** /**
* get_title * get_title
* This returns the standardized title for the rss feed based on this->type * This returns the standardized title for the rss feed based on this->type
* @return string
*/ */
public function get_title() public function get_title()
{ {
$titles = array('now_playing' => T_('Now Playing'), $titles = array('now_playing' => T_('Now Playing'),
'recently_played' => T_('Recently Played'), 'recently_played' => T_('Recently Played'),
'latest_album' => T_('Newest Albums'), 'latest_album' => T_('Newest Albums'),
'latest_artist' => T_('Newest Artists')); 'latest_artist' => T_('Newest Artists'),
'latest_shout' => T_('Newest Shouts')
);
return scrub_out(AmpConfig::get('site_title')) . ' - ' . $titles[$this->type]; return scrub_out(AmpConfig::get('site_title')) . ' - ' . $titles[$this->type];
@ -79,6 +105,7 @@ class Ampache_RSS
/** /**
* get_description * get_description
* This returns the standardized description for the rss feed based on this->type * This returns the standardized description for the rss feed based on this->type
* @return string
*/ */
public function get_description() public function get_description()
{ {
@ -90,11 +117,12 @@ class Ampache_RSS
/** /**
* validate_type * validate_type
* this returns a valid type for an rss feed, if the specified type is invalid it returns a default value * this returns a valid type for an rss feed, if the specified type is invalid it returns a default value
* @param string $type
* @return string
*/ */
public static function validate_type($type) public static function validate_type($type)
{ {
$valid_types = array('now_playing','recently_played','latest_album','latest_artist','latest_song', $valid_types = array('now_playing','recently_played','latest_album','latest_artist','latest_shout','podcast');
'popular_song','popular_album','popular_artist');
if (!in_array($type,$valid_types)) { if (!in_array($type,$valid_types)) {
return 'now_playing'; return 'now_playing';
@ -107,13 +135,28 @@ class Ampache_RSS
/** /**
* get_display * get_display
* This dumps out some html and an icon for the type of rss that we specify * This dumps out some html and an icon for the type of rss that we specify
* @param string $type
* @param string $title
* @param array|null $params
* @return string
*/ */
public static function get_display($type='now_playing') public static function get_display($type='now_playing', $title = '', $params = null)
{ {
// Default to now playing // Default to now playing
$type = self::validate_type($type); $type = self::validate_type($type);
$string = '<a href="' . AmpConfig::get('web_path') . '/rss.php?type=' . $type . '">' . UI::get_icon('feed', T_('RSS Feed')) . '</a>'; $strparams = "";
if ($params != null && is_array($params)) {
foreach ($params as $key => $value) {
$strparams .= "&" . scrub_out($key) . "=" . scrub_out($value);
}
}
$string = '<a rel="nohtml" href="' . AmpConfig::get('web_path') . '/rss.php?type=' . $type . $strparams . '">' . UI::get_icon('feed', T_('RSS Feed'));
if (!empty($title)) {
$string .= ' &nbsp;' . $title;
}
$string .= '</a>';
return $string; return $string;
@ -125,6 +168,7 @@ class Ampache_RSS
* load_now_playing * load_now_playing
* This loads in the now playing information. This is just the raw data with key=>value pairs that could be turned * This loads in the now playing information. This is just the raw data with key=>value pairs that could be turned
* into an xml document if we so wished * into an xml document if we so wished
* @return array
*/ */
public static function load_now_playing() public static function load_now_playing()
{ {
@ -152,7 +196,7 @@ class Ampache_RSS
'title' => $title, 'title' => $title,
'link' => $song->link, 'link' => $song->link,
'description' => $description, 'description' => $description,
'comments' => $client->fullname . ' - ' . $element['agent'], 'comments' => $client->f_name . ' - ' . $element['agent'],
'pubDate' => date('r', $element['expire']) 'pubDate' => date('r', $element['expire'])
); );
$results[] = $xml_array; $results[] = $xml_array;
@ -166,6 +210,7 @@ class Ampache_RSS
* pubdate_now_playing * pubdate_now_playing
* this is the pub date we should use for the now playing information, * this is the pub date we should use for the now playing information,
* this is a little specific as it uses the 'newest' expire we can find * this is a little specific as it uses the 'newest' expire we can find
* @return int
*/ */
public static function pubdate_now_playing() public static function pubdate_now_playing()
{ {
@ -181,6 +226,7 @@ class Ampache_RSS
/** /**
* load_recently_played * load_recently_played
* This loads in the recently played information and formats it up real nice like * This loads in the recently played information and formats it up real nice like
* @return array
*/ */
public static function load_recently_played() public static function load_recently_played()
{ {
@ -237,9 +283,104 @@ class Ampache_RSS
} // load_recently_played } // load_recently_played
/**
* load_latest_album
* This loads in the latest added albums
* @return array
*/
public static function load_latest_album()
{
$ids = Stats::get_newest('album', 10);
$results = array();
foreach ($ids as $id) {
$album = new Album($id);
$album->format();
$xml_array = array('title' => $album->f_name,
'link' => $album->link,
'description' => $album->f_artist_name . ' - ' . $album->f_name,
'image' => Art::url($album->id, 'album', null, 2),
'comments' => '',
'pubDate' => date("c", $album->get_addtime_first_song())
);
$results[] = $xml_array;
} // end foreach
return $results;
} // load_latest_album
/**
* load_latest_artist
* This loads in the latest added artists
* @return array
*/
public static function load_latest_artist()
{
$ids = Stats::get_newest('artist', 10);
$results = array();
foreach ($ids as $id) {
$artist = new Artist($id);
$artist->format();
$xml_array = array('title' => $artist->f_name,
'link' => $artist->link,
'description' => $artist->summary,
'image' => Art::url($artist->id, 'artist', null, 2),
'comments' => '',
'pubDate' => ''
);
$results[] = $xml_array;
} // end foreach
return $results;
} // load_latest_artist
/**
* load_latest_shout
* This loads in the latest added shouts
* @return array
*/
public static function load_latest_shout()
{
$ids = Shoutbox::get_top(10);
$results = array();
foreach ($ids as $id) {
$shout = new Shoutbox($id);
$shout->format();
$object = Shoutbox::get_object($shout->object_type, $shout->object_id);
$object->format();
$user = new User($shout->user);
$user->format();
$xml_array = array('title' => $user->username . ' ' . T_('on') . ' ' . $object->get_fullname(),
'link' => $object->link,
'description' => $shout->text,
'image' => Art::url($shout->object_id, $shout->object_type, null, 2),
'comments' => '',
'pubDate' => date("c", $shout->date)
);
$results[] = $xml_array;
} // end foreach
return $results;
} // load_latest_shout
/** /**
* pubdate_recently_played * pubdate_recently_played
* This just returns the 'newest' recently played entry * This just returns the 'newest' recently played entry
* @return int
*/ */
public static function pubdate_recently_played() public static function pubdate_recently_played()
{ {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -35,6 +35,9 @@
*/ */
class AmpConfig class AmpConfig
{ {
/**
* @var array $_global
*/
private static $_global = array(); private static $_global = array();
public function __construct() public function __construct()
@ -46,6 +49,7 @@ class AmpConfig
* get * get
* *
* This returns a config value. * This returns a config value.
* @param string $name
*/ */
public static function get($name) public static function get($name)
{ {
@ -60,6 +64,7 @@ class AmpConfig
* get_all * get_all
* *
* This returns all of the current config variables as an array. * This returns all of the current config variables as an array.
* @return array
*/ */
public static function get_all() public static function get_all()
{ {
@ -70,6 +75,8 @@ class AmpConfig
* set * set
* *
* This sets config values. * This sets config values.
* @param string $name
* @param boolean $clobber
*/ */
public static function set($name, $value, $clobber = false) public static function set($name, $value, $clobber = false)
{ {
@ -87,6 +94,8 @@ class AmpConfig
* *
* This is the same as the set function except it takes an array as * This is the same as the set function except it takes an array as
* input. * input.
* @param array $array
* @param boolean $clobber
*/ */
public static function set_by_array($array, $clobber = false) public static function set_by_array($array, $clobber = false)
{ {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -30,9 +30,18 @@
*/ */
class Api class Api
{ {
/**
* @var string $auth_version
*/
public static $auth_version = '350001'; public static $auth_version = '350001';
public static $version = '370001'; /**
* @var string $version
*/
public static $version = '380001';
/**
* @var Browse $browse
*/
private static $browse = null; private static $browse = null;
/** /**
@ -62,6 +71,9 @@ class Api
* the filters in a slightly different and vastly simpler way to the * the filters in a slightly different and vastly simpler way to the
* end users--so we have to do a little extra work to make them work * end users--so we have to do a little extra work to make them work
* internally. * internally.
* @param string $filter
* @param int|string|boolean|null $value
* @return boolean
*/ */
public static function set_filter($filter,$value) public static function set_filter($filter,$value)
{ {
@ -108,6 +120,8 @@ class Api
* *
* This is the function that handles verifying a new handshake * This is the function that handles verifying a new handshake
* Takes a timestamp, auth key, and username. * Takes a timestamp, auth key, and username.
* @param array
* @return boolean
*/ */
public static function handshake($input) public static function handshake($input)
{ {
@ -155,6 +169,7 @@ class Api
($timestamp > (time() + 1800))) { ($timestamp > (time() + 1800))) {
debug_event('API', 'Login Failed: timestamp out of range ' . $timestamp . '/' . time(), 1); debug_event('API', 'Login Failed: timestamp out of range ' . $timestamp . '/' . time(), 1);
Error::add('api', T_('Login Failed: timestamp out of range')); Error::add('api', T_('Login Failed: timestamp out of range'));
echo XML_Data::error('401', T_('Error Invalid Handshake - ') . T_('Login Failed: timestamp out of range'));
return false; return false;
} }
@ -166,6 +181,7 @@ class Api
if (!$realpwd) { if (!$realpwd) {
debug_event('API', 'Unable to find user with userid of ' . $user_id, 1); debug_event('API', 'Unable to find user with userid of ' . $user_id, 1);
Error::add('api', T_('Invalid Username/Password')); Error::add('api', T_('Invalid Username/Password'));
echo XML_Data::error('401', T_('Error Invalid Handshake - ') . T_('Invalid Username/Password'));
return false; return false;
} }
@ -184,6 +200,18 @@ class Api
$data['username'] = $client->username; $data['username'] = $client->username;
$data['type'] = 'api'; $data['type'] = 'api';
$data['value'] = $timestamp; $data['value'] = $timestamp;
if (isset($input['client'])) {
$data['agent'] = $input['client'];
}
if (isset($input['geo_latitude'])) {
$data['geo_latitude'] = $input['geo_latitude'];
}
if (isset($input['geo_longitude'])) {
$data['geo_longitude'] = $input['geo_longitude'];
}
if (isset($input['geo_name'])) {
$data['geo_name'] = $input['geo_name'];
}
$token = Session::create($data); $token = Session::create($data);
debug_event('API', 'Login Success, passphrase matched', 1); debug_event('API', 'Login Success, passphrase matched', 1);
@ -233,14 +261,16 @@ class Api
} // end while } // end while
debug_event('API','Login Failed, unable to match passphrase','1'); debug_event('API','Login Failed, unable to match passphrase','1');
XML_Data::error('401', T_('Error Invalid Handshake - ') . T_('Invalid Username/Password')); echo XML_Data::error('401', T_('Error Invalid Handshake - ') . T_('Invalid Username/Password'));
return false;
} // handshake } // handshake
/** /**
* ping * ping
* This can be called without being authenticated, it is useful for determining if what the status * This can be called without being authenticated, it is useful for determining if what the status
* of the server is, and what version it is running/compatible with * of the server is, and what version it is running/compatible with
* @param array $input
*/ */
public static function ping($input) public static function ping($input)
{ {
@ -264,6 +294,7 @@ class Api
* This takes a collection of inputs and returns * This takes a collection of inputs and returns
* artist objects. This function is deprecated! * artist objects. This function is deprecated!
* //DEPRECATED * //DEPRECATED
* @param array $input
*/ */
public static function artists($input) public static function artists($input)
{ {
@ -291,6 +322,7 @@ class Api
* artist * artist
* This returns a single artist based on the UID of said artist * This returns a single artist based on the UID of said artist
* //DEPRECATED * //DEPRECATED
* @param array $input
*/ */
public static function artist($input) public static function artist($input)
{ {
@ -302,6 +334,7 @@ class Api
/** /**
* artist_albums * artist_albums
* This returns the albums of an artist * This returns the albums of an artist
* @param array $input
*/ */
public static function artist_albums($input) public static function artist_albums($input)
{ {
@ -320,6 +353,7 @@ class Api
/** /**
* artist_songs * artist_songs
* This returns the songs of the specified artist * This returns the songs of the specified artist
* @param array $input
*/ */
public static function artist_songs($input) public static function artist_songs($input)
{ {
@ -337,6 +371,7 @@ class Api
/** /**
* albums * albums
* This returns albums based on the provided search filters * This returns albums based on the provided search filters
* @param array $input
*/ */
public static function albums($input) public static function albums($input)
{ {
@ -361,6 +396,7 @@ class Api
/** /**
* album * album
* This returns a single album based on the UID provided * This returns a single album based on the UID provided
* @param array $input
*/ */
public static function album($input) public static function album($input)
{ {
@ -372,6 +408,7 @@ class Api
/** /**
* album_songs * album_songs
* This returns the songs of a specified album * This returns the songs of a specified album
* @param array $input
*/ */
public static function album_songs($input) public static function album_songs($input)
{ {
@ -390,6 +427,7 @@ class Api
/** /**
* tags * tags
* This returns the tags based on the specified filter * This returns the tags based on the specified filter
* @param array $input
*/ */
public static function tags($input) public static function tags($input)
{ {
@ -413,6 +451,7 @@ class Api
/** /**
* tag * tag
* This returns a single tag based on UID * This returns a single tag based on UID
* @param array $input
*/ */
public static function tag($input) public static function tag($input)
{ {
@ -425,38 +464,43 @@ class Api
/** /**
* tag_artists * tag_artists
* This returns the artists associated with the tag in question as defined by the UID * This returns the artists associated with the tag in question as defined by the UID
* @param array $input
*/ */
public static function tag_artists($input) public static function tag_artists($input)
{ {
$artists = Tag::get_tag_objects('artist',$input['filter']); $artists = Tag::get_tag_objects('artist',$input['filter']);
if ($artists) {
XML_Data::set_offset($input['offset']);
XML_Data::set_limit($input['limit']);
XML_Data::set_offset($input['offset']); ob_end_clean();
XML_Data::set_limit($input['limit']); echo XML_Data::artists($artists);
}
ob_end_clean();
echo XML_Data::artists($artists);
} // tag_artists } // tag_artists
/** /**
* tag_albums * tag_albums
* This returns the albums associated with the tag in question * This returns the albums associated with the tag in question
* @param array $input
*/ */
public static function tag_albums($input) public static function tag_albums($input)
{ {
$albums = Tag::get_tag_objects('album',$input['filter']); $albums = Tag::get_tag_objects('album',$input['filter']);
if ($albums) {
XML_Data::set_offset($input['offset']);
XML_Data::set_limit($input['limit']);
XML_Data::set_offset($input['offset']); ob_end_clean();
XML_Data::set_limit($input['limit']); echo XML_Data::albums($albums);
}
ob_end_clean();
echo XML_Data::albums($albums);
} // tag_albums } // tag_albums
/** /**
* tag_songs * tag_songs
* returns the songs for this tag * returns the songs for this tag
* @param array $input
*/ */
public static function tag_songs($input) public static function tag_songs($input)
{ {
@ -473,6 +517,7 @@ class Api
/** /**
* songs * songs
* Returns songs based on the specified filter * Returns songs based on the specified filter
* @param array $input
*/ */
public static function songs($input) public static function songs($input)
{ {
@ -499,6 +544,7 @@ class Api
/** /**
* song * song
* returns a single song * returns a single song
* @param array $input
*/ */
public static function song($input) public static function song($input)
{ {
@ -513,6 +559,7 @@ class Api
* url_to_song * url_to_song
* *
* This takes a url and returns the song object in question * This takes a url and returns the song object in question
* @param array $input
*/ */
public static function url_to_song($input) public static function url_to_song($input)
{ {
@ -525,6 +572,7 @@ class Api
/** /**
* playlists * playlists
* This returns playlists based on the specified filter * This returns playlists based on the specified filter
* @param array $input
*/ */
public static function playlists($input) public static function playlists($input)
{ {
@ -548,6 +596,7 @@ class Api
/** /**
* playlist * playlist
* This returns a single playlist * This returns a single playlist
* @param array $input
*/ */
public static function playlist($input) public static function playlist($input)
{ {
@ -561,6 +610,7 @@ class Api
/** /**
* playlist_songs * playlist_songs
* This returns the songs for a playlist * This returns the songs for a playlist
* @param array $input
*/ */
public static function playlist_songs($input) public static function playlist_songs($input)
{ {
@ -577,13 +627,14 @@ class Api
XML_Data::set_offset($input['offset']); XML_Data::set_offset($input['offset']);
XML_Data::set_limit($input['limit']); XML_Data::set_limit($input['limit']);
ob_end_clean(); ob_end_clean();
echo XML_Data::songs($songs); echo XML_Data::songs($songs,$items);
} // playlist_songs } // playlist_songs
/** /**
* playlist_create * playlist_create
* This create a new playlist and return it * This create a new playlist and return it
* @param array $input
*/ */
public static function playlist_create($input) public static function playlist_create($input)
{ {
@ -600,6 +651,7 @@ class Api
/** /**
* playlist_delete * playlist_delete
* This delete a playlist * This delete a playlist
* @param array $input
*/ */
public static function playlist_delete($input) public static function playlist_delete($input)
{ {
@ -616,12 +668,13 @@ class Api
/** /**
* playlist_add_song * playlist_add_song
* This add a song to a playlist * This add a song to a playlist
* @param array $input
*/ */
public static function playlist_add_song($input) public static function playlist_add_song($input)
{ {
ob_end_clean(); ob_end_clean();
$playlist = new Playlist($input['filter']); $playlist = new Playlist($input['filter']);
$song = new Playlist($input['song']); $song = $input['song'];
if (!$playlist->has_access()) { if (!$playlist->has_access()) {
echo XML_Data::error('401', T_('Access denied to this playlist.')); echo XML_Data::error('401', T_('Access denied to this playlist.'));
} else { } else {
@ -634,12 +687,13 @@ class Api
/** /**
* playlist_remove_song * playlist_remove_song
* This remove a song from a playlist * This remove a song from a playlist
* @param array $input
*/ */
public static function playlist_remove_song($input) public static function playlist_remove_song($input)
{ {
ob_end_clean(); ob_end_clean();
$playlist = new Playlist($input['filter']); $playlist = new Playlist($input['filter']);
$track = new Playlist($input['track']); $track = scrub_in($input['track']);
if (!$playlist->has_access()) { if (!$playlist->has_access()) {
echo XML_Data::error('401', T_('Access denied to this playlist.')); echo XML_Data::error('401', T_('Access denied to this playlist.'));
} else { } else {
@ -652,6 +706,7 @@ class Api
/** /**
* search_songs * search_songs
* This searches the songs and returns... songs * This searches the songs and returns... songs
* @param array $input
*/ */
public static function search_songs($input) public static function search_songs($input)
{ {
@ -675,6 +730,7 @@ class Api
/** /**
* videos * videos
* This returns video objects! * This returns video objects!
* @param array $input
*/ */
public static function videos($input) public static function videos($input)
{ {
@ -697,6 +753,7 @@ class Api
/** /**
* video * video
* This returns a single video * This returns a single video
* @param array $input
*/ */
public static function video($input) public static function video($input)
{ {
@ -710,6 +767,7 @@ class Api
/** /**
* localplay * localplay
* This is for controling localplay * This is for controling localplay
* @param array $input
*/ */
public static function localplay($input) public static function localplay($input)
{ {
@ -737,6 +795,7 @@ class Api
/** /**
* democratic * democratic
* This is for controlling democratic play * This is for controlling democratic play
* @param array $input
*/ */
public static function democratic($input) public static function democratic($input)
{ {
@ -781,7 +840,7 @@ class Api
$objects = $democratic->get_items(); $objects = $democratic->get_items();
Song::build_cache($democratic->object_ids); Song::build_cache($democratic->object_ids);
Democratic::build_vote_cache($democratic->vote_ids); Democratic::build_vote_cache($democratic->vote_ids);
XML_Data::democratic($objects); echo XML_Data::democratic($objects);
break; break;
case 'play': case 'play':
$url = $democratic->play_url(); $url = $democratic->play_url();
@ -795,12 +854,18 @@ class Api
} // democratic } // democratic
/**
* This get library stats.
* @param array $input
*/
public static function stats($input) public static function stats($input)
{ {
$type = $input['type']; $type = $input['type'];
$offset = $input['offset']; $offset = $input['offset'];
$limit = $input['limit']; $limit = $input['limit'];
$username = $input['username'];
$albums = null;
if ($type == "newest") { if ($type == "newest") {
$albums = Stats::get_newest("album", $limit, $offset); $albums = Stats::get_newest("album", $limit, $offset);
} else if ($type == "highest") { } else if ($type == "highest") {
@ -808,7 +873,16 @@ class Api
} else if ($type == "frequent") { } else if ($type == "frequent") {
$albums = Stats::get_top("album", $limit, '', $offset); $albums = Stats::get_top("album", $limit, '', $offset);
} else if ($type == "recent") { } else if ($type == "recent") {
$albums = Stats::get_recent("album", $limit, $offset); if (!empty($username)) {
$user = User::get_from_username($username);
if ($user !== null) {
$albums = $user->get_recently_played($limit, 'album');
} else {
debug_event('api', 'User `' . $username . '` cannot be found.', 1);
}
} else {
$albums = Stats::get_recent("album", $limit, $offset);
}
} else if ($type == "flagged") { } else if ($type == "flagged") {
$albums = Userflag::get_latest('album'); $albums = Userflag::get_latest('album');
} else { } else {
@ -818,8 +892,109 @@ class Api
$albums = Album::get_random($limit); $albums = Album::get_random($limit);
} }
ob_end_clean(); if ($albums !== null) {
echo XML_Data::albums($albums); ob_end_clean();
} echo XML_Data::albums($albums);
}
} // stats
/**
* user
* This get an user public information
* @param array $input
*/
public static function user($input)
{
$username = $input['username'];
if (!empty($username)) {
$user = User::get_from_username($username);
if ($user !== null) {
ob_end_clean();
echo XML_Data::user($user);
} else {
debug_event('api', 'User `' . $username . '` cannot be found.', 1);
}
} else {
debug_event('api', 'Username required on user function call.', 1);
}
} // user
/**
* followers
* This get an user followers
* @param array $input
*/
public static function followers($input)
{
if (AmpConfig::get('sociable')) {
$username = $input['username'];
if (!empty($username)) {
$user = User::get_from_username($username);
if ($user !== null) {
$users = $user->get_followers();
ob_end_clean();
echo XML_Data::users($user);
} else {
debug_event('api', 'User `' . $username . '` cannot be found.', 1);
}
} else {
debug_event('api', 'Username required on followers function call.', 1);
}
} else {
debug_event('api', 'Sociable feature is not enabled.', 3);
}
} // followers
/**
* following
* This get the user list followed by an user
* @param array $input
*/
public static function following($input)
{
if (AmpConfig::get('sociable')) {
$username = $input['username'];
if (!empty($username)) {
$user = User::get_from_username($username);
if ($user !== null) {
$users = $user->get_following();
ob_end_clean();
echo XML_Data::users($user);
} else {
debug_event('api', 'User `' . $username . '` cannot be found.', 1);
}
} else {
debug_event('api', 'Username required on following function call.', 1);
}
} else {
debug_event('api', 'Sociable feature is not enabled.', 3);
}
} // following
/**
* last_shouts
* This get the latest posted shouts
* @param array $input
*/
public static function last_shouts($input)
{
$limit = intval($input['limit']);
if ($limit < 1) {
$limit = AmpConfig::get('popular_threshold');
}
if (AmpConfig::get('sociable')) {
$username = $input['username'];
if (!empty($username)) {
$shouts = Shoutbox::get_top($limit, $username);
} else {
$shouts = Shoutbox::get_top($limit);
}
ob_end_clean();
echo XML_Data::shouts($shouts);
} else {
debug_event('api', 'Sociable feature is not enabled.', 3);
}
} // last_shouts
} // API class } // API class

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -20,42 +20,123 @@
* *
*/ */
class Artist extends database_object class Artist extends database_object implements library_item
{ {
/* Variables from DB */ /* Variables from DB */
public $id;
public $name;
public $summary;
public $placeformed;
public $yearformed;
public $last_update;
public $songs;
public $albums;
public $prefix;
public $mbid; // MusicBrainz ID
public $catalog_id;
public $time;
/**
* @var int $id
*/
public $id;
/**
* @var string $name
*/
public $name;
/**
* @var string $summary
*/
public $summary;
/**
* @var string $placeformed
*/
public $placeformed;
/**
* @var int $yearformed
*/
public $yearformed;
/**
* @var int $last_update
*/
public $last_update;
/**
* @var int $songs
*/
public $songs;
/**
* @var int $albums
*/
public $albums;
/**
* @var string $prefix
*/
public $prefix;
/**
* @var string $mbid
*/
public $mbid; // MusicBrainz ID
/**
* @var int $catalog_id
*/
public $catalog_id;
/**
* @var int $time
*/
public $time;
/**
* @var int $user
*/
public $user;
/**
* @var array $tags
*/
public $tags; public $tags;
/**
* @var string $f_tags
*/
public $f_tags; public $f_tags;
/**
* @var array $labels
*/
public $labels;
/**
* @var string $f_labels
*/
public $f_labels;
/**
* @var int $object_cnt
*/
public $object_cnt; public $object_cnt;
/**
* @var string $f_name
*/
public $f_name; public $f_name;
/**
* @var string $f_full_name
*/
public $f_full_name; public $f_full_name;
/**
* @var string $link
*/
public $link;
/**
* @var string $f_link
*/
public $f_link; public $f_link;
public $f_name_link; /**
* @var string $f_time
*/
public $f_time; public $f_time;
// Constructed vars // Constructed vars
/**
* @var boolean $_fake
*/
public $_fake = false; // Set if construct_from_array() used public $_fake = false; // Set if construct_from_array() used
/**
* @var array $_mapcache
*/
private static $_mapcache = array(); private static $_mapcache = array();
/** /**
* Artist * Artist
* Artist class, for modifing a artist * Artist class, for modifing a artist
* Takes the ID of the artist and pulls the info from the db * Takes the ID of the artist and pulls the info from the db
* @param int|null $id
* @param int $catalog_init
*/ */
public function __construct($id='',$catalog_init=0) public function __construct($id=null,$catalog_init=0)
{ {
/* If they failed to pass in an id, just run for it */ /* If they failed to pass in an id, just run for it */
if (!$id) { return false; } if (!$id) { return false; }
@ -76,6 +157,8 @@ class Artist extends database_object
* construct_from_array * construct_from_array
* This is used by the metadata class specifically but fills out a Artist object * This is used by the metadata class specifically but fills out a Artist object
* based on a key'd array, it sets $_fake to true * based on a key'd array, it sets $_fake to true
* @param array $data
* @return Artist
*/ */
public static function construct_from_array($data) public static function construct_from_array($data)
{ {
@ -98,13 +181,20 @@ class Artist extends database_object
*/ */
public static function gc() public static function gc()
{ {
Dba::write('DELETE FROM `artist` USING `artist` LEFT JOIN `song` ON `song`.`artist` = `artist`.`id` LEFT JOIN `wanted` ON `wanted`.`artist` = `artist`.`id` WHERE `song`.`id` IS NULL AND `wanted`.`id` IS NULL'); Dba::write('DELETE FROM `artist` USING `artist` LEFT JOIN `song` ON `song`.`artist` = `artist`.`id` ' .
'LEFT JOIN `album` ON `album`.`album_artist` = `artist`.`id` ' .
'LEFT JOIN `wanted` ON `wanted`.`artist` = `artist`.`id` ' .
'LEFT JOIN `clip` ON `clip`.`artist` = `artist`.`id` ' .
'WHERE `song`.`id` IS NULL AND `album`.`id` IS NULL AND `wanted`.`id` IS NULL AND `clip`.`id` IS NULL');
} }
/** /**
* this attempts to build a cache of the data from the passed albums all in one query * this attempts to build a cache of the data from the passed albums all in one query
* @param int[] $ids
* @param boolean $extra
* @return boolean
*/ */
public static function build_cache($ids,$extra=false) public static function build_cache($ids, $extra=false, $limit_threshold = '')
{ {
if (!is_array($ids) OR !count($ids)) { return false; } if (!is_array($ids) OR !count($ids)) { return false; }
@ -119,14 +209,14 @@ class Artist extends database_object
// If we need to also pull the extra information, this is normally only used when we are doing the human display // If we need to also pull the extra information, this is normally only used when we are doing the human display
if ($extra) { if ($extra) {
$sql = "SELECT `song`.`artist`, COUNT(`song`.`id`) AS `song_count`, COUNT(DISTINCT `song`.`album`) AS `album_count`, SUM(`song`.`time`) AS `time` FROM `song` WHERE `song`.`artist` IN $idlist GROUP BY `song`.`artist`"; $sql = "SELECT `song`.`artist`, COUNT(DISTINCT `song`.`id`) AS `song_count`, COUNT(DISTINCT `song`.`album`) AS `album_count`, SUM(`song`.`time`) AS `time` FROM `song` WHERE `song`.`artist` IN $idlist GROUP BY `song`.`artist`";
debug_event("Artist", "build_cache sql: " . $sql, "6"); debug_event("Artist", "build_cache sql: " . $sql, "6");
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
if (AmpConfig::get('show_played_times')) { if (AmpConfig::get('show_played_times')) {
$row['object_cnt'] = Stats::get_object_count('artist', $row['artist']); $row['object_cnt'] = Stats::get_object_count('artist', $row['artist'], $limit_threshold);
} }
parent::add_to_cache('artist_extra',$row['artist'],$row); parent::add_to_cache('artist_extra',$row['artist'],$row);
} }
@ -140,6 +230,8 @@ class Artist extends database_object
/** /**
* get_from_name * get_from_name
* This gets an artist object based on the artist name * This gets an artist object based on the artist name
* @param string $name
* @return Artist
*/ */
public static function get_from_name($name) public static function get_from_name($name)
{ {
@ -158,13 +250,17 @@ class Artist extends database_object
* get_albums * get_albums
* gets the album ids that this artist is a part * gets the album ids that this artist is a part
* of * of
* @param int|null $catalog
* @param boolean $ignoreAlbumGroups
* @param boolean $group_release_type
* @return int[]
*/ */
public function get_albums($catalog = null, $ignoreAlbumGroups = false) public function get_albums($catalog = null, $ignoreAlbumGroups = false, $group_release_type = false)
{ {
$catalog_where = ""; $catalog_where = "";
$catalog_join = "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog`"; $catalog_join = "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog`";
if ($catalog) { if ($catalog) {
$catalog_where .= " AND `catalog`.`id` = '$catalog'"; $catalog_where .= " AND `catalog`.`id` = '" . $catalog . "'";
} }
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
$catalog_where .= " AND `catalog`.`enabled` = '1'"; $catalog_where .= " AND `catalog`.`enabled` = '1'";
@ -190,14 +286,38 @@ class Artist extends database_object
} }
$sql_group = "COALESCE($sql_group_type, `album`.`id`)"; $sql_group = "COALESCE($sql_group_type, `album`.`id`)";
$sql = "SELECT `album`.`id` FROM album LEFT JOIN `song` ON `song`.`album`=`album`.`id` $catalog_join " . $sql = "SELECT `album`.`id`, `album`.`release_type` FROM album LEFT JOIN `song` ON `song`.`album`=`album`.`id` $catalog_join " .
"WHERE `song`.`artist`='$this->id' $catalog_where GROUP BY $sql_group ORDER BY $sql_sort"; "WHERE (`song`.`artist`='$this->id' OR `album`.`album_artist`='$this->id') $catalog_where GROUP BY $sql_group ORDER BY $sql_sort";
debug_event("Artist", "$sql", "6"); debug_event("Artist", "$sql", "6");
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
while ($r = Dba::fetch_assoc($db_results)) { while ($r = Dba::fetch_assoc($db_results)) {
$results[] = $r['id']; if ($group_release_type) {
// We assume undefined release type is album
$rtype = $r['release_type'] ?: 'album';
if (!isset($results[$rtype])) {
$results[$rtype] = array();
}
$results[$rtype][] = $r['id'];
$sort = AmpConfig::get('album_release_type_sort');
if ($sort) {
$results_sort = array();
$asort = explode(',', $sort);
foreach ($asort as $rtype) {
if (array_key_exists($rtype, $results)) {
$results_sort[$rtype] = $results[$rtype];
unset($results[$rtype]);
}
}
$results = array_merge($results_sort, $results);
}
} else {
$results[] = $r['id'];
}
} }
return $results; return $results;
@ -207,6 +327,7 @@ class Artist extends database_object
/** /**
* get_songs * get_songs
* gets the songs for this artist * gets the songs for this artist
* @return int[]
*/ */
public function get_songs() public function get_songs()
{ {
@ -214,12 +335,12 @@ class Artist extends database_object
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
$sql .= "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` "; $sql .= "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` ";
} }
$sql .= "WHERE `song`.`artist`='" . Dba::escape($this->id) . "' "; $sql .= "WHERE `song`.`artist` = ? ";
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
$sql .= "AND `catalog`.`enabled` = '1' "; $sql .= "AND `catalog`.`enabled` = '1' ";
} }
$sql .= "ORDER BY album, track"; $sql .= "ORDER BY `song`.`album`, `song`.`track`";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
$results = array(); $results = array();
while ($r = Dba::fetch_assoc($db_results)) { while ($r = Dba::fetch_assoc($db_results)) {
@ -233,6 +354,7 @@ class Artist extends database_object
/** /**
* get_random_songs * get_random_songs
* Gets the songs from this artist in a random order * Gets the songs from this artist in a random order
* @return int[]
*/ */
public function get_random_songs() public function get_random_songs()
{ {
@ -242,12 +364,12 @@ class Artist extends database_object
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
$sql .= "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` "; $sql .= "LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` ";
} }
$sql .= "WHERE `song`.`artist`='$this->id' "; $sql .= "WHERE `song`.`artist` = ? ";
if (AmpConfig::get('catalog_disable')) { if (AmpConfig::get('catalog_disable')) {
$sql .= "AND `catalog`.`enabled` = '1' "; $sql .= "AND `catalog`.`enabled` = '1' ";
} }
$sql .= "ORDER BY RAND()"; $sql .= "ORDER BY RAND()";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
while ($r = Dba::fetch_assoc($db_results)) { while ($r = Dba::fetch_assoc($db_results)) {
$results[] = $r['id']; $results[] = $r['id'];
@ -260,15 +382,17 @@ class Artist extends database_object
/** /**
* _get_extra info * _get_extra info
* This returns the extra information for the artist, this means totals etc * This returns the extra information for the artist, this means totals etc
* @param int $catalog
* @return array
*/ */
private function _get_extra_info($catalog=FALSE) private function _get_extra_info($catalog=0, $limit_threshold ='')
{ {
// Try to find it in the cache and save ourselves the trouble // Try to find it in the cache and save ourselves the trouble
if (parent::is_cached('artist_extra',$this->id) ) { if (parent::is_cached('artist_extra',$this->id) ) {
$row = parent::get_from_cache('artist_extra',$this->id); $row = parent::get_from_cache('artist_extra',$this->id);
} else { } else {
$uid = Dba::escape($this->id); $uid = Dba::escape($this->id);
$sql = "SELECT `song`.`artist`,COUNT(`song`.`id`) AS `song_count`, COUNT(DISTINCT `song`.`album`) AS `album_count`, SUM(`song`.`time`) AS `time` FROM `song` LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` " . $sql = "SELECT `song`.`artist`,COUNT(DISTINCT `song`.`id`) AS `song_count`, COUNT(DISTINCT `song`.`album`) AS `album_count`, SUM(`song`.`time`) AS `time`, `song`.`catalog` as `catalog_id` FROM `song` LEFT JOIN `catalog` ON `catalog`.`id` = `song`.`catalog` " .
"WHERE `song`.`artist`='$uid' "; "WHERE `song`.`artist`='$uid' ";
if ($catalog) { if ($catalog) {
$sql .= "AND (`song`.`catalog` = '$catalog') "; $sql .= "AND (`song`.`catalog` = '$catalog') ";
@ -282,7 +406,7 @@ class Artist extends database_object
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
$row = Dba::fetch_assoc($db_results); $row = Dba::fetch_assoc($db_results);
if (AmpConfig::get('show_played_times')) { if (AmpConfig::get('show_played_times')) {
$row['object_cnt'] = Stats::get_object_count('artist', $row['artist']); $row['object_cnt'] = Stats::get_object_count('artist', $row['artist'], $limit_threshold);
} }
parent::add_to_cache('artist_extra',$row['artist'],$row); parent::add_to_cache('artist_extra',$row['artist'],$row);
} }
@ -291,6 +415,7 @@ class Artist extends database_object
$this->songs = $row['song_count']; $this->songs = $row['song_count'];
$this->albums = $row['album_count']; $this->albums = $row['album_count'];
$this->time = $row['time']; $this->time = $row['time'];
$this->catalog_id = $row['catalog_id'];
return $row; return $row;
@ -302,48 +427,225 @@ class Artist extends database_object
* information and reformats the relevent values * information and reformats the relevent values
* so they can be displayed in a table for example * so they can be displayed in a table for example
* it changes the title into a full link. * it changes the title into a full link.
* @return boolean
*/ */
public function format() public function format($details = true, $limit_threshold = '')
{ {
/* Combine prefix and name, trim then add ... if needed */ /* Combine prefix and name, trim then add ... if needed */
$name = trim($this->prefix . " " . $this->name); $name = trim($this->prefix . " " . $this->name);
$this->f_name = $name; $this->f_name = $name;
$this->f_full_name = trim(trim($this->prefix) . ' ' . trim($this->name)); $this->f_full_name = trim(trim($this->prefix) . ' ' . trim($this->name));
// If this is a fake object, we're done here // If this is a memory-only object, we're done here
if ($this->_fake) { return true; } if (!$this->id) { return true; }
if ($this->catalog_id) { if ($this->catalog_id) {
$this->f_link = AmpConfig::get('web_path') . '/artists.php?action=show&catalog=' . $this->catalog_id . '&artist=' . $this->id; $this->link = AmpConfig::get('web_path') . '/artists.php?action=show&catalog=' . $this->catalog_id . '&artist=' . $this->id;
$this->f_name_link = "<a href=\"" . $this->f_link . "\" title=\"" . $this->f_full_name . "\">" . $name . "</a>"; $this->f_link = "<a href=\"" . $this->link . "\" title=\"" . $this->f_full_name . "\">" . $name . "</a>";
} else { } else {
$this->f_link = AmpConfig::get('web_path') . '/artists.php?action=show&artist=' . $this->id; $this->link = AmpConfig::get('web_path') . '/artists.php?action=show&artist=' . $this->id;
$this->f_name_link = "<a href=\"" . $this->f_link . "\" title=\"" . $this->f_full_name . "\">" . $name . "</a>"; $this->f_link = "<a href=\"" . $this->link . "\" title=\"" . $this->f_full_name . "\">" . $name . "</a>";
} }
// Get the counts
$extra_info = $this->_get_extra_info($this->catalog_id);
//Format the new time thingy that we just got if ($details) {
$min = sprintf("%02d",(floor($extra_info['time']/60)%60)); // Get the counts
$extra_info = $this->_get_extra_info($this->catalog_id, $limit_threshold);
$sec = sprintf("%02d",($extra_info['time']%60)); //Format the new time thingy that we just got
$hours = floor($extra_info['time']/3600); $min = sprintf("%02d",(floor($extra_info['time']/60)%60));
$this->f_time = ltrim($hours . ':' . $min . ':' . $sec,'0:'); $sec = sprintf("%02d",($extra_info['time']%60));
$hours = floor($extra_info['time']/3600);
$this->tags = Tag::get_top_tags('artist', $this->id); $this->f_time = ltrim($hours . ':' . $min . ':' . $sec,'0:');
$this->f_tags = Tag::get_display($this->tags);
$this->object_cnt = $extra_info['object_cnt']; $this->tags = Tag::get_top_tags('artist', $this->id);
$this->f_tags = Tag::get_display($this->tags, true, 'artist');
if (AmpConfig::get('label')) {
$this->labels = Label::get_labels($this->id);
$this->f_labels = Label::get_display($this->labels, true);
}
$this->object_cnt = $extra_info['object_cnt'];
}
return true; return true;
} // format } // format
/**
* Get item keywords for metadata searches.
* @return array
*/
public function get_keywords()
{
$keywords = array();
$keywords['mb_artistid'] = array('important' => false,
'label' => T_('Artist MusicBrainzID'),
'value' => $this->mbid);
$keywords['artist'] = array('important' => true,
'label' => T_('Artist'),
'value' => $this->f_full_name);
return $keywords;
}
/**
* Get item fullname.
* @return string
*/
public function get_fullname()
{
return $this->f_full_name;
}
/**
* Get parent item description.
* @return array|null
*/
public function get_parent()
{
return null;
}
/**
* Get item childrens.
* @return array
*/
public function get_childrens()
{
$medias = array();
$albums = $this->get_albums();
foreach ($albums as $album_id) {
$medias[] = array(
'object_type' => 'album',
'object_id' => $album_id
);
}
return array('album' => $medias);
}
/**
* Search for item childrens.
* @param string $name
* @return array
*/
public function search_childrens($name)
{
$search['type'] = "album";
$search['rule_0_input'] = $name;
$search['rule_0_operator'] = 4;
$search['rule_0'] = "title";
$search['rule_1_input'] = $this->name;
$search['rule_1_operator'] = 4;
$search['rule_1'] = "artist";
$albums = Search::run($search);
$childrens = array();
foreach ($albums as $album) {
$childrens[] = array(
'object_type' => 'album',
'object_id' => $album
);
}
return $childrens;
}
/**
* Get all childrens and sub-childrens medias.
* @param string $filter_type
* @return array
*/
public function get_medias($filter_type = null)
{
$medias = array();
if (!$filter_type || $filter_type == 'song') {
$songs = $this->get_songs();
foreach ($songs as $song_id) {
$medias[] = array(
'object_type' => 'song',
'object_id' => $song_id
);
}
}
return $medias;
}
/**
* get_catalogs
*
* Get all catalog ids related to this item.
* @return int[]
*/
public function get_catalogs()
{
return array($this->catalog_id);
}
/**
* Get item's owner.
* @return int|null
*/
public function get_user_owner()
{
return $this->user;
}
/**
* Get default art kind for this item.
* @return string
*/
public function get_default_art_kind()
{
return 'default';
}
public function get_description()
{
return $this->summary;
}
public function display_art($thumb = 2)
{
$id = null;
$type = null;
if (Art::has_db($this->id, 'artist')) {
$id = $this->id;
$type = 'artist';
}
if ($id !== null && $type !== null) {
Art::display($type, $id, $this->get_fullname(), $thumb, $this->link);
}
}
public function can_edit($user = null)
{
if (!$user) {
$user = $GLOBALS['user']->id;
}
if (!$user)
return false;
if (AmpConfig::get('upload_allow_edit')) {
if ($this->user !== null && $user == $this->user)
return true;
}
return Access::check('interface', 50, $user);
}
/** /**
* check * check
* *
* Checks for an existing artist; if none exists, insert one. * Checks for an existing artist; if none exists, insert one.
* @param string $name
* @param string $mbid
* @param boolean $readonly
* @return int|null
*/ */
public static function check($name, $mbid = null, $readonly = false) public static function check($name, $mbid = null, $readonly = false)
{ {
@ -429,27 +731,37 @@ class Artist extends database_object
/** /**
* update * update
* This takes a key'd array of data and updates the current artist * This takes a key'd array of data and updates the current artist
* @param array $data
* @return int
*/ */
public function update($data) public function update(array $data)
{ {
// Save our current ID // Save our current ID
$name = isset($data['name']) ? $data['name'] : $this->name;
$mbid = isset($data['mbid']) ? $data['mbid'] : $this->mbid;
$summary = isset($data['summary']) ? $data['summary'] : $this->summary;
$placeformed = isset($data['placeformed']) ? $data['placeformed'] : $this->placeformed;
$yearformed = isset($data['yearformed']) ? $data['yearformed'] : $this->yearformed;
$current_id = $this->id; $current_id = $this->id;
// Check if name is different than current name // Check if name is different than current name
if ($this->name != $data['name']) { if ($this->name != $name) {
$artist_id = self::check($data['name'], $this->mbid); $artist_id = self::check($name, $mbid, true);
$updated = false; $updated = false;
$songs = array(); $songs = array();
// If it's changed we need to update // If it's changed we need to update
if ($artist_id != $this->id) { if ($artist_id != null && $artist_id != $this->id) {
$songs = $this->get_songs(); $songs = $this->get_songs();
foreach ($songs as $song_id) { foreach ($songs as $song_id) {
Song::update_artist($artist_id,$song_id); Song::update_artist($artist_id,$song_id);
} }
$updated = true; $updated = true;
$current_id = $artist_id; $current_id = $artist_id;
Stats::migrate('artist', $this->id, $artist_id);
Art::migrate('artist', $this->id, $artist_id);
self::gc(); self::gc();
} // end if it changed } // end if it changed
@ -461,24 +773,41 @@ class Artist extends database_object
Rating::gc(); Rating::gc();
Userflag::gc(); Userflag::gc();
} // if updated } // if updated
} else if ($this->mbid != $data['mbid']) { } else if ($this->mbid != $mbid) {
$sql = 'UPDATE `artist` SET `mbid` = ? WHERE `id` = ?'; $sql = 'UPDATE `artist` SET `mbid` = ? WHERE `id` = ?';
Dba::write($sql, array($data['mbid'], $current_id)); Dba::write($sql, array($mbid, $current_id));
} }
// Update artist name (if we don't want to use the MusicBrainz name) // Update artist name (if we don't want to use the MusicBrainz name)
$trimmed = Catalog::trim_prefix(trim($data['name'])); $trimmed = Catalog::trim_prefix(trim($name));
$name = $trimmed['string']; $name = $trimmed['string'];
if ($name != '' && $name != $this->name) { if ($name != '' && $name != $this->name) {
$sql = 'UPDATE `artist` SET `name` = ? WHERE `id` = ?'; $sql = 'UPDATE `artist` SET `name` = ? WHERE `id` = ?';
Dba::write($sql, array($name, $current_id)); Dba::write($sql, array($name, $current_id));
} }
$this->update_artist_info($summary, $placeformed, $yearformed);
$this->name = $name;
$this->mbid = $mbid;
$override_childs = false; $override_childs = false;
if ($data['apply_childs'] == 'checked') { if ($data['overwrite_childs'] == 'checked') {
$override_childs = true; $override_childs = true;
} }
$this->update_tags($data['edit_tags'], $override_childs, $current_id);
$add_to_childs = false;
if ($data['add_to_childs'] == 'checked') {
$add_to_childs = true;
}
if (isset($data['edit_tags'])) {
$this->update_tags($data['edit_tags'], $override_childs, $add_to_childs, $current_id, true);
}
if (AmpConfig::get('label') && isset($data['edit_labels'])) {
Label::update_label_list($data['edit_labels'], $this->id, true);
}
return $current_id; return $current_id;
@ -488,28 +817,82 @@ class Artist extends database_object
* update_tags * update_tags
* *
* Update tags of artists and/or albums * Update tags of artists and/or albums
* @param string $tags_comma
* @param boolean $override_childs
* @param int|null $current_id
*/ */
public function update_tags($tags_comma, $override_childs, $current_id = null) public function update_tags($tags_comma, $override_childs, $add_to_childs, $current_id = null, $force_update = false)
{ {
if ($current_id == null) { if ($current_id == null) {
$current_id = $this->id; $current_id = $this->id;
} }
Tag::update_tag_list($tags_comma, 'artist', $current_id); Tag::update_tag_list($tags_comma, 'artist', $current_id, $force_update ? true : $override_childs);
if ($override_childs) { if ($override_childs || $add_to_childs) {
$albums = $this->get_albums(null, true); $albums = $this->get_albums(null, true);
foreach ($albums as $album_id) { foreach ($albums as $album_id) {
$album = new Album($album_id); $album = new Album($album_id);
$album->update_tags($tags_comma, $override_childs); $album->update_tags($tags_comma, $override_childs, $add_to_childs);
} }
} }
} }
/**
* Update artist information.
* @param string $summary
* @param string $placeformed
* @param int $yearformed
* @return boolean
*/
public function update_artist_info($summary, $placeformed, $yearformed) public function update_artist_info($summary, $placeformed, $yearformed)
{ {
$sql = "UPDATE `artist` SET `summary` = ?, `placeformed` = ?, `yearformed` = ?, `last_update` = ? WHERE `id` = ?"; $sql = "UPDATE `artist` SET `summary` = ?, `placeformed` = ?, `yearformed` = ?, `last_update` = ? WHERE `id` = ?";
return Dba::write($sql, array($summary, $placeformed, $yearformed, time(), $this->id)); $sqlret = Dba::write($sql, array($summary, $placeformed, $yearformed, time(), $this->id));
$this->summary = $summary;
$this->placeformed = $placeformed;
$this->yearformed = $yearformed;
return $sqlret;
}
/**
* Update artist associated user.
* @param int $user
* @return boolean
*/
public function update_artist_user($user)
{
$sql = "UPDATE `artist` SET `user` = ? WHERE `id` = ?";
return Dba::write($sql, array($user, $this->id));
}
public function remove_from_disk()
{
$deleted = true;
$album_ids = $this->get_albums();
foreach ($album_ids as $id) {
$album = new Album($id);
$deleted = $album->remove_from_disk();
if (!$deleted) {
debug_event('artist', 'Error when deleting the album `' . $id .'`.', 1);
break;
}
}
if ($deleted) {
$sql = "DELETE FROM `artist` WHERE `id` = ?";
$deleted = Dba::write($sql, array($this->id));
if ($deleted) {
Art::gc('artist', $this->id);
Userflag::gc('artist', $this->id);
Rating::gc('artist', $this->id);
Shoutbox::gc('artist', $this->id);
}
}
return $deleted;
} }
} // end of artist class } // end of artist class

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -33,8 +33,10 @@ class Artist_Event
/** /**
* get_upcoming_events * get_upcoming_events
* Returns a list of upcoming events * Returns a list of upcoming events
* @param Artist $artist
* @return SimpleXMLElement|boolean
*/ */
public static function get_upcoming_events($artist) public static function get_upcoming_events(Artist $artist)
{ {
if (isset($artist->mbid)) { if (isset($artist->mbid)) {
$query = 'mbid=' . rawurlencode($artist->mbid); $query = 'mbid=' . rawurlencode($artist->mbid);
@ -59,8 +61,10 @@ class Artist_Event
/** /**
* get_past_events * get_past_events
* Returns a list of past events * Returns a list of past events
* @param Artist $artist
* @return SimpleXMLElement|boolean
*/ */
public static function get_past_events($artist) public static function get_past_events(Artist $artist)
{ {
if (isset($artist->mbid)) { if (isset($artist->mbid)) {
$query = 'mbid=' . rawurlencode($artist->mbid); $query = 'mbid=' . rawurlencode($artist->mbid);

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -44,6 +44,8 @@ class Auth
* This is called when you want to log out and nuke your session. * This is called when you want to log out and nuke your session.
* This is the function used for the Ajax logouts, if no id is passed * This is the function used for the Ajax logouts, if no id is passed
* it tries to find one from the session, * it tries to find one from the session,
* @param string $key
* @param boolean $relogin
*/ */
public static function logout($key='', $relogin = true) public static function logout($key='', $relogin = true)
{ {
@ -82,6 +84,10 @@ class Auth
* *
* This takes a username and password and then returns the results * This takes a username and password and then returns the results
* based on what happens when we try to do the auth. * based on what happens when we try to do the auth.
* @param string $username
* @param string $password
* @param boolean $allow_ui
* @return array
*/ */
public static function login($username, $password, $allow_ui = false) public static function login($username, $password, $allow_ui = false)
{ {
@ -104,6 +110,8 @@ class Auth
* login_step2 * login_step2
* *
* This process authenticate step2 for an auth module * This process authenticate step2 for an auth module
* @param string $auth_mod
* @return array
*/ */
public static function login_step2($auth_mod) public static function login_step2($auth_mod)
{ {
@ -122,6 +130,9 @@ class Auth
* mysql_auth * mysql_auth
* *
* This is the core function of our built-in authentication. * This is the core function of our built-in authentication.
* @param string $username
* @param string $password
* @return array
*/ */
private static function mysql_auth($username, $password) private static function mysql_auth($username, $password)
{ {
@ -168,6 +179,9 @@ class Auth
* *
* Check to make sure the pam_auth function is implemented (module is * Check to make sure the pam_auth function is implemented (module is
* installed), then check the credentials. * installed), then check the credentials.
* @param string $username
* @param string $password
* @return array
*/ */
private static function pam_auth($username, $password) private static function pam_auth($username, $password)
{ {
@ -197,6 +211,9 @@ class Auth
* *
* Calls an external program compatible with mod_authnz_external * Calls an external program compatible with mod_authnz_external
* such as pwauth. * such as pwauth.
* @param string $username
* @param string $password
* @return array
*/ */
private static function external_auth($username, $password) private static function external_auth($username, $password)
{ {
@ -221,7 +238,7 @@ class Auth
fclose($pipes[0]); fclose($pipes[0]);
fclose($pipes[1]); fclose($pipes[1]);
if ($stderr = fread($pipes[2], 8192)) { if ($stderr = fread($pipes[2], 8192)) {
debug_event('external_auth', $stderr, 5); debug_event('external_auth', "fread error: " . $stderr, 5);
} }
fclose($pipes[2]); fclose($pipes[2]);
} else { } else {
@ -257,6 +274,9 @@ class Auth
* the DN fetched from the LDAP directory" * the DN fetched from the LDAP directory"
* * require-attribute "an attribute fetched from the LDAP * * require-attribute "an attribute fetched from the LDAP
* directory matches the given value" * directory matches the given value"
* @param string $username
* @param string $password
* @return array
*/ */
private static function ldap_auth($username, $password) private static function ldap_auth($username, $password)
{ {
@ -285,6 +305,13 @@ class Auth
return $results; return $results;
} }
if (strpos($ldap_filter, "%v") >= 0) {
$ldap_filter = str_replace("%v", $username, $ldap_filter);
} else {
// This to support previous configuration where only the fieldname was set
$ldap_filter = "($ldap_filter=$username)";
}
$ldap_name_field = AmpConfig::get('ldap_name_field'); $ldap_name_field = AmpConfig::get('ldap_name_field');
$ldap_email_field = AmpConfig::get('ldap_email_field'); $ldap_email_field = AmpConfig::get('ldap_email_field');
@ -300,7 +327,9 @@ class Auth
return $results; return $results;
} // If bind fails } // If bind fails
$sr = ldap_search($ldap_link, $ldap_dn, "(&(objectclass=$ldap_class)($ldap_filter=$username))"); $searchstr = "(&(objectclass=$ldap_class)$ldap_filter)";
debug_event('ldap_auth', 'ldap_search: ' . $searchstr, 5);
$sr = ldap_search($ldap_link, $ldap_dn, $searchstr);
$info = ldap_get_entries($ldap_link, $sr); $info = ldap_get_entries($ldap_link, $sr);
if ($info["count"] == 1) { if ($info["count"] == 1) {
@ -367,6 +396,9 @@ class Auth
* http_auth * http_auth
* This auth method relies on HTTP auth from the webserver * This auth method relies on HTTP auth from the webserver
* *
* @param string $username
* @param string $password
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter) * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/ */
private static function http_auth($username, $password) private static function http_auth($username, $password)
@ -390,6 +422,9 @@ class Auth
* openid_auth * openid_auth
* Authenticate user with OpenID * Authenticate user with OpenID
* *
* @param string $username
* @param string $password
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter) * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/ */
private static function openid_auth($username, $password) private static function openid_auth($username, $password)
@ -468,6 +503,7 @@ class Auth
/** /**
* openid_auth_2 * openid_auth_2
* Authenticate user with OpenID, step 2 * Authenticate user with OpenID, step 2
* @return array
*/ */
private static function openid_auth_2() private static function openid_auth_2()
{ {

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -38,6 +38,10 @@ class AutoUpdate
// static class // static class
} }
/**
* Check if current version is a development version.
* @return boolean
*/
protected static function is_develop() protected static function is_develop()
{ {
$version = AmpConfig::get('version'); $version = AmpConfig::get('version');
@ -46,39 +50,56 @@ class AutoUpdate
return ($vspart[count($vspart) - 1] == 'develop'); return ($vspart[count($vspart) - 1] == 'develop');
} }
/**
* Check if current version is a git repository.
* @return boolean
*/
protected static function is_git_repository() protected static function is_git_repository()
{ {
return is_dir(AmpConfig::get('prefix') . '/.git'); return is_dir(AmpConfig::get('prefix') . '/.git');
} }
/**
* Check if branch develop exists in git repository.
* @return boolean
*/
protected static function is_branch_develop_exists() protected static function is_branch_develop_exists()
{ {
return is_readable(AmpConfig::get('prefix') . '/.git/refs/heads/develop'); return is_readable(AmpConfig::get('prefix') . '/.git/refs/heads/develop');
} }
/**
* Perform a GitHub request.
* @param string $action
* @return string|null
*/
public static function github_request($action) public static function github_request($action)
{ {
try { try {
// https is mandatory
$url = "https://api.github.com/repos/ampache/ampache" . $action; $url = "https://api.github.com/repos/ampache/ampache" . $action;
$request = Requests::get($url); $request = Requests::get($url, array(), Core::requests_options());
// Not connected / API rate limit exceeded: just ignore, it will pass next time // Not connected / API rate limit exceeded: just ignore, it will pass next time
if ($request->status_code != 200) { if ($request->status_code != 200) {
debug_event('autoupdate', 'Github API request ' . $url . ' failed with http code ' . $request->status_code, '1'); debug_event('autoupdate', 'Github API request ' . $url . ' failed with http code ' . $request->status_code, '1');
return; return null;
} }
return json_decode($request->body); return json_decode($request->body);
} catch (Exception $e) { } catch (Exception $e) {
debug_event('autoupdate', 'Request error: ' . $e->getMessage(), '1'); debug_event('autoupdate', 'Request error: ' . $e->getMessage(), '1');
return ""; return null;
} }
} }
/**
* Check if last github check expired.
* @return boolean
*/
protected static function lastcheck_expired() protected static function lastcheck_expired()
{ {
$lastcheck = AmpConfig::get('autoupdate_lastcheck'); $lastcheck = AmpConfig::get('autoupdate_lastcheck');
if (!$lastcheck) { if (!$lastcheck) {
User::rebuild_all_preferences();
Preference::update('autoupdate_lastcheck', $GLOBALS['user']->id, '1'); Preference::update('autoupdate_lastcheck', $GLOBALS['user']->id, '1');
AmpConfig::set('autoupdate_lastcheck', '1', true); AmpConfig::set('autoupdate_lastcheck', '1', true);
} }
@ -86,11 +107,21 @@ class AutoUpdate
return ((time() - (3600 * 3)) > $lastcheck); return ((time() - (3600 * 3)) > $lastcheck);
} }
/**
* Get latest available version from GitHub.
* @param boolean $force
* @return string
*/
public static function get_latest_version($force = false) public static function get_latest_version($force = false)
{ {
$lastversion = ''; $lastversion = '';
// Forced or last check expired, check latest version from Github // Forced or last check expired, check latest version from Github
if ($force || (self::lastcheck_expired() && AmpConfig::get('autoupdate'))) { if ($force || (self::lastcheck_expired() && AmpConfig::get('autoupdate'))) {
// Always update last check time to avoid infinite check on permanent errors (proxy, firewall, ...)
$time = time();
Preference::update('autoupdate_lastcheck', $GLOBALS['user']->id, $time);
AmpConfig::set('autoupdate_lastcheck', $time, true);
// Development version, get latest commit on develop branch // Development version, get latest commit on develop branch
if (self::is_develop()) { if (self::is_develop()) {
$commits = self::github_request('/commits/develop'); $commits = self::github_request('/commits/develop');
@ -98,9 +129,6 @@ class AutoUpdate
$lastversion = $commits->sha; $lastversion = $commits->sha;
Preference::update('autoupdate_lastversion', $GLOBALS['user']->id, $lastversion); Preference::update('autoupdate_lastversion', $GLOBALS['user']->id, $lastversion);
AmpConfig::set('autoupdate_lastversion', $lastversion, true); AmpConfig::set('autoupdate_lastversion', $lastversion, true);
$time = time();
Preference::update('autoupdate_lastcheck', $GLOBALS['user']->id, $time);
AmpConfig::set('autoupdate_lastcheck', $time, true);
$available = self::is_update_available(true); $available = self::is_update_available(true);
Preference::update('autoupdate_lastversion_new', $GLOBALS['user']->id, $available); Preference::update('autoupdate_lastversion_new', $GLOBALS['user']->id, $available);
AmpConfig::set('autoupdate_lastversion_new', $available, true); AmpConfig::set('autoupdate_lastversion_new', $available, true);
@ -113,9 +141,6 @@ class AutoUpdate
$lastversion = $tags[0]->name; $lastversion = $tags[0]->name;
Preference::update('autoupdate_lastversion', $GLOBALS['user']->id, $lastversion); Preference::update('autoupdate_lastversion', $GLOBALS['user']->id, $lastversion);
AmpConfig::set('autoupdate_lastversion', $lastversion, true); AmpConfig::set('autoupdate_lastversion', $lastversion, true);
$time = time();
Preference::update('autoupdate_lastcheck', $GLOBALS['user']->id, $time);
AmpConfig::set('autoupdate_lastcheck', $time, true);
$available = self::is_update_available(true); $available = self::is_update_available(true);
Preference::update('autoupdate_lastversion_new', $GLOBALS['user']->id, $available); Preference::update('autoupdate_lastversion_new', $GLOBALS['user']->id, $available);
AmpConfig::set('autoupdate_lastversion_new', $available, true); AmpConfig::set('autoupdate_lastversion_new', $available, true);
@ -130,6 +155,10 @@ class AutoUpdate
return $lastversion; return $lastversion;
} }
/**
* Get current local version.
* @return string
*/
public static function get_current_version() public static function get_current_version()
{ {
if (self::is_develop()) { if (self::is_develop()) {
@ -139,15 +168,24 @@ class AutoUpdate
} }
} }
/**
* Get current local git commit.
* @return string
*/
public static function get_current_commit() public static function get_current_commit()
{ {
if (self::is_branch_develop_exists()) { if (self::is_branch_develop_exists()) {
return trim(file_get_contents(AmpConfig::get('prefix') . '/.git/refs/heads/develop')); return trim(file_get_contents(AmpConfig::get('prefix') . '/.git/refs/heads/develop'));
} }
return false; return '';
} }
/**
* Check if an update is available.
* @param boolean $force
* @return boolean
*/
public static function is_update_available($force = false) public static function is_update_available($force = false)
{ {
if (!$force && (!self::lastcheck_expired() || !AmpConfig::get('autoupdate'))) { if (!$force && (!self::lastcheck_expired() || !AmpConfig::get('autoupdate'))) {
@ -183,6 +221,9 @@ class AutoUpdate
return $available; return $available;
} }
/**
* Display new version information and update link if possible.
*/
public static function show_new_version() public static function show_new_version()
{ {
echo '<div>'; echo '<div>';
@ -191,6 +232,23 @@ class AutoUpdate
echo T_('See') . ' <a href="https://github.com/ampache/ampache/' . (self::is_develop() ? 'compare/' . self::get_current_version() . '...' . self::get_latest_version() : 'blob/master/docs/CHANGELOG.md') . '" target="_blank">' . T_('changes') . '</a> '; echo T_('See') . ' <a href="https://github.com/ampache/ampache/' . (self::is_develop() ? 'compare/' . self::get_current_version() . '...' . self::get_latest_version() : 'blob/master/docs/CHANGELOG.md') . '" target="_blank">' . T_('changes') . '</a> ';
echo T_('or') . ' <a href="https://github.com/ampache/ampache/archive/' . (self::is_develop() ? 'develop.zip' : self::get_latest_version() . '.zip') . '" target="_blank"><b>' . T_('download') . '</b></a>.'; echo T_('or') . ' <a href="https://github.com/ampache/ampache/archive/' . (self::is_develop() ? 'develop.zip' : self::get_latest_version() . '.zip') . '" target="_blank"><b>' . T_('download') . '</b></a>.';
if (self::is_git_repository()) {
echo ' | <a rel="nohtml" href="' . AmpConfig::get('web_path') . '/update.php?type=sources&action=update">.:: Update ::.</a>';
}
echo '</div>'; echo '</div>';
} }
/**
* Update local git repository.
*/
public static function update_files()
{
echo T_('Updating Ampache sources with `git pull` ...') . '<br />';
ob_flush();
chdir(AmpConfig::get('prefix'));
exec('git pull https://github.com/ampache/ampache.git');
echo T_('Done') . '<br />';
ob_flush();
self::get_latest_version(true);
}
} }

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -20,22 +20,61 @@
* *
*/ */
class Broadcast extends database_object class Broadcast extends database_object implements library_item
{ {
/**
* @var int $id
*/
public $id; public $id;
/**
* @var boolean $started
*/
public $started; public $started;
/**
* @var int $listeners
*/
public $listeners; public $listeners;
/**
* @var int $song
*/
public $song; public $song;
/**
* @var int $song_position
*/
public $song_position; public $song_position;
/**
* @var string $name
*/
public $name; public $name;
/**
* @var int $user
*/
public $user;
/**
* @var array $tags
*/
public $tags; public $tags;
/**
* @var string $f_name
*/
public $f_name; public $f_name;
/**
* @var string $f_link
*/
public $f_link; public $f_link;
/**
* @var string $f_tags
*/
public $f_tags; public $f_tags;
/**
* @var boolean $is_private
*/
public $is_private;
/** /**
* Constructor * Constructor
* @param int $id
*/ */
public function __construct($id=0) public function __construct($id=0)
{ {
@ -52,6 +91,11 @@ class Broadcast extends database_object
return true; return true;
} //constructor } //constructor
/**
* Update broadcast state.
* @param boolean $started
* @param string $key
*/
public function update_state($started, $key='') public function update_state($started, $key='')
{ {
$sql = "UPDATE `broadcast` SET `started` = ?, `key` = ?, `song` = '0', `listeners` = '0' WHERE `id` = ?"; $sql = "UPDATE `broadcast` SET `started` = ?, `key` = ?, `song` = '0', `listeners` = '0' WHERE `id` = ?";
@ -60,6 +104,10 @@ class Broadcast extends database_object
$this->started = $started; $this->started = $started;
} }
/**
* Update broadcast listeners.
* @param int $listeners
*/
public function update_listeners($listeners) public function update_listeners($listeners)
{ {
$sql = "UPDATE `broadcast` SET `listeners` = ? " . $sql = "UPDATE `broadcast` SET `listeners` = ? " .
@ -68,6 +116,10 @@ class Broadcast extends database_object
$this->listeners = $listeners; $this->listeners = $listeners;
} }
/**
* Update broadcast current song.
* @param int $song_id
*/
public function update_song($song_id) public function update_song($song_id)
{ {
$sql = "UPDATE `broadcast` SET `song` = ? " . $sql = "UPDATE `broadcast` SET `song` = ? " .
@ -77,12 +129,22 @@ class Broadcast extends database_object
$this->song_position = 0; $this->song_position = 0;
} }
/**
* Delete the broadcast.
* @return boolean
*/
public function delete() public function delete()
{ {
$sql = "DELETE FROM `broadcast` WHERE `id` = ?"; $sql = "DELETE FROM `broadcast` WHERE `id` = ?";
return Dba::write($sql, array($this->id)); return Dba::write($sql, array($this->id));
} }
/**
* Create a broadcast
* @param string $name
* @param string $description
* @return int
*/
public static function create($name, $description='') public static function create($name, $description='')
{ {
if (!empty($name)) { if (!empty($name)) {
@ -95,26 +157,144 @@ class Broadcast extends database_object
return 0; return 0;
} }
public function update($data) /**
* Update a broadcast from data array.
* @param array $data
* @return int
*/
public function update(array $data)
{ {
if (isset($data['edit_tags'])) { if (isset($data['edit_tags'])) {
Tag::update_tag_list($data['edit_tags'], 'broadcast', $this->id); Tag::update_tag_list($data['edit_tags'], 'broadcast', $this->id, true);
} }
$sql = "UPDATE `broadcast` SET `name` = ?, `description` = ?, `is_private` = ? " . $sql = "UPDATE `broadcast` SET `name` = ?, `description` = ?, `is_private` = ? " .
"WHERE `id` = ?"; "WHERE `id` = ?";
$params = array($data['name'], $data['description'], !empty($data['private']), $this->id); $params = array($data['name'], $data['description'], !empty($data['private']), $this->id);
return Dba::write($sql, $params); Dba::write($sql, $params);
return $this->id;
} }
public function format() public function format($details = true)
{ {
$this->f_name = $this->name; $this->f_name = $this->name;
$this->f_link = '<a href="' . AmpConfig::get('web_path') . '/broadcast.php?id=' . $this->id . '">' . scrub_out($this->f_name) . '</a>'; $this->f_link = '<a href="' . AmpConfig::get('web_path') . '/broadcast.php?id=' . $this->id . '">' . scrub_out($this->f_name) . '</a>';
$this->tags = Tag::get_top_tags('broadcast', $this->id); if ($details) {
$this->f_tags = Tag::get_display($this->tags); $this->tags = Tag::get_top_tags('broadcast', $this->id);
$this->f_tags = Tag::get_display($this->tags, true, 'broadcast');
}
} }
/**
* Get item keywords for metadata searches.
* @return array
*/
public function get_keywords()
{
return array();
}
/**
* Get item fullname.
* @return string
*/
public function get_fullname()
{
return $this->f_name;
}
/**
* Get parent item description.
* @return array|null
*/
public function get_parent()
{
return null;
}
/**
* Get item childrens.
* @return array
*/
public function get_childrens()
{
return array();
}
/**
* Search for item childrens.
* @param string $name
* @return array
*/
public function search_childrens($name)
{
return array();
}
/**
* Get all childrens and sub-childrens medias.
* @param string $filter_type
* @return array
*/
public function get_medias($filter_type = null)
{
// Not a media, shouldn't be that
$medias = array();
if (!$filter_type || $filter_type == 'broadcast') {
$medias[] = array(
'object_type' => 'broadcast',
'object_id' => $this->id
);
}
return $medias;
}
/**
* get_catalogs
*
* Get all catalog ids related to this item.
* @return int[]
*/
public function get_catalogs()
{
return array();
}
/**
* Get item's owner.
* @return int|null
*/
public function get_user_owner()
{
return $this->user;
}
/**
* Get default art kind for this item.
* @return string
*/
public function get_default_art_kind()
{
return 'default';
}
public function get_description()
{
return null;
}
public function display_art($thumb = 2)
{
if (Art::has_db($this->id, 'broadcast')) {
Art::display('broadcast', $this->id, $this->get_fullname(), $thumb, $this->link);
}
}
/**
* Get all broadcasts sql query.
* @return string
*/
public static function get_broadcast_list_sql() public static function get_broadcast_list_sql()
{ {
$sql = "SELECT `id` FROM `broadcast` WHERE `started` = '1' "; $sql = "SELECT `id` FROM `broadcast` WHERE `started` = '1' ";
@ -122,6 +302,10 @@ class Broadcast extends database_object
return $sql; return $sql;
} }
/**
* Get all broadcasts.
* @return int[]
*/
public static function get_broadcast_list() public static function get_broadcast_list()
{ {
$sql = self::get_broadcast_list_sql(); $sql = self::get_broadcast_list_sql();
@ -135,12 +319,21 @@ class Broadcast extends database_object
return $results; return $results;
} }
/**
* Generate a new broadcast key.
* @return string
*/
public static function generate_key() public static function generate_key()
{ {
// Should be improved for security reasons! // Should be improved for security reasons!
return md5(uniqid(rand(), true)); return md5(uniqid(rand(), true));
} }
/**
* Get broadcast from its key.
* @param string $key
* @return Broadcast|null
*/
public static function get_broadcast($key) public static function get_broadcast($key)
{ {
$sql = "SELECT `id` FROM `broadcast` WHERE `key` = ?"; $sql = "SELECT `id` FROM `broadcast` WHERE `key` = ?";
@ -153,16 +346,23 @@ class Broadcast extends database_object
return null; return null;
} }
/**
* Show action buttons.
*/
public function show_action_buttons() public function show_action_buttons()
{ {
if ($this->id) { if ($this->id) {
if ($GLOBALS['user']->has_access('75')) { if ($GLOBALS['user']->has_access('75')) {
echo "<a id=\"edit_broadcast_ " . $this->id . "\" onclick=\"showEditDialog('broadcast_row', '" . $this->id . "', 'edit_broadcast_" . $this->id . "', '" . T_('Broadcast edit') . "', 'broadcast_row_', 'refresh_broadcast')\">" . UI::get_icon('edit', T_('Edit')) . "</a>"; echo "<a id=\"edit_broadcast_ " . $this->id . "\" onclick=\"showEditDialog('broadcast_row', '" . $this->id . "', 'edit_broadcast_" . $this->id . "', '" . T_('Broadcast edit') . "', 'broadcast_row_')\">" . UI::get_icon('edit', T_('Edit')) . "</a>";
echo " <a href=\"" . AmpConfig::get('web_path') . "/broadcast.php?action=show_delete&id=" . $this->id ."\">" . UI::get_icon('delete', T_('Delete')) . "</a>"; echo " <a href=\"" . AmpConfig::get('web_path') . "/broadcast.php?action=show_delete&id=" . $this->id ."\">" . UI::get_icon('delete', T_('Delete')) . "</a>";
} }
} }
} }
/**
* Get broadcast link.
* @return string
*/
public static function get_broadcast_link() public static function get_broadcast_link()
{ {
$link = "<div class=\"broadcast-action\">"; $link = "<div class=\"broadcast-action\">";
@ -171,6 +371,11 @@ class Broadcast extends database_object
return $link; return $link;
} }
/**
* Get unbroadcast link.
* @param int $id
* @return string
*/
public static function get_unbroadcast_link($id) public static function get_unbroadcast_link($id)
{ {
$link = "<div class=\"broadcast-action\">"; $link = "<div class=\"broadcast-action\">";
@ -180,6 +385,11 @@ class Broadcast extends database_object
return $link; return $link;
} }
/**
* Get broadcasts from an user.
* @param int $user_id
* @return int[]
*/
public static function get_broadcasts($user_id) public static function get_broadcasts($user_id)
{ {
$sql = "SELECT `id` FROM `broadcast` WHERE `user` = ?"; $sql = "SELECT `id` FROM `broadcast` WHERE `user` = ?";
@ -192,11 +402,22 @@ class Broadcast extends database_object
return $broadcasts; return $broadcasts;
} }
public static function gc()
{
}
/* /*
* Get play url.
* *
* @param int $oid
* @param string $additional_params
* @param string $player
* @param boolean $local
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter) * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/ */
public static function play_url($oid, $additional_params='') public static function play_url($oid, $additional_params='', $player=null, $local=false)
{ {
return $oid; return $oid;
} }

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -36,9 +36,21 @@ class Broadcast_Server implements MessageComponentInterface
const BROADCAST_AUTH_SID = "AUTH_SID"; const BROADCAST_AUTH_SID = "AUTH_SID";
public $verbose; public $verbose;
/**
* @var ConnectionInterface[] $clients
*/
protected $clients; protected $clients;
/**
* @var string[] $sids
*/
protected $sids; protected $sids;
/**
* @var ConnectionInterface[] $listeners
*/
protected $listeners; protected $listeners;
/**
* @var Broadcast[] $broadcasters
*/
protected $broadcasters; protected $broadcasters;
public function __construct() public function __construct()
@ -50,11 +62,20 @@ class Broadcast_Server implements MessageComponentInterface
$this->broadcasters = array(); $this->broadcasters = array();
} }
/**
*
* @param \Ratchet\ConnectionInterface $conn
*/
public function onOpen(ConnectionInterface $conn) public function onOpen(ConnectionInterface $conn)
{ {
$this->clients[$conn->resourceId] = $conn; $this->clients[$conn->resourceId] = $conn;
} }
/**
*
* @param \Ratchet\ConnectionInterface $from
* @param string $msg
*/
public function onMessage(ConnectionInterface $from, $msg) public function onMessage(ConnectionInterface $from, $msg)
{ {
$commands = explode(';', $msg); $commands = explode(';', $msg);
@ -101,6 +122,11 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
/**
*
* @param int $song_id
* @return string
*/
protected function getSongJS($song_id) protected function getSongJS($song_id)
{ {
$media = array(); $media = array();
@ -113,13 +139,18 @@ class Broadcast_Server implements MessageComponentInterface
return WebPlayer::get_media_js_param($item[0]); return WebPlayer::get_media_js_param($item[0]);
} }
protected function notifySong($from, $song_id) /**
*
* @param \Ratchet\ConnectionInterface $from
* @param int $song_id
*/
protected function notifySong(ConnectionInterface $from, $song_id)
{ {
if ($this->isBroadcaster($from)) { if ($this->isBroadcaster($from)) {
$broadcast = $this->broadcasters[$from->resourceId]; $broadcast = $this->broadcasters[$from->resourceId];
$clients = $this->getListeners($broadcast); $clients = $this->getListeners($broadcast);
Session::extend(Stream::$session, 'stream'); Session::extend(Stream::get_session(), 'stream');
$broadcast->update_song($song_id); $broadcast->update_song($song_id);
$this->broadcastMessage($clients, self::BROADCAST_SONG, base64_encode($this->getSongJS($song_id))); $this->broadcastMessage($clients, self::BROADCAST_SONG, base64_encode($this->getSongJS($song_id)));
@ -132,7 +163,12 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function notifySongPosition($from, $song_position) /**
*
* @param \Ratchet\ConnectionInterface $from
* @param int $song_position
*/
protected function notifySongPosition(ConnectionInterface $from, $song_position)
{ {
if ($this->isBroadcaster($from)) { if ($this->isBroadcaster($from)) {
$broadcast = $this->broadcasters[$from->resourceId]; $broadcast = $this->broadcasters[$from->resourceId];
@ -151,12 +187,17 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function notifyPlayerPlay($from, $play) /**
*
* @param \Ratchet\ConnectionInterface $from
* @param boolean $play
*/
protected function notifyPlayerPlay(ConnectionInterface $from, $play)
{ {
if ($this->isBroadcaster($from)) { if ($this->isBroadcaster($from)) {
$broadcast = $this->broadcasters[$from->resourceId]; $broadcast = $this->broadcasters[$from->resourceId];
$clients = $this->getListeners($broadcast); $clients = $this->getListeners($broadcast);
$this->broadcastMessage($clients, self::BROADCAST_PLAYER_PLAY, $play); $this->broadcastMessage($clients, self::BROADCAST_PLAYER_PLAY, $play ? 'true' : 'false');
if ($this->verbose) { if ($this->verbose) {
echo "[" . time() ."][info]Broadcast " . $broadcast->id . " player state: " . $play . "." . "\r\n"; echo "[" . time() ."][info]Broadcast " . $broadcast->id . " player state: " . $play . "." . "\r\n";
@ -166,7 +207,31 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function registerBroadcast($from, $broadcast_key) /**
*
* @param \Ratchet\ConnectionInterface $from
*/
protected function notifyEnded(ConnectionInterface $from)
{
if ($this->isBroadcaster($from)) {
$broadcast = $this->broadcasters[$from->resourceId];
$clients = $this->getListeners($broadcast);
$this->broadcastMessage($clients, self::BROADCAST_ENDED);
if ($this->verbose) {
echo "[" . time() ."][info]Broadcast " . $broadcast->id . " ended." . "\r\n";
}
} else {
debug_event('broadcast', 'Action unauthorized.', '3');
}
}
/**
*
* @param \Ratchet\ConnectionInterface $from
* @param string $broadcast_key
*/
protected function registerBroadcast(ConnectionInterface $from, $broadcast_key)
{ {
$broadcast = Broadcast::get_broadcast($broadcast_key); $broadcast = Broadcast::get_broadcast($broadcast_key);
if ($broadcast) { if ($broadcast) {
@ -179,7 +244,11 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function unregisterBroadcast($conn) /**
*
* @param \Ratchet\ConnectionInterface $conn
*/
protected function unregisterBroadcast(ConnectionInterface $conn)
{ {
$broadcast = $this->broadcasters[$conn->resourceId]; $broadcast = $this->broadcasters[$conn->resourceId];
$clients = $this->getListeners($broadcast); $clients = $this->getListeners($broadcast);
@ -194,6 +263,11 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
/**
*
* @param int $broadcast_id
* @return Broadcast
*/
protected function getRunningBroadcast($broadcast_id) protected function getRunningBroadcast($broadcast_id)
{ {
$broadcast = null; $broadcast = null;
@ -206,7 +280,12 @@ class Broadcast_Server implements MessageComponentInterface
return $broadcast; return $broadcast;
} }
protected function registerListener($from, $broadcast_id) /**
*
* @param \Ratchet\ConnectionInterface $from
* @param int $broadcast_id
*/
protected function registerListener(ConnectionInterface $from, $broadcast_id)
{ {
$broadcast = $this->getRunningBroadcast($broadcast_id); $broadcast = $this->getRunningBroadcast($broadcast_id);
@ -226,7 +305,12 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function authSid($conn, $sid) /**
*
* @param \Ratchet\ConnectionInterface $conn
* @param string $sid
*/
protected function authSid(ConnectionInterface $conn, $sid)
{ {
if (Session::exists('stream', $sid)) { if (Session::exists('stream', $sid)) {
$this->sids[$conn->resourceId] = $sid; $this->sids[$conn->resourceId] = $sid;
@ -237,7 +321,11 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function unregisterListener($conn) /**
*
* @param \Ratchet\ConnectionInterface $conn
*/
protected function unregisterListener(ConnectionInterface $conn)
{ {
foreach ($this->listeners as $broadcast_id => $brlisteners) { foreach ($this->listeners as $broadcast_id => $brlisteners) {
$lindex = array_search($conn, $brlisteners); $lindex = array_search($conn, $brlisteners);
@ -257,7 +345,11 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function notifyNbListeners($broadcast) /**
*
* @param Broadcast $broadcast
*/
protected function notifyNbListeners(Broadcast $broadcast)
{ {
$broadcaster_id = array_search($broadcast, $this->broadcasters); $broadcaster_id = array_search($broadcast, $this->broadcasters);
if ($broadcaster_id) { if ($broadcaster_id) {
@ -269,16 +361,32 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
protected function getListeners($broadcast) /**
*
* @param Broadcast $broadcast
* @return \Ratchet\ConnectionInterface
*/
protected function getListeners(Broadcast $broadcast)
{ {
return $this->listeners[$broadcast->id]; return $this->listeners[$broadcast->id];
} }
protected function isBroadcaster($conn) /**
*
* @param \Ratchet\ConnectionInterface $conn
* @return boolean
*/
protected function isBroadcaster(ConnectionInterface $conn)
{ {
return array_key_exists($conn->resourceId, $this->broadcasters); return array_key_exists($conn->resourceId, $this->broadcasters);
} }
/**
*
* @param \Ratchet\ConnectionInterface[] $clients
* @param string $cmd
* @param string $value
*/
protected function broadcastMessage($clients, $cmd, $value='') protected function broadcastMessage($clients, $cmd, $value='')
{ {
$msg = $cmd . ':' . $value . ';'; $msg = $cmd . ':' . $value . ';';
@ -291,6 +399,10 @@ class Broadcast_Server implements MessageComponentInterface
} }
} }
/**
*
* @param \Ratchet\ConnectionInterface $conn
*/
public function onClose(ConnectionInterface $conn) public function onClose(ConnectionInterface $conn)
{ {
if ($this->isBroadcaster($conn)) { if ($this->isBroadcaster($conn)) {
@ -303,11 +415,20 @@ class Broadcast_Server implements MessageComponentInterface
unset($this->sids[$conn->resourceId]); unset($this->sids[$conn->resourceId]);
} }
/**
*
* @param \Ratchet\ConnectionInterface $conn
* @param \Exception $e
*/
public function onError(ConnectionInterface $conn, \Exception $e) public function onError(ConnectionInterface $conn, \Exception $e)
{ {
$conn->close(); $conn->close();
} }
/**
*
* @return string
*/
public static function get_address() public static function get_address()
{ {
$websocket_address = AmpConfig::get('websocket_address'); $websocket_address = AmpConfig::get('websocket_address');

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -31,8 +31,17 @@
*/ */
class Browse extends Query class Browse extends Query
{ {
/**
* @var boolean $show_header
*/
public $show_header; public $show_header;
/**
* Constructor.
*
* @param int|null $id
* @param boolean $cached
*/
public function __construct($id = null, $cached = true) public function __construct($id = null, $cached = true)
{ {
parent::__construct($id, $cached); parent::__construct($id, $cached);
@ -48,6 +57,8 @@ class Browse extends Query
* set_simple_browse * set_simple_browse
* This sets the current browse object to a 'simple' browse method * This sets the current browse object to a 'simple' browse method
* which means use the base query provided and expand from there * which means use the base query provided and expand from there
*
* @param boolean $value
*/ */
public function set_simple_browse($value) public function set_simple_browse($value)
{ {
@ -58,6 +69,9 @@ class Browse extends Query
/** /**
* add_supplemental_object * add_supplemental_object
* Legacy function, need to find a better way to do that * Legacy function, need to find a better way to do that
*
* @param string $class
* @param int $uid
*/ */
public function add_supplemental_object($class, $uid) public function add_supplemental_object($class, $uid)
{ {
@ -71,6 +85,8 @@ class Browse extends Query
* get_supplemental_objects * get_supplemental_objects
* This returns an array of 'class','id' for additional objects that * This returns an array of 'class','id' for additional objects that
* need to be created before we start this whole browsing thing. * need to be created before we start this whole browsing thing.
*
* @return array
*/ */
public function get_supplemental_objects() public function get_supplemental_objects()
{ {
@ -84,11 +100,42 @@ class Browse extends Query
} // get_supplemental_objects } // get_supplemental_objects
/**
* update_browse_from_session
* Restore the previous start index from something saved into the current session.
*/
public function update_browse_from_session()
{
if ($this->is_simple() && $this->get_start() == 0) {
$name = 'browse_current_' . $this->get_type();
if (isset($_SESSION[$name]) && isset($_SESSION[$name]['start']) && $_SESSION[$name]['start'] > 0) {
// Checking if value is suitable
$start = $_SESSION[$name]['start'];
if ($this->get_offset() > 0) {
$set_page = floor($start / $this->get_offset());
if ($this->get_total() > $this->get_offset()) {
$total_pages = ceil($this->get_total() / $this->get_offset());
} else {
$total_pages = 0;
}
if ($set_page >= 0 && $set_page <= $total_pages) {
$this->set_start($start);
}
}
}
}
}
/** /**
* show_objects * show_objects
* This takes an array of objects * This takes an array of objects
* and requires the correct template based on the * and requires the correct template based on the
* type that we are currently browsing * type that we are currently browsing
*
* @param int[] $object_ids
*/ */
public function show_objects($object_ids = null, $argument = null) public function show_objects($object_ids = null, $argument = null)
{ {
@ -100,9 +147,8 @@ class Browse extends Query
// Limit is based on the user's preferences if this is not a // Limit is based on the user's preferences if this is not a
// simple browse because we've got too much here // simple browse because we've got too much here
if ((count($object_ids) > $this->get_start()) && if ($this->get_start() >= 0 && (count($object_ids) > $this->get_start()) &&
! $this->is_simple() && ! $this->is_simple()) {
! $this->is_static_content()) {
$object_ids = array_slice( $object_ids = array_slice(
$object_ids, $object_ids,
$this->get_start(), $this->get_start(),
@ -133,37 +179,53 @@ class Browse extends Query
$match = ' (' . $filter_value . ')';*/ $match = ' (' . $filter_value . ')';*/
} elseif ($filter_value = $this->get_filter('catalog')) { } elseif ($filter_value = $this->get_filter('catalog')) {
// Get the catalog title // Get the catalog title
$catalog = Catalog::create_from_id($filter_value); $catalog = Catalog::create_from_id(intval($filter_value));
$match = ' (' . $catalog->name . ')'; $match = ' (' . $catalog->name . ')';
} }
$type = $this->get_type(); $type = $this->get_type();
// Update the session value only if it's allowed on the current browser
if ($this->get_update_session()) {
$_SESSION['browse_current_' . $type]['start'] = $browse->get_start();
}
// Set the correct classes based on type // Set the correct classes based on type
$class = "box browse_" . $type; $class = "box browse_" . $type;
debug_event('browse', 'Called for type {'.$type.'}', '5'); $argument_param = ($argument ? '&argument=' . scrub_in($argument) : '');
debug_event('browse', 'Show objects called for type {'.$type.'}', '5');
$limit_threshold = $this->get_threshold();
// Switch on the type of browsing we're doing // Switch on the type of browsing we're doing
switch ($type) { switch ($type) {
case 'song': case 'song':
$box_title = T_('Songs') . $match; $box_title = T_('Songs') . $match;
Song::build_cache($object_ids); Song::build_cache($object_ids, $limit_threshold);
$box_req = AmpConfig::get('prefix') . '/templates/show_songs.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_songs.inc.php';
break; break;
case 'album': case 'album':
$box_title = T_('Albums') . $match;
Album::build_cache($object_ids); Album::build_cache($object_ids);
$allow_group_disks = $argument; $box_title = T_('Albums') . $match;
if (is_array($argument)) {
$allow_group_disks = $argument['group_disks'];
if ($argument['title']) {
$box_title = $argument['title'];
}
} else {
$allow_group_disks = false;
}
$box_req = AmpConfig::get('prefix') . '/templates/show_albums.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_albums.inc.php';
break; break;
case 'user': case 'user':
$box_title = T_('Manage Users') . $match; $box_title = T_('Users') . $match;
$box_req = AmpConfig::get('prefix') . '/templates/show_users.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_users.inc.php';
break; break;
case 'artist': case 'artist':
$box_title = T_('Artists') . $match; $box_title = T_('Artists') . $match;
Artist::build_cache($object_ids, 'extra'); Artist::build_cache($object_ids, true, $limit_threshold);
$box_req = AmpConfig::get('prefix') . '/templates/show_artists.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_artists.inc.php';
break; break;
case 'live_stream': case 'live_stream':
@ -187,7 +249,7 @@ class Browse extends Query
break; break;
case 'smartplaylist': case 'smartplaylist':
$box_title = T_('Smart Playlists') . $match; $box_title = T_('Smart Playlists') . $match;
$box_req = AmpConfig::get('prefix') . '/templates/show_smartplaylists.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_searches.inc.php';
break; break;
case 'catalog': case 'catalog':
$box_title = T_('Catalogs'); $box_title = T_('Catalogs');
@ -204,6 +266,7 @@ class Browse extends Query
break; break;
case 'video': case 'video':
Video::build_cache($object_ids); Video::build_cache($object_ids);
$video_type = 'video';
$box_title = T_('Videos'); $box_title = T_('Videos');
$box_req = AmpConfig::get('prefix') . '/templates/show_videos.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_videos.inc.php';
break; break;
@ -231,12 +294,52 @@ class Browse extends Query
$box_title = T_('Broadcasts'); $box_title = T_('Broadcasts');
$box_req = AmpConfig::get('prefix') . '/templates/show_broadcasts.inc.php'; $box_req = AmpConfig::get('prefix') . '/templates/show_broadcasts.inc.php';
break; break;
case 'license':
$box_title = T_('Media Licenses');
$box_req = AmpConfig::get('prefix') . '/templates/show_manage_license.inc.php';
break;
case 'tvshow':
$box_title = T_('TV Shows');
$box_req = AmpConfig::get('prefix') . '/templates/show_tvshows.inc.php';
break;
case 'tvshow_season':
$box_title = T_('Seasons');
$box_req = AmpConfig::get('prefix') . '/templates/show_tvshow_seasons.inc.php';
break;
case 'tvshow_episode':
$box_title = T_('Episodes');
$video_type = $type;
$box_req = AmpConfig::get('prefix') . '/templates/show_videos.inc.php';
break;
case 'movie':
$box_title = T_('Movies');
$video_type = $type;
$box_req = AmpConfig::get('prefix') . '/templates/show_videos.inc.php';
break;
case 'clip':
$box_title = T_('Clips');
$video_type = $type;
$box_req = AmpConfig::get('prefix') . '/templates/show_videos.inc.php';
break;
case 'personal_video':
$box_title = T_('Personal Videos');
$video_type = $type;
$box_req = AmpConfig::get('prefix') . '/templates/show_videos.inc.php';
break;
case 'label':
$box_title = T_('Labels');
$box_req = AmpConfig::get('prefix') . '/templates/show_labels.inc.php';
break;
case 'pvmsg':
$box_title = T_('Private Messages');
$box_req = AmpConfig::get('prefix') . '/templates/show_pvmsgs.inc.php';
break;
default: default:
// Rien a faire // Rien a faire
break; break;
} // end switch on type } // end switch on type
Ajax::start_container('browse_content_' . $type, 'browse_content'); Ajax::start_container($this->get_content_div(), 'browse_content');
if ($this->get_show_header()) { if ($this->get_show_header()) {
if (isset($box_req) && isset($box_title)) { if (isset($box_req) && isset($box_title)) {
UI::show_box_top($box_title, $class); UI::show_box_top($box_title, $class);
@ -252,31 +355,32 @@ class Browse extends Query
UI::show_box_bottom(); UI::show_box_bottom();
} }
echo '<script type="text/javascript">'; echo '<script type="text/javascript">';
echo Ajax::action('?page=browse&action=get_filters&browse_id=' . $this->id, ''); echo Ajax::action('?page=browse&action=get_filters&browse_id=' . $this->id . $argument_param, '');
echo ';</script>'; echo ';</script>';
} else { } else {
if (!$this->get_use_pages()) { if (!$this->get_use_pages()) {
$this->show_next_link(); $this->show_next_link($argument);
} }
} }
Ajax::end_container(); Ajax::end_container();
} // show_object } // show_object
public function show_next_link() public function show_next_link($argument = null)
{ {
$limit = $this->get_offset(); $limit = $this->get_offset();
$start = $this->get_start(); $start = $this->get_start();
$total = $this->get_total(); $total = $this->get_total();
$next_offset = $start + $limit; $next_offset = $start + $limit;
if ($next_offset <= $total) { if ($next_offset <= $total) {
echo '<a class="jscroll-next" href="' . AmpConfig::get('ajax_url') . '?page=browse&action=page&browse_id=' . $this->id . '&start=' . $next_offset . '&xoutput=raw&xoutputnode=browse_content_' . $this->get_type() . '&show_header=false">' . T_('More') . '</a>'; echo '<a class="jscroll-next" href="' . AmpConfig::get('ajax_url') . '?page=browse&action=page&browse_id=' . $this->id . '&start=' . $next_offset . '&xoutput=raw&xoutputnode='. $this->get_content_div() . '&show_header=false' . $argument . '">' . T_('More') . '</a>';
} }
} }
/** /**
* set_filter_from_request * set_filter_from_request
* //FIXME * //FIXME
* @param array $request
*/ */
public function set_filter_from_request($request) public function set_filter_from_request($request)
{ {
@ -300,6 +404,11 @@ class Browse extends Query
} }
} // set_filter_from_request } // set_filter_from_request
/**
*
* @param string $type
* @param string $custom_base
*/
public function set_type($type, $custom_base = '') public function set_type($type, $custom_base = '')
{ {
$cn = 'browse_' . $type . '_pages'; $cn = 'browse_' . $type . '_pages';
@ -321,6 +430,11 @@ class Browse extends Query
parent::set_type($type, $custom_base); parent::set_type($type, $custom_base);
} }
/**
*
* @param string $option
* @param string $value
*/
public function save_cookie_params($option, $value) public function save_cookie_params($option, $value)
{ {
if ($this->get_type()) { if ($this->get_type()) {
@ -328,36 +442,96 @@ class Browse extends Query
} }
} }
/**
*
* @param boolean $use_pages
*/
public function set_use_pages($use_pages) public function set_use_pages($use_pages)
{ {
$this->save_cookie_params('pages', $use_pages ? 'true' : 'false'); $this->save_cookie_params('pages', $use_pages ? 'true' : 'false');
$this->_state['use_pages'] = $use_pages; $this->_state['use_pages'] = $use_pages;
} }
/**
*
* @return boolean
*/
public function get_use_pages() public function get_use_pages()
{ {
return $this->_state['use_pages']; return $this->_state['use_pages'];
} }
/**
*
* @param boolean $use_alpha
*/
public function set_use_alpha($use_alpha) public function set_use_alpha($use_alpha)
{ {
$this->save_cookie_params('alpha', $use_alpha ? 'true' : 'false'); $this->save_cookie_params('alpha', $use_alpha ? 'true' : 'false');
$this->_state['use_alpha'] = $use_alpha; $this->_state['use_alpha'] = $use_alpha;
} }
/**
*
* @return boolean
*/
public function get_use_alpha() public function get_use_alpha()
{ {
return $this->_state['use_alpha']; return $this->_state['use_alpha'];
} }
/**
*
* @param boolean $show_header
*/
public function set_show_header($show_header) public function set_show_header($show_header)
{ {
$this->show_header = $show_header; $this->show_header = $show_header;
} }
/**
* Allow the current page to be save into the current session
* @param boolean $update_session
*/
public function set_update_session($update_session)
{
$this->_state['update_session'] = $update_session;
}
/**
*
* @return boolean
*/
public function get_show_header() public function get_show_header()
{ {
return $this->show_header; return $this->show_header;
} }
/**
*
* @return boolean
*/
public function get_update_session()
{
return $this->_state['update_session'];
}
/**
*
* @param string $threshold
*/
public function set_threshold($threshold)
{
$this->_state['threshold'] = $threshold;
}
/**
*
* @return string
*/
public function get_threshold()
{
return $this->_state['threshold'];
}
} // browse } // browse

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
/** /**
* *
* LICENSE: GNU General Public License, version 2 (GPLv2) * LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2014 Ampache.org * Copyright 2001 - 2015 Ampache.org
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2 * modify it under the terms of the GNU General Public License v2
@ -20,7 +20,7 @@
* *
*/ */
class Channel extends database_object class Channel extends database_object implements media, library_item
{ {
public $id; public $id;
public $is_private; public $is_private;
@ -37,6 +37,11 @@ class Channel extends database_object
public $loop; public $loop;
public $bitrate; public $bitrate;
public $name; public $name;
public $description;
public $header_chunk;
public $chunk_size = 4096;
private $header_chunk_remainder = 0;
public $tags; public $tags;
public $f_tags; public $f_tags;
@ -100,10 +105,12 @@ class Channel extends database_object
{ {
$tags = Tag::get_object_tags('channel', $this->id); $tags = Tag::get_object_tags('channel', $this->id);
$genre = ""; $genre = "";
foreach ($tags as $tag) { if ($tags) {
$genre .= $tag['name'] . ' '; foreach ($tags as $tag) {
$genre .= $tag['name'] . ' ';
}
$genre = trim($genre);
} }
$genre = trim($genre);
return $genre; return $genre;
} }
@ -140,16 +147,18 @@ class Channel extends database_object
return false; return false;
} }
public function update($data) public function update(array $data)
{ {
if (isset($data['edit_tags'])) { if (isset($data['edit_tags'])) {
Tag::update_tag_list($data['edit_tags'], 'channel', $this->id); Tag::update_tag_list($data['edit_tags'], 'channel', $this->id, true);
} }
$sql = "UPDATE `channel` SET `name` = ?, `description` = ?, `url` = ?, `interface` = ?, `port` = ?, `fixed_endpoint` = ?, `admin_password` = ?, `is_private` = ?, `max_listeners` = ?, `random` = ?, `loop` = ?, `stream_type` = ?, `bitrate` = ?, `object_id` = ? " . $sql = "UPDATE `channel` SET `name` = ?, `description` = ?, `url` = ?, `interface` = ?, `port` = ?, `fixed_endpoint` = ?, `admin_password` = ?, `is_private` = ?, `max_listeners` = ?, `random` = ?, `loop` = ?, `stream_type` = ?, `bitrate` = ?, `object_id` = ? " .
"WHERE `id` = ?"; "WHERE `id` = ?";
$params = array($data['name'], $data['description'], $data['url'], $data['interface'], $data['port'], (!empty($data['interface']) && !empty($data['port'])), $data['admin_password'], !empty($data['private']), $data['max_listeners'], $data['random'], $data['loop'], $data['stream_type'], $data['bitrate'], $data['object_id'], $this->id); $params = array($data['name'], $data['description'], $data['url'], $data['interface'], $data['port'], (!empty($data['interface']) && !empty($data['port'])), $data['admin_password'], !empty($data['private']), $data['max_listeners'], $data['random'], $data['loop'], $data['stream_type'], $data['bitrate'], $data['object_id'], $this->id);
return Dba::write($sql, $params); Dba::write($sql, $params);
return $this->id;
} }
public static function format_type($type) public static function format_type($type)
@ -157,10 +166,10 @@ class Channel extends database_object
switch ($type) { switch ($type) {
case 'playlist': case 'playlist':
$ftype = $type; $ftype = $type;
break; break;
default: default:
$ftype = ''; $ftype = '';
break; break;
} }
return $ftype; return $ftype;
@ -178,10 +187,71 @@ class Channel extends database_object
} }
} }
public function format() public function format($details = true)
{ {
$this->tags = Tag::get_top_tags('channel', $this->id); if ($details) {
$this->f_tags = Tag::get_display($this->tags); $this->tags = Tag::get_top_tags('channel', $this->id);
$this->f_tags = Tag::get_display($this->tags, true, 'channel');
}
}
public function get_keywords()
{
return array();
}
public function get_fullname()
{
return $this->name;
}
public function get_parent()
{
return null;
}
public function get_childrens()
{
return array();
}
public function search_childrens($name)
{
return array();
}
public function get_medias($filter_type = null)
{
$medias = array();
if (!$filter_type || $filter_type == 'channel') {
$medias[] = array(
'object_type' => 'channel',
'object_id' => $this->id
);
}
return $medias;
}
public function get_user_owner()
{
return null;
}
public function get_default_art_kind()
{
return 'default';
}
public function get_description()
{
return $this->description;
}
public function display_art($thumb = 2)
{
if (Art::has_db($this->id, 'channel')) {
Art::display('channel', $this->id, $this->get_fullname(), $thumb, $this->link);
}
} }
public function get_target_object() public function get_target_object()
@ -345,24 +415,64 @@ class Channel extends database_object
if ($this->media != null) { if ($this->media != null) {
// Stream not yet initialized for this media, start it // Stream not yet initialized for this media, start it
if (!$this->transcoder) { if (!$this->transcoder) {
$this->transcoder = Stream::start_transcode($this->media, $this->stream_type, $this->bitrate); $options = array(
'bitrate' => $this->bitrate
);
$this->transcoder = Stream::start_transcode($this->media, $this->stream_type, null, $options);
$this->media_bytes_streamed = 0; $this->media_bytes_streamed = 0;
} }
if (is_resource($this->transcoder['handle'])) { if (is_resource($this->transcoder['handle'])) {
if (ftell($this->transcoder['handle']) == 0)
$chunk = fread($this->transcoder['handle'], 4096); $this->header_chunk = '';
$chunk = fread($this->transcoder['handle'], $this->chunk_size);
$this->media_bytes_streamed += strlen($chunk); $this->media_bytes_streamed += strlen($chunk);
if ((ftell($this->transcoder['handle']) < 10000 && strtolower($this->stream_type) == "ogg") || $this->header_chunk_remainder) {
//debug_event('channel', 'File handle pointer: ' . ftell($this->transcoder['handle']) ,'5');
$clchunk = $chunk;
if ($this->header_chunk_remainder) {
$this->header_chunk .= substr($clchunk, 0, $this->header_chunk_remainder);
if (strlen($clchunk) >= $this->header_chunk_remainder) {
$clchunk = substr($clchunk, $this->header_chunk_remainder);
$this->header_chunk_remainder = 0;
} else {
$this->header_chunk_remainder = $this->header_chunk_remainder - strlen($clchunk);
$clchunk = '';
}
}
// see bin/channel_run.inc for explanation what's happening here
while ($this->strtohex(substr($clchunk, 0, 4)) == "4F676753") {
$hex = $this->strtohex(substr($clchunk, 0, 27));
$ogg_nr_of_segments = hexdec(substr($hex, 26*2, 2));
if ((substr($clchunk, 27 + $ogg_nr_of_segments + 1, 6) == "vorbis") || (substr($clchunk, 27 + $ogg_nr_of_segments, 4) == "Opus")) {
$hex .= $this->strtohex(substr($clchunk, 27, $ogg_nr_of_segments));
$ogg_sum_segm_laces = 0;
for ($segm = 0; $segm < $ogg_nr_of_segments; $segm++) {
$ogg_sum_segm_laces += hexdec(substr($hex, 27*2 + $segm*2, 2));
}
$this->header_chunk .= substr($clchunk, 0, 27 + $ogg_nr_of_segments + $ogg_sum_segm_laces);
if (strlen($clchunk) < (27 + $ogg_nr_of_segments + $ogg_sum_segm_laces))
$this->header_chunk_remainder = (int) (27 + $ogg_nr_of_segments + $ogg_sum_segm_laces - strlen($clchunk));
$clchunk = substr($clchunk, 27 + $ogg_nr_of_segments + $ogg_sum_segm_laces);
} else //no more interesting headers
$clchunk = '';
}
}
//debug_event('channel', 'File handle pointer: ' . ftell($this->transcoder['handle']) ,'5');
//debug_event('channel', 'CHUNK : ' . $chunk, '5');
//debug_event('channel', 'Chunk size: ' . strlen($chunk) ,'5');
// End of file, prepare to move on for next call // End of file, prepare to move on for next call
if (feof($this->transcoder['handle'])) { if (feof($this->transcoder['handle'])) {
$this->media->set_played(); $this->media->set_played(-1, 'Ampache', array());
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') { if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
fread($this->transcoder['stderr'], 4096); fread($this->transcoder['stderr'], 4096);
fclose($this->transcoder['stderr']); fclose($this->transcoder['stderr']);
} }
fclose($this->transcoder['handle']); fclose($this->transcoder['handle']);
proc_close($this->transcoder['process']); Stream::kill_process($this->transcoder);
$this->media = null; $this->media = null;
$this->transcoder = null; $this->transcoder = null;
@ -381,10 +491,55 @@ class Channel extends database_object
return $chunk; return $chunk;
} }
public static function play_url($oid, $additional_params='') /**
* get_catalogs
*
* Get all catalog ids related to this item.
* @return int[]
*/
public function get_catalogs()
{
return array();
}
public static function play_url($oid, $additional_params='', $player=null, $local=false)
{ {
$channel = new Channel($oid); $channel = new Channel($oid);
return $channel->get_stream_proxy_url() . '?rt=' . time() . '&filename=' . urlencode($channel->name) . '.' . $channel->stream_type . $additional_params; return $channel->get_stream_proxy_url() . '?rt=' . time() . '&filename=' . urlencode($channel->name) . '.' . $channel->stream_type . $additional_params;
} }
public function get_stream_types($player = null)
{
// Transcode is mandatory to keep a consistant stream
return array('transcode');
}
public function get_stream_name()
{
return $this->get_fullname();
}
public function set_played($user, $agent, $location)
{
// Do nothing
}
public function get_transcode_settings($target = null, $player = null, $options=array())
{
return false;
}
public static function gc()
{
}
private function strtohex($x)
{
$s='';
foreach(str_split($x) as $c) $s.=sprintf("%02X",ord($c));
return($s);
}
} // end of channel class } // end of channel class

View file

@ -0,0 +1,141 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2015 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.
*
*/
class Clip extends Video
{
public $artist;
public $song;
public $video;
public $f_artist;
public $f_song;
/**
* Constructor
* This pulls the clip information from the database and returns
* a constructed object
*/
public function __construct($id)
{
parent::__construct($id);
$info = $this->get_info($id);
foreach ($info as $key=>$value) {
$this->$key = $value;
}
return true;
} // Constructor
/**
* gc
*
* This cleans out unused clips
*/
public static function gc()
{
$sql = "DELETE FROM `clip` USING `clip` LEFT JOIN `video` ON `video`.`id` = `clip`.`id` " .
"WHERE `video`.`id` IS NULL";
Dba::write($sql);
}
/**
* create
* This takes a key'd array of data as input and inserts a new clip entry, it returns the record id
*/
public static function insert(array $data, $gtypes = array(), $options = array())
{
$sql = "INSERT INTO `clip` (`id`,`artist`,`song`) " .
"VALUES (?, ?, ?)";
Dba::write($sql, array($data['id'], $data['artist'], $data['song']));
return $data['id'];
} // create
/**
* update
* This takes a key'd array of data as input and updates a clip entry
*/
public function update(array $data)
{
$sql = "UPDATE `clip` SET `artist` = ?, `song` = ? WHERE `id` = ?";
Dba::write($sql, array($data['artist'], $data['song'], $this->id));
return $this->id;
} // update
/**
* format
* this function takes the object and reformats some values
*/
public function format($details = true)
{
parent::format($details);
if ($details) {
if ($this->artist) {
$artist = new Artist($this->artist);
$artist->format();
$this->f_artist = $artist->link;
}
if ($this->song) {
$song = new Song($this->song);
$song->format();
$this->f_song = $song->f_link;
}
}
return true;
} //format
/**
* Get item keywords for metadata searches.
* @return array
*/
public function get_keywords()
{
$keywords = parent::get_keywords();
if ($this->artist) {
$keywords['artist'] = array('important' => true,
'label' => T_('Artist'),
'value' => $this->f_artist);
}
return $keywords;
}
public function get_parent()
{
if ($this->artist) {
return array('object_type' => 'artist', 'object_id' => $this->artist);
}
return null;
}
} // Clip class

Some files were not shown because too many files have changed in this diff Show more