2025-10-22: Automatic update

This commit is contained in:
Moussouni, Yaël
2025-10-22 15:39:21 +02:00
parent b9240d7bf5
commit e7fbdad022
4 changed files with 192 additions and 227 deletions

View File

@@ -56,22 +56,6 @@ COLOUR_INFO="\033[34m"
COLOUR_WARNING="\033[93m" COLOUR_WARNING="\033[93m"
COLOUR_ERROR="\033[91m" COLOUR_ERROR="\033[91m"
ids = ["2510.06329", "2509.13163"]
bibcodes = ["2022A&A...658A.152V", "2021A&A...649A..97L"]
query = "first_author:\"Voggel, K\"year:(2022)"
#test1 = local_api.update_local_pdf()
#local_api.bibtex_to_file(test1, "test1")
#test1 = local_api.file_to_bibtex("test1")
#test2 = bib.Library()
#
#utils.arxtic_comment("2022ApJ...941L..11F", test1)
#utils.arxtic_library_add("2022ApJ...941L..11F", test1, "test1")
#utils.arxtic_keywords_add("2022ApJ...941L..11F", test1, "kw1")
#utils.arxtic_score("2022ApJ...941L..11F", test1, "42")
#utils.arxtic_date_read("2022ApJ...941L..11F", test1)
#utils.export_abstract(test1, "test1")
if __name__ == "__main__": if __name__ == "__main__":
q = False q = False
s = True s = True
@@ -79,6 +63,10 @@ if __name__ == "__main__":
if not f[0] == "." and ".bib" in f] if not f[0] == "." and ".bib" in f]
libraries = {l: local_api.file_to_bibtex(l + ".bib") libraries = {l: local_api.file_to_bibtex(l + ".bib")
for l in libraries_names} for l in libraries_names}
libraries["local"] = local_api.update_local_pdf(library=libraries["local"])
libraries["read"] = local_api.update_library(libraries["local"], "read")
libraries["unread"] = local_api.update_library(libraries["local"], "unread")
while not q: while not q:
print(COLOUR_INPUT + "Select an action") print(COLOUR_INPUT + "Select an action")
val = input("> " + COLOUR_DEFAULT) val = input("> " + COLOUR_DEFAULT)
@@ -104,6 +92,10 @@ if __name__ == "__main__":
lib_name = libraries_names[i] lib_name = libraries_names[i]
lib = libraries[lib_name] lib = libraries[lib_name]
local_api.bibtex_to_file(lib, lib_name) local_api.bibtex_to_file(lib, lib_name)
for i in range(len(libraries)):
lib_name = libraries_names[i]
lib = libraries[lib_name]
utils.export_author_year(lib, lib_name+".txt")
s = True s = True
elif arg0 in ["cancel", "reset", "reload"]: elif arg0 in ["cancel", "reset", "reload"]:
@@ -117,6 +109,13 @@ if __name__ == "__main__":
library=libraries["local"]) library=libraries["local"])
s = False s = False
elif arg0 in ["update"]:
libraries["local"] = local_api.update_local_pdf(
library=libraries["local"])
libraries["read"] = local_api.update_library(libraries["local"], "read")
libraries["unread"] = local_api.update_library(libraries["local"], "unread")
s = False
elif arg0 in ["today"]: elif arg0 in ["today"]:
today_lib = arxiv_api.arxiv_today() today_lib = arxiv_api.arxiv_today()
libraries_names.append("today") libraries_names.append("today")
@@ -129,10 +128,13 @@ if __name__ == "__main__":
elif nargs == 3: elif nargs == 3:
if args[2] in ["abstract", "abs"]: if args[2] in ["abstract", "abs"]:
utils.print_abstract(libraries[args[1]]) utils.print_abstract(libraries[args[1]])
if args[2] in ["title", "author", "authors"]: elif args[2] in ["title"]:
utils.print_title_author(libraries[args[1]]) utils.print_title_author(libraries[args[1]])
if args[2] in ["reference", "references", "ref", "refs"]: elif args[2] in ["reference", "references", "ref", "refs"]:
utils.print_reference(libraries[args[1]]) utils.print_reference(libraries[args[1]])
elif args[2] in ["author", "authors", "year"]:
utils.print_author_year(libraries[args[1]])
else: else:
raise Exception("Not recognized") raise Exception("Not recognized")
@@ -141,17 +143,19 @@ if __name__ == "__main__":
for i in range(len(libraries)): for i in range(len(libraries)):
lib_name = libraries_names[i] lib_name = libraries_names[i]
lib = libraries[lib_name] lib = libraries[lib_name]
utils.export_abstract(lib, lib_name+".txt") utils.export_author_year(lib, lib_name+".txt")
elif nargs == 2: elif nargs == 2:
utils.export_abstract(libraries[args[1]], args[1]+".txt") utils.export_author_year(libraries[args[1]], args[1]+".txt")
elif nargs == 3: elif nargs == 3:
if args[2] in ["abstract", "abs"]: if args[2] in ["abstract", "abs"]:
utils.export_abstract(libraries[args[1]], args[1]+".txt") utils.export_abstract(libraries[args[1]], args[1]+".txt")
if args[2] in ["title", "author", "authors"]: elif args[2] in ["title"]:
utils.export_title_author(libraries[args[1]], args[1]+".txt") utils.export_title_author(libraries[args[1]], args[1]+".txt")
if args[2] in ["reference", "references", "ref", "refs"]: elif args[2] in ["reference", "references", "ref", "refs"]:
utils.export_reference(libraries[args[1]], args[1]+".txt") utils.export_reference(libraries[args[1]], args[1]+".txt")
elif args[2] in ["author", "authors", "year"]:
utils.export_author_year(libraries[args[1]], args[1]+".txt")
else: else:
raise Exception("Not recognized") raise Exception("Not recognized")
@@ -181,14 +185,52 @@ if __name__ == "__main__":
utils.arxtic_comment(args[2], libraries[args[2]]) utils.arxtic_comment(args[2], libraries[args[2]])
s = False s = False
elif arg0 in ["unread", "todo"]:
if nargs == 2:
block = utils.find(args[1], libraries["local"])
known_libs = block["arxtic_library"]
if not "unread" in known_libs.split(","):
if "read" in known_libs.split(","):
utils.arxtic_library_remove(args[1], libraries["local"], "read")
utils.arxtic_library_add(args[1], libraries["local"], "unread")
s = False
elif nargs == 3:
block = utils.find(args[1], libraries[args[2]])
known_libs = block["arxtic_library"]
if not "unread" in known_libs.split(","):
if "read" in known_libs.split(","):
utils.arxtic_library_remove(args[1], libraries[args[2]], "read")
utils.arxtic_library_add(args[1], libraries[args[2]], "unread")
s = False
else:
raise Exception("Not recognized")
elif arg0 in ["read"]: elif arg0 in ["read"]:
if nargs == 2: if nargs == 2:
utils.launch_reader(args[1], libraries["local"]) utils.launch_reader(args[1], libraries["local"])
utils.arxtic_comment(args[1], libraries["local"]) utils.arxtic_comment(args[1], libraries["local"])
block = utils.find(args[1], libraries["local"])
known_libs = block["arxtic_library"]
if not "read" in known_libs.split(","):
if "unread" in known_libs.split(","):
utils.arxtic_library_remove(args[1], libraries["local"], "unread")
utils.arxtic_library_add(args[1], libraries["local"], "read")
utils.arxtic_date_read(args[1], libraries["local"])
s = False s = False
elif nargs == 3: elif nargs == 3:
utils.launch_reader(args[1], libraries[args[2]]) utils.launch_reader(args[1], libraries[args[2]])
utils.arxtic_comment(args[1], libraries[args[2]]) utils.arxtic_comment(args[1], libraries[args[2]])
block = utils.find(args[1], libraries[args[2]])
known_libs = block["arxtic_library"]
if not "read" in known_libs.split(","):
if "unread" in known_libs.split(","):
utils.arxtic_library_remove(args[1], libraries[args[2]], "unread")
utils.arxtic_library_add(args[1], libraries[args[2]], "read")
utils.arxtic_date_read(args[1], libraries[args[2]])
s = False s = False
else: else:
raise Exception("Not recognized") raise Exception("Not recognized")

