Initial commit
This commit is contained in:
14
.claude-plugin/plugin.json
Normal file
14
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "books",
|
||||||
|
"description": "TODO: Add description",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": {
|
||||||
|
"name": "TODO: Add author"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
]
|
||||||
|
}
|
||||||
100
commands/next.md
Normal file
100
commands/next.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
description: Analyze my reading patterns and suggest what to read next from my TBR
|
||||||
|
---
|
||||||
|
|
||||||
|
You are helping the user decide what to read next from their Calibre library TBR list.
|
||||||
|
|
||||||
|
## Analysis Steps
|
||||||
|
|
||||||
|
Perform the following analysis using the Calibre skill:
|
||||||
|
|
||||||
|
### 1. Analyze Recent Reading Patterns
|
||||||
|
|
||||||
|
Query the last 15 books marked as read (sorted by *dateread DESC):
|
||||||
|
- Calculate average page count of recent reads
|
||||||
|
- Identify if the user has been reading mostly long books (>600 pages)
|
||||||
|
- Look for series patterns in recent reads
|
||||||
|
- Use the `*dateread` field to determine actual reading order
|
||||||
|
- Look at `rating` field to see what books the user liked
|
||||||
|
|
||||||
|
### 2. Check for Series Continuity
|
||||||
|
|
||||||
|
For each series found in recent reads:
|
||||||
|
- Check if there are unread books in that series on the TBR
|
||||||
|
- Prioritize the next book in sequence (series_index), especially if the previous book had a high rating
|
||||||
|
- This is important for maintaining reading momentum!
|
||||||
|
|
||||||
|
### 3. Consider Reading Fatigue
|
||||||
|
|
||||||
|
Based on recent page counts:
|
||||||
|
- If average recent reads > 600 pages: Suggest shorter books (< 300 pages)
|
||||||
|
- If average recent reads < 400 pages: User might be ready for something longer
|
||||||
|
- Look for highly-rated short books as "palate cleansers"
|
||||||
|
|
||||||
|
### 4. Check Book Age in Library
|
||||||
|
|
||||||
|
Query books by timestamp (when added to library):
|
||||||
|
- Find recently added books (last 30 days) that are unread
|
||||||
|
- Find old books (added >1 year ago) that may have been forgotten
|
||||||
|
- Use `b.timestamp` field to determine when book was added
|
||||||
|
|
||||||
|
### 5. Filter by Quality
|
||||||
|
|
||||||
|
Prioritize books with:
|
||||||
|
- Goodreads rating >= 3.75 (if available)
|
||||||
|
- Consider page count relative to recent reading patterns
|
||||||
|
- Balance between series continuity and variety
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
Structure your response as a structured report with these categories:
|
||||||
|
|
||||||
|
```
|
||||||
|
# READING PATTERN SUMMARY
|
||||||
|
- Books read in last 30 days: X (use #dateread:">=30daysago")
|
||||||
|
- Average page count: Y pages
|
||||||
|
- Notable patterns: [e.g., "Completed Mistborn Era 2 series"]
|
||||||
|
|
||||||
|
# RECOMMENDATIONS BY CATEGORY
|
||||||
|
|
||||||
|
## 📚 SERIES CONTINUITY
|
||||||
|
Books that continue series you're currently reading:
|
||||||
|
|
||||||
|
- **Book Title** by Author
|
||||||
|
Series: Series Name #X | Pages: XXX | Rating: X/5 | Added: [date/age]
|
||||||
|
|
||||||
|
## 🆕 RECENTLY ADDED
|
||||||
|
Books added to your library in the last 30 days:
|
||||||
|
|
||||||
|
- **Book Title** by Author
|
||||||
|
Pages: XXX | Rating: X/5 | Added: [date]
|
||||||
|
|
||||||
|
## 💎 FORGOTTEN GEMS
|
||||||
|
Books added over a year ago that you may have forgotten:
|
||||||
|
|
||||||
|
- **Book Title** by Author
|
||||||
|
Pages: XXX | Rating: X/5 | Added: [date/years ago]
|
||||||
|
|
||||||
|
## ⚡ QUICK READS
|
||||||
|
Shorter books (< 300 pages) for reading fatigue:
|
||||||
|
|
||||||
|
- **Book Title** by Author
|
||||||
|
Pages: XXX | Rating: X/5 | Added: [age]
|
||||||
|
|
||||||
|
## 🌟 HIGHLY RATED
|
||||||
|
Top-rated unread books from your TBR:
|
||||||
|
|
||||||
|
- **Book Title** by Author
|
||||||
|
Pages: XXX | Rating: X/5 | Added: [age]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- Use `b.timestamp` to determine when books were added to the library
|
||||||
|
- Calculate age from timestamp (e.g., "2 days ago", "3 months ago", "2 years ago")
|
||||||
|
- Include 1-3 books per category (skip categories if no matches)
|
||||||
|
- ALWAYS check for incomplete series from recent reads first
|
||||||
|
- Balance series continuity with reading fatigue and variety
|
||||||
|
- Present data in a clean, scannable format
|
||||||
|
- Each category should help answer a different need: momentum, novelty, rediscovery, fatigue, or quality
|
||||||
|
- **IMPORTANT**: All queries should exclude archived books from recommendations
|
||||||
110
commands/random.md
Normal file
110
commands/random.md
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
---
|
||||||
|
description: Pick a random book from TBR or library
|
||||||
|
---
|
||||||
|
|
||||||
|
You are helping the user pick a random book from their Calibre library.
|
||||||
|
|
||||||
|
## Selection Process
|
||||||
|
|
||||||
|
Use the Calibre skill to select a random book:
|
||||||
|
|
||||||
|
### 1. Determine Selection Pool
|
||||||
|
|
||||||
|
By default, select from TBR list, but check if user specified:
|
||||||
|
- **TBR** (default): `#read:No and #archived:No`
|
||||||
|
- **All unread**: `#read:No`
|
||||||
|
- **Entire library**: no filter
|
||||||
|
- **Specific criteria**: by author, series, genre, rating, page count, etc.
|
||||||
|
|
||||||
|
### 2. Query the Pool
|
||||||
|
|
||||||
|
Query all books matching the criteria:
|
||||||
|
```bash
|
||||||
|
--fields='title,authors,series,series_index,*goodreads,*pages,timestamp'
|
||||||
|
--search='[appropriate search based on user criteria]'
|
||||||
|
--for-machine
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Random Selection
|
||||||
|
|
||||||
|
From the results:
|
||||||
|
- Count total books in pool
|
||||||
|
- Select one at random
|
||||||
|
- Present it with full details
|
||||||
|
|
||||||
|
### 4. Context About the Selection
|
||||||
|
|
||||||
|
Provide helpful context:
|
||||||
|
- When it was added to library (from `timestamp`)
|
||||||
|
- Why it might be interesting to read now
|
||||||
|
- How it fits current reading patterns
|
||||||
|
- Series context if applicable
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
Present the random selection:
|
||||||
|
|
||||||
|
```
|
||||||
|
# 🎲 RANDOM BOOK SELECTION
|
||||||
|
|
||||||
|
**[Book Title]** by [Author]
|
||||||
|
|
||||||
|
## Details
|
||||||
|
- **Series**: [Series Name #X] or "Standalone"
|
||||||
|
- **Pages**: XXX pages
|
||||||
|
- **Rating**: X.X / 5 (Goodreads)
|
||||||
|
- **Added to Library**: [date or "X months/years ago"]
|
||||||
|
|
||||||
|
## Why Read This Now?
|
||||||
|
|
||||||
|
[Provide 2-3 reasons why this might be a good choice, such as:]
|
||||||
|
- Fits your recent reading pattern of [genre/length/style]
|
||||||
|
- Next book in [Series Name] series
|
||||||
|
- Highly rated on Goodreads
|
||||||
|
- Been in your TBR for [time], might be a good time to revisit
|
||||||
|
- Quick read at XXX pages if you're between longer books
|
||||||
|
- This author is similar to [recent author] you enjoyed
|
||||||
|
|
||||||
|
## Pool Information
|
||||||
|
Selected randomly from **X books** in your [TBR/unread books/library/specified criteria]
|
||||||
|
|
||||||
|
---
|
||||||
|
Not feeling it? Run /books:random again for another suggestion!
|
||||||
|
Or try /books:vibes to find books with similar themes to one you enjoyed.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Options
|
||||||
|
|
||||||
|
If the user specifies additional criteria, combine them:
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
- "Random book under 300 pages": Add `#pages:"<300"`
|
||||||
|
- "Random unread Sanderson": Add `authors:"Sanderson"`
|
||||||
|
- "Random highly rated book": Add `#goodreads:">4"`
|
||||||
|
- "Random from series": Add `not series:""`
|
||||||
|
- "Random standalone": Add `series:""`
|
||||||
|
- "Random book added this year": Add `timestamp:">YYYY-01-01"`
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
- Use Python or similar to select random index from JSON array results
|
||||||
|
- Handle edge cases (empty pool, pool of 1)
|
||||||
|
- If pool is small (< 10 books), mention all options
|
||||||
|
- Exclude archived books by default unless user specifically asks
|
||||||
|
- Make selection truly random - don't bias toward highest rated or recently added
|
||||||
|
- If user runs command multiple times, try to avoid repeating recent suggestions
|
||||||
|
|
||||||
|
## Example Python Snippet for Randomization
|
||||||
|
|
||||||
|
```python
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
if data:
|
||||||
|
book = random.choice(data)
|
||||||
|
print(json.dumps(book, indent=2))
|
||||||
|
```
|
||||||
|
|
||||||
|
You can pipe calibredb output through this to get random selection.
|
||||||
7
commands/series.md
Normal file
7
commands/series.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
description: List unfinished series and the next book to read in each
|
||||||
|
---
|
||||||
|
|
||||||
|
Use the `books:find-incomplete-series` skill to find incomplete series. DO NOT call
|
||||||
|
calibredb yourself, use the skill! It provides a python script to help
|
||||||
|
you find unfinished series.
|
||||||
141
commands/stats.md
Normal file
141
commands/stats.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
---
|
||||||
|
description: Show reading statistics (books per year/month, pages read, average rating, genre breakdown)
|
||||||
|
---
|
||||||
|
|
||||||
|
You are helping the user analyze their reading statistics from their Calibre library.
|
||||||
|
|
||||||
|
## Analysis to Perform
|
||||||
|
|
||||||
|
Use the Calibre skill to gather and analyze the following statistics:
|
||||||
|
|
||||||
|
### 1. Reading Velocity
|
||||||
|
|
||||||
|
Query books read in different time periods:
|
||||||
|
- Books read this year (use `#dateread:">=YYYY-01-01"` where YYYY is current year)
|
||||||
|
- Books read last 30 days (use `#dateread:">=30daysago"`)
|
||||||
|
- Books read last 90 days (use `#dateread:">=90daysago"`)
|
||||||
|
- Break down by month for current year
|
||||||
|
|
||||||
|
Calculate:
|
||||||
|
- Books per month average (current year)
|
||||||
|
- Pages per month average
|
||||||
|
- Current reading pace vs yearly average
|
||||||
|
|
||||||
|
### 2. Page Statistics
|
||||||
|
|
||||||
|
Query all read books with page counts:
|
||||||
|
- Total pages read this year
|
||||||
|
- Total pages read all time
|
||||||
|
- Average pages per book
|
||||||
|
- Longest book read
|
||||||
|
- Shortest book read
|
||||||
|
|
||||||
|
### 3. Rating Analysis
|
||||||
|
|
||||||
|
Query all read books with ratings:
|
||||||
|
- Average rating given (your `rating` field)
|
||||||
|
- Average Goodreads rating of books read (`*goodreads` field)
|
||||||
|
- Most common rating you give
|
||||||
|
- Distribution of ratings (how many 5-star, 4-star, etc.)
|
||||||
|
|
||||||
|
### 4. Author Statistics
|
||||||
|
|
||||||
|
Query all read books:
|
||||||
|
- Most read authors (count by author name)
|
||||||
|
- Total unique authors read
|
||||||
|
|
||||||
|
### 5. Series Statistics
|
||||||
|
|
||||||
|
Query all read books with series information:
|
||||||
|
- Number of complete series finished
|
||||||
|
- Books read that are part of series vs standalone
|
||||||
|
- Most read series
|
||||||
|
|
||||||
|
### 6. To-Be-Read Statistics
|
||||||
|
|
||||||
|
Query TBR list (`#read:No and #archived:No`):
|
||||||
|
- Total books in TBR
|
||||||
|
- Total pages in TBR
|
||||||
|
- Average Goodreads rating of TBR
|
||||||
|
- Oldest book in TBR (by timestamp)
|
||||||
|
- Books added to TBR in last 30 days
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
Present statistics in a clean, organized report:
|
||||||
|
|
||||||
|
```
|
||||||
|
# READING STATISTICS
|
||||||
|
|
||||||
|
## 📊 Reading Velocity
|
||||||
|
- **This Year**: X books (Y pages)
|
||||||
|
- **Last 30 Days**: X books (Y pages)
|
||||||
|
- **Average Pace**: X books/month, Y pages/month
|
||||||
|
|
||||||
|
### Monthly Breakdown (YYYY)
|
||||||
|
Jan: X books | Feb: X books | Mar: X books | etc.
|
||||||
|
|
||||||
|
## 📖 Page Statistics
|
||||||
|
- **Total Pages Read (All Time)**: X,XXX pages
|
||||||
|
- **Total Pages Read (This Year)**: X,XXX pages
|
||||||
|
- **Average Book Length**: XXX pages
|
||||||
|
- **Longest Book**: [Title] by [Author] (XXX pages)
|
||||||
|
- **Shortest Book**: [Title] by [Author] (XXX pages)
|
||||||
|
|
||||||
|
## ⭐ Rating Analysis
|
||||||
|
- **Your Average Rating**: X.X / 5
|
||||||
|
- **Goodreads Average of Books Read**: X.X / 5
|
||||||
|
- **Most Common Rating**: X stars
|
||||||
|
|
||||||
|
### Rating Distribution
|
||||||
|
★★★★★: XX books (XX%)
|
||||||
|
★★★★☆: XX books (XX%)
|
||||||
|
★★★☆☆: XX books (XX%)
|
||||||
|
★★☆☆☆: XX books (XX%)
|
||||||
|
★☆☆☆☆: XX books (XX%)
|
||||||
|
|
||||||
|
## ✍️ Author Statistics
|
||||||
|
- **Total Authors Read**: XX unique authors
|
||||||
|
- **Most Read Authors**:
|
||||||
|
1. [Author Name]: X books
|
||||||
|
2. [Author Name]: X books
|
||||||
|
3. [Author Name]: X books
|
||||||
|
|
||||||
|
## 📚 Series Statistics
|
||||||
|
- **Books in Series**: XX books (XX% of total)
|
||||||
|
- **Standalone Books**: XX books (XX% of total)
|
||||||
|
- **Most Read Series**:
|
||||||
|
1. [Series Name]: X books
|
||||||
|
2. [Series Name]: X books
|
||||||
|
|
||||||
|
## 📋 To-Be-Read Statistics
|
||||||
|
- **Total TBR Books**: XXX books (X,XXX pages)
|
||||||
|
- **Average TBR Rating**: X.X / 5
|
||||||
|
- **Added Recently**: XX books in last 30 days
|
||||||
|
- **Oldest Unread**: [Title] (added X years/months ago)
|
||||||
|
|
||||||
|
## 🎯 Reading Insights
|
||||||
|
[Provide 2-3 interesting insights, such as:]
|
||||||
|
- You're on track to read XX books this year
|
||||||
|
- Your reading pace has [increased/decreased] by XX% compared to last year
|
||||||
|
- You tend to rate books higher/lower than Goodreads average
|
||||||
|
- You're reading more/fewer series books than standalone
|
||||||
|
```
|
||||||
|
|
||||||
|
## Query Tips
|
||||||
|
|
||||||
|
- Use `#dateread` field with date ranges for time-based queries
|
||||||
|
- Calculate percentages and averages from the data
|
||||||
|
- Present large numbers with thousand separators for readability
|
||||||
|
- Compare current year to all-time averages where interesting
|
||||||
|
- Exclude archived books from all queries
|
||||||
|
- Handle missing data gracefully (some books may not have all custom fields set)
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
**Bash/Python Pitfalls:**
|
||||||
|
- Multi-line bash for loops are tricky - use Python with heredoc instead for complex iteration
|
||||||
|
- When looping through months to count books, use Python's subprocess module rather than bash for loops
|
||||||
|
- When processing JSON data from calibredb, be careful with missing fields - always use `.get()` with defaults
|
||||||
|
- Keep Python data processing scripts simple - avoid complex inline data structures that can have KeyError issues
|
||||||
|
- Better to do multiple simple queries than one complex Python script with hard-coded data
|
||||||
231
commands/vibes.md
Normal file
231
commands/vibes.md
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
---
|
||||||
|
description: Find similar books in your library based on genre, author, or themes
|
||||||
|
---
|
||||||
|
|
||||||
|
You are helping the user find books in their TBR that have similar vibes/themes to a book they specify.
|
||||||
|
|
||||||
|
## Analysis Process
|
||||||
|
|
||||||
|
Use the Calibre skill to find books with similar vibes:
|
||||||
|
|
||||||
|
### 1. Get the Reference Book
|
||||||
|
|
||||||
|
First, query for the book the user mentions (or ask them to specify one):
|
||||||
|
```bash
|
||||||
|
--fields='title,authors,series,tags,comments,*goodreads,*pages'
|
||||||
|
--search='title:"[book title]"'
|
||||||
|
```
|
||||||
|
|
||||||
|
Get all available information:
|
||||||
|
- Author(s)
|
||||||
|
- Series (if part of one)
|
||||||
|
- Tags (if any)
|
||||||
|
- Comments/description
|
||||||
|
- Goodreads rating
|
||||||
|
- Page count
|
||||||
|
|
||||||
|
### 2. Identify Similar Books
|
||||||
|
|
||||||
|
Query TBR for books with similar characteristics:
|
||||||
|
|
||||||
|
**Same Author**
|
||||||
|
```bash
|
||||||
|
--search='authors:"[author]" and #read:No and #archived:No'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Same Series**
|
||||||
|
```bash
|
||||||
|
--search='series:"[series]" and #read:No and #archived:No'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Similar Tags/Genres**
|
||||||
|
If the reference book has tags, search for books with those tags:
|
||||||
|
```bash
|
||||||
|
--search='tags:"[tag]" and #read:No and #archived:No'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Similar Page Count** (±100 pages)
|
||||||
|
```bash
|
||||||
|
--search='#pages:">[low]" and #pages:"<[high]" and #read:No and #archived:No'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Similar Rating Range**
|
||||||
|
```bash
|
||||||
|
--search='#goodreads:">[rating-0.5]" and #goodreads:"<[rating+0.5]" and #read:No and #archived:No'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Use Available Information
|
||||||
|
|
||||||
|
Even without formal tags, extract information from:
|
||||||
|
- Book titles (often contain genre hints: "The [Fantasy] of...")
|
||||||
|
- Series names (often thematic)
|
||||||
|
- Author names (can search for co-authors, related authors)
|
||||||
|
- Comments field (may contain descriptions with genre/theme keywords)
|
||||||
|
|
||||||
|
### 4. Search for Community Recommendations
|
||||||
|
|
||||||
|
Use WebSearch to find what other readers recommend as similar books:
|
||||||
|
|
||||||
|
**Search for Reddit recommendations:**
|
||||||
|
```
|
||||||
|
"books like [book title]" site:reddit.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**Search for Goodreads lists:**
|
||||||
|
```
|
||||||
|
"similar to [book title]" site:goodreads.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**General recommendation searches:**
|
||||||
|
```
|
||||||
|
"if you liked [book title]" recommendations
|
||||||
|
"books similar to [book title]"
|
||||||
|
"read alikes [book title]"
|
||||||
|
```
|
||||||
|
|
||||||
|
Extract book titles and authors from search results, then:
|
||||||
|
- Check if any are in the user's TBR (prioritize these)
|
||||||
|
- Note popular recommendations even if not in TBR (user might want to add them)
|
||||||
|
|
||||||
|
### 5. Similarity Scoring
|
||||||
|
|
||||||
|
For each book found, explain WHY it's similar:
|
||||||
|
- Same author
|
||||||
|
- Same/related series
|
||||||
|
- Shared tags/genres
|
||||||
|
- Similar length (good for pacing match)
|
||||||
|
- Similar rating (quality match)
|
||||||
|
- Similar themes (if detectable from metadata)
|
||||||
|
- **Recommended by readers** (found in search results)
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
```
|
||||||
|
# 📖 BOOKS WITH SIMILAR VIBES
|
||||||
|
|
||||||
|
Finding books similar to: **[Reference Book]** by [Author]
|
||||||
|
|
||||||
|
## About the Reference Book
|
||||||
|
- **Series**: [Series Name] or "Standalone"
|
||||||
|
- **Length**: XXX pages
|
||||||
|
- **Rating**: X.X / 5
|
||||||
|
- **Key Themes**: [Based on tags, series, title, or "Limited metadata available"]
|
||||||
|
|
||||||
|
## Similar Books in Your TBR
|
||||||
|
|
||||||
|
### By Same Author
|
||||||
|
[If any found:]
|
||||||
|
- **[Title]** ([XXX pages], rated X.X/5, added [time ago])
|
||||||
|
Why similar: Same author, similar [length/rating/style]
|
||||||
|
|
||||||
|
### In Related Series
|
||||||
|
[If any found:]
|
||||||
|
- **[Title]** by [Author]
|
||||||
|
Series: [Series Name]
|
||||||
|
Why similar: [Connection to original series]
|
||||||
|
|
||||||
|
### Similar Themes/Genres
|
||||||
|
[If any found based on tags or metadata:]
|
||||||
|
- **[Title]** by [Author] ([XXX pages], rated X.X/5)
|
||||||
|
Why similar: [Shared tags/themes/genre indicators]
|
||||||
|
|
||||||
|
### Similar Length & Quality
|
||||||
|
[Books with similar page count and rating:]
|
||||||
|
- **[Title]** by [Author] ([XXX pages], rated X.X/5)
|
||||||
|
Why similar: Similar reading commitment and quality
|
||||||
|
|
||||||
|
### Recommended by the Community
|
||||||
|
[Books found via web search that are in your TBR:]
|
||||||
|
- **[Title]** by [Author] ([XXX pages], rated X.X/5)
|
||||||
|
✓ In your TBR
|
||||||
|
Why similar: Frequently mentioned on [Reddit/Goodreads/etc.] as similar to [reference book]
|
||||||
|
|
||||||
|
## 🎯 Top Recommendations from Your TBR
|
||||||
|
|
||||||
|
Based on the similarity analysis, here are the strongest matches:
|
||||||
|
|
||||||
|
1. **[Title]** by [Author]
|
||||||
|
Best match because: [Specific reasons]
|
||||||
|
|
||||||
|
2. **[Title]** by [Author]
|
||||||
|
Good match because: [Specific reasons]
|
||||||
|
|
||||||
|
3. **[Title]** by [Author]
|
||||||
|
Worth considering: [Specific reasons]
|
||||||
|
|
||||||
|
## 📚 Popular Recommendations Not in Your Library
|
||||||
|
|
||||||
|
Based on web search, these books are frequently recommended as similar but aren't in your TBR yet:
|
||||||
|
|
||||||
|
1. **[Title]** by [Author]
|
||||||
|
Why recommended: [Based on search results - Reddit threads, Goodreads lists, etc.]
|
||||||
|
Rating: X.X / 5 on Goodreads (if found)
|
||||||
|
|
||||||
|
2. **[Title]** by [Author]
|
||||||
|
Why recommended: [Reason from search results]
|
||||||
|
|
||||||
|
3. **[Title]** by [Author]
|
||||||
|
Why recommended: [Reason from search results]
|
||||||
|
|
||||||
|
---
|
||||||
|
💡 Tips:
|
||||||
|
- Want to add any of these to your library? Use Calibre to import them
|
||||||
|
- If no similar books were found in your TBR, try /books:random for a surprise pick
|
||||||
|
- Use /books:next for personalized recommendations based on reading patterns
|
||||||
|
```
|
||||||
|
|
||||||
|
## Handling Limited Metadata
|
||||||
|
|
||||||
|
If the reference book or TBR books have limited metadata:
|
||||||
|
- Focus on author and series connections (most reliable)
|
||||||
|
- Use page count for "similar reading experience"
|
||||||
|
- Use ratings for quality matching
|
||||||
|
- Look for patterns in titles
|
||||||
|
- Be transparent about limitations: "Based on available metadata..."
|
||||||
|
|
||||||
|
## User Interaction
|
||||||
|
|
||||||
|
If the user just says "/books:vibes" without specifying a book:
|
||||||
|
1. Ask them which book they want to find similar books to
|
||||||
|
2. Suggest they could use a recent read they enjoyed
|
||||||
|
3. Or ask them to name a book they loved
|
||||||
|
|
||||||
|
If they specify a book not in the library:
|
||||||
|
1. Ask if they want to find books similar to that book's:
|
||||||
|
- Author
|
||||||
|
- Genre/themes (ask them to describe)
|
||||||
|
- Length/style
|
||||||
|
|
||||||
|
## Query Strategy
|
||||||
|
|
||||||
|
1. **Start broad**: Query all potential matches from library
|
||||||
|
2. **Search the web**: Use WebSearch to find community recommendations (Reddit, Goodreads, book blogs)
|
||||||
|
3. **Cross-reference**: Match web recommendations against your TBR
|
||||||
|
4. **Present both**: Show matches in TBR first, then popular recommendations not in library
|
||||||
|
5. **Score by similarity**: Books matching multiple criteria rank higher
|
||||||
|
6. **Prioritize quality**: Weight highly-rated books (>4.0) higher
|
||||||
|
7. **Prioritize community picks**: Books mentioned by other readers are strong matches
|
||||||
|
8. **Limit results**: Show top 5-10 from each category (in TBR and not in TBR)
|
||||||
|
9. **Explain reasoning**: Always say WHY books are similar
|
||||||
|
10. **Exclude archived**: Always add `#archived:No` unless user specifies otherwise
|
||||||
|
11. **Include context**: Note which platform recommended the book (Reddit, Goodreads, etc.)
|
||||||
|
|
||||||
|
## Example Scenarios
|
||||||
|
|
||||||
|
**User**: "Books like Mistborn"
|
||||||
|
- Library query: Author (Sanderson), Series (Mistborn), Tags (fantasy, magic)
|
||||||
|
- Web search: "books like Mistborn" Reddit/Goodreads
|
||||||
|
- Find in TBR: Other Sanderson books, high fantasy, magic systems
|
||||||
|
- Suggest from web: Stormlight Archive, Wheel of Time, etc.
|
||||||
|
|
||||||
|
**User**: "Something like this cozy mystery I just finished"
|
||||||
|
- Library query: By title/author, look for tags like "mystery", "cozy"
|
||||||
|
- Web search: "[title] read alikes" "similar cozy mysteries"
|
||||||
|
- Find in TBR: Similar page count, similar authors, mystery tags
|
||||||
|
- Suggest from web: Popular cozy mystery series recommendations
|
||||||
|
|
||||||
|
**User**: "Books with similar vibes to Name of the Wind"
|
||||||
|
- Library query: Author (Rothfuss), Tags (fantasy, coming-of-age)
|
||||||
|
- Web search: "books similar to Name of the Wind" site:reddit.com
|
||||||
|
- Find in TBR: Epic fantasy, similar length, highly-rated
|
||||||
|
- Suggest from web: Popular epic fantasy series often recommended together
|
||||||
73
plugin.lock.json
Normal file
73
plugin.lock.json
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:stbenjam/claude-nine:plugins/books",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "967e4707fcffcbd1198f315288258bc4a03dd7a9",
|
||||||
|
"treeHash": "1cfbd76d0c993e2606d914b412e3436ab9cdd4c7503040188b6e1d30a6b48809",
|
||||||
|
"generatedAt": "2025-11-28T10:28:27.319664Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "books",
|
||||||
|
"description": "TODO: Add description",
|
||||||
|
"version": "0.0.1"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "26b81e542f16db968832cf056145cd445b5e52b69146494b344627ed8d17d320"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "d8fe64888b7afe9a9e19a06dcbb25875629777409e58ce72cc386b225a805f70"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/vibes.md",
|
||||||
|
"sha256": "81a63df2715a0e719e40665766cc29817f94ff556ec2c99d0779b9f499ca7ba9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/stats.md",
|
||||||
|
"sha256": "aefa603ab5abec105a6a67407f991f939bb9a7df33d6ec5dbc4d7db8c91f4738"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/next.md",
|
||||||
|
"sha256": "797f5c8e0cadb6c4b11627982010381632beb6422706bb00f02617b4d2624a00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/series.md",
|
||||||
|
"sha256": "b13f2a4472a0acaf4f18820c431e7a29f1b918b8315c03e4d9cc0a017ad409fc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/random.md",
|
||||||
|
"sha256": "88d21663e703888bf9b70b66b437ec08142b477e3a097374b671d309cd3119c7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/calibre/SKILL.md",
|
||||||
|
"sha256": "3bd13d886f4ee135e7e958ff1e57955c75195a24910c3d6bf7ceb898086ae2cb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/find-incomplete-series/SKILL.md",
|
||||||
|
"sha256": "98e418dc6ddf68d4046c51cd14360d535aeb641b8e1a39cc423c07b054980e4b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/find-incomplete-series/scripts/series.py",
|
||||||
|
"sha256": "e9e5c646af239e6cb88409b41ee4cda1326637c2e327eab393f3db834605101f"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "1cfbd76d0c993e2606d914b412e3436ab9cdd4c7503040188b6e1d30a6b48809"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
292
skills/calibre/SKILL.md
Normal file
292
skills/calibre/SKILL.md
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
---
|
||||||
|
name: calibre
|
||||||
|
description: Search and query Calibre library databases. Use when the user asks about books, TBR (to-be-read), reading lists, Calibre library queries, book searches, or mentions Calibre. Also use for queries about book ratings, authors, reading status, or library statistics.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Calibre Library Search Skill
|
||||||
|
|
||||||
|
You are helping the user search and query their Calibre library using `calibredb`.
|
||||||
|
|
||||||
|
## Library Setup
|
||||||
|
|
||||||
|
**Library URL**: `http://killington.home.bitbin.de:8454/#`
|
||||||
|
|
||||||
|
**calibredb Location**: `/Applications/calibre.app/Contents/MacOS/calibredb`
|
||||||
|
|
||||||
|
**Authentication**:
|
||||||
|
- Username: `calibre`
|
||||||
|
- Password: `calibre`
|
||||||
|
|
||||||
|
**Note**: Using Calibre Content Server means no database locking issues - queries work even while Calibre GUI is running.
|
||||||
|
|
||||||
|
## Custom Fields
|
||||||
|
|
||||||
|
The Calibre library has these custom fields:
|
||||||
|
|
||||||
|
| Field | Search Name | Display Name | Type | Values |
|
||||||
|
|------------|-------------|--------------|----------|--------------|
|
||||||
|
| read | #read | *read | Boolean | Yes/No |
|
||||||
|
| dateread | #dateread | *dateread | Datetime | ISO date |
|
||||||
|
| archived | #archived | *archived | Boolean | Yes/No |
|
||||||
|
| goodreads | #goodreads | *goodreads | Float | 0.0-5.0 |
|
||||||
|
| pages | #pages | *pages | Integer | page count |
|
||||||
|
| priority | #priority | *priority | Text | varies |
|
||||||
|
| words | #words | *words | Integer | word count |
|
||||||
|
|
||||||
|
**IMPORTANT - Boolean Field Syntax**:
|
||||||
|
- Use `#field` syntax in searches with `Yes` or `No` (capitalized): e.g., `#read:Yes`, `#read:No`
|
||||||
|
- Use `*field` syntax when displaying fields (e.g., `*read`)
|
||||||
|
- Boolean values are **NOT** `true`/`false` - they are `Yes`/`No`
|
||||||
|
|
||||||
|
## calibredb Command Pattern
|
||||||
|
|
||||||
|
Always use this pattern:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='field1,field2,*customfield' \
|
||||||
|
--search='search query' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Options
|
||||||
|
|
||||||
|
- `--fields='field1,field2'` - Comma-separated list of fields to display
|
||||||
|
- `--search='query'` - Search query using Calibre's search syntax
|
||||||
|
- `--sort-by='field'` - Sort results by field
|
||||||
|
- `--limit=N` - Limit results to N books
|
||||||
|
- `--for-machine` - Output as JSON (always use this for parsing)
|
||||||
|
|
||||||
|
### Available Built-in Fields
|
||||||
|
|
||||||
|
- `title`, `authors`, `series`, `series_index`
|
||||||
|
- `timestamp` (when added to library)
|
||||||
|
- `last_modified` (when book record was last modified)
|
||||||
|
- `pubdate`, `publisher`, `isbn`
|
||||||
|
- `rating`, `tags`, `comments`
|
||||||
|
- `formats`, `size`, `uuid`
|
||||||
|
|
||||||
|
## Search Query Syntax
|
||||||
|
|
||||||
|
### Basic Searches
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Search by title
|
||||||
|
--search='title:"Book Title"'
|
||||||
|
|
||||||
|
# Search by author
|
||||||
|
--search='authors:"Author Name"'
|
||||||
|
|
||||||
|
# Search in series
|
||||||
|
--search='series:"Series Name"'
|
||||||
|
|
||||||
|
# Combine searches with AND
|
||||||
|
--search='authors:"Sanderson" and series:"Mistborn"'
|
||||||
|
|
||||||
|
# Combine searches with OR
|
||||||
|
--search='authors:"Sanderson" or authors:"Wells"'
|
||||||
|
|
||||||
|
# NOT operator
|
||||||
|
--search='not #archived:Yes'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Field Searches
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Books marked as read
|
||||||
|
--search='#read:Yes'
|
||||||
|
|
||||||
|
# Books NOT read
|
||||||
|
--search='#read:No'
|
||||||
|
|
||||||
|
# Books not archived and not read (TBR)
|
||||||
|
--search='#read:No and #archived:No'
|
||||||
|
|
||||||
|
# Highly rated books (>= 4.0)
|
||||||
|
--search='#goodreads:">4"'
|
||||||
|
|
||||||
|
# Books with specific page count
|
||||||
|
--search='#pages:"<300"'
|
||||||
|
|
||||||
|
# Empty/not set custom fields
|
||||||
|
--search='#goodreads:""'
|
||||||
|
|
||||||
|
# Books read in a specific date range
|
||||||
|
--search='#dateread:">=2024-01-01" and #dateread:"<2025-01-01"'
|
||||||
|
|
||||||
|
# Books read in the last 30 days
|
||||||
|
--search='#dateread:">=30daysago"'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Query Examples
|
||||||
|
|
||||||
|
### To-Be-Read List
|
||||||
|
|
||||||
|
Get unread, non-archived books:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,series,series_index,*goodreads,*pages' \
|
||||||
|
--search='#read:No and #archived:No' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recently Added Books
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,*goodreads,*pages,timestamp' \
|
||||||
|
--search='#read:No and #archived:No' \
|
||||||
|
--sort-by='timestamp' \
|
||||||
|
--limit=10 \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recently Read Books
|
||||||
|
|
||||||
|
Use the `*dateread` field to see when books were actually finished:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,series,series_index,*goodreads,*pages,*dateread' \
|
||||||
|
--search='#read:Yes' \
|
||||||
|
--sort-by='*dateread' \
|
||||||
|
--limit=15 \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Highly Rated Unread Books
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,series,*goodreads,*pages' \
|
||||||
|
--search='#read:No and #archived:No and #goodreads:">4"' \
|
||||||
|
--sort-by='*goodreads' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Books by Specific Author
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,series,*read,*goodreads,*pages' \
|
||||||
|
--search='authors:"Sanderson" and #archived:No' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quick Reads (< 300 pages)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,*pages,*goodreads' \
|
||||||
|
--search='#read:No and #archived:No and #pages:"<300"' \
|
||||||
|
--sort-by='*goodreads' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unread Books in a Series
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,series,series_index,*goodreads,*pages,timestamp' \
|
||||||
|
--search='series:"Between Earth and Sky" and #read:No and #archived:No' \
|
||||||
|
--sort-by='series_index' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Books Read in a Time Period
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Books read in October 2024
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,*dateread,*goodreads,*pages' \
|
||||||
|
--search='#dateread:">=2024-10-01" and #dateread:"<2024-11-01"' \
|
||||||
|
--sort-by='*dateread' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
|
||||||
|
# Books read this year
|
||||||
|
/Applications/calibre.app/Contents/MacOS/calibredb list \
|
||||||
|
--with-library='http://killington.home.bitbin.de:8454/#' \
|
||||||
|
--username='calibre' \
|
||||||
|
--password='calibre' \
|
||||||
|
--fields='title,authors,*dateread,*goodreads' \
|
||||||
|
--search='#dateread:">=2025-01-01"' \
|
||||||
|
--sort-by='*dateread' \
|
||||||
|
--for-machine | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Instructions
|
||||||
|
|
||||||
|
When the user asks to search their Calibre library:
|
||||||
|
|
||||||
|
1. **Determine** what they're looking for (to-be-read, specific book, by rating, etc.)
|
||||||
|
2. **Construct** the appropriate calibredb command based on examples above
|
||||||
|
3. **Execute** the command using the Bash tool
|
||||||
|
4. **Parse** the JSON output and present results in a readable format
|
||||||
|
|
||||||
|
## Query Tips
|
||||||
|
|
||||||
|
- **Always exclude archived books** unless specifically requested: add `and #archived:No` to searches
|
||||||
|
- Use `--for-machine` to get JSON output that's easier to parse
|
||||||
|
- The `timestamp` field shows when a book was added to the library
|
||||||
|
- The `*dateread` field shows when a book was actually finished reading (synced from Goodreads)
|
||||||
|
- The `last_modified` field shows when a book record was last changed (not reliable for "recently read")
|
||||||
|
- When a custom field is not set, it won't appear in the JSON output
|
||||||
|
- Use `python3 -m json.tool` to pretty-print JSON for readability
|
||||||
|
- Search queries are case-insensitive
|
||||||
|
- Use quotes around field values that contain spaces
|
||||||
|
- **Boolean fields**: In search queries use `Yes`/`No` (e.g., `#read:Yes`), but in JSON output they appear as `true`/`false` (lowercase)
|
||||||
|
- **Date fields**: Use `*dateread` to sort by when books were actually read (more accurate than `last_modified`)
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
**User**: "Show me my to-be-read list"
|
||||||
|
→ Search with `#read:No and #archived:No`
|
||||||
|
|
||||||
|
**User**: "Find books by Sanderson"
|
||||||
|
→ Search with `authors:"Sanderson" and #archived:No`
|
||||||
|
|
||||||
|
**User**: "Show highly rated unread books"
|
||||||
|
→ Search with `#read:No and #archived:No and #goodreads:">4"`
|
||||||
|
|
||||||
|
**User**: "What did I read recently?"
|
||||||
|
→ Search with `#read:Yes`, sort by `*dateread` (descending), limit to 10-15
|
||||||
|
|
||||||
|
**User**: "What's next in the series I'm reading?"
|
||||||
|
→ Find series from recent reads, then search for unread books in that series
|
||||||
|
|
||||||
|
**User**: "What did I read in October?" or "Show me books I read this year"
|
||||||
|
→ Use date range searches with `#dateread:">=2024-10-01" and #dateread:"<2024-11-01"` or `#dateread:">=2025-01-01"`
|
||||||
|
|
||||||
|
## Safety Notes
|
||||||
|
|
||||||
|
- **Read-only access**: calibredb list is a read-only operation
|
||||||
|
- **Never use**: `calibredb add`, `calibredb set_metadata`, `calibredb remove` unless explicitly requested by user
|
||||||
|
- **No locking issues**: Using the Content Server means the Calibre GUI can remain open during queries
|
||||||
25
skills/find-incomplete-series/SKILL.md
Normal file
25
skills/find-incomplete-series/SKILL.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
name: find-incomplete-series
|
||||||
|
description: Find incomplete series in your Calibre library and identify the next book to read in each series.
|
||||||
|
---
|
||||||
|
|
||||||
|
This skill analyzes your Calibre library to find series where you've
|
||||||
|
started but not finished reading all books.
|
||||||
|
|
||||||
|
To complete this task, run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 __SKILL_DIR__/scripts/series.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This script will:
|
||||||
|
1. Query your Calibre library for all books that are part of a series
|
||||||
|
2. Exclude archived books
|
||||||
|
3. Identify series where you've read at least one book but haven't finished the entire series
|
||||||
|
4. Display the next unread book in each incomplete series
|
||||||
|
|
||||||
|
Important! Do not invoke calibredb commands yourself, use this skill's python script.
|
||||||
|
|
||||||
|
Important! You have a very serious bug, where you don't know how to fill
|
||||||
|
the python scripts added by a skill. You must look in the "scripts"
|
||||||
|
folder of where this SKILL.md is located!!
|
||||||
65
skills/find-incomplete-series/scripts/series.py
Executable file
65
skills/find-incomplete-series/scripts/series.py
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
# Query Calibre for all books in series
|
||||||
|
result = subprocess.run([
|
||||||
|
'/Applications/calibre.app/Contents/MacOS/calibredb', 'list',
|
||||||
|
'--with-library=http://killington.home.bitbin.de:8454/#',
|
||||||
|
'--username=calibre',
|
||||||
|
'--password=calibre',
|
||||||
|
'--fields=title,authors,series,series_index,*read,*archived',
|
||||||
|
'--search=series:true',
|
||||||
|
'--for-machine'
|
||||||
|
], capture_output=True, text=True)
|
||||||
|
|
||||||
|
books = json.loads(result.stdout)
|
||||||
|
|
||||||
|
# Group books by series, excluding archived books
|
||||||
|
series_dict = defaultdict(list)
|
||||||
|
for book in books:
|
||||||
|
if book.get('series') and not book.get('*archived'):
|
||||||
|
series_dict[book['series']].append(book)
|
||||||
|
|
||||||
|
# Sort books in each series by series_index
|
||||||
|
for series in series_dict:
|
||||||
|
series_dict[series].sort(key=lambda x: float(x.get('series_index', 0)))
|
||||||
|
|
||||||
|
# Find series with at least one read book but not all read
|
||||||
|
incomplete_series = []
|
||||||
|
for series, books_list in series_dict.items():
|
||||||
|
read_count = sum(1 for b in books_list if b.get('*read') == True)
|
||||||
|
total_count = len(books_list)
|
||||||
|
|
||||||
|
if read_count > 0 and read_count < total_count:
|
||||||
|
# Find the next unread book
|
||||||
|
next_unread = None
|
||||||
|
for book in books_list:
|
||||||
|
if not book.get('*read'):
|
||||||
|
next_unread = book
|
||||||
|
break
|
||||||
|
|
||||||
|
incomplete_series.append({
|
||||||
|
'series': series,
|
||||||
|
'read': read_count,
|
||||||
|
'total': total_count,
|
||||||
|
'next_book': next_unread
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sort by series name
|
||||||
|
incomplete_series.sort(key=lambda x: x['series'])
|
||||||
|
|
||||||
|
# Output results
|
||||||
|
print(f"\n# UNFINISHED SERIES\n")
|
||||||
|
print(f"You have {len(incomplete_series)} incomplete series:\n")
|
||||||
|
|
||||||
|
for i, s in enumerate(incomplete_series, 1):
|
||||||
|
print(f"{i}. **{s['series']}** ({s['read']}/{s['total']} books read)")
|
||||||
|
if s['next_book']:
|
||||||
|
authors = s['next_book'].get('authors', 'Unknown')
|
||||||
|
title = s['next_book'].get('title', 'Unknown')
|
||||||
|
index = s['next_book'].get('series_index', 0)
|
||||||
|
print(f" Next: **{title}** by {authors} (Book #{index})\n")
|
||||||
|
else:
|
||||||
|
print(f" Next: Unable to determine\n")
|
||||||
Reference in New Issue
Block a user