Förbättra pythonskript så att det klarar "å"

Här diskuteras programmering och utveckling
Användarvisningsbild
Rasmus
Inlägg: 2291
Blev medlem: 07 sep 2006, 18:33
OS: Ubuntu
Utgåva: 24.04 Noble Numbat LTS
Ort: Svalsta

Förbättra pythonskript så att det klarar "å"

Inlägg av Rasmus »

Jag använder skriptet lyricsdownloader som fungerar bra, oftast.

Ibland får jag dock endast

Kod: Markera allt

Jag kan hantera en såg jag kan yxa en båt jag kan ro.
Jag kan klara mig själv jag kan koka min mat jag kan sy

Då kom det en kvinna tvärs över mon
Nån stans i mitt inre hon slog an en ton.
Jag föll som en fura då på hennes kropp
Läppar som eld och en sammetslen kropp
Som jag plocka och sparade djupt i mitt sin

Jag är man, du är kvinna, nu tar jag din oskuld och går.
Du ska föda mitt barn som en gång ska ta över vår gård. 

Det var hon som kom en gång tvärs över mon,
det var hon som en gång i mig slog an en ton. 
Hon gav min sin vänskap liksom hennes kropp
Hennes läppar var heta hon skänkte mig hopp
Som ett styrkne tungsinnet över, över mig kom

Vill du stanna hos mig vill du dela mitt bröd och mitt hus?
Vill du dela min tid fram tills dess vi skall multna i jord?

Det var hon som kom en gång tvärs över mon,
det var hon som en gång i mig slog an en ton. 
Hon gav mig sin vänskap liksom hennes kropp
Hennes läppar var heta hon skänkte mig hopp
Som ett styrkne tungsinnet över mig kom
vilket jag inte vet vad det beror på. Jag har för mig att det bara har kommit på svenska låtar så jag antar att det är å som strular (ä och ö finns i tyskan och rammstein lyrics fungerar perfa)
Jag har tagit bort en massa if-satser så att den endast fungerar med mpd men det borde inte påverka ovan nämnda problem, jag kan posta det om nån vill.
zoombywoof
Inlägg: 202
Blev medlem: 27 nov 2006, 16:14
OS: Kubuntu
Ort: Stockholm

Re: Förbättra pythonskript så att det klarar "å"

Inlägg av zoombywoof »

Nu har du ju inte visat scriptet, men man kan ju tänka sig att det är ett encodningsproblem, om det bara är å som spökar, isåfall måste du ändra encoding i scriptet, och hoppas att det inte fuckar upp något annat...encoding problem kan vara mindre kul ibland....

/zw
Användarvisningsbild
Rasmus
Inlägg: 2291
Blev medlem: 07 sep 2006, 18:33
OS: Ubuntu
Utgåva: 24.04 Noble Numbat LTS
Ort: Svalsta

Re: Förbättra pythonskript så att det klarar "å"

Inlägg av Rasmus »

Jag skickade ju en länk, men kan visa "min" version om du vill.

Kod: Markera allt

#!/usr/bin/env python
# -*- coding: iso-latin-1 -*-
#       Lyricsdownloader for Conky
#         eightmillion@gmail.com

import urllib, os, sys, string, re, BeautifulSoup
from optparse import OptionParser, SUPPRESS_HELP

usage = "usage: %prog [-f|-q|-h|-v|-o|-c|-t|-d|-a|--template|--version] FILENAME DIRECTORY LINE NUMBER"

version = "0.9.6"
dbusErr = 10
infoErr = 15
mpcErr  = 20
noPlayerErr = 25
webErr = 30
missingErr = 35
validChars = "-_.() %s%s" % (string.ascii_letters, string.digits)
work_folder = os.path.expanduser ('~/.lyrics')
verbose, longstatus, quiet, outdir = 0,0,0,0
cutline, tailline, align = 0,0,""
wordDict = {
    '"' : '"',
    '\r\n'   : '\n',
    '>'   : '>',
    '<'   : '<'
}

def remove_html_tags(data):
    p = re.compile(r'<[^<]*?>')
    return p.sub('', data)

