From 3d3038bf5a0e2863d46d12b60e8844143344cdb2 Mon Sep 17 00:00:00 2001 From: lachlan Date: Mon, 23 Aug 2021 16:25:02 +1000 Subject: [PATCH 1/5] make sure the url is set when pinging an existing session --- docs/examples/ampyche.py | 77 +++++++++++++++++++++++----------------- src/ampache.py | 8 +++-- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/docs/examples/ampyche.py b/docs/examples/ampyche.py index 7800828..a3ac514 100644 --- a/docs/examples/ampyche.py +++ b/docs/examples/ampyche.py @@ -102,6 +102,7 @@ def show_help(): TRANSCODE = 'raw' TYPE = 'song' NUMERIC = False +COMMAND = 'status' # get custom options from launch arguments for arguments in sys.argv: @@ -146,29 +147,38 @@ def __init__(self): self.ampache_apikey = self.conf.get('conf', 'ampache_apikey') self.ampache_session = self.conf.get('conf', 'ampache_session') self.api_format = self.conf.get('conf', 'api_format') + self.ampacheConnection = ampache.API() + self.ampacheConnection.set_format(self.api_format) # ping the last session to see if active - my_ping = ampache.ping(self.ampache_url, self.ampache_session, self.api_format) + my_ping = self.ampacheConnection.ping(self.ampache_url, self.ampache_session) if not my_ping: self.handshake() + if not my_ping: + print('CONNECTION ERROR') + return + + # workaround for bug + if not self.ampacheConnection.AMPACHE_URL: + self.ampacheConnection.AMPACHE_URL = self.ampache_url # get your lists self.list_songs = list() - if TYPE == 'playlist': - self.playlist_songs(OID) - if TYPE == 'song': - song = ampache.song(self.ampache_url, self.ampache_session, OID, self.api_format) - if self.api_format == 'xml': - for child in song: - if child.tag == 'song': - self.list_songs.append(child.attrib['id']) - else: - for child in song: - self.list_songs.append(child['id']) - + if OID > 0: + if TYPE == 'playlist': + self.playlist_songs(OID) + if TYPE == 'song': + song = self.ampacheConnection.song(OID) + if self.api_format == 'xml': + for child in song: + if child.tag == 'song': + self.list_songs.append(child.attrib['id']) + else: + for child in song: + self.list_songs.append(child['id']) # run your action if ACTION == 'ping': - print("\nSESSION: " + ampache.ping(self.ampache_url, self.ampache_session, self.api_format)) + print("\nSESSION: " + self.ampacheConnection.ping(self.ampache_url, self.ampache_session)) elif ACTION == 'configure': self.saveconf() elif ACTION == 'logout': @@ -229,17 +239,17 @@ def saveconf(self): def handshake(self): """ Log into Ampache """ - encrypted_key = ampache.encrypt_string(self.ampache_apikey, self.ampache_user) + encrypted_key = self.ampacheConnection.encrypt_string(self.ampache_apikey, self.ampache_user) # handshake - self.ampache_session = ampache.handshake(self.ampache_url, encrypted_key, False, False, '430000', self.api_format) + self.ampache_session = self.ampacheConnection.handshake(self.ampache_url, encrypted_key, False, False, '430000') # if you didn't get a sessoin there's nothing you can do if not self.ampache_session: print() sys.exit('ERROR: Failed to connect to ' + self.ampache_url) # did all this work? - my_ping = ampache.ping(self.ampache_url, self.ampache_session, self.api_format) + my_ping = self.ampacheConnection.ping(self.ampache_url, self.ampache_session) if not my_ping: print() sys.exit('ERROR: Failed to ping ' + self.ampache_url) @@ -255,23 +265,24 @@ def handshake(self): def quit(self): """ delete your session and close the program""" - return ampache.goodbye(self.ampache_url, self.ampache_session, self.api_format) + return self.ampacheConnection.goodbye(self.ampache_url, self.ampache_session) def playlists(self): """ print a list of playlists """ - playlists = ampache.playlists(self.ampache_url, self.ampache_session, False, False, 0, LIMIT, self.api_format) print("\nChecking for playlists\n") - if self.api_format == 'xml': - for child in playlists: - if child.tag == 'playlist': - print("\t" + child.attrib['id'] + ":\t" + child.find('name').text) - else: - for child in playlists: - print("\t" + child['id'] + ":\t" + child['name']) + playlists = self.ampacheConnection.playlists(False, False, 0, LIMIT) + if playlists: + if self.api_format == 'xml': + for child in playlists: + if child.tag == 'playlist': + print("\t" + child.attrib['id'] + ":\t" + child.find('name').text) + else: + for child in playlists: + print("\t" + child['id'] + ":\t" + child['name']) def playlist_songs(self, playlist_id): """ collect all the songs in chosen playlist into self.list_songs """ - playlist = ampache.playlist_songs(self.ampache_url, self.ampache_session, playlist_id, 0, LIMIT, self.api_format) + playlist = self.ampacheConnection.playlist_songs(playlist_id, 0, LIMIT) print("\nChecking for songs in playlist " + str(playlist_id) + " with a limit of " + str(LIMIT) + "\n") if self.api_format == 'xml': for child in playlist: @@ -283,7 +294,7 @@ def playlist_songs(self, playlist_id): def localplay(self, action, object_id='', object_type='', clear=0): """ Perform a localplay command/action """ - command = ampache.localplay(self.ampache_url, self.ampache_session, action, object_id, object_type, clear, self.api_format) + command = self.ampacheConnection.localplay(action, object_id, object_type, clear) result = False statuslist = list() @@ -308,7 +319,7 @@ def localplay(self, action, object_id='', object_type='', clear=0): # All commands except status have a single response which isn't that exciting if object_id: print(action + " to localplay: " + str(object_id)) - ampache.localplay(self.ampache_url, self.ampache_session, 'play', False, False, False, + self.ampacheConnection.localplay('play', False, False, False, self.api_format) else: print("\n" + action + " sent to localplay\n") @@ -326,7 +337,7 @@ def download(self, song_id, destination, transcode='raw'): """ Download the requested track This could be extended or changed to support lists""" # look for various Artists object_id = song_id - search_song = ampache.song(self.ampache_url, self.ampache_session, object_id, self.api_format) + search_song = self.ampacheConnection.song(object_id) list_songs = list() # get your song details into a list for child in search_song: @@ -366,8 +377,8 @@ def download(self, song_id, destination, transcode='raw'): if not os.path.isfile(output): # download this file if it's not already there print('OUTPUT: ' + output) - ampache.download(self.ampache_url, self.ampache_session, object_id[0], - 'song', output, transcode, self.api_format) + self.ampacheConnection.download(object_id[0], + 'song', output, transcode) else: # skip existing files print('**EXISTS**: ' + output) @@ -376,7 +387,7 @@ def stream(self, song_id, transcode='raw'): """ Download the requested track This could be extended or changed to support lists""" # look for various Artists object_id = song_id - search_song = ampache.song(self.ampache_url, self.ampache_session, object_id, self.api_format) + search_song = self.ampacheConnection.song(object_id) list_songs = list() # get your song details into a list for child in search_song: diff --git a/src/ampache.py b/src/ampache.py index a59cad6..57a270e 100644 --- a/src/ampache.py +++ b/src/ampache.py @@ -400,6 +400,8 @@ def ping(self, ampache_url: str, ampache_api: str = False, version: str = '5.0.0 if self.AMPACHE_API == 'json': json_data = json.loads(ampache_response.decode('utf-8')) if 'session_expire' in json_data: + if not self.AMPACHE_URL: + self.AMPACHE_URL = ampache_url self.AMPACHE_SESSION = ampache_api return ampache_api else: @@ -412,6 +414,9 @@ def ping(self, ampache_url: str, ampache_api: str = False, version: str = '5.0.0 return False try: tree.find('session_expire').text + if not self.AMPACHE_URL: + self.AMPACHE_URL = ampache_url + self.AMPACHE_SESSION = ampache_api except AttributeError: return False return ampache_api @@ -940,8 +945,7 @@ def song_delete(self, filter_id: int): return False return self.return_data(ampache_response) - def playlists(self, filter_str: str = False, - exact: int = False, offset=0, limit=0): + def playlists(self, filter_str: str = False, exact: int = False, offset=0, limit=0): """ playlists MINIMUM_API_VERSION=380001 From 53401f2b606bcff75471cb61e8a5f7e4c8d2b287 Mon Sep 17 00:00:00 2001 From: lachlan Date: Mon, 23 Aug 2021 16:36:00 +1000 Subject: [PATCH 2/5] Update ampyche.py --- docs/examples/ampyche.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/examples/ampyche.py b/docs/examples/ampyche.py index a3ac514..dfe3dec 100644 --- a/docs/examples/ampyche.py +++ b/docs/examples/ampyche.py @@ -158,9 +158,11 @@ def __init__(self): print('CONNECTION ERROR') return - # workaround for bug + # workaround for bugs if not self.ampacheConnection.AMPACHE_URL: self.ampacheConnection.AMPACHE_URL = self.ampache_url + if not self.ampacheConnection.AMPACHE_SESSION: + self.ampacheConnection.AMPACHE_SESSION = self.ampache_session # get your lists self.list_songs = list() From 443b1719b72f85f8af8b96aaa7eb07c71e18fd0b Mon Sep 17 00:00:00 2001 From: lachlan Date: Mon, 23 Aug 2021 16:37:58 +1000 Subject: [PATCH 3/5] Update ampyche.py --- docs/examples/ampyche.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/ampyche.py b/docs/examples/ampyche.py index dfe3dec..f1a7dca 100644 --- a/docs/examples/ampyche.py +++ b/docs/examples/ampyche.py @@ -166,7 +166,7 @@ def __init__(self): # get your lists self.list_songs = list() - if OID > 0: + if int(OID) > 0: if TYPE == 'playlist': self.playlist_songs(OID) if TYPE == 'song': From 018d2c397e2bfef4b6e0a7792b7558bd20c814d0 Mon Sep 17 00:00:00 2001 From: lachlan Date: Tue, 24 Aug 2021 11:25:03 +1000 Subject: [PATCH 4/5] fix up docs and artists call --- README.rst | 4 + docs/MANUAL.md | 1150 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ampache.py | 41 +- 3 files changed, 1177 insertions(+), 18 deletions(-) create mode 100644 docs/MANUAL.md diff --git a/README.rst b/README.rst index 53fdae4..3e1b9cd 100644 --- a/README.rst +++ b/README.rst @@ -14,6 +14,10 @@ A python3 library for interaction with your Ampache 5.x.x server using the XML & Code examples and scripts are available from github +The class documentation has been extracted out into a markdown file for easier reading. + +``_ + There has been a pretty significant change in the library between Ampache 4 and Ampache 5. For anyone wanting to stay on v4 the branch has been separated from the master branch. diff --git a/docs/MANUAL.md b/docs/MANUAL.md new file mode 100644 index 0000000..c62ae8d --- /dev/null +++ b/docs/MANUAL.md @@ -0,0 +1,1150 @@ +# Ampache class API (object) + +## Variables + +* AMPACHE_API ('xml'|'json') default: 'xml' +* AMPACHE_DEBUG (bool) default: False +* AMPACHE_URL (string) +* AMPACHE_SESSION (string) +* AMPACHE_USER (string) +* AMPACHE_KEY (string) + +## HELPER FUNCTIONS + +Functions that are used by the library to manipulate data, connect to Ampache or general processing + +### set_format + +set_format(myformat: str) + +Allow forcing a default format + +* myformat = (string) 'xml'|'json' + +### set_debug + +set_debug(mybool: bool) + +This function can be used to enable/disable debugging messages + +* bool = (boolean) Enable/disable debug messages + +### set_user + +set_user(myuser: str) + +Set the user string for connection + +* myuser (string) + +### set_key + +set_key(mykey: str) + +Set AMPACHE_KEY (api key or password) + +* mykey (string) + +### set_url + +set_url(myurl: str) + +Set the ampache url + +* myurl (string) + +### test_result + +test_result(result, title) + +This function can be used to enable/disable debugging messages + +* bool = (boolean) Enable/disable debug messages + +### return_data + +return_data(data) + +Return json or xml data based on api format + +* data (string) + +### get_id_list + +get_id_list(data, attribute: str) + +Return a list of id's from the data you've got from the api + +* data = (mixed) XML or JSON from the API +* attribute = (string) attribute you are searching for + +### get_object_list + +get_object_list(data, field: str, data_format: str = 'xml') @staticmethod + +return a list of objects from the data matching your field stirng + +* data = (mixed) XML or JSON from the API +* field = (string) field you are searching for +* data_format = (string) 'xml','json' + +### write_xml + +write_xml(xmlstr, filename: str) @staticmethod + +This function can be used to write your xml responses to a file. + +* xmlstr = (xml) xml to write to file +* filename = (string) path and filename (e.g. './ampache.xml') + +### get_message + +get_message(data) @staticmethod + +Return the string message text from the api response + +* data = (mixed) XML or JSON from the API + +### write_json + +write_json(json_data: str, filename: str) @staticmethod + +This function can be used to write your json responses to a file. + +* json_data = (json) json to write to file +* filename = (string) path and filename (e.g. './ampache.json') + +### encrypt_password + +encrypt_password(password: str, current_time: int) @staticmethod + +This function can be used to encrypt your password into the accepted format. + +* password = (string) unencrypted password string +* time = (integer) linux time + +### encrypt_string + +encrypt_string(api_key: str, username: str) @staticmethod + +This function can be used to encrypt your apikey into the accepted format. + +* api_key = (string) unencrypted apikey +* user = (string) username + +### fetch_url + +fetch_url(full_url: str, api_format: str, method: str) + +This function is used to fetch the string results using urllib + +* full_url = (string) url to fetch +* api_format = (string) 'xml'|'json' +* method = (string) + +## API FUNCTIONS + +All the Ampache functions from the API + +### handshake + +handshake(ampache_url: str, ampache_api: str, ampache_user: str = False, timestamp: int = 0, version: str = '5.0.0') + +This is the function that handles verifying a new handshake +Takes a timestamp, auth key, and username. + +* ampache_url = (string) Full Ampache URL e.g. 'https://music.com.au' +* ampache_api = (string) encrypted apikey OR password if using password auth +* user = (string) username //optional +* timestamp = (integer) UNIXTIME() //optional +* version = (string) //optional + +### ping + +ping(ampache_url: str, ampache_api: str = False, version: str = '5.0.0') + +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 + +* ampache_url = (string) Full Ampache URL e.g. 'https://music.com.au' +* ampache_api = (string) encrypted apikey //optional + +### goodbye + +goodbye() + +Destroy session for ampache_api auth key. + +### url_to_song + +url_to_song(url) + +This takes a url and returns the song object in question + +* url = (string) Full Ampache URL from server, translates back into a song XML + +### get_similar + +get_similar(object_type, filter_id: int, offset=0, limit=0) + +Return similar artist id's or similar song ids compared to the input filter + +* object_type = (string) 'song'|'album'|'artist'|'playlist' +* filter_id = (integer) $artist_id or song_id +* offset = (integer) //optional +* limit = (integer) //optional + +### get_indexes + +get_indexes(object_type, filter_str: str = False, exact: int = False, add: int = False, update: int = False, include=False, offset=0, limit=0) + +This takes a collection of inputs and returns ID + name for the object type + +* object_type = (string) 'song'|'album'|'artist'|'album_artist'|'playlist' +* filter_str = (string) search the name of the object_type //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* add = (integer) UNIXTIME() //optional +* update = (integer) UNIXTIME() //optional +* include = (integer) 0,1 include songs if available for that object //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### artists + +artists(filter_str: str = False, add: int = False, update: int = False, offset=0, limit=0, include=False) + +This takes a collection of inputs and returns artist objects. + +* filter_str = (string) search the name of an artist //optional +* add = (integer) UNIXTIME() //optional +* update = (integer) UNIXTIME() //optional +* offset = (integer) //optional +* limit = (integer) //optional +* include = (string) 'albums', 'songs' //optional +* album_artist = (boolean) 0,1 if true filter for album artists only //optional + +### artist + +artist(filter_id: int, include=False) + +This returns a single artist based on the UID of said artist + +* filter_id = (integer) $artist_id +* include = (string) 'albums', 'songs' //optional + +### artist_albums + +artist_albums(filter_id: int, offset=0, limit=0) + +This returns the albums of an artist + +* filter_id = (integer) $artist_id +* offset = (integer) //optional +* limit = (integer) //optional + +### artist_songs + +artist_songs(filter_id: int, offset=0, limit=0) + +This returns the songs of the specified artist + +* filter_id = (integer) $artist_id +* offset = (integer) //optional +* limit = (integer) //optional + +### albums + +albums(filter_str: str = False, exact=False, add: int = False, update: int = False, offset=0, limit=0, include=False) + +This returns albums based on the provided search filters + +* filter_str = (string) search the name of an album //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* add = (integer) UNIXTIME() //optional +* update = (integer) UNIXTIME() //optional +* offset = (integer) //optional +* limit = (integer) //optional +* include = (string) 'songs' //optional + +### album + +album(filter_id: int, include=False) + +This returns a single album based on the UID provided + +* filter_id = (integer) $album_id +* include = (string) 'songs' //optional + +### album_songs + +album_songs(filter_id: int, offset=0, limit=0) + +This returns the songs of a specified album + +* filter_id = (integer) $album_id +* offset = (integer) //optional +* limit = (integer) //optional + +### genres + +genres(filter_str: str = False, exact: int = False, offset=0, limit=0) + +This returns the genres (Tags) based on the specified filter + +* filter_str = (string) search the name of a genre //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### genre + +genre(filter_id: int) + +This returns a single genre based on UID + +* filter_id = (integer) $genre_id + +### genre_artists + +genre_artists(filter_id: int, offset=0, limit=0) + +This returns the artists associated with the genre in question as defined by the UID + +* filter_id = (integer) $genre_id +* offset = (integer) //optional +* limit = (integer) //optional + +### genre_albums + +genre_albums(filter_id: int, offset=0, limit=0) + +This returns the albums associated with the genre in question + +* filter_id = (integer) $genre_id +* offset = (integer) //optional +* limit = (integer) //optional + +### genre_songs + +genre_songs(filter_id: int, offset=0, limit=0) + +returns the songs for this genre + +* filter_id = (integer) $genre_id +* offset = (integer) //optional +* limit = (integer) //optional + +### songs + +songs(filter_str: str = False, exact: int = False, add: int = False, update: int = False, offset=0, limit=0) + +Returns songs based on the specified filter_str + +* filter_str = (string) search the name of a song //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* add = (integer) UNIXTIME() //optional +* update = (integer) UNIXTIME() //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### song + +song(filter_id: int) + +returns a single song + +* filter_id = (integer) $song_id + +### song_delete + +song_delete(filter_id: int) + +Delete an existing song. + +* filter_id = (string) UID of song to delete + +### playlists + +playlists(filter_str: str = False, exact: int = False, offset=0, limit=0) + +This returns playlists based on the specified filter + +* filter_str = (string) search the name of a playlist //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### playlist + +playlist(filter_id: int) + +This returns a single playlist + +* filter_id = (integer) $playlist_id + +### playlist_songs + +playlist_songs(filter_id: int, offset=0, limit=0) + +This returns the songs for a playlist + +* filter_id = (integer) $playlist_id +* offset = (integer) //optional +* limit = (integer) //optional + +### playlist_create + +playlist_create(name, object_type) + +This create a new playlist and return it + +* name = (string) +* object_type = (string) + +### playlist_edit + +playlist_edit(filter_id: int, name=False, object_type=False) + +This modifies name and type of a playlist + +* filter_id = (integer) +* name = (string) playlist name //optional +* object_type = (string) 'public'|'private' + +### playlist_delete + +playlist_delete(filter_id: int) + +This deletes a playlist + +* filter_id = (integer) $playlist_id + +### playlist_add_song + +playlist_add_song(filter_id: int, song_id, check=False) + +This adds a song to a playlist. +Added duplicate checks in 400003 + +* filter_id = (integer) $playlist_id +* song_id = (integer) $song_id +* check = (boolean|integer) (True,False | 0|1) Check for duplicates //optional + +### playlist_remove_song + +playlist_remove_song(filter_id: int, song_id=False, track=False) + + +This removes a song from a playlist. Previous versions required 'track' instead of 'song'. + +* filter_id = (integer) $playlist_id +* song_id = (integer) $song_id //optional +* track = (integer) $playlist_track number //optional + +### playlist_generate + +playlist_generate(mode='random', filter_str: str = False, album_id=False, artist_id=False, flagged=False, list_format='song', offset=0, limit=0) + +Get a list of song XML, indexes or id's based on some simple search criteria + +'recent' will search for tracks played after 'Popular Threshold' days + +'forgotten' will search for tracks played before 'Popular Threshold' days + +'unplayed' added in 400002 for searching unplayed tracks + +* mode = (string) 'recent', 'forgotten', 'unplayed', 'random' (default = 'random') //optional +* filter_str = (string) string LIKE matched to song title //optional +* album_id = (integer) $album_id //optional +* artist_id = (integer) $artist_id //optional +* flagged = (integer) get flagged songs only 0, 1 (default=0) //optional +* list_format = (string) 'song', 'index','id' (default = 'song') //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### shares + +shares(filter_str: str = False, exact: int = False, offset=0, limit=0) + +* filter_str = (string) search the name of a share //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### share + +share(filter_id: int) + +Return shares by UID + +* filter_id = (integer) UID of Share + +### share_create + +share_create(filter_id: int, object_type, description=False, expires=False) + +Create a public url that can be used by anyone to stream media. +Takes the file id with optional description and expires parameters. + +* filter_id = (integer) $object_id +* object_type = (string) object_type ('song', 'album', 'artist') +* description = (string) description (will be filled for you if empty) //optional +* expires = (integer) days to keep active //optional + +### share_edit + +share_edit(filter_id: int, can_stream=False, can_download=False, expires=False, description=False) + +Update the description and/or expiration date for an existing share. +Takes the share id to update with optional description and expires parameters. + +INPUT +* filter_id = (integer) UID of Share +* can_stream = (boolean) 0,1 //optional +* can_download = (boolean) 0,1 //optional +* expires = (integer) number of whole days before expiry //optional +* description = (string) update description //optional + +### share_delete + +share_delete(filter_id: int) + +Delete an existing share. + +INPUT +* filter_id = (integer) UID of Share to delete + +### catalogs + +catalogs(filter_str: str = False, offset=0, limit=0) + +* filter_str = (string) search the name of a catalog //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### catalog + +catalog(filter_id: int, offset=0, limit=0) + +Return catalogs by UID + +* filter_id = (integer) UID of catalog + +### catalog_action + +catalog_action(task, catalog_id) + +Kick off a catalog update or clean for the selected catalog + +* task = (string) 'add_to_catalog'|'clean_catalog'|'verify_catalog'|'gather_art' +* catalog_id = (integer) $catalog_id + +### catalog_file + +catalog_file(file, task, catalog_id) + +Perform actions on local catalog files. +Single file versions of catalog add, clean and verify. +Make sure you remember to urlencode those file names! + +* file = (string) urlencode(FULL path to local file) +* task = (string) 'add'|'clean'|'verify'|'remove' +* catalog_id = (integer) $catalog_id + +### podcasts + +podcasts(filter_str: str = False, exact: int = False, offset=0, limit=0) + +* filter_str = (string) search the name of a podcast //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### podcast + +podcast(filter_id: int, include=False) + +Return podcasts by UID + +* filter_id = (integer) UID of Podcast +* include = (string) 'episodes' Include episodes with the response //optional + +### podcast_create + +podcast_create(url, catalog_id) + +Return podcasts by UID + +* url = (string) rss url for podcast +* catalog_id = (string) podcast catalog + +### podcast_edit + +podcast_edit(filter_id: int, feed=False, title=False, website=False, description=False, generator=False, copyright_str=False) + +Update the description and/or expiration date for an existing podcast. +Takes the podcast id to update with optional description and expires parameters. + +* filter_id = (integer) $podcast_id +* feed = (string) feed url (xml!) //optional +* title = (string) title string //optional +* website = (string) source website url //optional +* description = (string) //optional +* generator = (string) //optional +* copyright_str = (string) //optional + +### podcast_delete + +podcast_delete(filter_id: int) + +Delete an existing podcast. + +* filter_id = (integer) UID of podcast to delete + +### podcast_episodes + +podcast_episodes(filter_id: int, offset=0, limit=0) + +* filter_id = (string) UID of podcast +* offset = (integer) //optional +* limit = (integer) //optional + +### podcast_episode + +podcast_episode(filter_id: int) + +Return podcast_episodes by UID + +* filter_id = (integer) UID of Podcast + +### podcast_episode_delete + +podcast_episode_delete(filter_id: int) + +Delete an existing podcast_episode. + +* filter_id = (integer) UID of podcast_episode to delete + +### update_podcast + +update_podcast(filter_id: int) + +Sync and download new podcast episodes + +* filter_id = (integer) UID of Podcast + +### search_songs + +search_songs(filter_str, offset=0, limit=0) + +This searches the songs and returns... songs + +* filter_str = (string) search the name of a song +* offset = (integer) //optional +* limit = (integer) //optional + +### advanced_search + +advanced_search(rules, operator='and', object_type='song', offset=0, limit=0, random=0) + +Perform an advanced search given passed rules +the rules can occur multiple times and are joined by the operator item. + +Refer to the wiki for further information +http://ampache.org/api/api-advanced-search + +* rules = (array) = [[rule_1,rule_1_operator,rule_1_input], [rule_2,rule_2_operator,rule_2_input], [etc]] +* operator = (string) 'and'|'or' (whether to match one rule or all) //optional +* object_type = (string) //optional +* offset = (integer) //optional +* limit = (integer) //optional +* random = (integer) 0|1' //optional + +### videos + +videos(filter_str: str = False, exact: int = False, offset=0, limit=0) + +This returns video objects! + +* filter_str = (string) search the name of a video //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### video + +video(filter_id: int) + +This returns a single video + +* filter_id = (integer) $video_id + +### localplay + +localplay(command, oid=False, otype=False, clear=0) + +This is for controlling localplay + +* command = (string) 'next', 'prev', 'stop', 'play', 'pause', 'add', 'volume_up', 'volume_down', 'volume_mute', 'delete_all', 'skip', 'status' +* oid = (integer) object_id //optional +* otype = (string) 'Song', 'Video', 'Podcast_Episode', 'Channel', 'Broadcast', 'Democratic', 'Live_Stream' //optional +* clear = (integer) 0,1 Clear the current playlist before adding //optional + +### localplay_songs + +localplay() + +Get the list of songs in your localplay playlist + +### democratic + +democratic(method, oid) + +This is for controlling democratic play + +* oid = (integer) object_id (song_id|playlist_id) +* method = (string) 'vote'|'devote'|'playlist'|'play' + +### stats + +stats(object_type, filter_str='random', username=False, user_id=False, offset=0, limit=0) + +This gets library stats for different object types. When filter is null get some random items instead + +* object_type = (string) 'song'|'album'|'artist' +* filter_str = (string) 'newest'|'highest'|'frequent'|'recent'|'flagged'|'random' +* offset = (integer) //optional +* limit = (integer) //optional +* user_id = (integer) //optional +* username = (string) //optional + +### users + +users() + +Get ids and usernames for your site users + +INPUTS + +### user + +user(username) + +This get an user public information + +* username = (string) + +### followers + +followers(username) + +This get an user followers + +* username = (string) + +### following + +following(username) + +This get the user list followed by an user + +* username = (string) + +### toggle_follow + +toggle_follow(username) + +This follow/unfollow an user + +* username = (string) + +### last_shouts + +last_shouts(username, limit=0) + +This get the latest posted shouts + +* username = (string) +* limit = (integer) //optional + +### rate + +rate(object_type, object_id, rating) + +This rates a library item + +* object_type = (string) 'song'|'album'|'artist' +* object_id = (integer) $object_id +* rating = (integer) 0|1|2|3|4|5 + +### flag + +flag(object_type, object_id, flagbool) + +This flags a library item as a favorite + +Setting flagbool to true (1) will set the flag +Setting flagbool to false (0) will remove the flag + +* object_type = (string) 'song'|'album'|'artist' +* object_id = (integer) $object_id +* flagbool = (boolean|integer) (True,False | 0|1) + +### record_play + +record_play(object_id, user_id, client='AmpacheAPI') + +Take a song_id and update the object_count and user_activity table with a play. +This allows other sources to record play history to ampache + +* object_id = (integer) $object_id +* user_id = (integer) $user_id +* client = (string) $agent //optional + +### scrobble + +scrobble(title, artist_name, album_name, mbtitle=False, mbartist=False, mbalbum=False, stime=False, client='AmpacheAPI') + +Search for a song using text info and then record a play if found. +This allows other sources to record play history to ampache + +* title = (string) song title +* artist_name = (string) artist name +* album_name = (string) album name +* mbtitle = (string) song mbid //optional +* mbartist = (string) artist mbid //optional +* mbalbum = (string) album mbid //optional +* stime = (integer) UNIXTIME() //optional +* client = (string) //optional + +### timeline + +timeline(username, limit=0, since=0) + +This get a user timeline + +* username = (string) +* limit = (integer) //optional +* since = (integer) UNIXTIME() //optional + +### friends_timeline + +friends_timeline(limit=0, since=0) + +This get current user friends timeline + +* limit = (integer) //optional +* since = (integer) UNIXTIME() //optional + +### update_from_tags + +update_from_tags(ampache_type, ampache_id) + +updates a single album,artist,song from the tag data + +* object_type = (string) 'artist'|'album'|'song' +* object_id = (integer) $artist_id, $album_id, $song_id + +### update_art + +update_art(ampache_type, ampache_id, overwrite=False) + +updates a single album, artist, song looking for art files +Doesn't overwrite existing art by default. + +* object_type = (string) 'artist'|'album'|'song' +* object_id = (integer) $artist_id, $album_id, $song_id +* overwrite = (boolean|integer) (True,False | 0|1) //optional + +### update_artist_info + +update_artist_info(object_id) + +Update artist information and fetch similar artists from last.fm +Make sure lastfm_api_key is set in your configuration file + +* object_id = (integer) $artist_id + +### stream + +stream(object_id, object_type, destination) + +stream a song or podcast episode + +* object_id = (string) $song_id / $podcast_episode_id +* object_type = (string) 'song'|'podcast' +* destination = (string) full file path + +### download + +download(object_id, object_type, destination, transcode='raw') + +download a song or podcast episode + +* object_id = (string) $song_id / $podcast_episode_id +* object_type = (string) 'song'|'podcast' +* destination = (string) full file path +* transcode = (string) 'mp3', 'ogg', etc. ('raw' / original by default) //optional + +### get_art + +get_art(object_id, object_type, destination) + +get the binary art for an item + +* object_id = (string) $song_id / $podcast_episode_id +* object_type = (string) 'song', 'artist', 'album', 'playlist', 'search', 'podcast' +* destination = (string) output file path + +### user_create + +user_create(username: str, password: str, email: str, fullname: str = False, disable=False) + +Create a new user. (Requires the username, password and email.) @param array $input + +* username = (string) $username +* password = (string) hash('sha256', $password)) +* email = (string) 'user@gmail.com' +* fullname = (string) //optional +* disable = (boolean|integer) (True,False | 0|1) //optional + +### user_update + +user_update(username, password=False, fullname=False, email=False, website=False, state=False, city=False, disable=False, maxbitrate=False) + +Update an existing user. @param array $input + +* username = (string) $username +* password = (string) hash('sha256', $password)) //optional +* fullname = (string) //optional +* email = (string) 'user@gmail.com' //optional +* website = (string) //optional +* state = (string) //optional +* city = (string) //optional +* disable = (boolean|integer) (True,False | 0|1) //optional +* maxbitrate = (string) //optional + +### user_delete + +user_delete(username) + +Delete an existing user. @param array $input + +* username = (string) $username + +### user_preferences + +user_preferences() + +Returns user_preferences + +INPUTS + +### user_preference + +user_preference(filter_str) + +Returns preference based on the specified filter_str + +* filter_str = (string) search the name of a preference //optional + +### system_preferences + +system_preferences() + +Returns system_preferences + +INPUTS + +### system_preference + +system_preference(filter_str) + +Returns preference based on the specified filter_str + +* filter_str = (string) search the name of a preference //optional + +### system_update + +system_update() + +update ampache + +INPUTS + +### preference_create + +preference_create(filter_str, type_str, default, category, description=False, subcategory=False, level=100) + +Returns preference based on the specified filter_str + +* filter_str = (string) search the name of a preference +* type_str = (string) 'boolean', 'integer', 'string', 'special' +* default = (string|integer) default value +* category = (string) 'interface', 'internal', 'options', 'playlist', 'plugins', 'streaming', 'system' +* description = (string) description of preference //optional +* subcategory = (string) $subcategory //optional +* level = (integer) access level required to change the value (default 100) //optional + +### preference_edit + +preference_edit(filter_str, value, apply_all=0) + +Returns preference based on the specified filter_str + +* filter_str = (string) search the name of a preference +* value = (string|integer) Preference value +* apply_all = (boolean) apply to all users //optional + +### preference_delete + +preference_delete(filter_str) + +Returns preference based on the specified filter_str + +* filter_str = (string) search the name of a preference + +### licenses + +licenses(filter_str: str = False, exact: int = False, add: int = False, update: int = False, offset=0, limit=0) + +Returns licenses based on the specified filter_str + +* filter_str = (string) search the name of a license //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* add = (integer) UNIXTIME() //optional +* update = (integer) UNIXTIME() //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### license + +license(filter_id: int) + +returns a single license + +* filter_id = (integer) $license_id + +### license_songs + +license_songs(filter_id: int) + +returns a songs for a single license ID + +* filter_id = (integer) $license_id + +### labels + +labels(filter_str: str = False, exact: int = False, offset=0, limit=0) + +Returns labels based on the specified filter_str + +* filter_str = (string) search the name of a label //optional +* exact = (integer) 0,1, if true filter is exact rather then fuzzy //optional +* offset = (integer) //optional +* limit = (integer) //optional + +### label + +label(filter_id: int) + +returns a single label + +* filter_id = (integer) $label_id + +### label_artists + +label_artists(filter_id: int) + +returns a artists for a single label ID + +* filter_id = (integer) $label_id + +### get_bookmark + +get_bookmark(filter_id: str, object_type: str) + +Get the bookmark from it's object_id and object_type. + +* filter_id = (integer) object_id +* object_type = (string) object_type ('song', 'video', 'podcast_episode') + +### bookmarks + +bookmarks() + +Get information about bookmarked media this user is allowed to manage. + +INPUTS + +### bookmark_create + +bookmark_create(filter_id, object_type, position: int = 0, client: str = 'AmpacheAPI', date=False) + +Create a placeholder for the current media that you can return to later. + +* filter_id = (integer) object_id +* object_type = (string) object_type ('song', 'video', 'podcast_episode') +* position = (integer) current track time in seconds +* client = (string) Agent string. (Default: 'AmpacheAPI') //optional +* date = (integer) update time (Default: UNIXTIME()) //optional + +### bookmark_edit + +bookmark_edit(filter_id, object_type, position: int = 0, client: str = 'AmpacheAPI', date=False) + +Edit a placeholder for the current media that you can return to later. + +* filter_id = (integer) object_id +* object_type = (string) object_type ('song', 'video', 'podcast_episode') +* position = (integer) current track time in seconds +* client = (string) Agent string. (Default: 'AmpacheAPI') //optional +* date = (integer) update time (Default: UNIXTIME()) //optional + +### bookmark_delete + +bookmark_delete(filter_id: int, object_type=False) + +Delete an existing bookmark. (if it exists) + +* filter_id = (integer) object_id +* object_type = (string) object_type ('song', 'video', 'podcast_episode') + +### deleted_songs + +deleted_songs(offset=0, limit=0) + +Returns deleted_song + +* offset = (integer) //optional +* limit = (integer) //optional + +### deleted_podcast_episodes + +deleted_podcast_episodes(offset=0, limit=0) + +Returns deleted_podcast_episode + +* offset = (integer) //optional +* limit = (integer) //optional + +### deleted_videos + +deleted_videos(offset=0, limit=0) + +Returns deleted_video + +* offset = (integer) //optional +* limit = (integer) //optional + +## BACKWARD COMPATIBLE FUNCTION NAMES + +Renamed Ampache 4 functions that are not part of Ampache 5 + +* tag = genre +* tags = genres +* tag_artists = genre_artists +* tag_albums = genre_albums +* tag_songs = genre_songs + + diff --git a/src/ampache.py b/src/ampache.py index 57a270e..7e72c80 100644 --- a/src/ampache.py +++ b/src/ampache.py @@ -82,22 +82,22 @@ def set_debug(self, mybool: bool): def set_user(self, myuser: str): """ set_user - set user for connection + Set the user string for connection INPUTS - * myuser = (string) 'xml'|'json' + * myuser = (string) '' """ self.AMPACHE_USER = myuser def set_key(self, mykey: str): """ set_key - set api key + set AMPACHE_KEY (api key or password) INPUTS - * mykey = (string) 'xml'|'json' + * mykey = (string) '' """ - self.AMPACHE_API = mykey + self.AMPACHE_KEY = mykey def set_url(self, myurl: str): """ set_url @@ -105,7 +105,7 @@ def set_url(self, myurl: str): set the ampache url INPUTS - * myurl = (string) 'xml'|'json' + * myurl = (string) '' """ self.AMPACHE_URL = myurl @@ -130,6 +130,13 @@ def test_result(self, result, title): return False def return_data(self, data): + """ return_data + + return json or xml data based on api format + + INPUTS + * data = (string) + """ # json format if self.AMPACHE_API == 'json': json_data = json.loads(data.decode('utf-8')) @@ -212,9 +219,9 @@ def write_xml(xmlstr, filename: str): @staticmethod def get_message(data): - """ get_id_list + """ get_message - return a list of objects from the data matching your field stirng + Return the string message text from the api response INPUTS * data = (mixed) XML or JSON from the API @@ -533,7 +540,7 @@ def get_indexes(self, object_type, return self.return_data(ampache_response) def artists(self, filter_str: str = False, - add: int = False, update: int = False, offset=0, limit=0, include=False): + add: int = False, update: int = False, offset=0, limit=0, include=False, album_artist=False): """ artists MINIMUM_API_VERSION=380001 @@ -547,7 +554,6 @@ def artists(self, filter_str: str = False, * limit = (integer) //optional * include = (string) 'albums', 'songs' //optional * album_artist = (boolean) 0,1 if true filter for album artists only //optional - * self.AMPACHE_API = (string) 'xml'|'json' //optional """ ampache_url = self.AMPACHE_URL + '/server/' + self.AMPACHE_API + '.server.php' if bool(include) and not isinstance(include, str): @@ -559,7 +565,8 @@ def artists(self, filter_str: str = False, 'update': update, 'offset': str(offset), 'limit': str(limit), - 'include': include} + 'include': include, + 'album_artist': album_artist} if not filter_str: data.pop('filter') if not add: @@ -568,6 +575,8 @@ def artists(self, filter_str: str = False, data.pop('update') if not include: data.pop('include') + if not album_artist: + data.pop('album_artist') data = urllib.parse.urlencode(data) full_url = ampache_url + '?' + data ampache_response = self.fetch_url(full_url, self.AMPACHE_API, 'artists') @@ -1294,7 +1303,6 @@ def share_edit(self, filter_id: int, can_stream=False, can_download=False, * can_download = (boolean) 0,1 //optional * expires = (integer) number of whole days before expiry //optional * description = (string) update description //optional - * self.AMPACHE_API = (string) 'xml'|'json' //optional """ ampache_url = self.AMPACHE_URL + '/server/' + self.AMPACHE_API + '.server.php' data = {'action': 'share_edit', @@ -1327,7 +1335,7 @@ def share_delete(self, filter_id: int): INPUT * filter_id = (integer) UID of Share to delete - """ + """ ampache_url = self.AMPACHE_URL + '/server/' + self.AMPACHE_API + '.server.php' data = {'action': 'share_delete', 'auth': self.AMPACHE_SESSION, @@ -1525,7 +1533,6 @@ def podcast_edit(self, filter_id: int, * description = (string) //optional * generator = (string) //optional * copyright_str = (string) //optional - * self.AMPACHE_API = (string) 'xml'|'json' //optional """ ampache_url = self.AMPACHE_URL + '/server/' + self.AMPACHE_API + '.server.php' data = {'action': 'podcast_edit', @@ -1813,12 +1820,10 @@ def localplay(self, command, oid=False, otype=False, clear=0): return self.return_data(ampache_response) def localplay_songs(self): - """ localplay + """ localplay_songs MINIMUM_API_VERSION=5.0.0 - This is for controlling localplay - - INPUTS + Get the list of songs in your localplay playlist """ ampache_url = self.AMPACHE_URL + '/server/' + self.AMPACHE_API + '.server.php' data = {'action': 'localplay_songs', From 6d47341bca8f1f8fffc2c84ad732f52a54b74d69 Mon Sep 17 00:00:00 2001 From: lachlan Date: Tue, 24 Aug 2021 11:34:17 +1000 Subject: [PATCH 5/5] Update _meta.py --- src/_meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_meta.py b/src/_meta.py index d209c37..32694b3 100644 --- a/src/_meta.py +++ b/src/_meta.py @@ -14,6 +14,6 @@ """ __author__ = "Lachlan de Waard (lachlan-00)" -__version__ = "5.0.0" +__version__ = "5.0.1" DEBUG = False