clean up a little and add config

This commit is contained in:
Valentin Boettcher 2024-06-08 13:06:02 -04:00
parent 0d5dd16f7f
commit a759dfb98d
No known key found for this signature in database
GPG key ID: E034E12B7AF56ACE

View file

@ -7,6 +7,8 @@ import time
import shutil import shutil
import urllib.request import urllib.request
import asyncio import asyncio
import argparse
import subprocess
from aioimaplib import aioimaplib from aioimaplib import aioimaplib
from collections import namedtuple from collections import namedtuple
import re import re
@ -16,10 +18,31 @@ from email.message import Message
from email.parser import BytesHeaderParser, BytesParser from email.parser import BytesHeaderParser, BytesParser
from typing import Collection from typing import Collection
from contextlib import suppress from contextlib import suppress
from dataclasses import dataclass
KINDLE_DIR = Path.home() / "kindle_dump/"
LATEST_PATH = KINDLE_DIR / "latest.pdf" @dataclass
class Options:
server: str
"""The IMAP server to connect to."""
user: str
"""The IMAP username."""
password: str
"""The password to the server."""
kindle_dir: Path
"""The directory to dump the note PDFs in."""
latest_path: Path
"""
The path to the file that will contain the the most currently
downloaded pdf relative to :any:`kindle_dir`.
"""
mailbox: str
"""The folder to monitor for new messages."""
def get_document_title(header_string): def get_document_title(header_string):
@ -42,18 +65,6 @@ def get_download_link(text):
return m.group(1), page return m.group(1), page
# LAST_LINK = None
# while True:
# current_link = monitor_kindle()
# if current_link != LAST_LINK and current_link is not None:
# LAST_LINK = current_link
# print("Downloading:", LAST_LINK)
#
# time.sleep(5)
ID_HEADER_SET = { ID_HEADER_SET = {
"Subject", "Subject",
} }
@ -105,15 +116,20 @@ async def fetch_message_body(imap_client: aioimaplib.IMAP4_SSL, uid: int):
return BytesParser().parsebytes(dwnld_resp.lines[1]) return BytesParser().parsebytes(dwnld_resp.lines[1])
async def wait_for_new_message(imap_client): async def remove_message(imap_client: aioimaplib.IMAP4_SSL, uid: int):
await imap_client.uid("store", str(uid), "+FLAGS (\Deleted \Seen)")
return await imap_client.expunge()
async def wait_for_new_message(imap_client, options: Options):
persistent_max_uid = 1 persistent_max_uid = 1
persistent_max_uid, head = await fetch_messages_headers( persistent_max_uid, head = await fetch_messages_headers(
imap_client, persistent_max_uid imap_client, persistent_max_uid
) )
while True: while True:
print("Waiting for new message")
idle_task = await imap_client.idle_start(timeout=60) idle_task = await imap_client.idle_start(timeout=60)
msg = await imap_client.wait_server_push() msg = await imap_client.wait_server_push()
print(msg)
imap_client.idle_done() imap_client.idle_done()
await wait_for(idle_task, timeout=5) await wait_for(idle_task, timeout=5)
@ -145,28 +161,84 @@ async def wait_for_new_message(imap_client):
filename += ".pdf" filename += ".pdf"
print(f"Got '{doc_title}'") outpath = options.kindle_dir / filename
urllib.request.urlretrieve(link, LATEST_PATH) print(f"Downloading '{doc_title}' -> '{outpath}'")
shutil.copy(LATEST_PATH, KINDLE_DIR / filename)
urllib.request.urlretrieve(link, outpath)
shutil.copy(outpath, options.latest_path)
await remove_message(imap_client, persistent_max_uid)
# await asyncio.wait_for(idle_task, timeout=5) # await asyncio.wait_for(idle_task, timeout=5)
# print("ending idle") # print("ending idle")
async def make_client(host, user, password): async def make_client(host, user, password, folder):
imap_client = aioimaplib.IMAP4_SSL(host=host) imap_client = aioimaplib.IMAP4_SSL(host=host)
await imap_client.wait_hello_from_server() await imap_client.wait_hello_from_server()
await imap_client.login(user, password) await imap_client.login(user, password)
await imap_client.select("Kindle") await imap_client.select(folder)
return imap_client return imap_client
if __name__ == "__main__": def parse_args():
loop = asyncio.get_event_loop() parser = argparse.ArgumentParser(
client = loop.run_until_complete( prog="Kindle Fetcher",
make_client("protagon.space", "hiro@protagon.space", "DsAgeviNZ.") description="Monitors you Email and automatically downloads the notes sent to it.",
) )
loop.run_until_complete(wait_for_new_message(client))
parser.add_argument("server", type=str, help="the IMAP server to connect to")
parser.add_argument("user", type=str, help="the IMAP username")
parser.add_argument(
"pass_command",
type=str,
help="a shell command that returns the password to the server",
)
parser.add_argument(
"--outdir",
type=str,
help="the directory to dump the note PDFs in",
default="~/kindle_dump",
)
parser.add_argument(
"--current_file",
type=str,
help="the path to the file that will contain the the most currently downloaded pdf relative to `outdir`",
default="latest.pdf",
)
parser.add_argument(
"--imap_folder",
type=str,
help="the folder to monitor for new messages",
default="INBOX",
)
args = parser.parse_args()
password = subprocess.check_output(args.pass_command, shell=True, text=True).strip()
kindle_dir = Path(args.outdir).expanduser()
kindle_dir.mkdir(exist_ok=True, parents=True)
latest_path = Path(kindle_dir / args.current_file).with_suffix(".pdf")
return Options(
server=args.server,
user=args.user,
password=password,
kindle_dir=kindle_dir,
latest_path=latest_path,
mailbox=args.imap_folder,
)
if __name__ == "__main__":
options = parse_args()
loop = asyncio.get_event_loop()
client = loop.run_until_complete(
make_client(options.server, options.user, options.password, options.mailbox)
)
loop.run_until_complete(wait_for_new_message(client, options))
loop.run_until_complete(client.logout()) loop.run_until_complete(client.logout())