class player():
    def __init__(self):
        self.players = [ 'amarokapp','amarok','rhythmbox','audacious','banshee-1',
                'exaile','gmusicbrowser','juk','quodlibet','listen','songbird',
                'muine','beep-media-play','mpd' ]
        self.progs = os.popen('ps -eo comm').read().split('\n')
        self.dbusPlayers = [ 'amarok', 'audacious', 'juk', 'gmusicbrowser', 'songbird',
                    'muine', 'beep-media-play', 'exaile','listen','quodlibet','banshee-1'
                    ,'rhythmbox' ]
        if os.popen('pgrep quodli').read(): self.progs.append('quodlibet')
        if os.popen('pgrep listen').read(): self.progs.append('listen')
        for x in self.players:
            if x in self.progs:
                self.app = x
                break
        else: self.app = False
        if not self.app:
            if verbose: print "Couldn't find a supported media application."
            sys.exit(noPlayerErr)
        else: 
            if verbose: print "Found player: %s" % self.app
        if self.app in self.dbusPlayers:
            try:
                import dbus
                self.bus = dbus.SessionBus()
            except ImportError:
                print "Please install python-dbus"
                sys.exit(1)
    def prntime(self,ms):
        s = ms / 1000
        m,s = divmod(s,60)
        h,m = divmod(m,60)
        time = [ h , str(m) , str(s) ]
        if len(time[1]) == 1:      time[1] = '0' + time[1]
        if len(time[2]) == 1:      time[2] = '0' + time[2]
        if time[0] == 0:           del time[0]
        else: time[0] = str(time[0])
        return ':'.join(time)
    def prntimesec(self,sec):
        t = divmod(sec,60)
        x = []
        for i in t:
            x.append(str(i))
        if len(x[1]) == 1:
            x[1] = '0' + x[1]
        return ':'.join(x)
    def birdlength(self,length):
        if length == [u'']: return ''
        length = length.split(':')
        for i in range(3):
            if len(length[i]) == 1:
                length[i] = '0'+length[i]
        if length[0] == '00': length.remove(length[0])
        return ':'.join(length)    
    def zeroPad(self,x):
        if len(str(x)) == 1: return '0' + str(x)
        else: return str(x)
    def convSec(self,x):
        if len(x) == 3: return int(x[0])*3600 + int(x[1])*60 + int(x[2])
        else: return int(x[0])*60 + int(x[1])
    def getArtist(self):
        self.mpd = os.popen('mpc --format %artist%').read().split('\n')[0]
        if self.mpd.startswith('volume'):
            return ''
        else: return self.mpd
    def getTitle(self):
        self.mpd = os.popen('mpc --format %title% | sed s/[0-9][0-9]." "// | sed s/".mp3"// | sed s/[0-9][0-9]" - "//').read().split('\n')[0]
        if self.mpd.startswith('volume'):
            return ''
        else: return self.mpd
    def getAlbum(self):
        self.mpd = os.popen('mpc --format %album%').read().split('\n')[0]
        if self.mpd.startswith('volume'):
            return ''
        else: return self.mpd
    def getTrackNum(self):
        self.mpd = os.popen('mpc --format %track%').read().split('\n')[0]
        if self.mpd.startswith('volume'):
            return ''
        else: return self.mpd
    def getLength(self):
        self.mpd = os.popen('mpc --format %time%').read().split('\n')[0]
        if self.mpd.startswith('volume'):
            return ''
        else: return self.mpd
    def getPosition(self):
        try: self.mpd = os.popen('mpc').read().split('\n')[1].split('/')[1].split()[1]
        except IndexError: return ''
        return self.mpd
    def getStatus(self):
        try: self.status = os.popen('mpc').read().split('[')[1].split(']')[0]
        except: return 'Stopped'             
        if self.status == "playing": return "Playing"
        elif self.status == "paused": return "Paused"
        else: return ""   
    def getPercent(self):
        try: return int(self.convSec(self.getPosition().split(':'))/float(self.convSec(self.getLength().split(':')))*100)
        except: return ''
    def getVolume(self):
        for i in os.popen('mpc').read().split('\n'):
            if i.startswith('volume'):
                return int(i[7:][:3])
        return ''
        

# multi-word replace
def mReplace(text, wordDict):
    for key in wordDict:
        text = text.replace(key, str(wordDict[key]))
    return text