View File

@@ -1,194 +0,0 @@
#!/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-09-15
Licence:
ArXtic
Copyright (C) 2025 Yaël Moussouni (yael.moussouni@etu.unistra.fr)
legacy.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
import textwrap as tw
import feedparser as fp
import bibtexparser as bib
import requests as rq
import numpy as np
from urllib.parse import urlencode, quote_plus
FILTERS_DIR = os.environ.get("FILTERS_DIR")
DB_DIR = os.environ.get("DB_DIR")
PDF_DIR = os.environ.get("PDF_DIR")
ARXIV_QUERY_URL = os.environ.get("ARXIV_QUERY_URL")
ARXIV_RSS_URL = os.environ.get("ARXIV_RSS_URL")
ADSABS_QUERY_URL = os.environ.get("ADSABS_QUERY_URL")
ADSABS_EXPORT_URL = os.environ.get("ADSABS_EXPORT_URL")
ADSABS_API_KEY = os.environ.get("ADSABS_API_KEY")
COLOUR_DEFAULT="\033[0m"
COLOUR_INPUT="\033[36m"
COLOUR_OUTPUT="\033[32m"
COLOUR_INFO="\033[34m"
COLOUR_WARNING="\033[93m"
COLOUR_ERROR="\033[91m"
## Filters
def get_filters():
filters = []
filters_list = [f for f in os.listdir(FILTERS_DIR) if not f[0] == "."]
for i in range(len(filters_list)):
path = FILTERS_DIR + filters_list[i]
with open(path) as filter_file:
dic = {"fields": [], "values": [], "score": 1}
for line in filter_file.readlines():
if "#FIELD" in line:
field = line.split("=")[1].replace("\"", "").strip()
dic["fields"].append(field)
elif "#SCORE" in line:
field = line.split("=")[1].strip()
dic["score"] = int(field)
elif line[0] == "#" or line in [" \n", "\n", ""]:
continue
else:
value = line.replace("\n", "")
dic["values"].append(value)
filters.append(dic)
return filters
def filter_entries(filters, entries):
filtered_entries = []
filtered_fields = []
filtered_keywords = []
filtered_score = []
for entry in entries:
added = False
for filter_ in filters:
fields = filter_["fields"]
values = filter_["values"]
score = filter_["score"]
for field in fields:
for value in values:
if field in list(entry):
val = entry[field]
else:
val = ""
if not added and value.upper() in str(val).upper():
filtered_entries.append(entry)
filtered_fields.append([field])
filtered_keywords.append([value])
filtered_score.append(score)
added = True
elif added and value.upper() in str(val).upper():
filtered_score[-1] = filtered_score[-1] + score
if not field in filtered_fields[-1]:
filtered_fields[-1].append(field)
if not value in filtered_keywords[-1]:
filtered_keywords[-1].append(value)
filtered_data = {"fields": filtered_fields,
"keywords": filtered_keywords,
"score": filtered_score}
return filtered_entries, filtered_data
if __name__ == "__main__":
read = file_to_bibtex("read.bib")
unread = file_to_bibtex("unread.bib")
library = file_to_bibtex("library.bib")
quit_action = False
working_bibtex = bib.Library()
while not quit_action:
read_keys = [b.key for b in read.blocks]
unread_keys = [b.key for b in unread.blocks]
library_keys = [b.key for b in library.blocks]
library_keys = [b.key for b in library.blocks]
print(COLOUR_INPUT + "Select an action")
action = input("> " + 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)

