越到重要關頭的時候,就越?jīng)]事找事,總是“想做的事”優(yōu)先級高于正經(jīng)事,唉,沒救了~
早些時候,我就在用LongkeyMusic,很方便,可以下載蝦米的精選集,不過很久都不更新,下的精選集也常常是無效的,所以改用了 蝦米音樂河蟹姬,地址解析是不錯,UI做得也很二次元,就不知道寫這程序的人是怎么想的?一個好好的程序,下載的歌曲都是以ID號命名,批量下了一大推,沒聽過的都不知道叫啥!
跟上次的思路一樣,想從外部改進這個程序,控制程序句柄,不過很遺憾,用Spy++查看這個程序,風格也是子窗口嵌入主窗口里的,找不出我要的句柄。沒辦法了。
在網(wǎng)上搜搜還有沒有更好的蝦米音樂獲取辦法,找到一篇日志 蝦米音樂文件絕對地址解析 ,按上面試了試,雖有點不一樣,不過確實是可以獲取出蝦米音樂真實下載地址的,所以就想自己也寫個程序玩玩。
//*********************************************************************************************//
方法也是參考自:蝦米音樂文件絕對地址解析 http://kanoha.org/2011/08/30/xiami-absolute-address/
簡單原理如下:
以 http://www.xiami.com/song/3632733?spm=a1z1s.6659513.0.0.zzUExi 為例
1、把song替換成widget/xml-single/sid ,在網(wǎng)頁上打開替換后的地址,得到一個XML文件;有興趣的,可以試試對 專輯 album類的捕捉,XML我不會。。。反正是按圖索驥了
2、可以得到下圖,有很多信息,最后一個框就是下載地址的密文了。
密文如下:
9hFlc%2521%e213f45lt%eo2FE713y672e3Elt2.mF3532F%938e2-pFx%72%3_a314373%%mi2762_luD184c2535aF4%F1.t4%3%-%EA.m44537mhe5b515-%fi43E68p_3E5E3En2i.3%%363k73eb9%u
3、按上面日志說的,第一個字符是9,可以看成是凱撒方陣的列數(shù),按凱撒方陣來排列,由于字符串中包含有音樂文件的下載地址,很特殊,所以簡單一點,一般找出http這幾個字母也就得出了凱撒方陣
hFlc%2521%e213f45l
t%eo2FE713y672e3El
t2.mF3532F%938e2-
pFx%72%3_a314373%
%mi2762_luD184c25
35aF4%F1.t4%3%-%E
A.m44537mhe5b515-
%fi43E68p_3E5E3En
2i.3%%363k73eb9%u
4、豎著讀,得到
http%3A%2F%2Fm5.file.xiami.com%2F443%2F77443%2F326%5E%5E5%2F3632733_1786112_l.mp3%3Fauth_key%3D4e3726911%5E3173483b5e32834%5Ebfee7c-13943232%5E%5E-%5E-null
5、有木有感覺了?經(jīng)過在線網(wǎng)頁的URL解碼,得到
http://m5.file.xiami.com/443/77443/326^^5/3632733_1786112_l.mp3?auth_key=4e3726911^3173483b5e32834^bfee7c-13943232^^-^-null
6、替換^為0,即為真實下載地址了
?auth_key=4e372691103173483b5e328340bfee7c-1394323200-0-null
其中 3632733_1786112_l.mp3 即為默認文件名
//*********************************************************************************************//
//*********************************************************************************************//
有了上面的方法,那就差一個具體的實施了,最簡單的辦法,可以用網(wǎng)頁腳本語言,Java,HTML,css,Python.......
我不會,就用delphi了
界面布局: 顯示效果:
感覺UI做得越來越好了。
//*********************************************************************************************//
//*********************************************************************************************//
下面是部分關鍵代碼:
//************************ 點擊解析并保存按鈕 *****************************************//
procedure TForm1.resolveBtnClick(Sender: TObject); //解析地址
var
temp:String;
strRow:word;
begin
temp:=downloadAddr.Text;
if temp = '' then //判斷是否是空地址
begin
ShowMessage('搜索地址無效!');
Exit;
end;
temp:=StringReplace(temp,'song','widget/xml-single/sid',[rfReplaceAll]); //XML 解析
temp:=GetWebPage(temp); //獲取URL源代碼
Delete(temp,1,Pos('<song_name>',temp)+19);
songName:=Copy(temp,1,Pos(']',temp)-1); //獲取歌曲名字
Delete(temp,1,Pos('<album_name>',temp)+20);
albumName:=Copy(temp,1,Pos(']',temp)-1); //獲取歌曲所屬專輯名字
Delete(temp,1,Pos('<artist_name>',temp)+21);
artistName:=Copy(temp,1,Pos(']',temp)-1); //獲取歌手名字
Delete(temp,1,Pos('<location>',temp)+18);
strRow:=word(StrToInt(LeftStr(temp,1))); //獲取凱撒矩陣的行
downloadAddrStr:=Copy(temp,2,Pos(']',temp)-2); //獲取歌曲偽地址
//downloadAddr.Text:=downloadAddrStr; //調(diào)試用
downloadAddrStr:=CaesarShifts(downloadAddrStr,strRow); //解析歌曲地址
temp:=Copy(downloadAddrStr,1,Pos('mp3',downloadAddrStr)+2);
downloadName:=RightStr(temp,Pos('/',ReverseString(temp))-1); //獲取默認文件名稱
//下面保存ini,txt文件
SaveIniFile('Download Info.ini',downloadName,artistName,SongName,AlbumName);
//記錄:ini文件名,默認下載文件名,藝術家,作曲名,專輯名
SaveTxtFile('Download Path.txt',downloadAddrStr);
//記錄:下載地址
end;
//************************ 點擊粘到剪貼板按鈕 *****************************************//
procedure TForm1.clipBtnClick(Sender: TObject); //復制到剪貼板
var
path,temp,downloadAddrTemp:string;
txtFile:Textfile;
begin
downloadAddrTemp:='';//初始化剪貼板緩存
clipboard.AsText:='';//清空剪貼板內(nèi)容
path:=ExtractFilePath(Application.Exename)+'Download Path.txt';
AssignFile(txtFile,path);
Reset(txtFile); //打開讀取txt
SetLength(temp,5); //初始化數(shù)組長度
while not eof(txtFile) do
begin
Readln(txtFile,temp);
downloadAddrTemp:=downloadAddrTemp+temp+#13#10;
end;
clipboard.AsText:=downloadAddrTemp; //下載地址復制到剪貼板
CloseFile(txtFile);
end;
//************************ 點擊改名并分類按鈕 *****************************************//
procedure TForm1.changNameBtnClick(Sender: TObject); //批量改名
var
path,downloadNametemp,artistNametemp,songNametemp,albumNametemp:string;
oldName,newName:string;
iniFile:TIniFile;
I,countI:Integer;
SearchRec:TSearchRec;
dirPath:string;
begin
if (downloaderSaveDir.Text = '') or (musicLibraryDir.Text = '') then
begin
ShowMessage('請確認下載保存目錄和音樂庫路徑是否正確!');
Exit;
end;
path:=ExtractFilePath(Application.Exename)+'Download Info.ini';
iniFile:=Tinifile.Create(path);
countI:=iniFile.ReadInteger('已有','首歌',countI); //獲取歌曲數(shù)目
for I := 0 to (countI-1) do
begin
downloadNametemp:=iniFile.ReadString('默認文件名',IntToStr(I),downloadNametemp);
if Pos(':',dlAlbumName) > 0 then
dlAlbumName:=StringReplace(dlAlbumName,':','-',[rfReplaceAll]);//防止命名有:
artistNametemp:=iniFile.ReadString('藝術家',IntToStr(I),artistNametemp);
songNametemp:=iniFile.ReadString('作曲名',IntToStr(I),songNametemp);
albumNametemp:=iniFile.ReadString('專輯名',IntToStr(I),albumNametemp);
if FindFirst(downloaderSaveDir.Text+'\'+downloadNametemp,faAnyFile,SearchRec) =0 then
begin //查找相同名字文件
repeat
newName:=downloaderSaveDir.Text+'\'+artistNametemp+' - '+songNametemp+RightStr(downloadNametemp,4);
RenameFile(downloaderSaveDir.Text+'\'+SearchRec.Name,newName); //文件改名
dirPath:=musicLibraryDir.Text+'\'+artistNametemp+'\'+albumNametemp;//在F盤下QQ音樂下載目錄新建分類目錄文件夾
//目錄格式: 藝術家\專輯名\作曲名
ForceDirectories(dirPath);
//downloadAddr.Text:=dirPath; //調(diào)試用
MoveFile(PChar(newName),PChar(dirPath+RightStr(newName,Length(newName)-5))); //移動文件到新建目錄
until(FindNext(SearchRec)<>0);
FindClose(SearchRec);
end;
end;
iniFile.Free;
end;
//************************ 點擊清理記錄按鈕 *****************************************//
procedure TForm1.deleteBtnClick(Sender: TObject); //刪除txt、ini文件
var
path:string;
txtFile:Textfile;
iniFile:TIniFile;
begin
path:=ExtractFilePath(Application.Exename)+'Download Path.txt';
DeleteFile(path);
path:=ExtractFilePath(Application.Exename)+'Download Info.ini';
DeleteFile(path);
end;
//******************* 凱撒移位函數(shù),返回明碼 *************************//
function TForm1.CaesarShifts(str: string; row: word): string; //凱撒移位,返回值為明碼
var
arr1:array of char;
arr2:array of array of char;
len,n:Integer;
col,remainder,I,J:word;
begin
len:=Length(str); //字符串長度
SetLength(arr1,len); //初始化數(shù)組長度
for I := 0 to (len-1) do //字符串轉數(shù)組
arr1[I]:=str[I+1];
DivMod(len,row,col,remainder);
if remainder <> 0 then //有余數(shù),即沒填滿矩陣
begin
col:=col+1;
remainder:=word(col*row-len); //多出remainder個
end;
SetLength(arr2,row,col);
n:=0;
for I := 0 to (row-1) do
for J := 0 to (col-1) do
begin
if (I >= (row-remainder)) and (J >= (col-1)) then
begin
arr2[I,J]:=' ';
end
else
begin
arr2[I,J]:=arr1[n]; //矩陣賦值
inc(n);
end;
end;
n:=0;
for J := 0 to (col-1) do
for I := 0 to (row-1) do
begin
if n<len then
Result:=Result+arr2[I,J]; //數(shù)組轉字符串
inc(n);
end;
Result:=URLDecode(Result);
Result:=StringReplace(Result,'^','0',[rfReplaceAll]); //替換^為0
end;
//******** 監(jiān)視剪貼板,方便搜索地址欄完成自動粘貼,一條一條的復制粘貼很麻煩的 ************//
procedure TForm1.WMDrawClipBoard(var AMessage: TMessage); //監(jiān)視剪貼板
begin
SendMessage(NextClipHwnd,AMessage.Msg,AMessage.WParam,AMessage.LParam);
//將WM_DRAWCLIPBOARD消息傳遞到下一個觀察鏈中的窗口
if Clipboard.HasFormat(CF_TEXT) or Clipboard.HasFormat(CF_OEMTEXT) or Clipboard.HasFormat(CF_UNICODETEXT) then
begin
if Pos('www.xiami.com/song',Clipboard.AsText) > 0 then //過濾不是蝦米音樂的內(nèi)容
begin
if Clipboard.AsText = clipTemp then
ShowMessage('鏈接已復制粘貼!');
downloadAddr.Text:=Clipboard.AsText;
clipTemp:=Clipboard.AsText;
end;
end;
end;
//********************************************************************************//
//********************************************************************************//
運行效果:
由于迅雷有監(jiān)視剪貼板的功能,所以很方便,點了下“粘到剪貼板”,新建任務窗口就呼出來了
Download Info.ini 歌曲信息查看,可以看出 中文,英文,日文均顯示正常,韓文顯示成問號了,是保存編碼問題,要用Unicode去寫入,沒試成功,也不會寫到ini文件,寫到txt文件中又感覺不好看,算了,這Bug
Download Path.txt 真實下載地址查看
下載成功!
改名到分類目錄就不貼了
|