Quickstart

If you’re just here to add character metadata, check out Adding Character Metadata.

Firstly, open the scripts/test.py file you created in Installation & Setup in your desired text editor. You should see the following line:

pprint('shiHib')

This is a placeholder for the template, and we’ll replace this with actual code.

We’ll use Love Live! Sunshine!! as an example. First, let’s grab the group,

sunshine_group = client.groups['Love Live! Sunshine!!']

and then search for all tracks matching that group and print their names.

for track in client.iter_tracks(groups=[sunshine_group]):
    print(track.name)

In summary, your code should now look like

with amqcsl.DBClient(
    username=os.getenv('AMQ_USERNAME'),
    password=os.getenv('AMQ_PASSWORD'),
) as client:
    sunshine_group = client.groups['Love Live! Sunshine!!']
    for track in client.iter_tracks(groups=[sunshine_group]):
        print(track.name)

If you now run the file again, you should see the track names being printed to the console in 50 track batches:

[2025-06-03 00:06:46,953|httpx]:INFO: HTTP Request: POST https://amqbot.082640.xyz/api/tracks "HTTP/1.1 200 OK"
WATER BLUE NEW WORLD
WONDERFUL STORIES
"MY LIST" to you!
...
KU-RU-KU-RU Cruller! (Rockabilly Ver.)
LIVE with a smile!
LIVE with a smile!
[2025-06-03 00:06:46,965|amqcsl.client]:INFO: Page exhausted
[2025-06-03 00:06:46,965|amqcsl.client]:INFO: Querying next page

This is the client fetching each page of the search result and automatically chaining them together, so you don’t need to worry about iterating over pages yourself. Before we get into the features of the client, note that rich is a dependency of the library, and the database objects support pretty printing. You’ll need to import pprint:

from rich.pretty import pprint

and then you can use pprint to display objects.

Lists & Groups

To access your lists, amqcsl.DBClient provides the dictionary lists, which you index via list names. As we saw earlier, there is a similar dictionary groups. For example, I have a list called rat, so I would do

rat_list = client.lists['rat']
pprint(rat_list)

the output of which is:

CSLList(id='01969119-fe28-7299-b266-1798ae844f1f', name='rat', count=48)

You can create groups and lists,

# Don't actually run this it'll make a new group in the db
new_group = client.create_group('new group')

# This creates a list called test by containing tracks from lists rat and game
new_list = client.create_list('test', client.lists['rat'], client.lists['game'])

and add/remove tracks from these lists:

# Remove all existing tracks
client.list_remove(new_list, *client.iter_tracks(active_list=new_list))
# Add all idoly pride tracks
client.list_add(new_list, *client.iter_tracks(groups=[client.groups['IDOLY PRIDE']]))

# Or equivalently,
new_tracks = [*client.iter_tracks(groups=[client.groups['IDOLY PRIDE']])]
existing_tracks = [*client.iter_tracks(active_list=new_list])]
client.list_edit(new_list, new_tracks, existing_tracks)

Tracks, Songs & Artists

We’ve already seen iter_tracks, and there are similar methods iter_songs and iter_artists for iterating over songs and artists respectively:

sunshine_group = client.groups['Love Live! Sunshine!!']
for track in client.iter_tracks('You Watanabe', groups=[sunshine_group]):
    pprint(track)
for song in client.iter_songs('Shuka Saitou'):
    pprint(song)
for artist in client.iter_artists('Aoi Nagatsuki'):
    pprint(artist)

For iter_tracks, you can also filter by lists:

client.iter_tracks(active_list=client.lists['rat'])

As well as songs missing audio/info:

client.iter_tracks(groups=[sunshine_group], missing_audio=True, missing_info=True)

If you accidentally make a really large query, such as

for track in client.iter_tracks():
    pprint(track)

the code will raise a QueryError saying it is too large. You can change the max query size (defaults to 1500) via the max_query_size attribute in DBClient if necessary.

Detailed Object Fetching

When you click on a song/artist/track, you can get extra information like metadata, artist credits, etc. This is supported via the following methods:

for song in client.iter_songs('Shuka Saitou'):
    song = client.get_song(song)
for artist in client.iter_artists('Aoi Nagatsuki'):
    artist = client.get_artist(song)
for track in client.iter_tracks('You Watanabe'):
    meta = client.get_metadata(track)

Track metadata is stored separately, which is why get_metadata looks different to the other methods. See CSLSong, CSLArtist, and CSLMetadata for more information.

Editing Tracks

To edit a track, use track_edit:

terraria = client.groups['Terraria']
video_games = client.groups['Video Games']
for track in client.iter_tracks(groups=[terraria]):
    client.track_edit(track, groups=[terraria, video_games])

For metadata, you can add/remove them with track_add_metadata and track_remove_metadata:

from amqcsl.objects import ExtraMetadata

terraria = client.groups['Terraria']
game_meta = ExtraMetadata('Game', False, 'Terraria')
for track in client.iter_tracks(groups=[terraria]):
    meta = track.get_metadata(track)
    # This is just an example, don't actually do this
    for m in meta.extra_metas:
        client.track_remove_metadata(track, m)
    client.track_add_metadata(track, game_meta, existing_meta=meta)

You can pass in multiple metadata objects to track_add_metadata, and passing existing_meta means the client won’t duplicate the metadata if it already exists. The metadata objects can either be ArtistCredit or ExtraMetadata.

Queueing Operations

In many use cases, it’s likely you’d want to see your changes before actually applying them. The client offers a queue for this case. When calling track_add_metadata and track_remove_metadata, you can pass in a queue=True keyword argument to add the edit to the queue, and then commit the queue at the end after confirming your changes:

from amqcsl.objects import ExtraMetadata
from amqcsl.utils import prompt

terraria = client.groups['Terraria']
game_meta = ExtraMetadata('Game', False, 'Terraria')
for track in client.iter_tracks(groups=[terraria]):
    meta = track.get_metadata(track)
    client.track_add_metadata(track, game_meta, existing_meta=meta, queue=True)

if prompt(client.queue):
    client.commit()

Adding Albums and Adding Audio

You can upload albums with add_album, as well as upload audio with add_audio. The functionality for this is very basic right now, and a new workflow for doing this will be introduced next version, so probably don’t worry about this yet.