-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from hp0404/0.2.3
0.2.3
- Loading branch information
Showing
8 changed files
with
292 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"id": "8d385b85-a9b1-4ee7-ab87-2f2ad31df4c0", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from lastfm import LastFM" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 7, | ||
"id": "9dbaabba-41d2-4006-8c7b-54bce065603c", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"api = LastFM(\n", | ||
" api=\"244ec3b62b2501514191234eed07c75d\",\n", | ||
" username=\"way4music\", \n", | ||
" start_date=\"2021-08-21\",\n", | ||
" end_date=\"2021-09-01\"\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 8, | ||
"id": "19b84008-1a79-4f45-a5bd-26c870fe82c1", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"data = api.fetch()\n", | ||
"song = next(data)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 10, | ||
"id": "6bf1e7b4-6f38-4e99-ad96-60e17843f6bf", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"container = []\n", | ||
"for item in data:\n", | ||
" container.append(item)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 11, | ||
"id": "1f89a8fb-aada-41be-bda5-05e4cd124c14", | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"data": { | ||
"text/plain": [ | ||
"[{'artist': 'Sara Watkins',\n", | ||
" 'album': 'Without A Word',\n", | ||
" 'song': 'Without A Word',\n", | ||
" 'uts_timestamp': 1630421886,\n", | ||
" 'datetime': '31 Aug 2021, 14:58'},\n", | ||
" {'artist': 'Dave Rawlings Machine',\n", | ||
" 'album': 'A Friend Of A Friend',\n", | ||
" 'song': 'Bells Of Harlem',\n", | ||
" 'uts_timestamp': 1630421638,\n", | ||
" 'datetime': '31 Aug 2021, 14:53'},\n", | ||
" {'artist': 'Courtney Marie Andrews',\n", | ||
" 'album': 'May Your Kindness Remain',\n", | ||
" 'song': 'May Your Kindness Remain',\n", | ||
" 'uts_timestamp': 1630421403,\n", | ||
" 'datetime': '31 Aug 2021, 14:50'},\n", | ||
" {'artist': 'Lera Lynn',\n", | ||
" 'album': 'On My Own',\n", | ||
" 'song': 'A Light Comes Through',\n", | ||
" 'uts_timestamp': 1630421221,\n", | ||
" 'datetime': '31 Aug 2021, 14:47'},\n", | ||
" {'artist': 'The Deep Dark Woods',\n", | ||
" 'album': 'The Place I Left Behind',\n", | ||
" 'song': 'The Place I Left Behind',\n", | ||
" 'uts_timestamp': 1630420976,\n", | ||
" 'datetime': '31 Aug 2021, 14:42'}]" | ||
] | ||
}, | ||
"execution_count": 11, | ||
"metadata": {}, | ||
"output_type": "execute_result" | ||
} | ||
], | ||
"source": [ | ||
"container[:5]" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3 (ipykernel)", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.8.5" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# -*- coding: utf-8 -*- | ||
import datetime | ||
import requests | ||
from time import sleep | ||
|
||
|
||
class APIError(Exception): | ||
"""APIError is raised when provided key is invalid | ||
(should be 32 alphanum characters long).""" | ||
pass | ||
|
||
|
||
class LastFM: | ||
"""Base LastFM class.""" | ||
|
||
URL = "http://ws.audioscrobbler.com/2.0" | ||
DATE_FORMAT = "%Y-%m-%d" | ||
|
||
def __init__( | ||
self, | ||
api: str, | ||
username: str, | ||
method: str = "user.getrecenttracks", | ||
first_page: int = 1, | ||
limit_per_page: int = 200, | ||
extended: int = 0, | ||
start_date=None, | ||
end_date=None, | ||
): | ||
self.api = self._validate_apikey(api) | ||
self.username = username | ||
self.method = method | ||
self.first_page = first_page | ||
self.limit_per_page = limit_per_page | ||
self.extended = extended | ||
self.start_date = start_date | ||
self.end_date = end_date | ||
|
||
self.context_created = False | ||
self.session = None | ||
self.total_pages = None | ||
|
||
def __del__(self) -> None: | ||
if self.session: | ||
self.session.close() | ||
|
||
@staticmethod | ||
def _validate_apikey(api): | ||
"""Ensure apikey is valid.""" | ||
if api.isalnum() and len(api) == 32: | ||
return api | ||
raise APIError("API key should be 32 alphanum char. long.") | ||
|
||
@staticmethod | ||
def _convert_to_timestamp(date): | ||
"""Convert human-readable `date` - either `datetime.date` or `str` - to | ||
Unix Timestamp.""" | ||
if isinstance(date, datetime.date): | ||
return int(date.timestamp()) | ||
return int(datetime.datetime.strptime(date, LastFM.DATE_FORMAT).timestamp()) | ||
|
||
@staticmethod | ||
def process_response(page): | ||
"""Yield specific k:v items of each song within page.""" | ||
playlist = page["recenttracks"]["track"] | ||
for song in playlist: | ||
date = song.get("date", "") | ||
yield { | ||
"artist": song["artist"]["#text"], | ||
"album": song["album"]["#text"], | ||
"song": song["name"], | ||
"uts_timestamp": int(date["uts"]) if date else "", | ||
"datetime": date["#text"] if date else "", | ||
} | ||
|
||
def ensure_context_created(self): | ||
"""Make sure session, params, and request total number of pages exist.""" | ||
if self.context_created: | ||
return | ||
self.session = requests.Session() | ||
self.params = { | ||
"method": self.method, | ||
"user": self.username, | ||
"api_key": self.api, | ||
"page": self.first_page, | ||
"limit": self.limit_per_page, | ||
"extended": self.extended, | ||
"format": "json", | ||
} | ||
if self.start_date is not None: | ||
self.params["from"] = self._convert_to_timestamp(self.start_date) | ||
if self.end_date is not None: | ||
self.params["to"] = self._convert_to_timestamp(self.end_date) | ||
response = self.session.get(LastFM.URL, params=self.params).json() | ||
self.total_pages = int(response["recenttracks"]["@attr"]["totalPages"]) | ||
self.context_created = True | ||
|
||
def fetch(self): | ||
"""Fetch user's track history given the parametrs.""" | ||
self.ensure_context_created() | ||
while self.params["page"] <= self.total_pages: | ||
response = self.session.get(LastFM.URL, params=self.params).json() | ||
yield from self.process_response(response) | ||
self.params["page"] += 1 | ||
sleep(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.