Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download by series, download by author #184

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
77 changes: 73 additions & 4 deletions src/audible_cli/cmds/cmd_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,17 @@ def display_counter():
@click.option(
"--title", "-t",
multiple=True,
help="tile of the audiobook (partial search)"
help="title of the audiobook (partial search)"
)
@click.option(
"--author", "-a",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -a option is already used by --asin.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops =] I thought I'd looked for that.

All things considered, I think the more natural assumption would be to have the different lists merged before checking -- I just haven't had time to come back to this since then and I'm not sure how soon I can

Copy link
Owner

@mkb79 mkb79 Feb 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll have time this weekend to rework some things and then merge your request.

multiple=True,
help="author of the audiobook (partial search)"
)
@click.option(
"--series", "-s",
multiple=True,
help="series of the audiobook (partial search)"
)
@click.option(
"--aax",
Expand Down Expand Up @@ -748,10 +758,13 @@ async def cli(session, api_client, **params):
get_all = params.get("all") is True
asins = params.get("asin")
titles = params.get("title")
if get_all and (asins or titles):
logger.error("Do not mix *asin* or *title* option with *all* option.")
authors = params.get("author")
series = params.get("series")
if get_all and (asins or titles or authors or series):
logger.error("Do not mix *asin*, *title*, *series*, or *author* options with the *all* option.")
click.Abort()


# what to download
get_aax = params.get("aax")
get_aaxc = params.get("aaxc")
Expand Down Expand Up @@ -811,7 +824,7 @@ async def cli(session, api_client, **params):
image_sizes=", ".join(cover_sizes),
bunch_size=bunch_size,
response_groups=(
"product_desc, media, product_attrs, relationships, "
"product_desc, media, product_attrs, relationships, contributors, "
"series, customer_rights, pdf_url"
),
start_date=start_date,
Expand Down Expand Up @@ -869,6 +882,62 @@ async def cli(session, api_client, **params):
f"Skip title {title}: Not found in library"
)

for author in authors:
match = library.search_item_by_author(author)
full_match = [i for i in match if i[1] == 100]

if match:
if no_confirm:
[jobs.append(i[0].asin) for i in full_match or match]
else:
choices = []
for i in full_match or match:
a = i[0].asin
t = i[0].full_title
l = ", ".join(a["name"] for a in i[0].authors)
c = questionary.Choice(title=f"{a} # {t} by {l}", value=a)
choices.append(c)

answer = await questionary.checkbox(
f"Found the following matches for '{author}'. Which you want to download?",
choices=choices
).unsafe_ask_async()
if answer is not None:
[jobs.append(i) for i in answer]

else:
logger.error(
f"Skip author {author}: Not found in library"
)

for s in series:
match = library.search_item_by_series(s)
full_match = [i for i in match if i[1] == 100]

if match:
if no_confirm:
[jobs.append(i[0].asin) for i in full_match or match]
else:
choices = []
for i in full_match or match:
a = i[0].asin
t = i[0].full_title
l = ", ".join(s["title"] for s in i[0].series)
c = questionary.Choice(title=f"{a} # {t} in {l}", value=a)
choices.append(c)

answer = await questionary.checkbox(
f"Found the following matches for '{s}'. Which you want to download?",
choices=choices
).unsafe_ask_async()
if answer is not None:
[jobs.append(i) for i in answer]

else:
logger.error(
f"Skip series {s}: Not found in library"
)

# set queue
global QUEUE
QUEUE = asyncio.Queue()
Expand Down
34 changes: 34 additions & 0 deletions src/audible_cli/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ def substring_in_title(self, substring, p=100):
accuracy = self.substring_in_title_accuracy(substring)
return accuracy >= p

def substring_in_authors_accuracy(self, substring):
max_accuracy = 0
authors = self.authors or []
for author in authors:
name = author["name"]
match = LongestSubString(substring, name)
max_accuracy = max(max_accuracy, match.percentage)

return round(max_accuracy, 2)

def substring_in_series_accuracy(self, substring):
max_accuracy = 0
seriesList = self.series or []
for series in seriesList:
name = series["title"]
match = LongestSubString(substring, name)
max_accuracy = max(max_accuracy, match.percentage)

return round(max_accuracy, 2)

def get_cover_url(self, res: Union[str, int] = 500):
images = self.product_images
res = str(res)
Expand Down Expand Up @@ -460,6 +480,20 @@ def search_item_by_title(self, search_title, p=80):
match.append([i, accuracy]) if accuracy >= p else ""

return match
def search_item_by_author(self, search_author, p=80):
match = []
for i in self._data:
accuracy = i.substring_in_authors_accuracy(search_author)
match.append([i, accuracy]) if accuracy >= p else ""

return match
def search_item_by_series(self, search_series, p=80):
match = []
for i in self._data:
accuracy = i.substring_in_series_accuracy(search_series)
match.append([i, accuracy]) if accuracy >= p else ""

return match


class Library(BaseList):
Expand Down