aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2024-07-10 20:46:08 -0400
committerB. Stack <bgstack15@gmail.com>2024-07-10 20:46:08 -0400
commit230ed709a0631c4bd539cf698e0172a260f3bafd (patch)
treeb5759fa370a39cc56117098c2cb6f0c0efb38ae8
parentadd el8+py3.6 support (diff)
downloadlibrary-info-230ed709a0631c4bd539cf698e0172a260f3bafd.tar.gz
library-info-230ed709a0631c4bd539cf698e0172a260f3bafd.tar.bz2
library-info-230ed709a0631c4bd539cf698e0172a260f3bafd.zip
prepare for reservations
-rw-r--r--README.md21
-rw-r--r--libraries/aspen.py49
-rw-r--r--libraries/base.py7
-rwxr-xr-xlibrary_info_cli.py21
4 files changed, 86 insertions, 12 deletions
diff --git a/README.md b/README.md
index 4d2fcf1..407bab1 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,26 @@ Columns for items checked out:
* how many times renewed already
* when checked out
+### Reserved items
+
+* position in line
+* date placed
+* format
+* title
+* picture
+* pickup location
+* status
+
+### Reserved items
+
+* position in line
+* date placed
+* format
+* title
+* picture
+* pickup location
+* status
+
plugin-based, so I can write a plugins/aspen.py with some standard format output.
# Improvements
@@ -57,3 +77,4 @@ I still need to implement these features.
* add reservations for each library
* add library card expiration date
+* try designing the --output html to save the images to files in ./images/{img50}.{img_format}
diff --git a/libraries/aspen.py b/libraries/aspen.py
index 1d8de39..40e67c1 100644
--- a/libraries/aspen.py
+++ b/libraries/aspen.py
@@ -44,6 +44,51 @@ class Library(BaseLibrary):
# log in now. Why would we not?
self.login()
+ def get_reservations(self, verbose = False):
+ availableReservations = []
+ unavailableReservations = []
+ b = self.baseurl
+ s = self.session
+ # step 1: visit "titles on hold" page so it does not complain that I am taking shortcuts
+ headers = {
+ "Referer": f"{b}/MyAccount/CheckedOut?source=all"
+ }
+ s.get(f"{b}/Holds?source=ils",headers=headers)
+ output = s.get(f"{b}/AJAX?method=getHolds&source=all",headers=headers)
+ output = json.loads(output.content)["holds"].replace("\xa0"," ")
+ soup = BeautifulSoup(output, "html.parser")
+ try:
+ unavailableholds_all = soup.find("label",attrs={"for":"unavailableHoldSort_all"}).parent.next_sibling.next_sibling
+ except AttributeError:
+ # the label will not exist if there are no unavaiableHolds
+ unavailableholds_all = None
+ if unavailableholds_all:
+ items = unavailableholds_all.find_all("div",class_=["result"])
+ for i in items:
+ labels = [j.text for i in i.find_all("div","result-label")]
+ values = [j.text for i in i.find_all("div","result-value")]
+ values_dict = dict(map(lambda i,j:(i,j),labels,values))
+ title_obj = i.find("a",class_="result-title")
+ img_href = i.find("img")["src"]
+ img_b64, img_type = self.get_image(img_href)
+ obj = {
+ "position": values_dict["Position"],
+ "status": values_dict["Status"],
+ "date_placed": values_dict["Date Placed"],
+ "format": values_dict["Format"],
+ "location": values_dict["Pickup Location"],
+ "title": title_obj.text,
+ "img_href": img_href,
+ "img50": img_b64[:50],
+ "img": img_b64,
+ "img_type": img_type,
+ }
+ unavailableReservations.append(obj)
+
+ # WORKHERE: availableHolds, might not be available.
+ # Return a single list of objects
+ return availableReservations + unavailableReservations
+
def get_checkouts(self, verbose = False):
# WORKHERE: no example of possible/completed renewals at this time
checked_out_objects = []
@@ -80,9 +125,7 @@ class Library(BaseLibrary):
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"]
+ img_b64, img_type = self.get_image(img_href)
# normalize format
item_format = ""
item_format = "book" if "book" in values_dict["Format"].lower() else ""
diff --git a/libraries/base.py b/libraries/base.py
index 74394be..f6f75e4 100644
--- a/libraries/base.py
+++ b/libraries/base.py
@@ -48,3 +48,10 @@ class BaseLibrary:
"""
This is where the login interaction should happen.
"""
+
+ def get_image(self, url):
+ """ Given the url, return the base64-encoded contents and image type as a tuple. """
+ img_response = self.session.get(url)
+ img_b64 = base64.b64encode(img_response.content).decode()
+ img_type = img_response.headers["Content-Type"]
+ return img_b64, img_type
diff --git a/library_info_cli.py b/library_info_cli.py
index 57b9188..b77e9f4 100755
--- a/library_info_cli.py
+++ b/library_info_cli.py
@@ -61,7 +61,7 @@ def serialize(item):
eprint(f"WARNING: unknown type {type(item)} for json-serializing object {item}")
return item
-def html(items):
+def html(checkouts):
# Uses https://datatables.net/download/builder?dt/jq-3.7.0/dt-2.0.8/cr-2.0.3/fh-4.0.1
# with css corrected by having the utf-8 line at the top of the .min.css file.
""" Make an html of the items """
@@ -78,7 +78,7 @@ def html(items):
prn("</head>\n")
prn("<body>\n")
seen_accounts = []
- for i in items:
+ for i in checkouts:
if i["patron"] not in seen_accounts:
seen_accounts.append(i["patron"])
if seen_accounts:
@@ -91,11 +91,12 @@ def html(items):
except AttributeError:
now = datetime.datetime.utcnow()
prn("<span class='eighty'>Last modified: " + now.strftime("%FT%TZ") + "</span>\n")
- if len(items):
+ prn("<h2>Checkouts</h2>\n")
+ if len(checkouts):
prn("<table class='display' id='checkouts'>\n")
prn(f"<thead><tr><th>Patron</th><th>barcode</th><th>due</th><th>format</th><th>cover</th><th>Title</th></tr></thead>\n")
prn("<tbody>\n")
- for i in items:
+ for i in checkouts:
prn(f"<tr>")
prn(f"<td>{i['patron']}</td>")
prn(f"<td>{i['barcode']}</td>")
@@ -112,6 +113,8 @@ def html(items):
prn(f"</tr>\n")
prn(f"</tbody>\n")
prn(f"</table>\n")
+ else:
+ prn(f"No checkouts.\n")
prn(f"</body>\n")
prn(f"<footer>\n")
prn(f"</footer>\n")
@@ -132,14 +135,14 @@ if "__main__" == __name__:
if debuglevel >= 1:
eprint(args)
if single:
- items = library_info_lib.get_single_checkouts(alias = single, full_images = full_images, verbose = debuglevel >= 5)
+ checkouts = library_info_lib.get_single_checkouts(alias = single, full_images = full_images, verbose = debuglevel >= 5)
else:
- items = library_info_lib.get_all_checkouts(full_images = full_images, verbose = debuglevel >= 5)
+ checkouts = library_info_lib.get_all_checkouts(full_images = full_images, verbose = debuglevel >= 5)
if "raw" == output:
- print(items)
+ print(checkouts)
elif "json" == output:
- print(json.dumps(items,default=serialize))
+ print(json.dumps(checkouts,default=serialize))
elif "html" == output:
- html(items)
+ html(checkouts)
else:
print(f"Error! Invalid choice for output format {output}.")
bgstack15