#checks if the last song in missingsongs.txt is the current song so we don't
#keep hitting lyricwiki over and over again
def checkmissing(artistname,songname):
    if os.path.isfile(work_folder + "/missingsongs.txt"):
        try:
            lastmissing = open(work_folder + "/missingsongs.txt","r").readlines()[-1]
        except IndexError:
            lastmissing = "foobar"
        if lastmissing == artistname + " : " + songname +"\n":
            if verbose: print "Failed to find lyrics for song: %s" % lastmissing
            return True

def getlyrics(artistname,songname):    

    #make names lowercase for folders and remove trailing newlines
    artistname = artistname.strip()
    songname = songname.strip()

    #set lyrics folder, the folder used by default rhythmbox lyrics plugin is ~/.lyrics
    if not outdir:
        lyrics_folder = os.path.join(work_folder,''.join(c for c in artistname[:128].lower() if c in validChars))
    else:
        lyrics_folder = outdir
    #check if lyrics folder exists, if not then create it
    if not os.path.isdir(work_folder):
        if verbose: print "Lyrics folder: %s doesn't exist. Creating it..." % work_folder
        os.mkdir(work_folder)

    #check if the artist folder exists, if not then create it
    if not os.path.isdir(lyrics_folder):
        if verbose: print "Artist folder: %s doesn't exist. Creating it..." % lyrics_folder
        os.mkdir(lyrics_folder)

    #file name is just the song title
    lyricfile = os.path.join(lyrics_folder,''.join(c for c in songname[:128].lower() if c in validChars) + '.lyric')

    #make the names ready for the intertubes urls
    artist = artistname.replace(' ','_')
    title = songname.replace(' ','_')
    artist = urllib.quote(artistname)
    title = urllib.quote(songname)

    #check if the lyric file already exists
    if os.path.isfile(lyricfile) == False:
        #get lyrics from lyric wiki who nicely return just the lyrics in plain text
        try:
            lyrics = urllib.urlopen('http://lyricwiki.org/%s:%s' % (artist, title))
        except:
            if verbose: print "Could not connect to lyricwiki.org. Exiting..."
            sys.exit(webErr)
        text = lyrics.read()
	soup = BeautifulSoup.BeautifulSoup(text)
        lyrics = soup.findAll(attrs= {"class" : "lyricbox"})
        #check that if lyrics were found lyric wiki returns the string "Not Found" if not
        if lyrics:
            text = remove_html_tags(lyrics[0].renderContents().replace('<br />','\n'))
            #write the lyrics to their appropriate file
            f = file (lyricfile, 'w')
            f.write (text)
            f = file (lyricfile, 'r')
            lyrics = mReplace(f.read(),wordDict).split('\n')
            if verbose: print "Found lyrics. Writing to %s" % lyricfile
            if not quiet: printlyrics(lyrics)
            f.close ()
            return True
        else:
    #append the info to the unfound list
            f = file (work_folder + "/missingsongs.txt", 'a')
            f.write (artistname + " : " + songname +"\n")
            f.close ()
            if verbose: print "Failed to find lyrics for song: %s  :  %s" % (artistname, songname)
            return False
    else:
        if verbose: print "Lyrics file already exist for: %s  :  %s" % (artistname, songname)
        f = file (lyricfile, 'r')
        lyrics = mReplace(f.read(),wordDict).split('\n')
        if not quiet: printlyrics(lyrics) 
        f.close ()
        return True

def printlyrics(lyrics):
    if cutline:
        x = 0
        while x < cutline:
            try:
                if align: print align + lyrics[x]
                else: print lyrics[x]
                x += 1
            except IndexError: break
    elif tailline:
        x = 0
        for i in lyrics:
            if x < tailline:
                x +=1
            else:
                try:
                    if align: print align + lyrics[x]
                    else: print lyrics[x]
                    x += 1
                except IndexError:
                    break
    elif align: print '\n'.join(map(lambda x:align + x,lyrics))
    else: print '\n'.join(lyrics)

        
def getlyricsfile(filename):
    try: from ID3 import ID3
    except ImportError: 
        print 'Failed to import module id3. Please install python-id3'
        sys.exit(1)
    filename = os.path.realpath(filename)
    if not os.path.isfile(filename):
        filename = os.path.join(os.getcwd, filename)
    tag = ID3(filename)
    try:
        artistname = tag['ARTIST']
        songname   = tag['TITLE']
        if verbose: print "Artist: %s        Songname: %s" % ( artistname, songname)
    except KeyError:
        if verbose: print "Couldn't find the artist name or song title for: %s.  Check the ID3 tags." % filename
        return False
    if getlyrics(artistname,songname): return True
    else: return False
    
