Compare commits

10 Commits

Author SHA1 Message Date
f637a97fc2 use EditorConfig 2021-07-25 15:32:55 +03:00
f6f3a653df use black library for code 2020-10-05 02:32:15 +03:00
b63e1f1536 Merge pull request #3 from Nitemice/fix/export-formats
Fix/export formats
2020-10-04 13:25:09 +03:00
f799d31052 Improved README
Fixed some spelling mistakes
Added info on export formats
2020-10-04 18:09:15 +11:00
abbf9df872 Minor export improvements
Added album field to CSV.
Write all records to CSV at once.
Renamed "is as" export mode to "dump". It's more accurate and nicer with
a single word.
2020-10-04 17:59:57 +11:00
a0a84a212f Added field names to export
Added header row to CSV.
Added field names for simple export.
2020-10-04 17:09:41 +11:00
679bcdd633 Fix simple and csv export
JSON needs an array to append into.

CSV was misspelt.
Also fixed extra newlines being added to CSV file on Windows.
2020-10-04 17:04:43 +11:00
029af27ea2 add export more format 2020-07-02 04:03:07 +03:00
4c1480be4c new version 2020-07-02 02:24:51 +03:00
f2d7ad058c add link to web service 2019-08-30 02:04:45 +03:00
8 changed files with 189 additions and 80 deletions

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# EditorConfig is awesome: https://EditorConfig.org
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,config.json.example}]
indent_style = tab
indent_size = 4

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.json *.json
*.csv
*.pyc *.pyc
build/ build/
dist/ dist/

View File

