Skip to content

Chapters

Hirdaya Shrestha edited this page Sep 14, 2026 · 1 revision

hAudiotagger supports reading and writing chapter markers (ID3v2 CHAP frames) for MP3 files. Chapters are commonly used for podcasts, audiobooks, and multi-part songs.

What Are Chapters?

Chapters mark positions within an audio file with start and end times. They're used for:

  • Podcasts — Mark segments, topics, or ads
  • Audiobooks — Mark chapters or sections
  • Multi-part songs — Mark movements or parts
  • DJ mixes — Mark track transitions

Usage

Read Chapters

final chapters = await Haudiotagger.getChapters('/path/to/song.mp3');

for (final ch in chapters) {
  print('${ch.title}: ${ch.startMs}ms - ${ch.endMs}ms');
}

Write Chapters

await Haudiotagger.setChapters('/path/to/song.mp3', [
  Chapter(title: 'Introduction', startMs: 0, endMs: 42000),
  Chapter(title: 'Main Content', startMs: 42000, endMs: 180000),
  Chapter(title: 'Outro', startMs: 180000, endMs: 240000),
]);

Clear Chapters

await Haudiotagger.setChapters('/path/to/song.mp3', []);

Chapter Data Structure

Field Type Description
title String Chapter name
startMs int Start time in milliseconds
endMs int End time in milliseconds

Web Usage

// Read from bytes
final chapters = await Haudiotagger.getChaptersFromBytes(fileBytes);

// Write to bytes
final modified = await Haudiotagger.setChaptersFromBytes(fileBytes, chapters);

Example: Podcast Player

import 'package:haudiotagger/haudiotagger.dart';

class PodcastPlayer {
  final String audioPath;
  List<Chapter> chapters = [];
  
  PodcastPlayer(this.audioPath);
  
  Future<void> loadChapters() async {
    chapters = await Haudiotagger.getChapters(audioPath);
  }
  
  Chapter? getCurrentChapter(int positionMs) {
    for (final ch in chapters) {
      if (positionMs >= ch.startMs && positionMs < ch.endMs) {
        return ch;
      }
    }
    return null;
  }
  
  List<Chapter> getChapterList() {
    return chapters.asMap().entries.map((entry) {
      final i = entry.key;
      final ch = entry.value;
      final duration = Duration(milliseconds: ch.endMs - ch.startMs);
      return Chapter(
        title: '${i + 1}. ${ch.title} (${duration.inMinutes}m)',
        startMs: ch.startMs,
        endMs: ch.endMs,
      );
    }).toList();
  }
}

Example: Generate Chapters from Timecodes

import 'package:haudiotagger/haudiotagger.dart';

List<Chapter> generateChapters(List<int> timecodes, List<String> titles) {
  final chapters = <Chapter>[];
  
  for (var i = 0; i < timecodes.length; i++) {
    final startMs = timecodes[i];
    final endMs = i < timecodes.length - 1 
        ? timecodes[i + 1] 
        : startMs + 300000; // Default 5 minutes
    
    chapters.add(Chapter(
      title: titles[i],
      startMs: startMs,
      endMs: endMs,
    ));
  }
  
  return chapters;
}

// Usage
final chapters = generateChapters(
  [0, 180000, 360000, 540000],
  ['Intro', 'Topic 1', 'Topic 2', 'Conclusion'],
);

await Haudiotagger.setChapters('/path/to/podcast.mp3', chapters);

Format Support

Format Support
MP3 (ID3v2) Full read/write
FLAC Not supported
MP4/M4A Not supported
Ogg Vorbis Not supported

Note

Chapters are currently only supported for MP3 files using ID3v2 CHAP frames.


Clone this wiki locally