Skip to content

libgpod Integration

This document covers the libgpod C library and how podkit integrates with it through native Node.js bindings.

Overview

libgpod is a C library for reading and writing the iTunes database (iTunesDB) on iPod devices. It is the de facto standard library used by most Linux iPod management tools.

AttributeValue
Repositoryhttps://github.com/fadingred/libgpod
LanguageC (with GLib)
LicenseLGPL-2.1
Current Version0.8.3
StatusMaintenance mode (stable, infrequent updates)

IpodDatabase Abstraction

For application code, use IpodDatabase from @podkit/core instead of @podkit/libgpod-node directly.

The IpodDatabase class provides a clean, high-level API that:

  • Hides internal details like TrackHandle references
  • Provides type-safe track and playlist operations
  • Returns immutable snapshots for safe data access
  • Handles error translation to structured IpodError types

When to Use Each Package

Use CasePackage
CLI commands, application code@podkit/core (IpodDatabase)
Sync engine, business logic@podkit/core (IpodDatabase)
libgpod binding tests@podkit/libgpod-node
Debugging low-level issues@podkit/libgpod-node

Quick Example

import { IpodDatabase } from '@podkit/core';
// Open iPod
const ipod = await IpodDatabase.open('/Volumes/IPOD');
// Display info
const info = ipod.getInfo();
console.log(`${info.device.modelName} (${info.device.capacity}GB)`);
// List tracks
for (const track of ipod.getTracks()) {
console.log(`${track.artist} - ${track.title}`);
}
// Add a track
const track = ipod.addTrack({
title: 'New Song',
artist: 'Artist',
album: 'Album',
});
track.copyFile('/path/to/song.mp3');
// Save and close
await ipod.save();
ipod.close();

libgpod Core API

Database Operations

#include <gpod/itdb.h>
// Parse iPod database from mount point
Itdb_iTunesDB *itdb_parse(const char *mountpoint, GError **error);
// Write database back to iPod
gboolean itdb_write(Itdb_iTunesDB *itdb, GError **error);
// Free database structure
void itdb_free(Itdb_iTunesDB *itdb);

Track Management

// Create new track
Itdb_Track *itdb_track_new(void);
// Add track to database
void itdb_track_add(Itdb_iTunesDB *itdb, Itdb_Track *track, gint32 pos);
// Remove track from database
void itdb_track_remove(Itdb_Track *track);
// Copy file to iPod
gboolean itdb_cp_track_to_ipod(Itdb_Track *track,
const char *filename,
GError **error);
// Set track artwork
gboolean itdb_track_set_thumbnails(Itdb_Track *track,
const char *filename);

Playlist Management

// Create new playlist
Itdb_Playlist *itdb_playlist_new(const char *title, gboolean spl);
// Add playlist to database
void itdb_playlist_add(Itdb_iTunesDB *itdb, Itdb_Playlist *pl, gint32 pos);
// Add track to playlist
void itdb_playlist_add_track(Itdb_Playlist *pl, Itdb_Track *track, gint32 pos);

Track Identification

libgpod provides several identifiers, but only pointers (Itdb_Track*) are reliable references.

Why IDs Are Unreliable

The id field has limitations:

  • Assigned during itdb_write(), not itdb_track_add()
  • Reassigned on every export
  • New tracks have id = 0 until database is saved

How libgpod-node Uses TrackHandle

The TrackHandle abstraction wraps raw Itdb_Track* pointers safely:

import { Database } from '@podkit/libgpod-node';
const db = Database.openSync('/Volumes/IPOD');
// addTrack returns a TrackHandle
const handle = db.addTrack({ title: 'Song', artist: 'Artist' });
// All operations accept TrackHandle
db.updateTrack(handle, { rating: 80 });
db.copyTrackToDevice(handle, '/path/to/song.mp3');
// After save, handle remains valid
db.saveSync();
const track = db.getTrack(handle); // Still works

Handles become invalid after removeTrack() or close(). Attempting to use an invalid handle throws a LibgpodError.

Behavioral Deviations

The libgpod-node bindings intentionally deviate from raw libgpod to prevent data corruption and assertion failures:

Operationlibgpod IssueOur Fix
removeTrack()Doesn’t remove from playlistsRemove from all playlists first
create()No master playlistCreate master playlist
initializeIpod()Requires mountpoint to existCreates directory with g_mkdir_with_parents()
clearTrackChapters()NULL chapterdata crashesCreate empty chapterdata

See packages/libgpod-node/README.md for detailed rationale and code examples for each deviation.

GLib Type Handling

libgpod uses GLib extensively:

GLib TypeComplexityNotes
gchar*LowJust C strings
gint32, guint32LowStandard integers
gbooleanLow0/1 integer
GList*MediumLinked list, needs iteration
GError**MediumOutput parameter for errors

Thread Safety

libgpod is not thread-safe. All operations on a single database must be serialized. Multiple databases can be used in parallel if they’re for different devices.

Investigating Issues

When encountering libgpod CRITICAL assertions:

  1. Reproduce with a test - Create an integration test that triggers the issue
  2. Check libgpod source - Look at tools/libgpod-macos/build/libgpod-0.8.3/src/
  3. Understand the expectation - What does libgpod expect vs. what we’re providing?
  4. Fix and document - Apply the fix and document the deviation

Native Code Structure

The C++ native code in packages/libgpod-node/native/ is organized by concern:

FilePurpose
gpod_binding.ccN-API module entry, database open/create/init
database_wrapper.ccDatabase class wrapping Itdb_iTunesDB
track_operations.ccTrack add/remove/update/chapters
playlist_operations.ccPlaylist create/add/remove
artwork_operations.ccArtwork thumbnail management
gpod_converters.ccType conversion between N-API and GLib
gpod_helpers.ccUtility functions
photo_database_wrapper.ccPhoto database operations

See Also