# Aozora Bunko New Public-Domain Text Delta Feed (`stefano_seggio/aozora-bunko-public-domain-text-feed`) Actor

Watches Aozora Bunko's own official catalog export for newly digitized or revised confirmed-public-domain Japanese texts and emits NEW\_TEXT/REVISED\_TEXT/STATUS\_CHANGE events with full decoded text where available. Pay-per-event: billed only for what's new or changed.

- **URL**: https://apify.com/stefano\_seggio/aozora-bunko-public-domain-text-feed.md
- **Developed by:** [Stefano Seggio](https://apify.com/stefano_seggio) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 full-text delta delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Aozora Bunko New Public-Domain Text Delta Feed

#### Stop refreshing a library's catalog page by hand — get told the moment a new public-domain Japanese text appears, full text included

Aozora Bunko keeps adding and revising public-domain Japanese texts on its own schedule, with no push notification when something new lands — so you either check back manually or build a scraper that re-pulls the whole catalog every run, most of which hasn't changed since the last time you looked. That wastes time and money re-downloading texts you already have, and it's easy to quietly miss a revision to a text you're already using. **This Actor solves that**: it watches Aozora Bunko's own official catalog export and emits an event only when a text is newly digitized (`NEW_TEXT`), revised (`REVISED_TEXT`), or changes status (`STATUS_CHANGE`) — with the full decoded text attached where available, so a new discovery lands in your feed ready to read, not just referenced.

***

### Why this outperforms a standard scraper

- **Delta tracking, not re-scraping.** Every record is fingerprinted on every run. Unchanged records are never re-delivered — and never billed.
- **Pay only for what's new.** A newly digitized or revised text delivered with its full decoded text costs $0.05. If Aozora Bunko only changes a text's status without new full text to go with it, that's just $0.01. Nothing else is billed.
- **Public-domain confirmation built in.** Aozora Bunko's catalog includes texts still under copyright review alongside its confirmed public-domain holdings; `onlyConfirmedPublicDomain` (on by default) keeps your feed limited to texts the library itself has already cleared, so you're not left cross-checking copyright status by hand before you use anything.

### See it before you trust it

```json
{
  "eventType": "NEW_TEXT",
  "title": "吾輩は猫である",
  "author": "夏目漱石",
  "isConfirmedPublicDomain": true,
  "fullText": "吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。...",
  "sourceUrl": "https://www.aozora.gr.jp/cards/000148/files/789.html"
}
```

`eventType` tells you instantly whether this is a brand-new digitization or a revision to something you already have, and `fullText` means you're reading the work itself, not chasing down a second link to get it.

### Zero-risk trial

Unchanged records cost **$0.00**. Run it once against real data before you commit to anything:

```bash
curl -X POST "https://api.apify.com/v2/acts/K0XRDbUteacQL3jeF/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"onlyNew":true,"onlyConfirmedPublicDomain":true}'
```

```python
import requests

response = requests.post(
    "https://api.apify.com/v2/acts/K0XRDbUteacQL3jeF/run-sync-get-dataset-items",
    params={"token": "<YOUR_API_TOKEN>"},
    json={"onlyNew": True, "onlyConfirmedPublicDomain": True},
)
records = response.json()
print(f"{len(records)} records returned")
```

```javascript
const response = await fetch(
  "https://api.apify.com/v2/acts/K0XRDbUteacQL3jeF/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ onlyNew: true, onlyConfirmedPublicDomain: true }),
  }
);
const records = await response.json();
console.log(records.length + " records returned");
```

### Pricing

| Event | What it means | Price |
|---|---|---|
| Full-Text Delivered | A newly digitized or revised confirmed-public-domain text, with full decoded text. | $0.05 |
| Metadata-Only Change Summary | A status change without new full text. | $0.01 |

Actor-start fee: $0.00005/GB-memory (one-time per run, not per record).

### What you get on every record

- A clear `eventType` of `NEW_TEXT`, `REVISED_TEXT`, or `STATUS_CHANGE`, so you always know why a text showed up in your feed
- Full-text events arrive with the complete decoded text attached — no separate fetch needed to actually read the work
- Every text checked against Aozora Bunko's own public-domain confirmation whenever `onlyConfirmedPublicDomain` is left on (the default)
- Only new-or-changed rows by default (`onlyNew` defaults to true) — no need to filter out the unchanged bulk of the catalog yourself

### Input parameters

| Field | Type | Description | Default |
|---|---|---|---|
| onlyNew | boolean | Only NEW\_TEXT, REVISED\_TEXT and STATUS\_CHANGE rows are pushed. | true |
| onlyConfirmedPublicDomain | boolean | Restricts output to texts Aozora Bunko itself has confirmed as public domain. | true |
| resetState | boolean | Clears stored seen-work state so the next run re-baselines from scratch. | false |

### Source & reliability

This feed reads directly from Aozora Bunko's own official catalog export — the library's canonical record, not a scraped mirror — so titles, authorship, and public-domain status always match what Aozora Bunko itself publishes. A persistent seen-work state is what lets the delta engine tell a genuinely new digitization apart from a revision to a text you've already received; if that state ever needs a clean slate, `resetState` clears it and re-baselines the next run from scratch.

# Changelog

This Actor's version history is a separate document: https://apify.com/stefano\_seggio/aozora-bunko-public-domain-text-feed/changelog.md

# Actor input Schema

## `onlyNew` (type: `boolean`):

When true (default), only NEW\_TEXT, REVISED\_TEXT and STATUS\_CHANGE rows are pushed, each as a charged PPE event. Set to false for a free baseline run: every catalog row that passes the public-domain filter is pushed once as an uncharged SNAPSHOT\_NO\_DIFF record.

## `resetState` (type: `boolean`):

When true, clears this feed's stored seen-work state before this run, so the next run re-baselines from scratch (every catalog row becomes a fresh, uncharged SNAPSHOT\_NO\_DIFF again, subject to onlyNew). Use for testing or recovering a corrupted state store, not routine operation.

## `onlyConfirmedPublicDomain` (type: `boolean`):

When true (default), keeps only catalog rows where Aozora's own work-copyright flag reads なし (no copyright - confirmed public domain). When false, also includes rows flagged あり (the author/estate granted free-use permission, but the work is NOT public domain).

## `includeFullText` (type: `boolean`):

When true (default), NEW\_TEXT/REVISED\_TEXT events download the linked text ZIP, decode it from Shift\_JIS, strip Aozora's ruby/annotation markup and legend preamble, and embed both plain\_text and raw\_text\_with\_markup - delivered as the higher-priced 'result' event. When false, or when a text file fails to download/decode, the same events are delivered as metadata-only 'result-summary' records instead.

## `authorIdAllowlist` (type: `array`):

Aozora 人物ID values (e.g. "001257") to restrict this feed to. Leave empty to monitor the entire catalog.

## `maxItemsPerRun` (type: `integer`):

Caps the number of charged (result/result-summary) events this run will push, independent of your Apify spending limit. 0 means no Actor-side cap.

## `requestDelayMs` (type: `integer`):

Aozora Bunko is a small, volunteer-run, non-commercial mirror with no published rate limit - this default trades a slower walk for not needing to trust an unconfirmed number, and for being a polite citizen of a small server, not only a cost control.

## `maxRetries` (type: `integer`):

Retry attempts (exponential backoff with jitter) for a 429/5xx response or a network-level failure before a single catalog or text-ZIP fetch is given up on as failed.

## `requestTimeoutSecs` (type: `integer`):

Aborts a single request to Aozora Bunko (catalog export or per-work text ZIP) that takes longer than this, so one slow response never stalls the whole run.

## `deltaStateName` (type: `string`):

Names the Key-Value Store this feed's seen-work state is kept in. Run multiple independent schedules - e.g. filtered to different author allowlists - without them draining each other's baseline by giving each a distinct name here.

## Actor input object example

```json
{
  "onlyNew": true,
  "resetState": false,
  "onlyConfirmedPublicDomain": true,
  "includeFullText": false,
  "authorIdAllowlist": [],
  "maxItemsPerRun": 20,
  "requestDelayMs": 500,
  "maxRetries": 5,
  "requestTimeoutSecs": 30,
  "deltaStateName": "default"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("stefano_seggio/aozora-bunko-public-domain-text-feed").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("stefano_seggio/aozora-bunko-public-domain-text-feed").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call stefano_seggio/aozora-bunko-public-domain-text-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stefano_seggio/aozora-bunko-public-domain-text-feed"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/K0XRDbUteacQL3jeF/builds/y7QHuxXbBdVJl9htL/openapi.json