@ -1,19 +1,26 @@
![Version](https://img.shields.io/pypi/v/lastfm-backup.svg?style=flat-square) # Last.fm Backup
![License](https://img.shields.io/pypi/l/lastfm-backup.svg?style=flat-square)
![PyVersion](https://img.shields.io/pypi/pyversions/lastfm-backup.svg?style=flat-square)
**How to use:** ![Version](https://img.shields.io/pypi/v/lastfm-backup.svg?style=for-the-badge)
-------------- ![License](https://img.shields.io/pypi/l/lastfm-backup.svg?style=for-the-badge)
* [Get](http://www.last.fm/api/account/create) API Key. ![PyVersion](https://img.shields.io/pypi/pyversions/lastfm-backup.svg?style=for-the-badge)
### Features:
* Simple
* Three formats for export data:
1. `dump` - JSON, direct from API
2. `simple` - Artist, track name, album & date as JSON
3. `csv` - Artist, track name, album & date as comma separated values
### How to use:
* Stop scrobbling! * Stop scrobbling!
* Rename `config.json.example` to `config.json` and edit. * Modify `config.json`.
* Run script `lastfm_backup.py`. * [Get API Key](http://www.last.fm/api/account/create).
* Run `lastfm_backup.py`.
* WAIT =) * WAIT =)
**TODO:** ### TODO:
-------- - [ ] web service [see lfmbak](https://github.com/iiiypuk/lfmbak)
- [ ] web service - [x] more output types (sqlite, csv)
- [ ] more output types (sqlite, csv) - [ ] configurable output
- [ ] confirugurabled output
- [ ] continue backup - [ ] continue backup
- [ ] multithreading - [ ] multi-threading

View File

@ -1,4 +1,5 @@
{ {
"username" : "", "username" : "",
"api_key" : "" "api_key" : "",
"export_format": "dump, simple, csv"
} }

View File

@ -1,61 +1,138 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import json import json
import urllib.request import csv
import os.path import os.path
import requests
__author__ = 'Alexander Popov' __author__ = "Alexander Popov"
__version__ = '1.0.1' __version__ = "2.1.0"
__license__ = 'Unlicense' __license__ = "Unlicense"
def get_pages(username, api_key): def get_pages(username, api_key, limit=200):
response = urllib.request.urlopen( """ Getting the number of pages with scrobbling data """
'http://ws.audioscrobbler.com/2.0/'
'?method=user.getrecenttracks&user={0}&api_key={1}&format=json'
'&limit=200'.format(username, api_key)).read().decode("utf8")
pages = int(json.loads(response)['recenttracks']['@attr']['totalPages'])
return(pages) response = requests.get(
"https://ws.audioscrobbler.com/2.0/"
"?method=user.getrecenttracks&user="
"{0}&api_key={1}&format=json&limit={2}".format(username, api_key, limit)
)
data = json.loads(response.content.decode("utf8"))
return int(data["recenttracks"]["@attr"]["totalPages"])
def get_scrobbles(username, api_key, page): def get_page(username, api_key, page, limit=200):
response = json.loads(urllib.request.urlopen( """ Getting scrobbling data from a page """
'http://ws.audioscrobbler.com/2.0/'
'?method=user.getrecenttracks&user={0}&api_key={1}&format=json'
'&limit=200&page={2}'.format(username, api_key, page)
).read().decode("utf8"))['recenttracks']['track']
return(response) response = requests.get(
"https://ws.audioscrobbler.com/2.0/"
"?method=user.getrecenttracks&user={0}&api_key={1}&format=json"
"&limit={2}&page={3}".format(username, api_key, limit, page)
)
if __name__ == '__main__': data = json.loads(response.content.decode("utf8"))
CFG = dict()
if os.path.exists('./config.json'): return data["recenttracks"]["track"]
with open('./config.json') as f:
CFG = json.loads(f.read())
def get_now_scrobbling(username, api_key):
""" Getting now scrobbling track """
response = requests.get(
"https://ws.audioscrobbler.com/2.0/"
"?method=user.getrecenttracks&user={0}"
"&api_key={1}&format=json&limit=1".format(username, api_key)
)
data = json.loads(response.content.decode("utf-8"))
if "@attr" in data["recenttracks"]["track"][0]:
return True
else: else:
CFG['api_key'] = input('API Key: ') return False
CFG['username'] = input('Username: ')
PAGES = get_pages(CFG['username'], CFG['api_key'])
curPage = 1 def scrobbling_export(tracks, username, export_format="dump"):
tracks = [] """ Save scrobbled track via various format """
while curPage <= PAGES:
print('\r{0}% [{1} of {2}]'.format((curPage * 100 / PAGES), curPage, PAGES), end='') if export_format == "dump":
response = get_scrobbles(CFG['username'], CFG['api_key'], curPage) with open("%s.json" % (username), "w", encoding="utf-8") as f:
data = json.dumps(tracks, indent=4, sort_keys=True, ensure_ascii=False)
f.write(data)
elif export_format == "simple":
_ = []
for track in tracks:
_.append(
{
"artist": track["artist"]["#text"],
"name": track["name"],
"album": track["album"]["#text"],
"date": int(track["date"]["uts"]),
}
)
with open("%s.json" % (username), "w", encoding="utf-8") as f:
data = json.dumps(_, indent=4, sort_keys=True, ensure_ascii=False)
f.write(data)
elif export_format == "csv":
_ = []
for track in tracks:
_.append(
[
track["artist"]["#text"],
track["name"],
track["album"]["#text"],
int(track["date"]["uts"]),
]
)
with open("%s.csv" % (username), "w", encoding="utf-8", newline="") as f:
data = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC, delimiter=",")
data.writerow(["artist", "track", "album", "date"])
data.writerows(_)
return 1
if __name__ == "__main__":
_ = dict()
if os.path.exists("./config.json"):
with open("./config.json") as f:
_ = json.loads(f.read())
else:
_["api_key"] = input("API Key: ")
_["username"] = input("Username: ")
api_key, username = _["api_key"], _["username"]
total_pages = get_pages(username, api_key)
current_page = 1
scrobbled = []
while current_page <= total_pages:
print(
"\r{0:.2f}% [{1} of {2}]".format(
(current_page * 100 / total_pages), current_page, total_pages
),
end="",
)
response = get_page(username, api_key, current_page)
for track in response: for track in response:
tracks.append({'artist': track['artist']['#text'], scrobbled.append(track)
'name': track['name'],
'album': track['album']['#text'],
'date': track['date']['uts']})
curPage += 1 current_page += 1
with open('%s.json' % (CFG['username']), 'w+', encoding='utf-8') as f: # if get_now_scrobbling(username, api_key):
f.write( # scrobbled.pop(0)
json.dumps(tracks, indent=4, sort_keys=True, ensure_ascii=False))
print('\n{0} tracks saved in {1}.json!'.format( if scrobbling_export(scrobbled, username, _["export_format"]):
len(tracks), CFG['username'],)) print("\n{0} tracks saved!".format(len(scrobbled), username))

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
requests==2.24.0

View File

@ -2,18 +2,24 @@
import lastfm_backup as lfm import lastfm_backup as lfm
API_KEY = '0' API_KEY = "0"
USERNAME = 'admin' USERNAME = "admin"
if __name__ == '__main__': if __name__ == "__main__":
pages = lfm.get_pages(USERNAME, API_KEY) pages = lfm.get_pages(USERNAME, API_KEY)
count = 0 count = 0
for page in range(1, pages + 1): for page in range(1, pages + 1):
tracks = lfm.get_scrobbles(USERNAME, API_KEY, page) tracks = lfm.get_scrobbles(USERNAME, API_KEY, page)
for track in tracks: for track in tracks:
print('%s - %s' % (track['artist']['#text'], track['name'],)) print(
count = count + 1 "%s - %s"
% (
track["artist"]["#text"],
track["name"],
)
)
count = count + 1
print('\nTotal scrobbling tracks: %d' % count) print("\nTotal scrobbling tracks: %d" % count)

View File

@ -3,19 +3,21 @@ import setuptools
import lastfm_backup import lastfm_backup
setuptools.setup( setuptools.setup(
name='lastfm-backup', name="lastfm-backup",
version=lastfm_backup.__version__, version=lastfm_backup.__version__,
description='Last.fm scrobbles backup', description="Last.fm scrobbling backup",
author=lastfm_backup.__author__, author=lastfm_backup.__author__,
author_email='iiiypuk@fastmail.fm', author_email="iiiypuk@fastmail.fm",
url='https://github.com/iiiypuk/lastfm-backup', url="https://github.com/iiiypuk/lastfm-backup",
py_modules=['lastfm_backup'], py_modules=["lastfm_backup"],
scripts=['lastfm_backup.py'], scripts=["lastfm_backup.py"],
license=lastfm_backup.__license__, license=lastfm_backup.__license__,
platforms='any', platforms="any",
keywords=['last.fm', 'lastfm', 'backup'], keywords=["last.fm", "lastfm", "backup"],
classifiers=['License :: Public Domain', classifiers=[
'Programming Language :: Python :: 3', "License :: Public Domain",
'Operating System :: OS Independent'], "Programming Language :: Python :: 3",
python_requires='>=3.0' "Operating System :: OS Independent",
],
python_requires=">=3.2",
) )