SongKong Jaikoz

SongKong and Jaikoz Music Tagger Community Forum

Bandcamp support for SongKong

Tested against larger dataset and and added Bandcamp Filter

Added option to Ignore albums already matched to MusicBrainz and Discogs because this makes it easier to focus on unmatched albums, because of limits of the bandcamp search and rate limiting matching cannot be as quick as for MusicBrainz/Discogs

image

1 Like

Well, in my use case matched albums are moved to a matched folder. But for people re-processing the matched folder, I guess this will indeed be usefull ! :slight_smile:

Ah, thats a point.

Matched Folder option in Rename Files hasn’t been changed to consider a match to Bandcamp a match. And the Yes, if matched to a release option of Rename files based on metadata hasnt been modified to consider a match to bandcamp a match, so if you ran your rename task on albums matched to bandcamp only they wouldnt be renamed or moved.

I suppose they should ?

Well, here is where I am now, I basically do have a matched folder, where everything is matched, and should not be processed again, and I have a sump folder, where new music lands, and should be re-processed with the bandcamp feature, in order to try to reduce the unmatched amount of albums.

So once the bandcamp feat will be available, I guess I’ll want to run it on the whole Music_dump folder, where everything should be 100% identically tagged to the tags found on bandcamp (as they are actually coming FROM bandcamp).

once matched, the rename should indeed move the files to their usual Artist/Album/ folder inside music_matched.

By the way, you’ll notice how much terrabytes of dupes I was able to get rid of since I started using Songkong. It’s pretty impressive :slight_smile:

Now available

1 Like

I’m off atm, but I’ll add this to my list asap :stuck_out_tongue:

Thanks Paul !

hi @paultaylor,

Quick check of the new bandcamp feature, it looks like there is a problem when going back to a working task.

image

Once the task is tsrted, I can see the usual loaded tracks, saved tracks etc. screen. If I closethe browser, then go back to bandcamp task, the screen remains fully white, it’s impossible to have an idea of where the process is.

the logs are reporting things, though :

Okay I will look into that tommorrow, but obvious solution is don’t close browser

Also I notice you are getting some http 429 error codes. This is due to submitting too many requests to bandcamp, with my own testing I had the rate at a level where it wasn’t generating any errors so I wonder if you are trying to run on multiple machines at same time, if you are this is going you cause issues.

I am running this on a 23TB backlog :slight_smile: I cannot leave it open.

Tomorrow, I’ll adapt the autokong script, for the sake of making it run per folder, each folder been divided in 500gb parts.

Sorry I don’t get why you can’t leave a tab on Web browser open?

But you normally run from cmd line anyway.

by the way, here :

songkong:server unable to recreate start pagenull
>>>>>/start.task
songkong:server unable to recreate start pagenull

I just did try to start songkong using the cli, it looks like I have to use specific options to run this or that task. I’ll dig it.