def formatOutput(format):
    a = player()
    if '%aa' in format: format = format.replace('%aa', a.getArtist())
    if '%bb' in format: format = format.replace('%bb', a.getAlbum())
    if '%tt' in format: format = format.replace('%tt', a.getTitle()) 
    if '%nn' in format: format = format.replace('%nn', a.getTrackNum()) 
    if '%td' in format: format = format.replace('%td', a.getLength())
    if '%te' in format: format = format.replace('%te', a.getPosition())
    if '%ss' in format: format = format.replace('%ss', a.getStatus())
    if '%pp' in format: format = format.replace('%pp', str(a.getPercent()))
    if '%vv' in format: format = format.replace('%vv', str(a.getVolume()))
    return format

def tryFormatting(): print formatOutput('Artist: %aa \nAlbum: %bb \nTitle: %tt \nNumber: %nn \nDuration: %td \nElapsed: %te \nStatus: %ss \nPercent: %pp')  #this is for debugging

def formatOutputTemp(template):
    template = os.path.realpath(template)
    if not os.path.isfile(template):
        print "Template file not found."
        sys.exit(1)
    f = open(template).read().decode('utf-8','ignore')
    a = player()
    if 'ARTIST' in f: f = f.replace('ARTIST', a.getArtist())
    if 'ALBUM' in f: f = f.replace('ALBUM', a.getAlbum())
    if 'TITLE' in f: f = f.replace('TITLE', a.getTitle()) 
    if 'TRACKNUM' in f: f = f.replace('TRACKNUM', a.getTrackNum()) 
    if 'DURATION' in f: f = f.replace('DURATION', a.getLength())
    if 'ELAPSED' in f: f = f.replace('ELAPSED', a.getPosition())
    if 'STATUS' in f: f = f.replace('STATUS', a.getStatus())
    if 'PERCENT' in f: f = f.replace('PERCENT', str(a.getPercent()))
    return f

def main():
    a = player()
    artistname, songname = a.getArtist(), a.getTitle()
    if not songname or not artistname: sys.exit(infoErr) 
    elif verbose: print "Artist: %s        Songname: %s" % ( artistname, songname)
    if checkmissing(artistname,songname): 
        sys.exit(missingErr)
    getlyrics(artistname,songname)
    
