1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#!/usr/bin/env python3
# File: libraries/aspen.py
# Author: bgstack15
# Startdate: 2024-07-06-7 08:06
# SPDX-License-Identifier: GPL-3.0-only
# Title: Library Plugin for Aspen
# Project: library_info
# Purpose: plugin for aspen-based library websites
# History:
# Usage:
# Reference:
# Improve:
# Dependencies:
# dep-devuan: python3-bs4
from .base import *
import requests, json, dateutil, base64, os, sys
from bs4 import BeautifulSoup
class Library(BaseLibrary):
def __init__(self, config_obj = None, alias = None, username = None, password = None, baseurl = None, session = None):
if config_obj and "username" in config_obj:
self.username = config_obj["username"]
else:
self.username = username
if config_obj and "password" in config_obj:
self.password = config_obj["password"]
else:
self.password = password
if config_obj and "baseurl" in config_obj:
self.baseurl = config_obj["baseurl"]
else:
self.baseurl = baseurl if baseurl else "https://aspen.example.org"
self.baseurl = self.baseurl.rstrip("/")
if session and type(session) == requests.sessions.Session:
self.session = session
else:
self.session = requests.Session()
if config_obj and "alias" in config_obj:
self.alias = config_obj["alias"]
else:
self.alias = alias if alias else "Aspen-based library"
# log in now. Why would we not?
self.login()
def get_checkouts(self, verbose = False):
# WORKHERE: no example of possible/completed renewals at this time
checked_out_objects = []
b = self.baseurl
s = self.session
# step 1: visit the "checked out" web page, so it doesn't freak out that I am taking shortcuts
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Referer": f"{b}/MyAccount/Home",
"Priority": "u=1"
}
s.get(f"{b}/MyAccount/CheckedOut", headers = headers)
# step 2: visit the checkout list which is a cruddy html-inside-json garbage
headers = {
"Referer": f"{b}/MyAccount/CheckedOut?source=all"
}
params = {
"method": "getCheckouts",
"source": "all"
}
output = s.get(f"{b}/MyAccount/AJAX",params=params,headers=headers)
output = json.loads(output.content)["checkouts"].replace("\xa0"," ")
soup = BeautifulSoup(output, "html.parser")
# goals: get title, format, picture, barcode, due date, possible renewal date, times_renewed, when_checked_out
results = soup.find_all("div", class_ = "result row")
#results = soup.find_all("span",class_="result-index")
#results = [i.parent.parent.parent for i in results]
for i in results:
title = i.find(class_ = "result-title").contents[0]
labels = [j.contents[0] for j in i.find_all("div", class_ = "result-label")]
values = [j.contents[0] for j in i.find_all("div", class_ = "result-value")]
values_dict = dict(map(lambda i,j:(i,j),labels,values))
if verbose:
print(f"DEBUG: Values_dict: {values_dict}",file=sys.stderr)
# contains Call number, Format, Barcode, Due
img_href = i.find("img", class_="listResultImage")["src"]
img_response = s.get(img_href)
img_b64 = base64.b64encode(img_response.content).decode()
img_type = img_response.headers["Content-Type"]
# normalize format
item_format = ""
item_format = "book" if "book" in values_dict["Format"].lower() else ""
if not item_format:
item_format = values_dict["Format"]
obj = {
"patron": self.alias,
"title": title,
"format": item_format,
"barcode": values_dict["Barcode"],
"due": dateutil.parser.parse(values_dict["Due"]),
"img_href": img_href,
"img50": img_b64[:50],
"img": img_b64,
"img_type": img_type,
}
checked_out_objects.append(obj)
return checked_out_objects
def get_class_name(self):
return os.path.basename(__file__).replace(".py","")
def login(self):
b = self.baseurl
s = self.session
# step 1: visit login page
s.get(f"{b}/MyAccount/Home")
# step 2: log in
# curl 'https://aspen.example.org/MyAccount/Home' -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'Referer: https://aspen.example.org/MyAccount/Home' -H 'Priority: u=1' --data-raw 'username=987213497234&password=1234&submit=Login'
data = {
"username": self.username,
"password": self.password,
"submit": "Login"
}
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Referer": f"{b}/MyAccount/Home",
"Priority": "u=1"
}
s.post(f"{b}/MyAccount/Home", headers = headers, data = data)
|