From 7baa9137bf086674ebda48d5b7f56de7e47aa559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moussouni=2C=20Ya=C3=ABl?= Date: Sat, 11 Oct 2025 11:38:33 +0200 Subject: [PATCH] 2025-10-11: Rewriting and segmentation of the code --- setup.sh | 1 + src/__pycache__/ads_api.cpython-312.pyc | Bin 0 -> 4551 bytes src/__pycache__/arxiv_api.cpython-312.pyc | Bin 0 -> 6571 bytes .../bibtex_interface.cpython-312.pyc | Bin 0 -> 6135 bytes src/__pycache__/local_api.cpython-312.pyc | Bin 0 -> 5310 bytes src/__pycache__/utils.cpython-312.pyc | Bin 0 -> 5081 bytes src/ads_api.py | 112 ++++++ src/arxiv_api.py | 149 ++++++++ src/arxtic.py | 350 +----------------- src/legacy.py | 194 ++++++++++ src/local_api.py | 127 +++++++ src/utils.py | 103 ++++++ 12 files changed, 704 insertions(+), 332 deletions(-) create mode 100644 src/__pycache__/ads_api.cpython-312.pyc create mode 100644 src/__pycache__/arxiv_api.cpython-312.pyc create mode 100644 src/__pycache__/bibtex_interface.cpython-312.pyc create mode 100644 src/__pycache__/local_api.cpython-312.pyc create mode 100644 src/__pycache__/utils.cpython-312.pyc create mode 100644 src/ads_api.py create mode 100644 src/arxiv_api.py create mode 100644 src/legacy.py create mode 100644 src/local_api.py create mode 100644 src/utils.py diff --git a/setup.sh b/setup.sh index 2f48983..a39416b 100755 --- a/setup.sh +++ b/setup.sh @@ -32,6 +32,7 @@ mkdir -p -v cfg/filters mkdir -p -v db touch db/read.bib touch db/unread.bib +touch db/library.bib chmod u+x *.sh echo "=== Done ===" diff --git a/src/__pycache__/ads_api.cpython-312.pyc b/src/__pycache__/ads_api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31e03aa84fb3ee342588587a8a92a32d720b20dc GIT binary patch literal 4551 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 literal 0 HcmV?d00001 diff --git a/src/__pycache__/arxiv_api.cpython-312.pyc b/src/__pycache__/arxiv_api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13b0891549c3f8aecef0012df5d138b8b97e10f4 GIT binary patch literal 6571 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 literal 0 HcmV?d00001 diff --git a/src/__pycache__/bibtex_interface.cpython-312.pyc b/src/__pycache__/bibtex_interface.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85bbabebee09b1531fc4ddd8378b9fd221630b43 GIT binary patch literal 6135 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 literal 0 HcmV?d00001 diff --git a/src/__pycache__/local_api.cpython-312.pyc b/src/__pycache__/local_api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe30ffdaa052f2575b266790946dbb0b5fb08812 GIT binary patch literal 5310 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 " + COLOUR_DEFAULT) + if action.upper() in ["QUIT", "EXIT", "Q"]: + quit_action = True + elif action in ["", " ", "help", "h"]: + print(COLOUR_OUTPUT + + "Available commands:\n" + + "\t- quit, exit, q: exit\n" + + COLOUR_DEFAULT) + + # Print + elif action.split(" ")[0].upper() in ["PRINT", "P"]: + if len(action.split(" ")) == 1: + print_bibtex(working_bibtex) + elif action.split(" ")[1].upper() == "READ": + print_bibtex(read) + elif action.split(" ")[1].upper() == "UNREAD": + print_bibtex(unread) + elif action.split(" ")[1].upper() == "LIBRARY": + print_bibtex(library) + else: + search_key = action.split(" ")[1] + + if search_key in read_keys: + print_bibtex(read.blocks[read_keys.index(search_key)]) + elif search_key in unread_keys: + print_bibtex(unread.blocks[unread_keys.index(search_key)]) + elif search_key in library_keys: + print_bibtex(library.blocks[library_keys.index(search_key)]) + else: + print(COLOUR_WARNING + + f"Warning: {search_key} cannot be found" + + COLOUR_DEFAULT) + # Clear + elif action.upper() in ["CLEAR", "CLEAN"]: + working_bibtex = bib.Library() + # Today + elif action.upper() in ["TODAY"]: + today_bibtex = today_arxiv() + working_bibtex.add(today_bibtex.blocks) + + # Library + elif action.upper() in ["LIBRARY"]: + library = list_pdf(library) + bibtex_to_file(library, "library.bib") + + # Arxiv + elif action.split(" ")[0].upper() == "ARXIV": + arxiv_ids = action.split(" ")[1:] + feed = get_arxiv_from_ids(arxiv_ids) + entries = get_arxiv_entries(feed) + for entry in entries: + bibtex_entry = arxiv_to_bibtex(entry, + arxtic_score=99) + working_bibtex.add(bibtex_entry.blocks) + + # ADS + elif action.split(" ")[0].upper() == "ADS": + ads_bibcode = "".join(action.split(" ")[1:]) + feed = get_ads_from_bibcode(ads_bibcode) + entries = get_ads_entries(feed) + for entry in entries: + bibtex_entry = ads_to_bibtex(entry, + arxtic_score=99) + working_bibtex.add(bibtex_entry.blocks) diff --git a/src/local_api.py b/src/local_api.py new file mode 100644 index 0000000..030ce10 --- /dev/null +++ b/src/local_api.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +#[TLP:AMBER] LIMITED DISTRIBUTION: WORK IN PROGRESS +""" +ArXtic: + +ArXtic queries arXiv and filters the output. + +@ Author: Moussouni, Yaël (MSc student; yael.moussouni@etu.unistra.fr) +@ Institution: Université de Strasbourg, CNRS, Observatoire astronomique + de Strasbourg, UMR 7550, F-67000 Strasbourg, France +@ Date: 2025-10-10 + +Licence: +ArXtic +Copyright (C) 2025 Yaël Moussouni (yael.moussouni@etu.unistra.fr) + +local_api.py +Copyright (C) 2025 Yaël Moussouni (yael.moussouni@etu.unistra.fr) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see www.gnu.org/licenses/. +""" +import os +from urllib.parse import urlencode, quote_plus + +import requests as rq +import numpy as np +import textwrap as tw +import feedparser as fp +import bibtexparser as bib + +import arxiv_api +import ads_api + +FILTERS_DIR = os.environ.get("FILTERS_DIR") +DB_DIR = os.environ.get("DB_DIR") +PDF_DIR = os.environ.get("PDF_DIR") + +COLOUR_DEFAULT="\033[0m" +COLOUR_INPUT="\033[36m" +COLOUR_OUTPUT="\033[32m" +COLOUR_INFO="\033[34m" +COLOUR_WARNING="\033[93m" +COLOUR_ERROR="\033[91m" + +def file_to_bibtex(filename, directory=DB_DIR): + if not ".bib" in filename: + filename += ".bib" + bibtex = bib.parse_file(directory + filename) + bibtex.remove(bibtex.failed_blocks) + return bibtex + +def bibtex_to_file(bibtex, filename, directory=DB_DIR): + if not ".bib" in filename: + filename += ".bib" + bibentry = bib.write_file(directory+filename, bibtex) + return bibtex + +def update_local_pdf(library=None, directory=PDF_DIR): + # TODO: delete entry in library if the PDF file is deleted. + if library is None: + library = bib.Library() + known_pdf = [] + else: + blocks = [b for b in library.blocks if isinstance(b, bib.model.Block)] + known_pdf = [block["arxtic_filename"] for block in blocks] + + folder_pdf = [f for f in os.listdir(directory) + if not f[0] == "." and ".pdf" if f] + + for pdf in folder_pdf: + fields = pdf.replace(".pdf", "").split("_") + + if pdf in known_pdf: + continue + elif len(fields) < 2: + print(COLOUR_WARNING + + f"Warning: {pdf} has not been correctly identified. " + + "(unrecognized format #1)" + + COLOUR_DEFAULT) + elif fields[1].upper() == "ARXIV": + arxiv_id = "/".join(fields[2:]) + arxiv_library = arxiv_api.arxiv_id(arxiv_id) + if len(arxiv_library.blocks) == 1: + library.add(arxiv_library.blocks) + else: + print(COLOUR_WARNING + + f"Warning: {pdf} has not been correctly identified. " + + "(ambiguous #1)" + + COLOUR_DEFAULT) + elif len(fields) == 5: + first_author = fields[0] + year = fields[1] + bibstem = fields[2] + volume = fields[3] + page = fields[4] + if bibstem == "AA": bibstem = "A&A" + query=(f"first_author:\"{first_author}\"" + f"year:({year})" + f"bibstem:\"{bibstem}\"" + f"volume:\"{volume}\"" + f"page:\"{page}\"") + bibcodes = ads_api.ads_bibcode_search(query, num=2) + if len(bibcodes) == 1: + ads_library = ads_api.ads_bibcode(bibcodes) + library.add(ads_library.blocks) + else: + print(COLOUR_WARNING + + f"Warning: {pdf} has not been correctly identified. " + + "(ambiguous #2)" + + COLOUR_DEFAULT) + else: + print(COLOUR_WARNING + + f"Warning: {pdf} has not been correctly identified. " + + "(unrecognized format #2)" + + COLOUR_DEFAULT) + return library diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..3fb7576 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +#[TLP:AMBER] LIMITED DISTRIBUTION: WORK IN PROGRESS +""" +ArXtic: + +ArXtic queries arXiv and filters the output. + +@ Author: Moussouni, Yaël (MSc student; yael.moussouni@etu.unistra.fr) +@ Institution: Université de Strasbourg, CNRS, Observatoire astronomique + de Strasbourg, UMR 7550, F-67000 Strasbourg, France +@ Date: 2025-10-10 + +Licence: +ArXtic +Copyright (C) 2025 Yaël Moussouni (yael.moussouni@etu.unistra.fr) + +utils.py +Copyright (C) 2025 Yaël Moussouni (yael.moussouni@etu.unistra.fr) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see www.gnu.org/licenses/. +""" +import os +from urllib.parse import urlencode, quote_plus + +import requests as rq +import numpy as np +import textwrap as tw +import feedparser as fp +import bibtexparser as bib + +FILTERS_DIR = os.environ.get("FILTERS_DIR") +DB_DIR = os.environ.get("DB_DIR") +PDF_DIR = os.environ.get("PDF_DIR") + +COLOUR_DEFAULT="\033[0m" +COLOUR_INPUT="\033[36m" +COLOUR_OUTPUT="\033[32m" +COLOUR_INFO="\033[34m" +COLOUR_WARNING="\033[93m" +COLOUR_ERROR="\033[91m" + +def wrap(txt, length=80): + wrapped_txt = '\n'.join(tw.wrap(txt, length, break_long_words=False)) + return wrapped_txt + +def print_abstract(library): + if not isinstance(library, bib.Library): + library = bib.Library(library) + for block in library.blocks: + if isinstance(block, bib.model.Block): + print(COLOUR_INFO, end="") + print(block.key, end="") + print(" [" + block["url"] + "]", end="") + print(COLOUR_DEFAULT) + + print(COLOUR_DEFAULT + wrap(block["title"]) + COLOUR_DEFAULT) + print(COLOUR_OUTPUT + + wrap(", ".join(block["author"].split(" and "))) + + COLOUR_DEFAULT) + print(COLOUR_INPUT + + wrap(block["abstract"]) + + COLOUR_DEFAULT) + print("") + return 0 + +def print_title_author(library): + if not isinstance(library, bib.Library): + library = bib.Library(library) + for block in library.blocks: + if isinstance(block, bib.model.Block): + print(COLOUR_INFO, end="") + print(block.key, end="") + print(" [" + block["url"] + "]", end="") + print(COLOUR_DEFAULT) + + print(COLOUR_DEFAULT + wrap(block["title"]) + COLOUR_DEFAULT) + print(COLOUR_OUTPUT + + wrap(", ".join(block["author"].split(" and "))) + + COLOUR_DEFAULT) + print("") + return 0 + +def print_reference(library): + if not isinstance(library, bib.Library): + library = bib.Library(library) + for block in library.blocks: + if isinstance(block, bib.model.Block): + print(COLOUR_INFO, end="") + print(block.key, end="") + print(" [" + block["url"] + "]", end="") + print(COLOUR_DEFAULT) + return 0