if __name__ == '__main__':
    parser = OptionParser(usage=usage, version="%prog 0.9.6")
    parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="request verbose output.")
    parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, help="Download the lyrics only")
    parser.add_option("-f", "--file", dest="filename", help="Download lyrics for MP3 file")
    parser.add_option("-o", "--outputdir", dest="outputdirectory",metavar="DIRECTORY", help="Set the output directory for the download")
    parser.add_option("--test", dest="test", action="store_true", default=False, help=SUPPRESS_HELP )
    parser.add_option("-c", "--cut", dest="cutline", type="int", metavar="LINE NUMBER",  help="Print the ouptut from the beginning to the specified line.")
    parser.add_option("-t", "--tail", dest="tailline", type="int", metavar="LINE NUMBER", help="Print the ouptut from the specified line to the end.")
    parser.add_option("-d", "--dir", action="store_true", default=False, dest="directory", help="Download lyrics for all the songs in the current directory. This option also turns on the quiet option. To turn it off add -q.")
    parser.add_option("-l","--format",  dest="format", help="Format the output for the song that's currently playing. The metadata delimiters are: %aa  -  Artist | %bb  -  Album | %tt  -  Title | %nn  -  Track Number | %td  -  Track Duration | %te  -  Track Elapsed | %ss  -  Status")
    parser.add_option("--template", dest="template", help="Format the song metadata with a template file. The delimiters are ARTIST ALBUM TITLE TRACKNUM DURATION ELAPSED STATUS See the example template file :/usr/share/doc/lyricsdownloader/template")
    parser.add_option("-a", "--align", dest="align",metavar="VALUE" , help='''Add an alignment setting for conky (${alignr},${alignc},${goto}). Make sure to single quote the arguments so that bash doesn't interpret it as a variable. This option is still experimental.''')
    parser.add_option("--artist", dest="artistname", help="Find lyrics for specific song.")
    parser.add_option("--songname", dest="songname", help="Find lyrics for specific song.")
    (options, args) = parser.parse_args()
    if options.quiet: quiet = True
    else: quiet = False
    if options.verbose: 
        verbose = True
        if options.quiet: quiet = False
        else: quiet = True
    else: verbose = False
    if options.test:
        tryFormatting()
        sys.exit()
    if options.template:
        if options.filename:
            print "Options --template and -f conflict."
            sys.exit(1)
        elif options.quiet: quiet = False
        else: quiet = True
        print formatOutputTemp(options.template)
    if options.artistname:
	if not options.songname:
	    print 'When using "--artist" a songname must be supplied with the option: --songname'
	    sys.exit(1)
        if not getlyrics(options.artistname,options.songname):
            print "Lyrics not found."
	sys.exit(0)
    if options.songname:
	print 'When using "--songname" an artistname must be supplied with the option: --artist'
        sys.exit(1)
    if options.format: 
        if options.filename:
            print "Options --format and -f conflict."
            sys.exit(1)
        elif options.quiet: quiet = False
        else: quiet = True
        print formatOutput(options.format)
    if options.cutline: cutline = options.cutline
    else: cutline = False
    if options.tailline: tailline = options.tailline
    else: tailline = False
    if options.align: 
       align =  options.align
       print align
    else: align = ''
    if options.outputdirectory != None:
        if os.path.isdir(os.path.realpath(options.outputdirectory)):
            outdir = os.path.realpath(options.outputdirectory)
        else: 
            print "%s is not a valid directory" % options.outputdirectory
            sys.exit(1)
    else: outdir = False
    if options.filename:
        result = getlyricsfile(options.filename)
        if result and quiet:
            print "Added lyrics for file: %s" % options.filename
        elif quiet or not result:
            print "Failed to find lyrics for file: %s" % options.filename
        sys.exit(0)
    if options.directory:
        if options.quiet: quiet = False
        else: quiet = True
        files = [ f for f in os.listdir('.') if os.path.splitext(f)[1].lower() == '.mp3' ]
        if len(files) == 0:
            print "No valid music files found."
            sys.exit(1)
        for f in files:
            if getlyricsfile(f):
                print "Added lyrics for file: %s" % f
            else: print "Failed to find lyrics for file: %s" % f
        sys.exit(0)
    main()
Är inte iso-latin-1 = iso 8859-1?

Nu anropar jag detta skript genom ett annat som är fyllt av en massa sed kommandon för att byta ut tecknen mot förståeliga tecken.
Lars
Inlägg: 6191
Blev medlem: 14 jan 2007, 19:31
OS: Ubuntu
Utgåva: 22.10 Kinetic Kudu
Ort: Stockholm

Re: Förbättra pythonskript så att det klarar "å"

Inlägg av Lars »

Teckenkodning kan vara knepigt. Det gäller att inte bara ändra där symptomen uppkommer utan man måste ändra vid källan till problemet, annars blir man lätt tokig.

Jo, visst är iso-latin-1 samma sak som iso-8859-1. Men det är väl bara vad själva skriptet är skrivet i. Indata kan vara någonting helt annat.

Jag orkar inte läsa igenom hela koden, men BeautifulSoup ger tydligen Unicode som utdata, oavsett indata. Så alla teckenkonvertering borde skötas automatiskt.

Börja med att kolla HTML-källan. Vad är den kodad i vad säger den att den är kodad i? Kan du ge oss ett exempel på en URL?
Användarvisningsbild
Rasmus
Inlägg: 2291
Blev medlem: 07 sep 2006, 18:33
OS: Ubuntu
Utgåva: 24.04 Noble Numbat LTS
Ort: Svalsta

Re: Förbättra pythonskript så att det klarar "å"

Inlägg av Rasmus »

Här är låten i första inlägget
http://lyrics.wikia.com/Dia_Psalma:Hon_ ... %96ver_Mon
men nästan alla med "å" verkar ha samma problem, kan det vara så att ie/windows byter kodning om man använder å,ä eller ö och den enda låten som fungerade var inskriven m.h.a. annan webläsare/annat os.
Här är ett exempel på en "fungerande låt"
http://lyrics.wikia.com/Flyleaf:I%27m_So_Sick

Vilken låt det var som "fungerade" även fast den innehöll "å" minns jag inte.
Skriv svar

Återgå till "Programmering och webbdesign"