Getting a tracklist from MusicBrainz - python

I am trying to learn Python, and thought I'd learn by writing something I'd actually use. SO I'm trying to write a little script to rip some music CDs.
I am using the musicbrainzngs package. I would like to get the tracklist of the CD. My code currently:
#! /usr/bin/env python
import argparse
import musicbrainzngs
import discid
musicbrainzngs.set_useragent("Audacious", "0.1", "https://github.com/jonnybarnes/audacious")
parser = argparse.ArgumentParser()
parser.add_argument("--cdrom", help="provide the source of the cd", default="/dev/cdrom")
args = parser.parse_args()
device = args.cdrom
print("device: %s" % device)
disc = discid.read(device)
print("id: %s" % disc.id)
try:
result = musicbrainzngs.get_releases_by_discid(disc.id, includes=["artists"])
except musicbrainzngs.ResponseError:
print("disc not found or bad response")
else:
if result.get("disc"):
print("artist:\t%s" %
result["disc"]["release-list"][0]["artist-credit-phrase"])
print("title:\t%s" % result["disc"]["release-list"][0]["title"])
elif result.get("cdstub"):
print("artist:\t" % result["cdstub"]["artist"])
print("title:\t" % result["cdstub"]["title"])
How can I get the tracklist, looking at the full results returned there is a track-list property but regardless of what CD I try the result is always empty

Getting releases by discid is a lookup and its "'inc=' arguments supported are identical to a lookup request for a release" which are listed earlier on that page. To get a non-empty tracklist you simply need to add the "recordings" include:
result = musicbrainzngs.get_releases_by_discid(disc.id, includes=["artists", "recordings"])

This is an example script for getting the tracklist for an album using musicbrainzngs
#!/usr/bin/python3
from __future__ import print_function
from __future__ import unicode_literals
import musicbrainzngs
import sys
musicbrainzngs.set_useragent(
"python-musicbrainzngs-example",
"0.1",
"https://github.com/alastair/python-musicbrainzngs/",
)
def get_tracklist(artist, album):
result = musicbrainzngs.search_releases(artist=artist, release=album, limit=1)
id = result["release-list"][0]["id"]
#### get tracklist
new_result = musicbrainzngs.get_release_by_id(id, includes=["recordings"])
t = (new_result["release"]["medium-list"][0]["track-list"])
for x in range(len(t)):
line = (t[x])
print(f'{line["number"]}. {line["recording"]["title"]}')
if __name__ == '__main__':
### get first release
if len(sys.argv) > 1:
artist, album = [sys.argv[1], sys.argv[2]]
get_tracklist(artist, album)
else:
artist = input("Artist: ")
album = input("Album: ")
if not artist == "" and not album == "":
get_tracklist(artist, album)
else:
print("Artist or Album missing")
Usage:
python3 album_get_tracklist.py "rolling stones" "beggars banquet"
or
python3 album_get_tracklist.py
it will ask for Artist and Album

Related

Trouble converting PDF Join Script from 2.7 to 3.10

