Compare commits

28 Commits
Author SHA1 Message Date
matthias 99386b99e1 Merge branch 'master' of gitea.d1v3.de:matthias/bibreminder
continuous-integration/drone/push Build is passing
2020-01-11 07:11:42 +01:00
matthias 571c1c73e1 allow definition of ids per username 2020-01-11 07:09:12 +01:00
matthias 337d332638 fixed health heck, respect timezone
continuous-integration/drone/push Build is passing
2020-01-04 07:30:09 +01:00
matthias 78817a9193 fixed check
continuous-integration/drone/push Build is passing
2020-01-03 19:43:12 +01:00
matthias ed600bae22 run forever
continuous-integration/drone/push Build is passing
2020-01-03 19:39:51 +01:00
matthias 55fa4d7aa8 make configurable
continuous-integration/drone/push Build is passing
2020-01-03 19:33:53 +01:00
matthias e74169291f „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2020-01-03 06:57:22 +00:00
matthias 66d28eb649 „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2020-01-03 06:55:15 +00:00
matthias 3f5a7f2c2a „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2020-01-03 06:48:20 +00:00
matthias 5ea4ecfe29 „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2019-09-30 15:49:49 +00:00
matthias 1b5858e491 „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2019-09-30 15:47:02 +00:00
matthias 9d091504ef „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2019-09-30 15:44:02 +00:00
matthias 8b28c50266 Added Lilys account
continuous-integration/drone/push Build is passing
2019-09-30 15:42:24 +00:00
matthias 95e7002447 added start notification to healthcheck
continuous-integration/drone/push Build is passing
2019-09-28 18:49:45 +02:00
matthias a92fc0f291 utf8 encoding
continuous-integration/drone/push Build is passing
2019-09-28 18:46:57 +02:00
matthias 96090f8f8c Merge remote-tracking branch 'refs/remotes/origin/master'
continuous-integration/drone/push Build is passing
2019-09-28 18:41:16 +02:00
matthias 8ef54a6306 including post data in healthcheck 2019-09-28 18:39:45 +02:00
matthias 9a139de37a „bibcheck.py“ ändern
continuous-integration/drone/push Build is passing
2019-09-26 04:41:20 +00:00
matthias bd671a4492 Added automatic renew of all lent books
continuous-integration/drone/push Build is passing
2019-09-25 10:05:24 +00:00
matthias 131a90a0e0 „Dockerfile“ ändern
continuous-integration/drone/push Build is passing
2019-09-25 04:42:57 +00:00
matthias defa866a56 log somethings
continuous-integration/drone/push Build is passing
2019-09-25 06:30:25 +02:00
matthias ba8a714bc2 improved dockerfile
continuous-integration/drone/push Build is passing
Install deps
Use a user
2019-09-25 06:24:34 +02:00
matthias d01b879003 added healthcheck
continuous-integration/drone/push Build is passing
2019-09-24 17:59:25 +02:00
matthias 26056e25a9 added CI config
continuous-integration/drone/push Build is passing
2019-09-24 17:52:08 +02:00
matthias fc88f93fb3 added dockerfile 2019-09-24 17:49:00 +02:00
matthias 5a467dee04 added notification 2019-09-24 17:48:02 +02:00
matthias afc6e42570 requirements.txt 2019-09-24 07:04:16 +02:00
matthias 28fc539601 bibcheck 2019-09-24 07:03:15 +02:00
4 changed files with 42 additions and 174 deletions
-24
View File
@@ -1,24 +0,0 @@
name: Docker Image CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the Docker image
run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)
- name: Docker Publish
uses: manusa/actions-publish-docker@v1.0.1
with:
# Name of the Docker image
name: m42e/bibreminder
# Username for Docker registry
username: ${{ secrets.Dockeruser }}
# Password for Docker registry
password: ${{ secrets.Dockertoken }}
+4 -12
View File
@@ -1,18 +1,10 @@
FROM python:3.8-alpine as base
FROM python:3.7
FROM base as builder
RUN mkdir /install
WORKDIR /install
COPY requirements.txt /requirements.txt
RUN pip install --prefix=/install -r /requirements.txt
RUN useradd --create-home appuser
COPY requirements.txt /home/appuser
RUN pip install -r /home/appuser/requirements.txt
FROM base
COPY --from=builder /install /usr/local
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
RUN apk add --no-cache tzdata
ENV TZ=Europe/Berlin
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /home/appuser
USER appuser
+5 -28
View File
@@ -1,37 +1,14 @@
# Bib Reminder for Munich public library
This automatically sending pushover messages when a lent item is about to be returned, while also extending the period of the lending if possible.
It will remind you 20 and 15 days before you have to return the media And if there are only 10 or less days left, it gets pretty annoying and bothers you each and every day, till you return it.
It's not much code nor is it complicated, but maybe it prevents someone else from paying for books kept to long.
This automatically sending pushover messages when a lent item is about to be returned, while also extending the period if possible.
Configure the docker container with the following variables.
## Docker Config
The container by default keeps running. It sleeps till it is time to check again. But you can configure it to be a one shot.
It does not keep any track of any data.
### Required
- `PUSHOVER_KEY` Your pushover API Key
- `PUSHOVER_CLIENTS` A comma seperated list of pushover client ids. All the notifications will be sent to this ids
- `BIB_USERS` A comma seperated list of combinations of <USER>:<PWD> combinations to check and extend lent items.
### Optional:
- `LIBRARY_URL` The url of the OPAC entry page of your library, defaults to the one of Stadtbibliothek München
- `RUN_AT_HOUR` Check at hour, default 6
- `RUN_AT_MINUTE` Check at minute, default 0
- `HEALTHCHECK_URL` OPTIONAL url for performing a healthcheck (see healthckeck.io for details)
- `NOTIFY_USERS` A coma separated list of <USER>:<pushover client id> tulles to send pushover messages selectivly
- `RUN_FOREVER` If set to `False` (mind the capitalization) the container will only perform a one time check. This way you could trigger it externally e.g. using cron.
### Example:
```
PUSHOVER_KEY=abcdef1234567890abcdef12345678
HEALTHCHECK_URL=https://healthcheck.io/ping/0000000-0000-0000-0000-000000000000
BIB_USERS=400001234567:password,40000987654:drowssap
NOTIFY_USERS=400001234567:12345678abcdef1234567890abcdef,40000987654:12345678abcdef1234567890abcdef
```
`PUSHOVER_KEY` Your pushover API Key
`PUSHOVER_CLIENTS` A comma seperated list of pushover client ids.
`HEALTHCHECK_URL` An url for performing a healthcheck (see healthckeck.io for details)
`BIB_USERS` A comma seperated list of combinations of <USER>:<PWD> combinations to check and extend lent items.
+33 -110
View File
@@ -8,138 +8,61 @@ import mechanize
import pushover
import datetime
import os
import logging
#logging.basicConfig(level=getattr(logging, os.environ.get("LOG_LEVEL", "INFO")))
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
def split_notify(string):
values = string.split(":")
values = string.split(':')
return (values[0], values[1:])
def main():
try:
pushover.init(os.environ["PUSHOVER_KEY"])
except:
_logger.exception("Pushover KEY is required")
return
while True:
try:
_logger.info("Starting Bibcheck")
if "HEALTHCHECK_URL" in os.environ:
_logger.info("Pinging Healthcheck [start]")
_logger.debug(
f"Pinging Healthcheck Url {os.environ['HEALTHCHECK_URL']}/start"
)
requests.get(f"{os.environ['HEALTHCHECK_URL']}/start")
allinfo = []
users = list(
map(lambda x: x.split(":", 1), os.environ["BIB_USERS"].split(","))
)
notify = dict(map(split_notify, os.environ["NOTIFY_USERS"].split(",")))
_logger.info(f"Found {len(users)} user(s) to check for")
for user, pwd in users:
_logger.info(f"Check for {user}")
allinfo += check(user, pwd, notify.get(user, []))
if "HEALTHCHECK_URL" in os.environ:
_logger.info("Pinging Healthcheck [stop]")
requests.post(
f"{os.environ['HEALTHCHECK_URL']}",
data="\n".join(allinfo).encode("utf8"),
)
if "RUN_FOREVER" in os.environ and os.environ["RUN_FOREVER"] == "False":
_logger.info("Finished")
break
except Exception as e:
_logger.exception("Check Failed ")
if "HEALTHCHECK_URL" in os.environ:
_logger.info("Pinging Healthcheck [failed]")
_logger.debug(
f"Pinging Healthcheck Url {os.environ['HEALTHCHECK_URL']}/fail"
)
requests.post(
f"{os.environ['HEALTHCHECK_URL']}/fail",
data="\n".join(allinfo).encode("utf8"),
)
pushover.init(os.environ['PUSHOVER_KEY'])
if 'HEALTHCHECK_URL' in os.environ:
requests.get(f"{os.environ['HEALTHCHECK_URL']}/start")
allinfo = []
users = list(map(lambda x: x.split(':', 1), os.environ['BIB_USERS'].split(',')))
notify = dict(map(split_notify, os.environ['NOTIFY_USERS'].split(',')))
for user, pwd in users:
allinfo += check(user, pwd, notify.get(user, []))
if 'HEALTHCHECK_URL' in os.environ:
requests.post(f"{os.environ['HEALTHCHECK_URL']}", data='\n'.join(allinfo).encode('utf8'))
if 'RUN_FOREVER' in os.environ and os.environ['RUN_FOREVER'] == 'False':
break
now = datetime.datetime.utcnow
to = (now() + datetime.timedelta(days=1)).replace(
hour=os.environ.get("RUN_AT_HOUR", 6),
minute=os.environ.get("RUN_AT_MINUTE", 0),
second=0,
)
_logger.info(f"Sleeping till {to.isoformat()}")
time.sleep((to - now()).seconds)
to = (now() + datetime.timedelta(days = 1)).replace(hour=6, minute=0, second=0)
time.sleep((to-now()).seconds)
def check(username, password, notify_ids):
br = mechanize.Browser()
starturl = os.environ.get(
"LIBRARY_URL",
"https://ssl.muenchen.de/aDISWeb/app?service=direct/0/Home/$DirectLink&sp=SOPAC&sp=SBK00000000",
)
_logger.info(f"Library URL used: {starturl}")
_logger.info(f"Goto loginpage")
starturl = 'https://ssl.muenchen.de/aDISWeb/app?service=direct/0/Home/$DirectLink&sp=SOPAC'
response = br.open(starturl)
_logger.info(f"Fill form")
br.select_form("Form0")
br["$Textfield"] = username
br["$Textfield$0"] = password
_logger.info(f"Sumbit form")
response = br.submit(name='textButton')
print (b'Matthias' in response.read())
currenturl = response.geturl()
cookies = br.cookiejar
# _logger.info(f"Open account page using form0")
#br.select_form(nr=0)
#br.set_all_readonly(False)
#br["$ScriptButton_hidden"] = 'BK'
br.set_debug_http(True)
# response = br.submit()
br.follow_link(text_regex=r"Anmelden")
br.select_form('Form0')
br['$Textfield'] = username
br['$Textfield$0'] = password
response = br.submit()
br.follow_link(text_regex=r"Konto")
try:
_logger.info(f"Open lent list")
req = mechanize.Request(currenturl + '?service=direct/1/POOLSTPM@@@@@@@@_4400E200_3B328A80/Tabelle_Z1LP01.cellInternalLink.directlink&sp=SRGLINK_5&sp=SZA&requestCount=1',method='GET',headers={'Referer': currenturl})
cookies.add_cookie_header(req)
response = br.open(req)
print(response.read())
_logger.info(f"Extend all")
br.select_form("Form0")
response = br.submit(name="textButton$0", label="Alle verlängern")
lentlist = bs4.BeautifulSoup(response.read(), "html.parser")
response = br.follow_link(text_regex=r"Ausleihen? zeigen")
br.select_form('Form0')
response = br.submit(name='textButton$0', label='Alle verlängern')
lentlist = bs4.BeautifulSoup(response.read(), 'html.parser')
table = lentlist.select('table[class="rTable_table"]')[0]
allinfo = []
_logger.info(f"Parsing table")
for entry in table.tbody.select("tr"):
info = list(map(lambda x: str(x.text).strip(), entry.select("td")))
date = datetime.datetime.strptime(info[1], "%d.%m.%Y")
for entry in table.tbody.select('tr'):
info = list(map(lambda x: str(x.text).strip(), entry.select('td')))
date = datetime.datetime.strptime(info[1], '%d.%m.%Y')
delta = date - datetime.datetime.now()
allinfo.append(str(info))
if delta.days <= 10 or delta.days == 20 or delta.days == 15:
message = f"Bitte an {info[3]} denken\n"
if delta.days <= 7:
message += '<font color="#ff0000">'
message += f"Abgabe <b>{info[1]}</b>"
if delta.days <= 7:
message += "</font>"
message += f" - {username}"
for client in itertools.chain(
notify_ids, os.environ.get("PUSHOVER_CLIENTS", "").split(",")
):
try:
pushover.Client(client).send_message(
message, title="Erinnerung", html=1
)
except:
print("No client")
for client in itertools.join(notify_ids, os.environ['PUSHOVER_CLIENTS'].split(',')):
pushover.Client(client).send_message(f'Bitte an {info[3]} denken, Abgabe {info[3]} - {username}', title="Erinnerung")
except (StopIteration, mechanize._mechanize.LinkNotFoundError) as e:
_logger.exception("Failed to read information")
for client in itertools.join(notify_ids, os.environ['PUSHOVER_CLIENTS'].split(',')):
pushover.Client(client).send_message(f'nichts ausgeliehen {username} ({e})')
return []
return allinfo
if __name__ == "__main__":
main()