
Here's another, called
DownloadLyrics, without the dependency of Tag.exe
To make it work, save the text below as DownloadLyrics.ahk, then make a shortcut to it, rightclick the shortcut and select properties, and add the text after the command line, so it looks something like this:
"C:\DownloadLyrics\DownloadLyrics.ahk" "D:\*.mp3" Recurse Overwrite
Skrommel
;DownloadLyrics.ahk
; Downloads the lyrics of MP3 files
; For more tags and info on id3, check out the two first links on http://www.id3.org/develop.html
;Skrommel @2006
#SingleInstance,Force
#NoEnv
SetBatchLines,-1
If 0=0
{
MsgBox,0,DownloadLyrics - 1 Hour Software,DownloadLyrics - Downloads the lyrics of mp3 files from azlyrics.com`n`nCommand line: `tDownloadLyrics <path to mp3(s)> [Recurse Replace]`nExample: `t`tDownloadLyrics "C:\MP3\*.mp3" Recurse Replace`n`nRecurse=Recurse into subfolders`nReplace=Replace exsting lyrics`n`nFor more tools and information, visit www.1hoursoftware.com
ExitApp
}
path=%1%
recurse=0
If (2="recurse" Or 3="recurse")
recurse=1
replace=0
If (2="replace" Or 3="replace")
replace=1
Loop,%path%,0,%recurse%
{
TrayTip,DownloadLyrics,%A_LoopFileLongPath%
SplitPath,A_LoopFileLongPath,name,dir,ext,name_no_ext,drive
file=%A_LoopFileLongPath%
output=%dir%\%name_no_ext%.txt
title=
performer=
lyrics=
Gosub,READTAGS
Gosub,RETRIEVE
}
ExitApp
RETRIEVE:
If title=
Return
If performer=
Return
StringReplace,performer,performer,%A_Space%,+
Loop
{
StringGetPos,start,performer,++
If start<0
Break
StringReplace,performer,performer,++,+,All
}
StringReplace,title,title,%A_Space%,+,All
Loop
{
StringGetPos,start,title,++
If start<0
Break
StringReplace,title,title,++,+,All
}
lyricsexist=1
If lyrics<>
lyricsexist=0
file=http://search.azlyrics.com/cgi-bin/azseek.cgi?q=%performer%+%title%
UrlDownloadToFile,%file%,file.htm
FileRead,file,file.htm
StringGetPos,start,file,<b>1.</b>
If start=0
Return
StringGetPos,start,file,<a href=",,% start
start+=10
StringGetPos,stop,file,",,% start
StringMid,file,file,% start,% stop-start+1
TrayTip,DownloadLyrics,%file%
UrlDownloadToFile,%file%,file.htm
FileRead,file,file.htm
StringGetPos,start,file,"</b>
start+=9
StringGetPos,stop,file,`n<BR><BR>,,% start
StringMid,file,file,% start,% stop-start-2
tag=0
lyrics=
Loop,Parse,file
{
If A_LoopField=<
{
tag=1
Continue
}
If A_LoopField=>
{
tag=0
Continue
}
If tag=0
lyrics:=lyrics A_LoopField
}
If (lyrics<>"" And (replace=1 or lyricsexist=0))
{
FileDelete,%output%
FileAppend,%lyrics%,%output%
}
Return
READTAGS:
;;;;;;; HEADER ;;;;;;;
res:=BinRead(file,data,3,0)
fileidentifier:=DeHexify(data)
res:=BinRead(file,data,1,3)
majorversion:=data+0
res:=BinRead(file,data,1,4)
revisionnumber:=data+0
version=%majorversion%.%revisionnumber%
res:=BinRead(file,data,1,5)
flags=0x%data%
Transform,unsync,BitAnd,%flags%,256
Transform,extheader,BitAnd,%flags%,128
Transform,experimentalid,BitAnd,%flags%,64
Transform,footer,BitAnd,%flags%,32
res:=BinRead(file,data,2,8)
size=0x%data%
size+=0
extheaderpos:=10
;;;;;;; EXTENDEDHEADER ;;;;;;;
If extendedheader=1
{
res:=BinRead(file,data,4,extheaderpos)
frameid:=DeHexify(data)
res:=BinRead(file,data,4,extheaderpos+4)
extheadersize=0x%data%
extheadersize+=10
frameheaderpos:=extheaderpos+extheadersize
}
Else
frameheaderpos:=extheaderpos
;;;;;;; FRAMES ;;;;;;;
Loop
{
;;;;;;; FRAMEHEADER ;;;;;;;
res:=BinRead(file,data,4,frameheaderpos)
frameid:=DeHexify(data)
res:=BinRead(file,data,4,frameheaderpos+4)
framesize=0x%data%
framesize+=0
res:=BinRead(file,data,1,frameheaderpos+8)
flaga:=data
res:=BinRead(file,data,1,frameheaderpos+9)
flagb:=data
If frameid=
Break
; TIT2: title
; USLT: lyrics
; TPE1: performer
If (frameid="TPE1" Or frameid="TIT2" Or frameid="USLT")
{
framepos:=frameheaderpos+10 ;frameheadersize=10
;;;;;;; FRAME ;;;;;;;
If framesize>0
{
res:=BinRead(file,data,framesize,framepos)
frametext:=DeHexify(data)
If (frameid="TPE1")
performer:=frametext
Else
If (frameid="TIT2")
title:=frametext
Else
If (frameid="USLT")
StringTrimLeft,lyrics,frametext,3
}
}
frameheaderpos:=frameheaderpos+framesize+10 ;frameheadersize=10
If (frameheaderpos>=size)
Break
}
;MsgBox,0,id3v2,Performer:%performer% `nTitle:%title% `nLyrics:`n%lyrics%
Return
DeHexify(x)
{
StringLen,len,x
len:=len/2
string=
Loop,%len%
{
StringLeft,hex,x,2
hex=0x%hex%
Transform,y,Chr,%hex%
string:=string y
StringTrimLeft,x,x,2
}
Return,string
}
;By lazlo at http://www.autohotkey.com/forum/viewtopic.php?t=4546
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinWrite ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
| - Open binary file
| - (Over)Write n bytes (n = 0: all)
| - From offset (offset < 0: counted from end)
| - Close file
| data -> file[offset + 0..n-1], rest of file unchanged
| Return #bytes actually written
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BinWrite(file, data, n=0, offset=0)
{
; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists
h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
IfEqual h,-1, SetEnv, ErrorLevel, -1
IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file
m = 0 ; seek to offset
IfLess offset,0, SetEnv,m,2
r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
IfEqual r,0, SetEnv, ErrorLevel, -3
IfNotEqual ErrorLevel,0, {
t = %ErrorLevel% ; save ErrorLevel to be returned
DllCall("CloseHandle", "Uint", h)
ErrorLevel = %t% ; return seek error
Return 0
}
TotalWritten = 0
m := Ceil(StrLen(data)/2)
If (n <= 0 or n > m)
n := m
Loop %n%
{
StringLeft c, data, 2 ; extract next byte
StringTrimLeft data, data, 2 ; remove used byte
c = 0x%c% ; make it number
result := DllCall("WriteFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Written,"UInt",0)
TotalWritten += Written ; count written
if (!result or Written < 1 or ErrorLevel)
break
}
IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%
h := DllCall("CloseHandle", "Uint", h)
IfEqual h,-1, SetEnv, ErrorLevel, -2
IfNotEqual t,,SetEnv, ErrorLevel, %t%
Return TotalWritten
}
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinRead ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
| - Open binary file
| - Read n bytes (n = 0: all)
| - From offset (offset < 0: counted from end)
| - Close file
| data (replaced) <- file[offset + 0..n-1]
| Return #bytes actually read
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BinRead(file, ByRef data, n=0, offset=0)
{
h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
IfEqual h,-1, SetEnv, ErrorLevel, -1
IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file
m = 0 ; seek to offset
IfLess offset,0, SetEnv,m,2
r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
IfEqual r,0, SetEnv, ErrorLevel, -3
IfNotEqual ErrorLevel,0, {
t = %ErrorLevel% ; save ErrorLevel to be returned
DllCall("CloseHandle", "Uint", h)
ErrorLevel = %t% ; return seek error
Return 0
}
TotalRead = 0
data =
IfEqual n,0, SetEnv n,0xffffffff ; almost infinite
format = %A_FormatInteger% ; save original integer format
SetFormat Integer, Hex ; for converting bytes to hex
Loop %n%
{
result := DllCall("ReadFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Read,"UInt",0)
if (!result or Read < 1 or ErrorLevel)
break
TotalRead += Read ; count read
c += 0 ; convert to hex
StringTrimLeft c, c, 2 ; remove 0x
c = 0%c% ; pad left with 0
StringRight c, c, 2 ; always 2 digits
data = %data%%c% ; append 2 hex digits
}
IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%
h := DllCall("CloseHandle", "Uint", h)
IfEqual h,-1, SetEnv, ErrorLevel, -2
IfNotEqual t,,SetEnv, ErrorLevel, %t%
SetFormat Integer, %format% ; restore original format
Totalread += 0 ; convert to original format
Return TotalRead
}