Compare commits
5 commits
bcd06ffecc
...
329b076caf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
329b076caf | ||
|
|
e31ae00528 | ||
|
|
330554435d | ||
|
|
043f57842a | ||
|
|
6e151a8d28 |
3 changed files with 66 additions and 38 deletions
92
main.py
92
main.py
|
|
@ -1,3 +1,4 @@
|
||||||
|
import alive_progress
|
||||||
import requests
|
import requests
|
||||||
import connectors
|
import connectors
|
||||||
import argparse
|
import argparse
|
||||||
|
|
@ -29,6 +30,8 @@ class BookCollection(dict):
|
||||||
keys = expand_range(sequence)
|
keys = expand_range(sequence)
|
||||||
|
|
||||||
for key in keys:
|
for key in keys:
|
||||||
|
if not args.non_series and not float(key).is_integer():
|
||||||
|
continue
|
||||||
self.setdefault(key, [])
|
self.setdefault(key, [])
|
||||||
self[key].append(book.asin)
|
self[key].append(book.asin)
|
||||||
|
|
||||||
|
|
@ -55,39 +58,17 @@ def expand_range(part):
|
||||||
return [] # Handle non-numeric input or invalid format
|
return [] # Handle non-numeric input or invalid format
|
||||||
|
|
||||||
|
|
||||||
def process_sequence(books):
|
|
||||||
"""Groups books by ASIN, handling sequence ranges (including floats)."""
|
|
||||||
books_sequence = {}
|
|
||||||
for book in books:
|
|
||||||
asin = book["asin"]
|
|
||||||
sequence = book.get("sequence", "")
|
|
||||||
|
|
||||||
if sequence:
|
|
||||||
keys = expand_range(sequence.split(", ")[0])
|
|
||||||
else:
|
|
||||||
keys = [float(book.get("sort", "1")) * -1]
|
|
||||||
|
|
||||||
for key in keys:
|
|
||||||
if key not in books_sequence:
|
|
||||||
books_sequence[key] = []
|
|
||||||
books_sequence[key].append(asin)
|
|
||||||
|
|
||||||
keys = sorted(books_sequence.keys(), key=lambda x: float(x))
|
|
||||||
ordered_sequence = {}
|
|
||||||
for key in keys:
|
|
||||||
ordered_sequence[key] = books_sequence[key]
|
|
||||||
return ordered_sequence
|
|
||||||
|
|
||||||
|
|
||||||
def process_audible_serie(books, serie_name):
|
def process_audible_serie(books, serie_name):
|
||||||
processed_books = BookCollection(serie_name)
|
processed_books = BookCollection(serie_name)
|
||||||
|
|
||||||
for json in books:
|
for json in books:
|
||||||
if book["relationship_type"] == "series":
|
if json["relationship_type"] == "series":
|
||||||
book = Book(json["asin"])
|
book = Book(json["asin"])
|
||||||
book.series.setdefault(serie_name, json["sequence"])
|
book.series.setdefault(serie_name, json["sequence"])
|
||||||
book.series.setdefault(serie_name, f"-{json['sort']}")
|
book.series.setdefault(serie_name, f"-{json['sort']}")
|
||||||
processed_books.add(book)
|
processed_books.add(book)
|
||||||
|
else:
|
||||||
|
logger.debug("Skipping non-series book: %s", json["asin"])
|
||||||
|
|
||||||
return processed_books
|
return processed_books
|
||||||
|
|
||||||
|
|
@ -150,9 +131,13 @@ def main():
|
||||||
libraries = abs.get_library_ids()
|
libraries = abs.get_library_ids()
|
||||||
|
|
||||||
for library in libraries:
|
for library in libraries:
|
||||||
series = abs.get_series_by_library_id(library["id"])
|
if library["mediaType"] != "book" or library["provider"] != "audible":
|
||||||
|
continue
|
||||||
|
|
||||||
for serie in series:
|
logger.info("==== %s ====", library["name"])
|
||||||
|
|
||||||
|
series = abs.get_series_by_library_id(library["id"])
|
||||||
|
for serie in alive_progress.alive_it(series, title=library["name"]):
|
||||||
series_name = serie["name"]
|
series_name = serie["name"]
|
||||||
abs_book_sequence = process_abs_serie(serie["books"], series_name)
|
abs_book_sequence = process_abs_serie(serie["books"], series_name)
|
||||||
|
|
||||||
|
|
@ -168,7 +153,9 @@ def main():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
audible_serie = audible.get_produce_from_asin(series_asin)
|
audible_serie = audible.get_produce_from_asin(series_asin)
|
||||||
audible_book_sequence = process_sequence(audible_serie["relationships"])
|
audible_book_sequence = process_audible_serie(
|
||||||
|
audible_serie["relationships"], series_name
|
||||||
|
)
|
||||||
|
|
||||||
if len(abs_book_sequence) >= len(audible_book_sequence):
|
if len(abs_book_sequence) >= len(audible_book_sequence):
|
||||||
continue
|
continue
|
||||||
|
|
@ -186,13 +173,30 @@ def main():
|
||||||
soon_to_release_books = []
|
soon_to_release_books = []
|
||||||
|
|
||||||
for key in missing_keys:
|
for key in missing_keys:
|
||||||
|
found = False
|
||||||
|
for asin in audible_book_sequence[key]:
|
||||||
try:
|
try:
|
||||||
audnexus.get_book_from_asin(audible_book_sequence[key][0])
|
audnexus.get_book_from_asin(asin)
|
||||||
missing_books.append(key)
|
missing_books.append(key)
|
||||||
|
logger.debug(
|
||||||
|
"%s Book %.1f is missing - %s",
|
||||||
|
series_name,
|
||||||
|
key,
|
||||||
|
audible_book_sequence[key][0],
|
||||||
|
)
|
||||||
|
found = True
|
||||||
|
break
|
||||||
except requests.exceptions.HTTPError:
|
except requests.exceptions.HTTPError:
|
||||||
logger.debug("%s Book %d is yet to be released", series_name, key)
|
pass
|
||||||
|
|
||||||
|
if not found and args.oncoming:
|
||||||
soon_to_release_books.append(key)
|
soon_to_release_books.append(key)
|
||||||
|
logger.debug(
|
||||||
|
"%s Book %d is yet to be released - %s",
|
||||||
|
series_name,
|
||||||
|
key,
|
||||||
|
audible_book_sequence[key][0],
|
||||||
|
)
|
||||||
|
|
||||||
msgs = []
|
msgs = []
|
||||||
|
|
||||||
|
|
@ -208,15 +212,29 @@ def main():
|
||||||
msg,
|
msg,
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: add input to choose which library is to be scaned
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("-d", "--dev", action="store_true")
|
# General flags
|
||||||
parser.add_argument("-v", "--verbose", action="store_true")
|
parser.add_argument(
|
||||||
|
"-v", "--verbose", action="store_true", help="Enable verbose logging"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", "--dev", action="store_true", help="Use development/mock connectors"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Feature-specific flags
|
||||||
|
parser.add_argument(
|
||||||
|
"--non-series",
|
||||||
|
action="store_true",
|
||||||
|
help="Include non-series books (books not part of a numbered series)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--oncoming",
|
||||||
|
action="store_true",
|
||||||
|
help="Show books to be released",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
@ -239,6 +257,8 @@ if __name__ == "__main__":
|
||||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||||
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
alive_progress.config_handler.set_global(enrich_print=False)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.DEBUG if args.verbose else logging.INFO)
|
logger.setLevel(logging.DEBUG if args.verbose else logging.INFO)
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,14 @@ python main.py
|
||||||
|
|
||||||
Logs are written to the `log` file.
|
Logs are written to the `log` file.
|
||||||
|
|
||||||
|
### Feature-specific Arguments
|
||||||
|
|
||||||
|
- `--non-series`
|
||||||
|
Include non-series books (books not part of a numbered series).
|
||||||
|
|
||||||
|
- `--oncoming`
|
||||||
|
Show books that are yet to be released.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
- [main.py](main.py): Entry point and main logic
|
- [main.py](main.py): Entry point and main logic
|
||||||
|
|
|
||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue