Pylistenbrainz import lastfm csv with this csv format

here’s the output of a lastfm export to csv. the Loved columnn is 0 for not loved and 1 for loved. I’m not a programmer. I’ve been using GPT(both openai GPT 3.5, and googles Bard), Bard has heard of pythonlistenbrainz but doesn’t know enough about it and openai, has no clue about it I’m just looking for a python script to import this format csv, both scrobbles and loved tracks. If anyone can help I’d appreciate it.

Track,Artist,Album,Date,Loved
Copper Brown,Muddy Waters,I'M Ready,2023-11-04 11:09:14,0
Let's Dance On (Original Stereo Version; 2006 Remaster),The Monkees,The Monkees (Deluxe Edition),2023-11-04 11:06:43,0
The Dance,Garth Brooks,Garth Brooks (Special Edition),2023-11-04 11:02:57,1

Per Feature request - Import loved tracks from LastFM to ListenBrainz plus questions about doing it manually and Usage Examples — ListenBrainz 0.1.0 documentation, it sounds like there’s no way to import loved tracks without having recording MBIDs.

I don’t use LB so I haven’t tested that the submission code works, but I think that something similar to this should work for importing the listens without the “loved” data:

#!/usr/bin/env python3

import csv
import pylistenbrainz
import sys
import time

MAX_LISTENS_PER_REQUEST = 1000

if len(sys.argv) != 2:
    print("Usage: %s <csv-file>" % sys.argv[0], file=sys.stderr)
    sys.exit(2)

auth_token = input('Please enter your auth token: ')
client = pylistenbrainz.ListenBrainz()
client.set_auth_token(auth_token)

def submit_listens(listens):
    print("Submitting %d listen(s)..." % len(listens))
    response = client.submit_multiple_listens(listens)
    assert response['status'] == 'ok'

listens = []
with open(sys.argv[1], newline='') as f:
    reader = csv.reader(f, dialect='unix')
    next(reader, None)  # skip header row
    for row in reader:
        tm = time.strptime(row[3], '%Y-%m-%d %H:%M:%S')
        listens.append(pylistenbrainz.Listen(
            track_name=row[0],
            artist_name=row[1],
            release_name=row[2],
            listened_at=int(time.mktime(tm)),
        ))
        if len(listens) >= MAX_LISTENS_PER_REQUEST:
            submit_listens(listens)
            listens = []

if len(listens) > 0:
    submit_listens(listens)

Presumably it’d be possible to run a separate small script that uses the metadata endpoint as described at Usage Examples — ListenBrainz 0.1.0 documentation to look up MBIDs and submit the “loved” data.

1 Like

One way is to first look up the recording by artist name and track title using the /1/metadata/lookup endpoint (documentation) and the us the recording_mbid from the result to submit the loved track.

E.g. lookup something like https://api.listenbrainz.org/1/metadata/lookup/?artist_name=Paradise%20Lost&recording_name=Say%20Just%20Words , then do the “love” feedback request with the resulting MBID (here 569436a1-234a-44bc-a370-8f4d252bef21).

Of course there is some potential for wrong mapping. But as I understand the underlying functionality is the same that LB also uses to match submitted tracks without MBID, and this in my experience works rather well.

Yeah, makes sense. Something like this might work (again, untested):

import requests
import sys
import time

if len(sys.argv) != 2:
    print("Usage: %s <csv-file>" % sys.argv[0], file=sys.stderr)
    sys.exit(2)
    
token = input('Please enter your auth token: ').strip()

def submit_loved(rec_mbid):
    res = requests.post(
        url = 'https://api.listenbrainz.org/1/feedback/recording-feedback',
        json={'recording_mbid': rec_mbid, 'score': 1},
        headers={'Authorization': f"Token {token}"}
    )
    res.raise_for_status()

with open(sys.argv[1], newline='') as f:
    reader = csv.reader(f, dialect='unix')
    next(reader, None)  # skip header row
    for row in reader:
        rec = row[0]
        artist = row[1]

        res = requests.get(
            url='https://api.listenbrainz.org/1/metadata/lookup/',
            params={'recording_name': rec, 'artist_name': artist},
        )
        res.raise_for_status()
        md = res.json() 
        mbid = md and md['recording_mbid']

        if mbid:
            print(f"Submitting {artist} - {rec} ({mbid})")
            submit_loved(mbid)
        else:
            print(f"MBID not found for {artist} - {rec}")

        # Bogus; see
        # https://listenbrainz.readthedocs.io/en/latest/users/api/index.html#rate-limiting.
        time.sleep(1)
1 Like