The Python script below has worked for me in converting multiple PDF documents to a single PDF when running on Python 2.7. I'm now trying to use it on 3.10 and am getting errors.
I believe I've conquered most of them, especially changing print to print( and disabling imports of CoreFoundation and Quartz.CoreGraphics.
It seems that the only remaining error is:
line 85, in main
writeContext = CGPDFContextCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
arg, len(arg), False), None, None) NameError: name
'CGPDFContextCreateWithURL' is not defined
If I declare CGPDFContextCreateWithURL as an empty global, the error shifts to CFURLCreateFromFileSystemRepresentation. Declare that and the error is kCFAllocatorDefault.
Here's how I'm trying to handle those.
global CGPDFContextCreateWithURL CGPDFContextCreateWithURL = ""
I don't understand that entire line so any help in making it right would be appreciated.
#
# join
# Joing pages from a a collection of PDF files into a single PDF file.
#
# join [--output <file>] [--shuffle] [--verbose]"
#
# Parameter:
#
# --shuffle
# Take a page from each PDF input file in turn before taking another from each file.
# If this option is not specified then all of the pages from a PDF file are appended
# to the output PDF file before the next input PDF file is processed.
#
# --verbose
# Write information about the doings of this tool to stderr.
#
import sys
import os
import getopt
import tempfile
import shutil
# from CoreFoundation import *
# from Quartz.CoreGraphics import *
global verbose
verbose = False
def createPDFDocumentWithPath(path):
if verbose:
print("Creating PDF document from file %s" % (path))
return CGPDFDocumentCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, path, len(path), False))
def writePageFromDoc(writeContext, doc, pageNum):
page = CGPDFDocumentGetPage(doc, pageNum)
if page:
mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox)
if CGRectIsEmpty(mediaBox):
mediaBox = None
CGContextBeginPage(writeContext, mediaBox)
CGContextDrawPDFPage(writeContext, page)
CGContextEndPage(writeContext)
if verbose:
print("Copied page %d from %s" % (pageNum, doc))
def shufflePages(writeContext, docs, maxPages):
for pageNum in xrange(1, maxPages + 1):
for doc in docs:
writePageFromDoc(writeContext, doc, pageNum)
def append(writeContext, docs, maxPages):
for doc in docs:
for pageNum in xrange(1, maxPages + 1) :
writePageFromDoc(writeContext, doc, pageNum)
def main(argv):
global verbose
# The PDF context we will draw into to create a new PDF
writeContext = None
# If True then generate more verbose information
source = None
shuffle = False
# Parse the command line options
try:
options, args = getopt.getopt(argv, "o:sv", ["output=", "shuffle", "verbose"])
except getopt.GetoptError:
usage()
sys.exit(2)
for option, arg in options:
if option in ("-o", "--output") :
if verbose:
print("Setting %s as the destination." % (arg))
writeContext = CGPDFContextCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, arg, len(arg), False), None, None)
elif option in ("-s", "--shuffle") :
if verbose :
print("Shuffle pages to the output file.")
shuffle = True
elif option in ("-v", "--verbose") :
print("Verbose mode enabled.")
verbose = True
else :
print("Unknown argument: %s" % (option))
if writeContext:
# create PDFDocuments for all of the files.
docs = map(createPDFDocumentWithPath, args)
# find the maximum number of pages.
maxPages = 0
for doc in docs:
if CGPDFDocumentGetNumberOfPages(doc) > maxPages:
maxPages = CGPDFDocumentGetNumberOfPages(doc)
if shuffle:
shufflePages(writeContext, docs, maxPages)
else:
append(writeContext, docs, maxPages)
CGPDFContextClose(writeContext)
del writeContext
#CGContextRelease(writeContext)
def usage():
print("Usage: join [--output <file>] [--shuffle] [--verbose]")
if __name__ == "__main__":
main(sys.argv[1:])

get audio device GUID in Python

I am trying to get GUID of audio device. The GUID can be found in registry Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\ the guid should look like {0.0.0.00000000}.{37e73048-025a-47ea-bf9f-59d5ef8f2b43}
basically like this. but I want in python Getting GUID of audio output device (speaker,headphones)
I've tried myself but only thing I can find is to use command line and parse it in Python
import subprocess
sd = subprocess.run(
["pnputil", "/enum-devices", "/connected", "/class", "AudioEndpoint"],
capture_output=True,
text=True,
)
output = sd.stdout.split("\n")[1:-1]
def getDevices(devices):
deviceList = {}
for device in range(len(devices)):
if "Instance ID:" in devices[device]:
deviceList[devices[device+1].split(":")[-1].strip()] = devices[device].split("\\")[-1].strip()
return deviceList
print(getDevices(output))
which got me
{'Headset (Soundcore Life Q30 Hands-Free)': '{0.0.0.00000000}.{4ac89ef7-f00d-4069-b96b-421bd3276295}', 'Speakers (Echo Dot-BQP)': '{0.0.0.00000000}.{8085b216-297a-4d02-bc3d-83b997b79524}', 'Headphones (Soundcore Life Q30)': '{0.0.0.00000000}.{37e73048-025a-47ea-bf9f-59d5ef8f2b43}'}
Hopping there is better way
from __future__ import print_function
import comtypes
from pycaw.pycaw import AudioUtilities, IMMDeviceEnumerator, EDataFlow, DEVICE_STATE
from pycaw.constants import CLSID_MMDeviceEnumerator
def MyGetAudioDevices(direction="in", State = DEVICE_STATE.ACTIVE.value):
devices = []
# for all use EDataFlow.eAll.value
if direction == "in":
Flow = EDataFlow.eCapture.value # 1
else:
Flow = EDataFlow.eRender.value # 0
deviceEnumerator = comtypes.CoCreateInstance(
CLSID_MMDeviceEnumerator,
IMMDeviceEnumerator,
comtypes.CLSCTX_INPROC_SERVER)
if deviceEnumerator is None:
return devices
collection = deviceEnumerator.EnumAudioEndpoints(Flow, State)
if collection is None:
return devices
count = collection.GetCount()
for i in range(count):
dev = collection.Item(i)
if dev is not None:
if not ": None" in str(AudioUtilities.CreateDevice(dev)):
devices.append(AudioUtilities.CreateDevice(dev))
return devices
output_device = MyGetAudioDevices("out")
input_device = MyGetAudioDevices("in")
print(output_device)
print(input_device)
This worked for me

