inital commit

This commit is contained in:
Rekushi authored and GitHub committed 2026-10-25 22:54:32 +00:00
commit 8e155b599b
15 files changed
+711

No files matched your search

+109
View File
@@ -0,0 +1,109 @@
# Flipnote Subtitle (.fsrt)
Subtitles timed to Flipnote pages, rather than seconds.
```text
1
1 --> 12
Hello!
2
18 --> 30
Thanks for watching.
See you next time!
```
FSRT uses the same numbered blocks as a basic SRT file, with page ranges in
place of timestamps. Pages start at 1, and both ends are included:
`12 --> 12` displays a subtitle for one page. A gap between ranges has no text.
Changing playback speed doesn't change which drawings have subtitles.
Save files as UTF-8 with the `.fsrt` extension. Each file is one language track.
Names such as `my-flipnote.en.fsrt` and `my-flipnote.ar.fsrt` help people tell
tracks apart, but language codes are not part of the file format.
An FSRT contains text and page ranges. It contains no animation, audio,
account details or author signature, and it doesn't change the original
Flipnote. It can be used with PPM or KWZ animations.
## JavaScript
No dependencies are needed. Use Node.js 18 or later:
```js
const fs = require('node:fs');
const {parse, stringify} = require('./fsrt.js');
const cues = parse(fs.readFileSync('examples/english.fsrt', 'utf8'));
fs.writeFileSync('copy.fsrt', stringify(cues));
```
For browser use, load `fsrt.js` with a script tag:
```html
<script src="fsrt.js"></script>
<script>
const cues = FlipnoteSubtitle.parse('1\n1 --> 12\nHello!\n');
console.log(cues[0]); // {start: 1, end: 12, text: 'Hello!'}
</script>
```
Both functions accept optional `{maxPage: 999, maxCues: 200}` limits. Catch
`FsrtError` to show a readable message for an invalid file or range.
## Python
Use Python 3.9 or later. Copy `fsrt.py` into your project:
```python
from pathlib import Path
from fsrt import parse, stringify
cues = parse(Path('examples/english.fsrt').read_text(encoding='utf-8-sig'))
Path('copy.fsrt').write_text(stringify(cues), encoding='utf-8')
```
The optional keyword arguments are `max_page` and `max_cues`. Parser and
validation errors raise `FsrtError`, a subclass of `ValueError`.
## Playing a track
Each parser returns objects or dictionaries with `start`, `end` and `text`
fields, sorted by starting page. If your player reports zero-based frame
indices, add 1 before comparing them with a cue's inclusive range:
```js
const page = player.currentFrame + 1;
const cue = cues.find(cue => cue.start <= page && page <= cue.end);
caption.textContent = cue ? cue.text : '';
```
Render the text literally, including line breaks. Do not put it into
`innerHTML`: `<b>` and similar strings are subtitle text, not formatting.
Fonts, placement and language selection are the player's responsibility.
Readers reject overlapping cues, reversed or out-of-range pages, blank text
and invalid control characters. The reference code accepts UTF-8 BOMs and
common line endings, and limits files to 1 MiB and 10,000 cues by default.
The [specification](SPEC.md) defines the format; individual applications may
apply stricter limits.
## Using it on RexiMemo
See [the RexiMemo instructions](docs/reximemo.md) for importing and exporting
tracks through Manage Flipnote. Those application limits do not restrict the
FSRT format itself.
## Tests
```sh
node --test tests/fsrt.test.js
python -m unittest discover -s tests
```
The two implementations use the same [conformance cases](tests/cases.json).
The [examples](examples/) include English, Japanese and Arabic tracks.
## Licence
[MIT](LICENSE). The format and reference code are maintained by RexiMemo.