Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:58:23 +08:00
commit b8dc705a95
11 changed files with 1061 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
{
"name": "books",
"description": "TODO: Add description",
"version": "0.0.1",
"author": {
"name": "TODO: Add author"
},
"skills": [
"./skills"
],
"commands": [
"./commands"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# books
TODO: Add description

100
commands/next.md Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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!!

View 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")