Expand python function to return onee more value

I have this script to perform config-backups from juniper-devices based on input from Netbox. I would like to expand this script a little to fetch the firmware version from the juniper device and update our netbox using a custom field.
#!/usr/bin/python3
import sys,os,getopt
from getpass import getpass
from jnpr.junos import Device
import jnpr.junos.facts
from jnpr.junos.utils.config import Config
from jnpr.junos.exception import *
from lxml import etree
from pprint import pprint
import pynetbox
import datetime
nb = pynetbox.api(url='https://netbox-test/', token='<censored>')
save_path = '/config-backups/'
def printProgress(logtype,hostname,message):
print("%s:%s:%s"%(logtype,hostname,message))
def GetConfig(my_hostname, my_username, my_password):
try:
printProgress("INFO",my_hostname,"Connecting to device")
dev=Device(host=my_hostname,user=my_username,password=my_password)
dev.open(auto_probe=10)
dev.timeout=10
printProgress("INFO",my_hostname,"Retrieving config")
config = dev.rpc.get_config(options={'database':'committed','format':'set'})
junos_version = dev.facts['version']
configbackup = (etree.tostring(config, encoding='unicode', pretty_print=True))
completefilename = os.path.join(save_path, my_hostname+".set.config")
outfile=open(completefilename, "w")
outfile.write(configbackup)
dev.close()
outfile.close()
return True,junos_version
except Exception as err:
printProgress("ERROR",my_hostname,"Encountered exception while backing up config")
printProgress("ERROR",my_hostname,str(err))
return False
def main(argv):
junos_password = ''
try:
opts, args = getopt.getopt(argv,"?u:p:",["username=","password"])
except getopt.GetoptError:
print ('configbackup_junos.py -u <username> [-p <junos admin password>]')
sys.exit(2)
for opt, arg in opts:
if opt == '-?':
print ('configbackup_junos.py -u <username> [-p <junos admin password>]')
sys.exit()
elif opt in ("-u", "--username"):
junos_username = arg
elif opt in ("-p", "--password"):
junos_password = arg
print ('Will attempt to backup junos devices documented in Netbox using username:', junos_username)
if len(junos_password) > 0:
print ('Junos Password set on commandline\n')
else:
print ('password not entered, will ask for it')
junos_password=getpass(prompt="\nPassword: ")
nb_devicelist = nb.dcim.devices.all()
for nb_device in nb_devicelist:
platform = str(nb_device.platform)
pri_ip = str(nb_device.primary_ip)
asset = nb_device.asset_tag
devstatus = str(nb_device.status)
backup_enabled = nb_device.custom_fields['backup_enable']
if nb_device.virtual_chassis:
vchassismaster = str(nb_device.virtual_chassis.master)
else:
vchassismaster = 'no_chassis'
if backup_enabled == 'Yes' and platform == 'Junos' and devstatus == 'Active' and pri_ip != 'None' and asset:
if vchassismaster == (nb_device.name) or vchassismaster == 'no_chassis':
if GetConfig(asset,junos_username,junos_password):
print ("Config Successfully backed up from device.",nb_device)
nb_device.custom_fields['backup_status'] = "OK"
timenow = datetime.datetime.now()
timestamp = timenow.strftime("%Y-%m-d %X")
nb_device.custom_fields['backup_timestamp'] = timestamp
nb_device.save()
print (junos_version)
else:
printProgress ("ERROR",nb_device,"Config backup failed! ")
nb_device.custom_fields['backup_status'] = "FAILED"
nb_device.save()
print("")
if len(sys.argv) == 1:
sys.exit()
if __name__ == "__main__":
main(sys.argv[1:])
My problem is how do I get the variable "junos_version" returned from the function GetConfig. As you can see I have tried using "return True,junos_version", but how do I grab it in the output of the function?
(I have read all the articles I could find about this and tried a number of suggestions, but nothing works.
I need to be able to input the "junos_version" into this command
nb_device.custom_fields['firmware_version'] = junos_version
Which I wouldd placee just before the nb_device.save
I suspect it is my sense of logic that fails here, I just cannot see the forest for trees.
if GetConfig(asset,junos_username,junos_password):
you can change this with :
with flag, junos_version=GetConfig(asset,junos_username,junos_password):
If you return multiple values from a function, consider them a tuple.
In your case you can get the second value in the following way:
cfg = GetConfig(...) // add your args
junos_version = cfg[1] // get the 2-nd returned value from a tuple.
First you have to have a stable return.
def GetConfig(my_hostname, my_username, my_password):
try:
...
return True,junos_version
except Exception as err:
...
return False
In here you can have a tuple (of boolean and version) or a bool (True or False) as return.
I would change it as:
def GetConfig(my_hostname, my_username, my_password):
try:
...
return True,junos_version
except Exception as err:
...
return False, None
since there is no junos_version in exception.
Now you change the code where you use it as:
def main(argv):
...
if GetConfig(asset,junos_username,junos_password):
...
to
def main(argv):
...
cfg, version = GetConfig(asset,junos_username,junos_password)
if cfg:
...

Print new line not working in Python

The \n just doesn't seem to work for me when I use it with print. I am using Python 2.7.8. I don't get whats wrong, I think \n with a print should print a new line very straight forwardly.
import sys
import os
import subprocess
from collections import OrderedDict
import xmlrpclib
import hawkey
op_name = sys.argv[1]
pkg_name = sys.argv[2]
# Hawkey Configurations
sack = hawkey.Sack()
path = "/home/thejdeep/test_repo/repodata/%s"
repo = hawkey.Repo("test")
repo.repomd_fn = path % "repomd.xml"
repo.primary_fn = path % "b6f6911f7d9fb63f001388f1ecd0766cec060c1d04c703c6a74969eadc24ec97-primary.xml.gz"
repo.filelists_fn = path % "df5897ed6d3f87f2be4432543edf2f58996e5c9e6a7acee054f9dbfe513df4da-filelists.xml.gz"
sack.load_repo(repo,load_filelists=True)
# Main Function
if __name__ == "__main__":
print "Querying the repository\n"
print "-----------------------\n"
print "Found packages :\n"
print "--------------\n"
q = hawkey.Query(sack)
q = q.filter(name=pkg_name,latest_per_arch=True)[0]
if q:
for pkg in q:
print str(pkg)
else:
print "No packages with name "+pkg_name+" found. Exiting"
sys.exit()
print "--------------------"
print "Performing Dependency Check"
Output is something like this. Basically its printing in the same line :
Querying the repository ----------------------- Found packages : --------------
Using print method automatically add \n at the end of the line so its not necessary put \n at the end of each line.

Compare RPM Packages using Python

I'm trying to compare a csv file containing required Linux packages with the current installed packages. The comparison should output any packages not installed or newer than the current installed packages.
The problem is that I'm unable to loop through the list of installed packages and show all hits, for instance packages with the same name and version, but different architecture should be shown twice(for instance compat-libstdc++-33), but I only getting the first hit with the script below.
#!/usr/bin/python
import rpm
import csv
import sys
import os
'''
Script to check installed rpms against a csv file containing the package name and version similar to the list below:
atk,1.12.2
libart_lgpl,2.3
info,4.9
libsepol,1.15.2
libusb,0.1.12
libfontenc,1.4.2
'''
if len(sys.argv) !=2:
print ''
print 'Usage: ', sys.argv[0], '/path/to/csv_input_file'
print ''
sys.exit(1)
if not os.path.isfile(sys.argv[1]):
print ''
print sys.argv[1], 'not found!'
print ''
sys.exit(1)
else:
input_csv = sys.argv[1]
pkgRequired = csv.reader(open(input_csv),delimiter=',')
pkgInstalledName = []
pkgInstalledVersion = []
pkgInstalledArch = []
ts = rpm.TransactionSet()
mi = ts.dbMatch()
for h in mi:
pkgInstalledName.append((h['name']))
pkgInstalledVersion.append((h['version']))
pkgInstalledArch.append((h['arch']))
for row in pkgRequired:
pkgRequiredName = row[0]
pkgRequiredVersion = row[1]
#pkgRequiredArch = row[2]
if pkgRequiredName in pkgInstalledName:
if pkgInstalledVersion[pkgInstalledName.index(pkgRequiredName)] >= pkgRequiredVersion:
pass
else:
print '\nInstalled: ',pkgInstalledName[pkgInstalledName.index(pkgRequiredName)], pkgInstalledVersion[pkgInstalledName.index(pkgRequiredName)], pkgInstalledArch[pkgInstalledName.index(pkgRequiredName)], ' \nRequired: ', ' ', pkgRequiredName,pkgRequiredVersion
Assuming that there's no problem with the way that you're reading the list of installed packages (I'm not familiar with the rpm module), then your only problem is with using the index() function. This function return the first occurrence of an item with the specified value - and it isn't what you want.
A correct implementation (which is also much more efficient) would be:
installedPackages = {} #create a hash table, mapping package names to LISTS of installed package versions and architectures
for h in mi:
l = installedPackages.get(h['name'], list()) #return either the existing list, or a new one if this is the first time that the name appears.
l.append( (h['version'], h['arch']) )
...
if requiredPackageName in installedPackages:
for ver, arch in installedPackages[requiredPackageName]: print ...
This is what I ended up doing to get this working. The script currently is not checking for the architecture of required packages, but at least it shows the arch installed. The script works (as far as I know) but can be improved as its my first at python :)
#!/usr/bin/python
import rpm
import csv
import sys
import os
'''
Script to check installed rpms against a csv file containing the package name and version similar to the list below:
atk,1.12.2
libart_lgpl,2.3
info,4.9
libsepol,1.15.2
libusb,0.1.12
libfontenc,1.4.2
'''
#silverbullet - 20120301
if len(sys.argv) !=2:
print ''
print 'Usage: ', sys.argv[0], '/path/to/csv_input_file'
print ''
sys.exit(1)
if not os.path.isfile(sys.argv[1]):
print ''
print sys.argv[1], 'not found!'
print ''
sys.exit(1)
else:
input_csv = sys.argv[1]
pkgRequired = csv.reader(open(input_csv),delimiter=',')
pkgInstalledName = []
pkgInstalledVersion = []
pkgInstalledArch = []
ts = rpm.TransactionSet()
mi = ts.dbMatch()
for h in mi:
pkgInstalledName.append((h['name']))
pkgInstalledVersion.append((h['version']))
pkgInstalledArch.append((h['arch']))
for row in pkgRequired:
try:
pkgRequiredName = row[0]
pkgRequiredVersion = row[1]
#pkgRequiredArch = row[2] - This is not implemented yet, ie, script will ignore architecture in csv input file
except:
print "Unexpected Error. Check if input is csv format with no blank lines. "#, sys.exc_info()[1]
break
else:
for pos, pkg in enumerate(pkgInstalledName):
if pkg == pkgRequiredName:
if pkgInstalledVersion[pos] >= pkgRequiredVersion:
pass
else:
print '\nInstalled:', pkgInstalledName[pos], pkgInstalledVersion[pos], pkgInstalledArch[pos], '\nRequired: ', pkg, pkgRequiredVersion

Categories

Resources