commit
71bef027c4
178
pylast.py
178
pylast.py
|
@ -18,7 +18,7 @@
|
|||
#
|
||||
# http://code.google.com/p/pylast/
|
||||
|
||||
__version__ = '0.5'
|
||||
__version__ = '0.6'
|
||||
__author__ = 'Amr Hassan'
|
||||
__copyright__ = "Copyright (C) 2008-2010 Amr Hassan"
|
||||
__license__ = "apache2"
|
||||
|
@ -47,7 +47,7 @@ if sys.version_info[0] == 3:
|
|||
|
||||
elif sys.version_info[0] == 2:
|
||||
from httplib import HTTPConnection
|
||||
import htmlentitydefs
|
||||
import htmlentitydefs
|
||||
from urllib import splithost as url_split_host
|
||||
from urllib import quote_plus as url_quote_plus
|
||||
|
||||
|
@ -143,7 +143,7 @@ class _Network(object):
|
|||
"""
|
||||
|
||||
self.name = name
|
||||
self.homepage = homepage
|
||||
self.homepage = homepage
|
||||
self.ws_server = ws_server
|
||||
self.api_key = api_key
|
||||
self.api_secret = api_secret
|
||||
|
@ -241,13 +241,13 @@ class _Network(object):
|
|||
|
||||
Quote from http://www.last.fm/api/submissions:
|
||||
========
|
||||
Client identifiers are used to provide a centrally managed database of
|
||||
the client versions, allowing clients to be banned if they are found to
|
||||
be behaving undesirably. The client ID is associated with a version
|
||||
number on the server, however these are only incremented if a client is
|
||||
Client identifiers are used to provide a centrally managed database of
|
||||
the client versions, allowing clients to be banned if they are found to
|
||||
be behaving undesirably. The client ID is associated with a version
|
||||
number on the server, however these are only incremented if a client is
|
||||
banned and do not have to reflect the version of the actual client application.
|
||||
|
||||
During development, clients which have not been allocated an identifier should
|
||||
During development, clients which have not been allocated an identifier should
|
||||
use the identifier tst, with a version number of 1.0. Do not distribute code or
|
||||
client implementations which use this test identifier. Do not use the identifiers
|
||||
used by other clients.
|
||||
|
@ -257,7 +257,7 @@ class _Network(object):
|
|||
* Last.fm: submissions@last.fm
|
||||
* # TODO: list others
|
||||
|
||||
...and provide us with the name of your client and its homepage address.
|
||||
...and provide us with the name of your client and its homepage address.
|
||||
"""
|
||||
|
||||
_deprecation_warning("Use _Network.scrobble(...), _Network.scrobble_many(...), and Netowrk.update_now_playing(...) instead")
|
||||
|
@ -353,7 +353,7 @@ class _Network(object):
|
|||
def enable_caching(self, file_path = None):
|
||||
"""Enables caching request-wide for all cachable calls.
|
||||
|
||||
* file_path: A file path for the backend storage file. If
|
||||
* file_path: A file path for the backend storage file. If
|
||||
None set, a temp file would probably be created, according the backend.
|
||||
"""
|
||||
|
||||
|
@ -435,10 +435,10 @@ class _Network(object):
|
|||
|
||||
return Album(_extract(doc, "artist"), _extract(doc, "name"), self)
|
||||
|
||||
def update_now_playing(self, artist, title, album = None, album_artist = None,
|
||||
def update_now_playing(self, artist, title, album = None, album_artist = None,
|
||||
duration = None, track_number = None, mbid = None, context = None):
|
||||
"""
|
||||
Used to notify Last.fm that a user has started listening to a track.
|
||||
Used to notify Last.fm that a user has started listening to a track.
|
||||
|
||||
Parameters:
|
||||
artist (Required) : The artist name
|
||||
|
@ -462,7 +462,7 @@ class _Network(object):
|
|||
|
||||
_Request(self, "track.updateNowPlaying", params).execute()
|
||||
|
||||
def scrobble(self, artist, title, timestamp, album = None, album_artist = None, track_number = None,
|
||||
def scrobble(self, artist, title, timestamp, album = None, album_artist = None, track_number = None,
|
||||
duration = None, stream_id = None, context = None, mbid = None):
|
||||
|
||||
"""Used to add a track-play to a user's profile.
|
||||
|
@ -578,7 +578,7 @@ class LastFMNetwork(_Network):
|
|||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "pylast.LastFMNetwork(%s)" %(", ".join(("'%s'" %self.api_key, "'%s'" %self.api_secret, "'%s'" %self.session_key,
|
||||
return "pylast.LastFMNetwork(%s)" %(", ".join(("'%s'" %self.api_key, "'%s'" %self.api_secret, "'%s'" %self.session_key,
|
||||
"'%s'" %self.username, "'%s'" %self.password_hash)))
|
||||
|
||||
def __str__(self):
|
||||
|
@ -661,7 +661,7 @@ class LibreFMNetwork(_Network):
|
|||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "pylast.LibreFMNetwork(%s)" %(", ".join(("'%s'" %self.api_key, "'%s'" %self.api_secret, "'%s'" %self.session_key,
|
||||
return "pylast.LibreFMNetwork(%s)" %(", ".join(("'%s'" %self.api_key, "'%s'" %self.api_secret, "'%s'" %self.session_key,
|
||||
"'%s'" %self.username, "'%s'" %self.password_hash)))
|
||||
|
||||
def __str__(self):
|
||||
|
@ -788,7 +788,7 @@ class _Request(object):
|
|||
"Content-type": "application/x-www-form-urlencoded",
|
||||
'Accept-Charset': 'utf-8',
|
||||
'User-Agent': "pylast" + '/' + __version__
|
||||
}
|
||||
}
|
||||
|
||||
(HOST_NAME, HOST_SUBDIR) = self.network.ws_server
|
||||
|
||||
|
@ -796,7 +796,7 @@ class _Request(object):
|
|||
conn = HTTPConnection(host = self._get_proxy()[0], port = self._get_proxy()[1])
|
||||
|
||||
try:
|
||||
conn.request(method='POST', url="http://" + HOST_NAME + HOST_SUBDIR,
|
||||
conn.request(method='POST', url="http://" + HOST_NAME + HOST_SUBDIR,
|
||||
body=data, headers=headers)
|
||||
except Exception as e:
|
||||
raise NetworkError(self.network, e)
|
||||
|
@ -864,7 +864,7 @@ class SessionKeyGenerator(object):
|
|||
manually, unless you want to.
|
||||
"""
|
||||
|
||||
def __init__(self, network):
|
||||
def __init__(self, network):
|
||||
self.network = network
|
||||
self.web_auth_tokens = {}
|
||||
|
||||
|
@ -1272,7 +1272,7 @@ class Album(_BaseObject, _Taggable):
|
|||
return _extract(self._request("album.getInfo", cacheable = True), "mbid")
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the album page on the network.
|
||||
"""Returns the url of the album page on the network.
|
||||
# Parameters:
|
||||
* domain_name str: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
|
@ -1537,10 +1537,10 @@ class Artist(_BaseObject, _Taggable):
|
|||
return seq
|
||||
|
||||
def share(self, users, message = None):
|
||||
"""Shares this artist (sends out recommendations).
|
||||
"""Shares this artist (sends out recommendations).
|
||||
# Parameters:
|
||||
* users [User|str,]: A list that can contain usernames, emails, User objects, or all of them.
|
||||
* message str: A message to include in the recommendation message.
|
||||
* message str: A message to include in the recommendation message.
|
||||
"""
|
||||
|
||||
#last.fm currently accepts a max of 10 recipient at a time
|
||||
|
@ -1565,7 +1565,7 @@ class Artist(_BaseObject, _Taggable):
|
|||
self._request('artist.share', False, params)
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the artist page on the network.
|
||||
"""Returns the url of the artist page on the network.
|
||||
# Parameters:
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
|
@ -1579,7 +1579,7 @@ class Artist(_BaseObject, _Taggable):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
artist = _url_safe(self.get_name())
|
||||
|
@ -1675,7 +1675,7 @@ class Event(_BaseObject):
|
|||
* attending_status: The attending status. Possible values:
|
||||
o EVENT_ATTENDING
|
||||
o EVENT_MAYBE_ATTENDING
|
||||
o EVENT_NOT_ATTENDING
|
||||
o EVENT_NOT_ATTENDING
|
||||
"""
|
||||
|
||||
params = self._get_params()
|
||||
|
@ -1735,7 +1735,7 @@ class Event(_BaseObject):
|
|||
v = doc.getElementsByTagName("venue")[0]
|
||||
venue_id = _number(_extract(v, "id"))
|
||||
|
||||
return Venue(venue_id, self.network)
|
||||
return Venue(venue_id, self.network, venue_element=v)
|
||||
|
||||
def get_start_date(self):
|
||||
"""Returns the date when the event starts."""
|
||||
|
@ -1781,7 +1781,7 @@ class Event(_BaseObject):
|
|||
return _number(_extract(doc, "reviews"))
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the event page on the network.
|
||||
"""Returns the url of the event page on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -1794,15 +1794,15 @@ class Event(_BaseObject):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
return self.network._get_url(domain_name, "event") %{'id': self.get_id()}
|
||||
|
||||
def share(self, users, message = None):
|
||||
"""Shares this event (sends out recommendations).
|
||||
"""Shares this event (sends out recommendations).
|
||||
* users: A list that can contain usernames, emails, User objects, or all of them.
|
||||
* message: A message to include in the recommendation message.
|
||||
* message: A message to include in the recommendation message.
|
||||
"""
|
||||
|
||||
#last.fm currently accepts a max of 10 recipient at a time
|
||||
|
@ -1919,7 +1919,7 @@ class Country(_BaseObject):
|
|||
return seq
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the event page on the network.
|
||||
"""Returns the url of the event page on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -1932,7 +1932,7 @@ class Country(_BaseObject):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
country_name = _url_safe(self.get_name())
|
||||
|
@ -2188,7 +2188,7 @@ class Playlist(_BaseObject):
|
|||
return _extract(self._get_info_node(), "image")[size]
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the playlist on the network.
|
||||
"""Returns the url of the playlist on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -2201,7 +2201,7 @@ class Playlist(_BaseObject):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
english_url = _extract(self._get_info_node(), "url")
|
||||
|
@ -2334,7 +2334,7 @@ class Tag(_BaseObject):
|
|||
return seq
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the tag page on the network.
|
||||
"""Returns the url of the tag page on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -2347,7 +2347,7 @@ class Tag(_BaseObject):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
name = _url_safe(self.get_name())
|
||||
|
@ -2563,9 +2563,9 @@ class Track(_BaseObject, _Taggable):
|
|||
return seq
|
||||
|
||||
def share(self, users, message = None):
|
||||
"""Shares this track (sends out recommendations).
|
||||
"""Shares this track (sends out recommendations).
|
||||
* users: A list that can contain usernames, emails, User objects, or all of them.
|
||||
* message: A message to include in the recommendation message.
|
||||
* message: A message to include in the recommendation message.
|
||||
"""
|
||||
|
||||
#last.fm currently accepts a max of 10 recipient at a time
|
||||
|
@ -2590,7 +2590,7 @@ class Track(_BaseObject, _Taggable):
|
|||
self._request('track.share', False, params)
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the track page on the network.
|
||||
"""Returns the url of the track page on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -2603,7 +2603,7 @@ class Track(_BaseObject, _Taggable):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
artist = _url_safe(self.get_artist().get_name())
|
||||
|
@ -2722,7 +2722,7 @@ class Group(_BaseObject):
|
|||
return seq
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the group page on the network.
|
||||
"""Returns the url of the group page on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -2735,7 +2735,7 @@ class Group(_BaseObject):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
name = _url_safe(self.get_name())
|
||||
|
@ -2847,13 +2847,13 @@ class User(_BaseObject):
|
|||
|
||||
for e_id in ids:
|
||||
events.append(Event(e_id, self.network))
|
||||
|
||||
|
||||
return events
|
||||
|
||||
|
||||
def get_artist_tracks(self, artist):
|
||||
"""Get a list of tracks by a given artist scrobbled by this user, including scrobble time."""
|
||||
# Not implemented: "Can be limited to specific timeranges, defaults to all time."
|
||||
|
||||
|
||||
params = self._get_params()
|
||||
params['artist'] = artist
|
||||
|
||||
|
@ -2863,14 +2863,14 @@ class User(_BaseObject):
|
|||
artist = _extract(track, "artist")
|
||||
date = _extract(track, "date")
|
||||
timestamp = track.getElementsByTagName("date")[0].getAttribute("uts")
|
||||
|
||||
|
||||
seq.append(PlayedTrack(Track(artist, title, self.network), date, timestamp))
|
||||
|
||||
return seq
|
||||
|
||||
def get_friends(self, limit = 50):
|
||||
"""Returns a list of the user's friends. """
|
||||
|
||||
|
||||
seq = []
|
||||
for node in _collect_nodes(limit, self, "user.getFriends", False):
|
||||
seq.append(User(_extract(node, "name"), self.network))
|
||||
|
@ -3052,13 +3052,13 @@ class User(_BaseObject):
|
|||
return _number(_extract(doc, "playcount"))
|
||||
|
||||
def get_top_albums(self, period = PERIOD_OVERALL):
|
||||
"""Returns the top albums played by a user.
|
||||
"""Returns the top albums played by a user.
|
||||
* period: The period of time. Possible values:
|
||||
o PERIOD_OVERALL
|
||||
o PERIOD_7DAYS
|
||||
o PERIOD_3MONTHS
|
||||
o PERIOD_6MONTHS
|
||||
o PERIOD_12MONTHS
|
||||
o PERIOD_12MONTHS
|
||||
"""
|
||||
|
||||
params = self._get_params()
|
||||
|
@ -3077,13 +3077,13 @@ class User(_BaseObject):
|
|||
return seq
|
||||
|
||||
def get_top_artists(self, period = PERIOD_OVERALL):
|
||||
"""Returns the top artists played by a user.
|
||||
"""Returns the top artists played by a user.
|
||||
* period: The period of time. Possible values:
|
||||
o PERIOD_OVERALL
|
||||
o PERIOD_7DAYS
|
||||
o PERIOD_3MONTHS
|
||||
o PERIOD_6MONTHS
|
||||
o PERIOD_12MONTHS
|
||||
o PERIOD_12MONTHS
|
||||
"""
|
||||
|
||||
params = self._get_params()
|
||||
|
@ -3101,8 +3101,8 @@ class User(_BaseObject):
|
|||
return seq
|
||||
|
||||
def get_top_tags(self, limit=None):
|
||||
"""Returns a sequence of the top tags used by this user with their counts as TopItem objects.
|
||||
* limit: The limit of how many tags to return.
|
||||
"""Returns a sequence of the top tags used by this user with their counts as TopItem objects.
|
||||
* limit: The limit of how many tags to return.
|
||||
"""
|
||||
|
||||
doc = self._request("user.getTopTags", True)
|
||||
|
@ -3117,13 +3117,13 @@ class User(_BaseObject):
|
|||
return seq
|
||||
|
||||
def get_top_tracks(self, period = PERIOD_OVERALL):
|
||||
"""Returns the top tracks played by a user.
|
||||
"""Returns the top tracks played by a user.
|
||||
* period: The period of time. Possible values:
|
||||
o PERIOD_OVERALL
|
||||
o PERIOD_7DAYS
|
||||
o PERIOD_3MONTHS
|
||||
o PERIOD_6MONTHS
|
||||
o PERIOD_12MONTHS
|
||||
o PERIOD_12MONTHS
|
||||
"""
|
||||
|
||||
params = self._get_params()
|
||||
|
@ -3245,7 +3245,7 @@ class User(_BaseObject):
|
|||
return _extract(doc, "image")
|
||||
|
||||
def get_url(self, domain_name = DOMAIN_ENGLISH):
|
||||
"""Returns the url of the user page on the network.
|
||||
"""Returns the url of the user page on the network.
|
||||
* domain_name: The network's language domain. Possible values:
|
||||
o DOMAIN_ENGLISH
|
||||
o DOMAIN_GERMAN
|
||||
|
@ -3258,7 +3258,7 @@ class User(_BaseObject):
|
|||
o DOMAIN_TURKISH
|
||||
o DOMAIN_RUSSIAN
|
||||
o DOMAIN_JAPANESE
|
||||
o DOMAIN_CHINESE
|
||||
o DOMAIN_CHINESE
|
||||
"""
|
||||
|
||||
name = _url_safe(self.get_name())
|
||||
|
@ -3474,13 +3474,25 @@ class Venue(_BaseObject):
|
|||
"""A venue where events are held."""
|
||||
|
||||
# TODO: waiting for a venue.getInfo web service to use.
|
||||
# TODO: As an intermediate use case, can pass the venue DOM element when using
|
||||
# Event.get_venue() to populate the venue info, if the venue.getInfo API
|
||||
# call becomes available this workaround should be removed
|
||||
|
||||
id = None
|
||||
info = None
|
||||
name = None
|
||||
location = None
|
||||
url = None
|
||||
|
||||
def __init__(self, id, network):
|
||||
def __init__(self, id, network, venue_element=None):
|
||||
_BaseObject.__init__(self, network)
|
||||
|
||||
self.id = _number(id)
|
||||
if venue_element is not None:
|
||||
self.info = _extract_element_tree(venue_element)
|
||||
self.name = self.info.get('name')
|
||||
self.url = self.info.get('url')
|
||||
self.location = self.info.get('location')
|
||||
|
||||
def __repr__(self):
|
||||
return "pylast.Venue(%s, %s)" %(repr(self.id), repr(self.network))
|
||||
|
@ -3500,6 +3512,21 @@ class Venue(_BaseObject):
|
|||
|
||||
return self.id
|
||||
|
||||
def get_name(self):
|
||||
"""Returns the name of the venue."""
|
||||
|
||||
return self.name
|
||||
|
||||
def get_url(self):
|
||||
"""Returns the URL of the venue page."""
|
||||
|
||||
return self.url
|
||||
|
||||
def get_location(self):
|
||||
"""Returns the location of the venue (dictionary)."""
|
||||
|
||||
return self.location
|
||||
|
||||
def get_upcoming_events(self):
|
||||
"""Returns the upcoming events in this venue."""
|
||||
|
||||
|
@ -3590,14 +3617,14 @@ def _collect_nodes(limit, sender, method_name, cacheable, params=None):
|
|||
total_pages = _number(main.getAttribute("totalpages"))
|
||||
else:
|
||||
raise Exception("No total pages attribute")
|
||||
|
||||
|
||||
for node in main.childNodes:
|
||||
if not node.nodeType == xml.dom.Node.TEXT_NODE and (not limit or (len(nodes) < limit)):
|
||||
nodes.append(node)
|
||||
|
||||
|
||||
if page >= total_pages:
|
||||
end_of_pages = True
|
||||
|
||||
|
||||
page += 1
|
||||
|
||||
return nodes
|
||||
|
@ -3613,6 +3640,35 @@ def _extract(node, name, index = 0):
|
|||
else:
|
||||
return None
|
||||
|
||||
def _extract_element_tree(node, index = 0):
|
||||
"""Extract an element tree into a multi-level dictionary
|
||||
|
||||
NB: If any elements have text nodes as well as nested
|
||||
elements this will ignore the text nodes"""
|
||||
|
||||
def _recurse_build_tree(rootNode, targetDict):
|
||||
"""Recursively build a multi-level dict"""
|
||||
|
||||
def _has_child_elements(rootNode):
|
||||
"""Check if an element has any nested (child) elements"""
|
||||
|
||||
for node in rootNode.childNodes:
|
||||
if node.nodeType == node.ELEMENT_NODE:
|
||||
return True
|
||||
return False
|
||||
|
||||
for node in rootNode.childNodes:
|
||||
if node.nodeType == node.ELEMENT_NODE:
|
||||
if _has_child_elements(node):
|
||||
targetDict[node.tagName] = {}
|
||||
_recurse_build_tree(node, targetDict[node.tagName])
|
||||
else:
|
||||
val = None if node.firstChild is None else _unescape_htmlentity(node.firstChild.data.strip())
|
||||
targetDict[node.tagName] = val
|
||||
return targetDict
|
||||
|
||||
return _recurse_build_tree(node, {})
|
||||
|
||||
def _extract_all(node, name, limit_count = None):
|
||||
"""Extracts all the values from the xml string. returning a list."""
|
||||
|
||||
|
@ -3648,7 +3704,7 @@ def _number(string):
|
|||
|
||||
def _unescape_htmlentity(string):
|
||||
|
||||
#string = _unicode(string)
|
||||
#string = _unicode(string)
|
||||
|
||||
mapping = htmlentitydefs.name2codepoint
|
||||
for key in mapping:
|
||||
|
|
10
setup.py
10
setup.py
|
@ -5,7 +5,7 @@ from distutils.core import setup
|
|||
import os
|
||||
def get_build():
|
||||
path = "./.build"
|
||||
|
||||
|
||||
if os.path.exists(path):
|
||||
fp = open(path, "r")
|
||||
build = eval(fp.read())
|
||||
|
@ -14,19 +14,19 @@ def get_build():
|
|||
fp.close()
|
||||
else:
|
||||
build = 1
|
||||
|
||||
|
||||
fp = open(path, "w")
|
||||
fp.write(str(build))
|
||||
fp.close()
|
||||
|
||||
|
||||
return str(build)
|
||||
|
||||
setup(name = "pylast",
|
||||
version = "0.1+0.5." + get_build(),
|
||||
version = "0.6." + get_build(),
|
||||
author = "Amr Hassan <amr.hassan@gmail.com>",
|
||||
description = "A Python interface to Last.fm (and other API compatible social networks)",
|
||||
author_email = "amr.hassan@gmail.com",
|
||||
url = "https://github.com/Elizacat/",
|
||||
url = "https://github.com/inversion/",
|
||||
py_modules = ("pylast",),
|
||||
license = "Apache2"
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue