pyinstantref/pdf_data.py

114 lines
3.7 KiB
Python

from pathlib import Path
from datatypes import *
from typing import cast, Any
from util import rofi
import pydbus
import subprocess
import fitz
def get_section_pdf() -> PDFSection:
page_ref: PDFPage = get_page_pdf()
with fitz.Document(page_ref.filepath) as doc:
toc = [FitzBookmark(*x) for x in cast(Any, doc).get_toc()]
page_headers = [x for x in toc if x.page == page_ref.page]
rofi_res = rofi([f"{x.title}" for x in page_headers], prompt="Select header: ")
if rofi_res is None or rofi_res.index is None:
raise RuntimeError("No header was selected.")
else:
selected_header = page_headers[rofi_res.index]
return PDFSection(filepath=page_ref.filepath, title=selected_header.title)
def get_destination_pdf() -> PDFDestination:
page_ref: PDFPage = get_page_pdf()
with fitz.Document(page_ref.filepath) as doc:
destinations = cast(FitzDestinations, cast(Any, doc).resolve_names())
page_dests = {
k: x
for k, x in destinations.items()
if cast(Any, x)["page"] + 1 == page_ref.page
}
rofi_res = rofi(
[f"{k}" for k, _ in page_dests.items()], prompt="Select named destination: "
)
if rofi_res is None or rofi_res.index is None:
raise RuntimeError("No destination was selected.")
else:
selected_header = [x for x in page_dests.items()][rofi_res.index]
return PDFDestination(filepath=page_ref.filepath, name=selected_header[0])
def get_page_pdf() -> PDFPage:
"""Find current page of focused PDF reader window.
Returns
-------
`PDFPage` reference to the current page.
"""
try:
res = subprocess.run(
["xdotool", "getactivewindow"], capture_output=True, text=True
)
window_id: WindowId = WindowId(int(res.stdout))
res = subprocess.run(
["xdotool", "getactivewindow", "getwindowpid"],
capture_output=True,
text=True,
)
pid: ProcessId = ProcessId(int(res.stdout))
except OSError as e:
raise Exception("Please install `xdotool`.") from e
except subprocess.CalledProcessError as e:
raise Exception(
"Could not get current active window ID. Is a window focused right now?"
)
try:
res = subprocess.run(
["xprop", "-id", str(window_id), "WM_CLASS"], capture_output=True, text=True
)
# WM_CLASS(STRING) = "org.pwmt.zathura", "Zathura"
wm_class: list[str] = [
i.strip('"\n') for i in res.stdout.split(" = ")[-1].split(", ")
]
except OSError as e:
raise Exception("Please install `xprop`.") from e
except subprocess.CalledProcessError as e:
raise Exception("Could not get focused window class.") from e
match wm_class[0]:
case "Zathura":
return get_page_zathura(pid)
case "org.pwmt.zathura":
return get_page_zathura(pid)
case _:
raise Exception(
f"Can not retrieve pdf data from this type of window {wm_class}."
)
def get_page_zathura(pid: ProcessId) -> PDFPage:
"""Given the PID of a Zathura instance, find which page of which file it's on.
Parameters
----------
pid
Process ID of the Zathura instance to retrieve the reference from.
Returns
-------
`PDFPage` that the Zathura instance is currently on.
"""
bus = pydbus.SessionBus()
obj = bus.get(f"org.pwmt.zathura.PID-{pid}", "/org/pwmt/zathura")
filename: str = obj.filename
# zathura returns 0-indexed pages
pagenumber: PageNumber = obj.pagenumber + 1
return PDFPage(filepath=Path(filename), page=pagenumber)