View File

@@ -66,6 +66,17 @@ def bibtex_to_file(bibtex, filename, directory=DB_DIR):
bibentry = bib.write_file(directory+filename, bibtex) bibentry = bib.write_file(directory+filename, bibtex)
return bibtex return bibtex
def update_library(source_library, lib_name):
new_library = bib.Library()
for block in source_library.blocks:
if isinstance(block, bib.model.Block):
arxtic_library = block["arxtic_library"]
if lib_name in arxtic_library.split(","):
new_library.add(block)
return new_library
def update_local_pdf(library=None, directory=PDF_DIR): def update_local_pdf(library=None, directory=PDF_DIR):
# TODO: delete entry in library if the PDF file is deleted. <YM, 2025-10-11> # TODO: delete entry in library if the PDF file is deleted. <YM, 2025-10-11>
if library is None: if library is None:

View File

@@ -61,10 +61,28 @@ COLOUR_ARXTIC = "\033[91m"
## General ## General
def wrap(txt, length=80): def wrap(txt, length=80, keep_line_break = False):
if keep_line_break:
wrapped_table = []
for line in txt.split("\n"):
wrapped_line = '\n'.join(tw.wrap(line, length, break_long_words=False))
wrapped_table += [wrapped_line]
wrapped_txt = "\n".join(wrapped_table)
else:
wrapped_txt = '\n'.join(tw.wrap(txt, length, break_long_words=False)) wrapped_txt = '\n'.join(tw.wrap(txt, length, break_long_words=False))
return wrapped_txt return wrapped_txt
def parse_authors(authors):
author_list = authors.replace("{", "").replace("}", "").split(" and ")
N = len(author_list)
if N == 1:
return author_list[0]
elif N == 2:
return f"{author_list[0]} & {author_list[1]}"
else:
return f"{author_list[0]} et al."
## Prints ## Prints
def print_abstract(library): def print_abstract(library):
@@ -72,7 +90,7 @@ def print_abstract(library):
library = bib.Library(library) library = bib.Library(library)
for block in library.blocks: for block in library.blocks:
if isinstance(block, bib.model.Block): if isinstance(block, bib.model.Block):
print("#" print("# "
+ COLOUR_REF + COLOUR_REF
+ block.key + " [" + block["url"] + "]" + block.key + " [" + block["url"] + "]"
+ COLOUR_DEFAULT) + COLOUR_DEFAULT)
@@ -98,7 +116,7 @@ def print_abstract(library):
if block["arxtic_comment"] != "": if block["arxtic_comment"] != "":
print("Comment: " print("Comment: "
+ COLOUR_ARXTIC + COLOUR_ARXTIC
+ wrap(block["arxtic_comment"]) + wrap(block["arxtic_comment"], keep_line_break=True)
+ COLOUR_DEFAULT) + COLOUR_DEFAULT)
if block["arxtic_library"] != "": if block["arxtic_library"] != "":
print("Library: " print("Library: "
@@ -130,7 +148,7 @@ def print_title_author(library):
library = bib.Library(library) library = bib.Library(library)
for block in library.blocks: for block in library.blocks:
if isinstance(block, bib.model.Block): if isinstance(block, bib.model.Block):
print("#" print("# "
+ COLOUR_REF + COLOUR_REF
+ block.key + " [" + block["url"] + "]" + block.key + " [" + block["url"] + "]"
+ COLOUR_DEFAULT) + COLOUR_DEFAULT)
@@ -152,7 +170,7 @@ def print_title_author(library):
if block["arxtic_comment"] != "": if block["arxtic_comment"] != "":
print("Comment: " print("Comment: "
+ COLOUR_ARXTIC + COLOUR_ARXTIC
+ wrap(block["arxtic_comment"]) + wrap(block["arxtic_comment"], keep_line_break=True)
+ COLOUR_DEFAULT) + COLOUR_DEFAULT)
if block["arxtic_library"] != "": if block["arxtic_library"] != "":
print("Library: " print("Library: "
@@ -190,6 +208,60 @@ def print_reference(library):
print(COLOUR_DEFAULT) print(COLOUR_DEFAULT)
return 0 return 0
def print_author_year(library):
if not isinstance(library, bib.Library):
library = bib.Library(library)
for block in library.blocks:
if isinstance(block, bib.model.Block):
print("# "
+ COLOUR_REF
+ block.key + " [" + block["url"] + "]"
+ COLOUR_DEFAULT)
if block["arxtic_filename"] != "":
print(COLOUR_REF
+ "("
+ PDF_DIR
+ block["arxtic_filename"]
+ ")"
+ COLOUR_DEFAULT)
print("Article: "
+ COLOUR_AUTHOR
+ wrap(parse_authors(block["author"])
+ " (" + block["year"] + ")")
+ COLOUR_DEFAULT)
print("Title: "
+ COLOUR_TITLE
+ wrap(block["title"])
+ COLOUR_DEFAULT)
if block["arxtic_comment"] != "":
print("Comment: "
+ COLOUR_ARXTIC
+ wrap(block["arxtic_comment"], keep_line_break=True)
+ COLOUR_DEFAULT)
if block["arxtic_library"] != "":
print("Library: "
+ COLOUR_ARXTIC
+ ", ".join(block["arxtic_library"].split(","))
+ COLOUR_DEFAULT)
if block["arxtic_keywords"] != "":
print("Keywords: "
+ COLOUR_ARXTIC
+ ", ".join(block["arxtic_library"].split(","))
+ COLOUR_DEFAULT)
if float(block["arxtic_score"]) >= 0:
print("Score: "
+ COLOUR_ARXTIC
+ block["arxtic_score"]
+ COLOUR_DEFAULT)
if block["arxtic_date_read"] != "":
print("Read date: "
+ COLOUR_ARXTIC
+ block["arxtic_date_read"]
+ COLOUR_DEFAULT)
print("")
print(80*"=")
print("")
return 0
## Exports ## Exports
def export_abstract(library, filename, directory=PDF_DIR): def export_abstract(library, filename, directory=PDF_DIR):
@@ -198,14 +270,15 @@ def export_abstract(library, filename, directory=PDF_DIR):
with open(directory + filename, "w+") as file: with open(directory + filename, "w+") as file:
for block in library.blocks: for block in library.blocks:
if isinstance(block, bib.model.Block): if isinstance(block, bib.model.Block):
file.write("#" + block.key + " [" + block["url"] + "]\n") file.write("# " + block.key + " [" + block["url"] + "]\n")
file.write(wrap("Title: " + block["title"]) + "\n") file.write(wrap("Title: " + block["title"]) + "\n")
file.write(wrap("Author(s): " file.write(wrap("Author(s): "
+ ", ".join(block["author"].split(" and "))) + ", ".join(block["author"].split(" and ")))
+ "\n") + "\n")
file.write(wrap("Abstract: " + block["abstract"]) + "\n") file.write(wrap("Abstract: " + block["abstract"]) + "\n")
if block["arxtic_comment"] != "": if block["arxtic_comment"] != "":
file.write(wrap("Comment: " + block["arxtic_comment"]) file.write(wrap("Comment: " + block["arxtic_comment"],
keep_line_break=True)
+ "\n") + "\n")
if block["arxtic_library"] != "": if block["arxtic_library"] != "":
file.write("Library: " file.write("Library: "
@@ -229,13 +302,14 @@ def export_title_author(library, filename, directory=PDF_DIR):
with open(directory + filename, "w+") as file: with open(directory + filename, "w+") as file:
for block in library.blocks: for block in library.blocks:
if isinstance(block, bib.model.Block): if isinstance(block, bib.model.Block):
file.write("#" + block.key + " [" + block["url"] + "]\n") file.write("# " + block.key + " [" + block["url"] + "]\n")
file.write(wrap("Title: " + block["title"]) + "\n") file.write(wrap("Title: " + block["title"]) + "\n")
file.write(wrap("Author(s): " file.write(wrap("Author(s): "
+ ", ".join(block["author"].split(" and "))) + ", ".join(block["author"].split(" and ")))
+ "\n") + "\n")
if block["arxtic_comment"] != "": if block["arxtic_comment"] != "":
file.write(wrap("Comment: " + block["arxtic_comment"]) file.write(wrap("Comment: " + block["arxtic_comment"],
keep_line_break=True)
+ "\n") + "\n")
if block["arxtic_library"] != "": if block["arxtic_library"] != "":
file.write("Library: " file.write("Library: "
@@ -259,9 +333,41 @@ def export_reference(library, filename, directory=PDF_DIR):
with open(directory + filename, "w+") as file: with open(directory + filename, "w+") as file:
for block in library.blocks: for block in library.blocks:
if isinstance(block, bib.model.Block): if isinstance(block, bib.model.Block):
file.write("#" + block.key + " [" + block["url"] + "]\n") file.write("# " + block.key + " [" + block["url"] + "]\n")
return 0 return 0
def export_author_year(library, filename, directory=PDF_DIR):
if not isinstance(library, bib.Library):
library = bib.Library(library)
with open(directory + filename, "w+") as file:
for block in library.blocks:
if isinstance(block, bib.model.Block):
file.write("# " + block.key + " [" + block["url"] + "]\n")
file.write(wrap("Article: "
+ parse_authors(block["author"])
+ " (" + block["year"] + ")")
+ "\n")
file.write(wrap("Title: " + block["title"]) + "\n")
if block["arxtic_comment"] != "":
file.write(wrap("Comment: " + block["arxtic_comment"],
keep_line_break=True)
+ "\n")
if block["arxtic_library"] != "":
file.write("Library: "
+ ", ".join(block["arxtic_library"].split(","))
+ "\n")
if block["arxtic_keywords"] != "":
file.write("Keywords: "
+ ", ".join(block["arxtic_library"].split(","))
+ "\n")
if float(block["arxtic_score"]) >= 0:
file.write("Score: " + block["arxtic_score"] + "\n")
if block["arxtic_date_read"] != "":
file.write("Read date: " + block["arxtic_date_read"] + "\n")
file.write("\n" + 80*"=" + "\n")
file.write("\n")
return 0
## Manipulation ## Manipulation
def find(key, library): def find(key, library):