Author Topic: Get clipboard contents and search Musicbee library automatically (Python script)  (Read 5427 times)


  • Full Member
  • ***
  • Posts: 174
Hi All

I've been doing a lot of tagging recently and found it mildly irritating to alt-tab to paste a search term when all I was looking for was a "yes / no" as to if I already had the album or not. (Bandcamp often has entire discographies on offer for low prices / free and I forget which ones I have already. With 480k tracks and counting it adds up.)

I brought this up in the Wishlist, but I thought it was a perfect excuse to get into Python again (the only language I know)

This is a crude proof-of-concept that uses the MusicBeeIPC by Zorexx (link below), ctypes and pyperclip. It watches the clipboard for changes, then runs that text as a search that against the Album, Artist, AlbumArtist, Title and Comment fields in the Musicbee library.

The results passed back are the full file URL, and the total number of hits for that field. You can choose to list the file url, or not, before you start by altering lines 14 & 15.


Python 2.7, including IDLE (I have had issues running this in the windows command line due to unicode weridness I don't fully grasp yet)

Zorexx MusicBeeIPC for plugin installed in MusicBee (including the SDK - this is a separate download needs to be installed manually)

pyperclip - a clipboard extension for Python which can be installed via PIP

If all is well, when run you should get a basic window with an OK button - when you click this, the window will hang but the script should now capture any new clipboard text and show the results in the IDLE Shell. You will have to Ctrl-C to exit as I have yet to work out cancel buttons.

Major bugs:

Zero sanity checking of any kind - it will crash if there are certain things in the clipboard (images, non text objects, python code snippets)

File URLs show character codes for most non alphanumeric characters (next to fix)

Picky about unicode in general when run outside IDLE

Blatantly copy/pasted from stackoverflow clipboard logic didn't work under Python3.

Feel free to suggest, modify or re-use as you see fit at your own risk, but you have my assurance I am neither smart nor skilled enough to do anything dodgy with this.  


Screenshot: link

MusicbeeIPC by Zorexx (link)

# MB Library Dinger v0.1

import os
import time
import struct
from musicbeeipc import *
import ctypes
import pyperclip
from Tkinter import *
import json # not used yet

##preferences variables (move the comment # to change)
show_hits_file_url = 0
#show_hits_file_url = 1

#var/env setup
mbIPC = MusicBeeIPC()
recent_value = ""

#crude cancel button (not implemented)
global haltstate

#counter setup for the output

#lists for searches to append and sort

#clipboard parse setup
#scary stuff I dont understand
OpenClipboard = ctypes.windll.user32.OpenClipboard
EmptyClipboard = ctypes.windll.user32.EmptyClipboard
GetClipboardData = ctypes.windll.user32.GetClipboardData
SetClipboardData = ctypes.windll.user32.SetClipboardData
CloseClipboard = ctypes.windll.user32.CloseClipboard

GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
GlobalLock = ctypes.windll.kernel32.GlobalLock
GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
GlobalSize = ctypes.windll.kernel32.GlobalSize

unicode_type = type(u'')

#TODO: change to "is" and iterate from there

comparison = "Contains"

# scrape text from clipboard

def get_clipboard_text():
    text = None
    handle = GetClipboardData(CF_UNICODETEXT)
    pcontents = GlobalLock(handle)
    size = GlobalSize(handle)
    if pcontents and size:
        raw_data = ctypes.create_string_buffer(size)
        ctypes.memmove(raw_data, pcontents, size)
        text = raw_data.raw.decode('utf-16le').rstrip(u'\0')
    return text

# main scrape

def get_result_artist(findme, comparison):
    result_artist = mbIPC.library_search(findme.lower(), comparison, ["Artist"])
    for r in result_artist:
        n_artist = n_artist + 1
    #print ("artist:" + str(n_artist))
    print ("Fetching...")
    return n_artist

def get_result_albumartist(findme, comparison):
    result_albumartist = mbIPC.library_search(findme.lower(), comparison, ["AlbumArtist"])
    for r in result_albumartist:
        n_albumartist = n_albumartist + 1
    #print ("albumartist:" + str(n_albumartist))
    print ("Fetching...")
    return n_albumartist

def get_result_title(findme, comparison):
    result_title = mbIPC.library_search(findme.lower(), comparison, ["Title"])
    for r in result_title:
        n_title = n_title + 1
    #print ("title:" + str(n_title))
        # print (list_albumartist_raw)
    print ("Fetching...")
    return n_title    

def get_result_album(findme, comparison):
    result_album = mbIPC.library_search(findme.lower(), comparison, ["album"])
    for r in result_album:
        n_album = n_album + 1
    #print ("album:" + str(n_album))
        # print (list_albumartist_raw)
    print ("Fetching...")
    return n_album  

def get_result_comment(findme, comparison):
    result_comment = mbIPC.library_search(findme.lower(), comparison, ["comment"])
    for r in result_comment:
        n_comment = n_comment + 1
    #print ("comment:" + str(n_comment))
        # print (list_albumartist_raw)
    print ("Fetching...\n")
    return n_comment

#open the window
window = Tk()
lbl = Label(window, text="Click to start --->")
#lbl2 = Label(window, text="Click to stop --->")  
lbl.grid(column=0, row=0)
#lbl2.grid(column=0, row=1)

######NOT USED
def cancel(haltstate):
haltstate = True
return haltstate

#Start watching
def clicked():
haltstate = False
while haltstate == False:
global recent_value
global show_hits_file_url
tmp_value = pyperclip.paste()
if tmp_value != recent_value:
recent_value = tmp_value
print ("Searching For = " + findme)
total_artist = get_result_artist(findme, comparison)
total_albumartist = get_result_albumartist(findme, comparison)
total_title = get_result_title(findme, comparison)
total_album = get_result_album(findme, comparison)
total_comment = get_result_comment(findme, comparison)

###### show raw results here
if show_hits_file_url == 1:
print (list_artist_raw)
print (list_albumartist_raw)
print (list_title_raw)
print (list_album_raw)
print (list_comment_raw)
print ("Resuts for search:" + findme)
print ("Hits for Artist: "+ str(total_artist))
print ("Hits for Album Artist: "+ str(total_albumartist))
print ("Hits for Tracks: "+ str(total_title))
print ("Hits for Album Title: "+ str(total_album))
print ("Total Hits for Comments: "+ str(total_comment))
total_overall = total_artist + total_albumartist + total_title + total_album + total_comment
print ("Total Hits across All: "+ str(total_overall))
print ("Waiting...")
#indents to the IF, not the while
btn = Button(window, text="OK", command=clicked)
#btn1 = Button(window, text="STOP", command=cancel(haltstate))
btn.grid(column=1, row=0)
#btn1.grid(column=1, row=1)

Last Edit: May 19, 2019, 02:41:39 AM by mrbenn


  • Newbie
  • *
  • Posts: 3
Are you able to reupload the Musicbee IPC? Seems like it's been deleted. All the links are dead.


  • Global Moderator
  • Hero Member
  • *****
  • Posts: 9447
Are you able to reupload the Musicbee IPC? Seems like it's been deleted. All the links are dead.
You'd need to post your request on the IPC thread so the plugin developer can update the links. The OP of this thread has nothing to do with the IPC plugin other than his making use of it.
Download the latest MusicBee v3.5 or 3.6 patch from here.
Unzip into your MusicBee directory and overwrite existing files.

The Wiki
Posting screenshots is here
Searching the forum with Google is  here


  • Guest
Are you able to reupload the Musicbee IPC? Seems like it's been deleted. All the links are dead.

They are working fine for me. Could be about your security app or ad blocker.