root@Murray:/mnt/cache/appdata/songkong/Prefs# docker run --rm --name songkong_bandcamp_manual -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music songkong/songkong -p songkong_deleteduplicates2.properties
debuglogfile is:/songkong/Logs/songkong_debug%u-%g.log
userlogfile is:/songkong/Logs/songkong_user%u-%g.log
Unrecognised Options for SongKong
Options for SongKong are as follows:
Usage: songkong [options] file1 file2 file3 ...
  Options:
    -a
       auto edit
       Default: false
    -b
       remove specified fields with metagrater
       Default: false
    -c
       match one album, must also specify release id using -o
       musicbrainzOrDiscogsId=url
       Default: false
    -d
       delete duplicates in specified files
       Default: false
    -e
       bandcamp matcher for specified files
       Default: false
    -f
       rename or move files
       Default: false
    -g
       run in gui
       Default: false
    -h
       show usage information
       Default: false
    -m
       fix songs in specified files
       Default: false
    -n
       import naim metadata files for specified files
       Default: false
    -o
       overrideOption1=value1, overideOption2=value2
       Default: []
    -p
       profile
    -r
       run in remote mode, access via browser (i.e http://localhost:4567)
       Default: false
    -s
       create status report for specified files
       Default: false
    -u
       undo any changes made to songs in specified files by SongKong
       Default: false
    -w
       watch folder in specified folder
       Default: false
root@Murray:~# docker run --rm --name songkong_bandcamp_manual -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music songkong/songkong -e /music/Music_dump/01-1800/
debuglogfile is:/songkong/Logs/songkong_debug%u-%g.log
userlogfile is:/songkong/Logs/songkong_user%u-%g.log
Using Current Profile:Default:songkong_bandcamp.properties
Start Bandcamp Matcher
Songs Loaded 3506: Bandcamp Matched 0: Saved 0: Done 0

lets see. But for now it seems I cannot pass a profile anymore

Looking at first line it looks that you specified a profile but not a task. You always have to specify a task and you can optionally specify a profile as well.

I can tell you that my script that was working fine before the update now also do report these options errors. so it definitely looks like the syntax changed. here is what happens if I run it manually :

root@Murray:/mnt/cache/appdata/scripts# python3 Autokong_nightly_process.py


Starting processing for folder: /mnt/user/MURRAY/Music/Music_dump/06-2024/
Executing the musicbrainz command: docker run --rm --name songkong_musicbrainz_mnt-user-MURRAY-Music-Music_dump-06-2024 -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music songkong/songkong -p songkong_musicbrainz.properties
debuglogfile is:/songkong/Logs/songkong_debug%u-%g.log
userlogfile is:/songkong/Logs/songkong_user%u-%g.log
Usage: songkong [options] file1 file2 file3 ...
Options:
-a
auto edit
Default: false
-b
remove specified fields with metagrater
Default: false
-c
match one album, must also specify release id using -o
musicbrainzOrDiscogsId=url
Default: false
-d
delete duplicates in specified files
Default: false
-e
bandcamp matcher for specified files
Default: false
-f
rename or move files
Default: false
-g
run in gui
Default: false
-h
show usage information
-n
import naim metadata files for specified files
Default: false
-o
overrideOption1=value1, overideOption2=value2
Default: []
-p
profile
-r
run in remote mode, access via browser (i.e http://localhost:4567)
Default: false
-s
create status report for specified files
Default: false
-u
undo any changes made to songs in specified files by SongKong
Default: false
-w
watch folder in specified folder
Default: false

Sending Pushover notification: 🎵 SongKong Musicbrainz Summary for folder: /mnt/user/MURRAY/Music/Music_dump/06-2024/ 🎵


⏱ Total Time Taken: 0:00:09.912550 ⏱

📊 Overall Progress: 1/10 folders processed (10.00%). 9 folders remaining.
🔗 Report URL: http://192.168.3.2:4569

🔍 Estimated Time for Next Folder: -1 day, 23:59:59.954847
❗ Error Count: 0
📊 Efficiency: 0.00 songs/second
💾 Disk Usage: Total: 288057660344, Used: 250415157168, Free: 37626034456
Executing the bandcamp command: docker run --rm --name songkong_bandcamp_mnt-user-MURRAY-Music-Music_dump-06-2024 -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music songkong/songkong -p songkong_bandcamp.properties
debuglogfile is:/songkong/Logs/songkong_debug%u-%g.log
userlogfile is:/songkong/Logs/songkong_user%u-%g.log
auto edit
Default: false
-b
remove specified fields with metagrater
Default: false
-c
match one album, must also specify release id using -o
musicbrainzOrDiscogsId=url
Default: false
-d
delete duplicates in specified files
Default: false
-e
bandcamp matcher for specified files
Default: false
-f
rename or move files
Default: false
-g
run in gui
Default: false
-h
show usage information
Default: false
-m
fix songs in specified files
Default: false
-n
import naim metadata files for specified files
Default: false
-o
overrideOption1=value1, overideOption2=value2
Default: []
-p
profile
-r
run in remote mode, access via browser (i.e http://localhost:4567)
Default: false
-s
create status report for specified files
Default: false
-u
undo any changes made to songs in specified files by SongKong
Default: false
-w
watch folder in specified folder
Default: false

Sending Pushover notification: 🎵 SongKong Musicbrainz Summary for folder: /mnt/user/MURRAY/Music/Music_dump/06-2024/ 🎵


⏱ Total Time Taken: 0:00:09.912550 ⏱

📊 Overall Progress: 1/10 folders processed (10.00%). 9 folders remaining.
🔗 Report URL: http://192.168.3.2:4569

🔍 Estimated Time for Next Folder: -1 day, 23:59:59.954847
❗ Error Count: 0
📊 Efficiency: 0.00 songs/second
💾 Disk Usage: Total: 288057660344, Used: 250415157168, Free: 37626034456
Executing the bandcamp command: docker run --rm --name songkong_bandcamp_mnt-user-MURRAY-Music-Music_dump-06-2024 -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music songkong/songkong -p songkong_bandcamp.properties
debuglogfile is:/songkong/Logs/songkong_debug%u-%g.log
userlogfile is:/songkong/Logs/songkong_user%u-%g.log
Usage: songkong [options] file1 file2 file3 ...
Options:
-a
auto edit
Default: false
-b
remove specified fields with metagrater
Default: false
-c
match one album, must also specify release id using -o
musicbrainzOrDiscogsId=url
Default: false
-d
delete duplicates in specified files
Default: false
-e
bandcamp matcher for specified files
Default: false
-f
rename or move files
Default: false
-g
run in gui
Default: false
-h
show usage information
Default: false
-m
fix songs in specified files
Default: false
-n
import naim metadata files for specified files
Default: false
-o
overrideOption1=value1, overideOption2=value2
Default: []
-p
profile
-r
run in remote mode, access via browser (i.e http://localhost:4567)
Default: false
-s
create status report for specified files
Default: false
-u
undo any changes made to songs in specified files by SongKong
Default: false
-w
watch folder in specified folder
Default: false

Sending Pushover notification: 🎵 SongKong Bandcamp Summary for folder: /mnt/user/MURRAY/Music/Music_dump/06-2024/ 🎵


⏱ Total Time Taken: 0:00:05.271638 ⏱

📊 Overall Progress: 2/10 folders processed (20.00%). 8 folders remaining.
🔗 Report URL: http://192.168.3.2:4569

🔍 Estimated Time for Next Folder: 0:00:02.266810
❗ Error Count: 0
📊 Efficiency: 0.00 songs/second
💾 Disk Usage: Total: 288057660344, Used: 250415037808, Free: 37626153560
^CTraceback (most recent call last):
  File "/mnt/cache/appdata/scripts/Autokong_nightly_process.py", line 277, in <module>
    run_songkong_task(HOST_FOLDER, "songkong_bandcamp.properties", "bandcamp")  # Bandcamp verification task
  File "/mnt/cache/appdata/scripts/Autokong_nightly_process.py", line 216, in run_songkong_task
    send_pushover_notification(summary_message)
  File "/mnt/cache/appdata/scripts/Autokong_nightly_process.py", line 87, in send_pushover_notification
    requests.post(url, data=data)
  File "/usr/lib64/python3.9/site-packages/requests/api.py", line 115, in post
    return request("post", url, data=data, json=json, **kwargs)
  File "/usr/lib64/python3.9/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/lib64/python3.9/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib64/python3.9/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib64/python3.9/site-packages/requests/adapters.py", line 486, in send
    resp = conn.urlopen(
  File "/usr/lib64/python3.9/site-packages/urllib3/connectionpool.py", line 793, in urlopen
    response = self._make_request(
  File "/usr/lib64/python3.9/site-packages/urllib3/connectionpool.py", line 537, in _make_request
    response = conn.getresponse()
  File "/usr/lib64/python3.9/site-packages/urllib3/connection.py", line 466, in getresponse
    httplib_response = super().getresponse()
  File "/usr/lib64/python3.9/http/client.py", line 1377, in getresponse
    response.begin()
  File "/usr/lib64/python3.9/http/client.py", line 320, in begin
    version, status, reason = self._read_status()
  File "/usr/lib64/python3.9/http/client.py", line 281, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/lib64/python3.9/socket.py", line 704, in readinto
    return self._sock.recv_into(b)
  File "/usr/lib64/python3.9/ssl.py", line 1242, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/lib64/python3.9/ssl.py", line 1100, in read
    return self._sslobj.read(len, buffer)
KeyboardInterrupt

FYI, there is no implication of the bandcamp task at all in this script for now, it is just the same script running just like it did for months before this update

See this thread you’ll see the default docker settings ran -r for remote mode but you had to modify to -m to run Fix Songs

Also see Tutorial: SongKong Command Line

I dont know the situation regarding your script but SongKong has always required a task to be passed to it not just a profile.

@meaning did you manage to resolve this ?

I’m underwater work wise, but I will try to find a spot to debug this, I’ll get back to you as soon it is done !

Thing is, I am running the exact same script as I was before. The files load, but are not been processed.

Not sure I already shared my nightly process script with you by the way:

import os
import subprocess
import re
from datetime import datetime, timedelta
import time
import threading
import shutil

try:
    import requests
except ImportError:
    import subprocess
    subprocess.check_call(["pip3", "install", "requests"])
    import requests

# Calculate the date of the previous day
yesterday = datetime.now() - timedelta(days=1)
day = yesterday.strftime("%d")
month_year = yesterday.strftime("%m-%Y")
day_month = yesterday.strftime("%d-%m")

# Configuration
HOST_FOLDER = f"/mnt/user/MURRAY/Music/Music_dump/{month_year}/"
DOCKER_FOLDER = f"/music/Music_dump/{month_year}/"
DOCKER_IMAGE_NAME = "songkong/songkong"
pushover_user_key = "u8pztbghz47d689h8nwsctga1jp7z1"
pushover_api_token = "ajnkq8s9f9ggwg5ooyq9zppxi2z2is"
NOTIFICATION_INTERVAL_MINUTES = 60
FULL_REPORTING = True  # Change to True for full reporting
SEND_INTERMEDIATE_NOTIFICATIONS = False  # Set to False to disable intermediate notifications
RUN_FOLDERS_SPLIT_BASH_SCRIPT = False  # Change to False if you do not want to run the Bash script
SERVER_IP = "192.168.3.2" # Your usual SongKong server IP
SERVER_PORT = "4569" # Your SongKong port

# Delete the database before starting the processing
shutil.rmtree("/mnt/cache/appdata/songkong/Prefs/Database", ignore_errors=True)

# Run the Bash script before starting processing, if configured to do so
if RUN_FOLDERS_SPLIT_BASH_SCRIPT:
    bash_script_path = "split_script.sh"
    subprocess.run(["bash", bash_script_path], check=True)

# Global variable to store past processing times and processed folders
past_processing_times = []
processed_folders = []

# Add the new global variable here
processing_complete = False

def get_server_url():
    """
    Returns the server URL based on the SERVER_IP and SERVER_PORT configuration.
    """
    if SERVER_PORT:
        return f"http://{SERVER_IP}:{SERVER_PORT}"
    return f"http://{SERVER_IP}"

def initialize_processed_folders():
    global processed_folders
    if os.path.exists("songkong_log.txt"):
        with open("songkong_log.txt", "r") as log_file:
            processed_folders = [line.strip() for line in log_file.readlines()]

def calculate_eta(start_time):
    if not past_processing_times:
        return "Unknown"
    average_time = sum(past_processing_times) / len(past_processing_times)
    remaining_time = average_time - (datetime.now() - start_time).total_seconds()
    return str(timedelta(seconds=remaining_time))

def get_progress_summary():
    total_folders = len(find_all_subfolders())
    processed_count = len(processed_folders)
    remaining_count = total_folders - processed_count
    progress_percentage = (processed_count / total_folders) * 100
    return f"📊 Overall Progress: {processed_count}/{total_folders} folders processed ({progress_percentage:.2f}%). {remaining_count} folders remaining."

def send_pushover_notification(message):
    log_action(f"Sending Pushover notification: {message}")
    if pushover_user_key and pushover_api_token:
        url = "https://api.pushover.net/1/messages.json"
        data = {
            "token": pushover_api_token,
            "user": pushover_user_key,
            "message": message
        }
        requests.post(url, data=data)

def log_action(action):
    print(action)
    with open("action_log.txt", "a") as log_file:
        log_file.write(f"{datetime.now()} - {action}\n")

def was_folder_processed(folder):
    print(f"Checking if folder {folder} was processed...")
    if not os.path.exists("songkong_log.txt"):
        return False
    with open("songkong_log.txt", "r") as log_file:
        logs = log_file.read()
        print(f"Complete Log Contents:\n{logs}\n")  # Add this line for debugging
        if folder in logs:
            print(f"Folder {folder} was found in the log.")
            return True
        return False

def move_logs_to_backup(relative_path, end_time):
    log_folder = "/mnt/cache/appdata/songkong/Logs/"
    backup_folder = "/mnt/cache/appdata/songkong/Logs_backup/"
    date_time_suffix = end_time.strftime("%Y%m%d_%H%M%S")
    for log_file in os.listdir(log_folder):
        new_log_file = f"{relative_path}_{date_time_suffix}_{log_file}"
        shutil.move(os.path.join(log_folder, log_file), os.path.join(backup_folder, new_log_file))

def extract_value(pattern, text):
    match = re.search(pattern, text)
    if match:
        return int(match.group(1).replace(',', ''))
    return 0

def send_periodic_notification(process_output, start_time):
    global processing_complete
    if processing_complete:
        return
    if process_output:
        last_line = process_output[-1]
        loaded = extract_value(r'Songs loaded ([\d,]+)', last_line)
        fingerprinted = extract_value(r'Fingerprinted ([\d,]+)', last_line)
        musicbrainz = extract_value(r'MusicBrainz ([\d,]+)', last_line)
        discogs = extract_value(r'Discogs ([\d,]+)', last_line)
        saved = extract_value(r'Saved ([\d,]+)', last_line)

        if not (loaded or fingerprinted or musicbrainz or discogs or saved):
            return

        fingerprinted_percent = (fingerprinted / loaded) * 100 if loaded else 0
        musicbrainz_percent = (musicbrainz / loaded) * 100 if loaded else 0
        discogs_percent = (discogs / loaded) * 100 if loaded else 0
        saved_percent = (saved / loaded) * 100 if loaded else 0

        elapsed_time = str(datetime.now() - start_time).split('.')[0]

        notification_message = f"🎵 SongKong Processing Summary for folder: {current_folder} 🎵\n\n"
        notification_message += f"Songs loaded: {loaded} (100.00%)\n"
        notification_message += f"Songs fingerprinted: {fingerprinted} ({fingerprinted_percent:.2f}%)\n"
        notification_message += f"Songs matched to MusicBrainz: {musicbrainz} ({musicbrainz_percent:.2f}%)\n"
        notification_message += f"Songs matched to Discogs: {discogs} ({discogs_percent:.2f}%)\n"
        notification_message += f"Songs saved: {saved} ({saved_percent:.2f}%)\n"
        notification_message += f"⏱ Total Time Taken: {elapsed_time} ⏱\n\n"
        notification_message += get_progress_summary()

        send_pushover_notification(notification_message)

    threading.Timer(NOTIFICATION_INTERVAL_MINUTES * 60, send_periodic_notification, args=[process_output, start_time]).start()

def run_songkong_task(relative_path, task_properties, task_name):
    global current_folder, processing_complete
    processing_complete = False
    start_time = datetime.now()
    current_folder = relative_path.replace('/', '-').strip('-')
    container_name = f"songkong_{task_name}_{current_folder}"
    cmd = f'docker run --rm --name {container_name} -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music {DOCKER_IMAGE_NAME} -p {task_properties}'
    retry_count = 0
    MAX_RETRIES = 2
    database_corrupt_error = "Database /songkong/Prefs/Database appears corrupt"

    while retry_count <= MAX_RETRIES:
        log_action(f"Executing the {task_name} command: {cmd}")
        process_output = []
        process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        error_detected = False

        for line in iter(process.stdout.readline, ''):
            print(line.strip())
            process_output.append(line.strip())
            if database_corrupt_error in line:
                error_detected = True
                process.terminate()
                log_action(f"Error detected: {database_corrupt_error}. Deleting database and retrying...")
                shutil.rmtree("/mnt/cache/appdata/songkong/Prefs/Database", ignore_errors=True)
                retry_count += 1
                break

        if not error_detected:
            break

    end_time = datetime.now()
    time_taken = (end_time - start_time).total_seconds()
    past_processing_times.append(time_taken)
    processed_folders.append(relative_path)

    summary_message = f"🎵 SongKong {task_name.capitalize()} Summary for folder: {relative_path} 🎵\n\n"
    total_songs = 0
    error_count = 0
    for line in process_output:
        if "Songs loaded:" in line:
            total_songs = int(re.search(r'\d+', line).group())
        if "Error" in line:
            error_count += 1
        if any(keyword in line for keyword in ["Songs loaded:", "Songs fingerprinted:", "Songs matched to MusicBrainz", "Songs matched to Discogs", "Songs matched to Bandcamp", "Songs saved", "Completed", "Errors and Warnings", "Reports"]):
            value = int(re.search(r'\d+', line).group())
            percent = (value / total_songs) * 100 if total_songs else 0
            summary_message += f"{line} ({percent:.2f}%)\n"

    summary_message += f"\n⏱ Total Time Taken: {str(timedelta(seconds=time_taken))} ⏱\n\n"
    summary_message += get_progress_summary()
    if FULL_REPORTING:
        summary_message += f"\n🔗 Report URL: {get_server_url()}\n"
        summary_message += f"\n🔍 Estimated Time for Next Folder: {calculate_eta(start_time)}"
        summary_message += f"\n❗ Error Count: {error_count}"
        summary_message += f"\n📊 Efficiency: {total_songs/time_taken:.2f} songs/second"
        total_space, used_space, free_space = os.popen('df /mnt/user/MURRAY/Music').read().split("\n")[1].split()[1:4]
        summary_message += f"\n💾 Disk Usage: Total: {total_space}, Used: {used_space}, Free: {free_space}"

    summary_message = summary_message.replace("/songkong/Reports", get_server_url())
    processing_complete = True
    send_pushover_notification(summary_message)
    move_logs_to_backup(relative_path, end_time)

def extract_delete_duplicates_summary(output):
    summary_pattern = re.compile(r"(Processing:\d+|Songs loaded:\d+|Duplicate groups found :\d+|Duplicate songs deleted:\d+|Errors and Warnings:\d+)")
    summary = "\n".join(summary_pattern.findall(output))
    return summary

def send_delete_duplicates_notification(relative_path, summary):
    notification_message = f"🎵 SongKong Delete Duplicates Summary for folder: {relative_path} 🎵\n\n"
    notification_message += summary
    send_pushover_notification(notification_message)

def run_songkong_delete_duplicates(relative_path):
    current_folder = relative_path.replace('/', '-').strip('-')  # Formatting for container name
    container_name = f"songkong_delete_{current_folder}"
    cmd = f'docker run --rm --name {container_name} -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music {DOCKER_IMAGE_NAME} -d "{DOCKER_FOLDER}" -p songkong_deleteduplicates2.properties'
    time.sleep(60)
    log_action(f"Executing the delete duplicates command: {cmd}")

    process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    output, _ = process.communicate()

    summary = extract_delete_duplicates_summary(output)
    send_delete_duplicates_notification(relative_path, summary)

def extract_rename_summary(output):
    summary_pattern = re.compile(r"Songs Report is: (.+)|Songs loaded:(\d+)|Songs renamed:(\d+)|Completed:(\d+)|Errors and Warnings:(\d+)|Report Creation:(\d+)")
    summary = "\n".join(summary_pattern.findall(output))
    return summary

def run_songkong_rename(relative_path):
    current_folder = relative_path.replace('/', '-').strip('-')  # Formatting for container name
    container_name = f"songkong_rename_{current_folder}"
    cmd = f'docker run --rm --name {container_name} -v /mnt/cache/appdata/songkong:/songkong -v /mnt/user/MURRAY/Music:/music {DOCKER_IMAGE_NAME} -f "{DOCKER_FOLDER}"'
    time.sleep(60)
    log_action(f"Executing the rename command: {cmd}")

    process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    output, _ = process.communicate()

    rename_summary = extract_rename_summary(output)
    send_pushover_notification(rename_summary)

def find_all_subfolders():
    return [folder for folder in os.listdir(HOST_FOLDER) if os.path.isdir(os.path.join(HOST_FOLDER, folder))]

def is_folder_empty(folder_path):
    return not os.listdir(folder_path)

def delete_folder(folder_path):
    os.rmdir(folder_path)
    log_action(f"Deleted empty folder: {folder_path}")

if __name__ == "__main__":
    if RUN_FOLDERS_SPLIT_BASH_SCRIPT:
        bash_script_path = "split_script.sh"
        subprocess.run(["bash", bash_script_path], check=True)

    print(f"\n\nStarting processing for folder: {HOST_FOLDER}")
    run_songkong_task(HOST_FOLDER, "songkong_musicbrainz.properties", "musicbrainz")  # Correction task
    run_songkong_task(HOST_FOLDER, "songkong_bandcamp.properties", "bandcamp")  # Bandcamp verification task
    run_songkong_delete_duplicates(HOST_FOLDER)  # Duplicate deletion task
    run_songkong_rename(HOST_FOLDER)  # Renaming task

    send_pushover_notification("🎉 Script has finished processing the folder. 🎉")

@paultaylor

One thing ain’t clear :

fix songs (-m) is the fix songs task, but how do we call the bandcamp task using the cli ? I can’t see any parameter allowing to start this specific task type.