鱼C论坛

 找回密码
 立即注册
查看: 3161|回复: 6

[技术交流] 做了个播放器 求改进

[复制链接]
发表于 2013-3-18 08:55:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x

共享链接:http://163.fm/U5hpzsk提取码:cIHPiixp
1.在歌单上无法实现点击播放  只能右键快捷播放
2.不能实现自动下载歌词
求大牛改进源码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2013-3-18 08:57:18 | 显示全部楼层
是用delphi的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-3-27 14:03:12 | 显示全部楼层
下来学习学习!!!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-5-14 15:55:49 | 显示全部楼层
本帖最后由 aminghanhua 于 2013-5-14 16:13 编辑
procedure TForm1.Lv1DblClick(Sender: TObject);
begin
if Lv1.Items.Count <> 0 then
begin
   if Lv.ItemIndex <> -1 then
    begin
    form1.mp1.URL:=Lv1.Selected.Caption;
    form1.mp1.controls.play;
    end;
end;
end;
unit lyric;//歌词显示单元
interface
uses Classes,SysUtils;
type
TOneLyric=Record
time:longint;
lyStr:string;
end;
TLyric=class
private
FFilename:string;
FOffset:integer; //时间补偿值 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
FAur:string; //艺人名
FBy:string; //编者(指编辑LRC歌词的人)
FAl:string; //专辑名
FTi:string; //曲名
FCount:integer;
FLyricArray : array of TOneLyric;
function GetLyric(i:integer): TOneLyric ;
function ExistTime(vTime:longint):boolean;
procedure sortLyric;
procedure ResetLyrics(FTxt:Tstrings);
protected
public
constructor Create;
destructor Destroy; override;
procedure loadLyric(afilename:string);
procedure SetTxt(aLyrics:Tstrings);
procedure UnloadLyric(strs:Tstrings);
//整体提前(正值)或整体延后(负值)atime毫秒
function ChgOffset(atime:integer):boolean;
//提前(正值)/延后(负值)某一句歌词 aTime毫秒
function ChgOneLyric(oldTime:longint;aTime:integer):boolean;
//保存歌词内容到文件
function SaveLyricsToFile(vFileName:string):boolean;
property filename:string read ffilename;
property Ar:string read FAur;
property By:string read FBy;
property Al:string read FAl;
property Ti:string read FTi;
property Offset :integer read FOffset;
property LyricArray[i:integer]: TOneLyric read GetLyric ;
property Count:integer read FCount;
end;
implementation
constructor TLyric.Create;
begin
inherited Create;
FTi:='';
FAur:='';
Fal:='';
FBy:='';
FOffset:=0;
end;
function TLyric.ExistTime(vTime:longint):boolean;
var i:integer;
begin
result:=false;
for i:=0 to length(FLyricArray) -1 do
if FLyricArray[i].time =vTime then
begin
result:=true;
break;
end;
end;
procedure TLyric.loadLyric(afilename:string);
var
FTxt:Tstrings;
begin
FTi:='';
FAur:='';
Fal:='';
FBy:='';
FOffset:=0;
FFilename:=afilename;
//载入歌词
FTxt:=TStringlist.create;
FTxt.LoadFromFile(Ffilename);
ResetLyrics(FTxt);
FTxt.Clear;
FTxt.free;
end;
procedure TLyric.SetTxt(aLyrics:Tstrings);
begin
FTi:='';
FAur:='';
Fal:='';
FBy:='';
FOffset:=0;
//载入歌词
ResetLyrics(aLyrics);
end;
//根据歌词文件 载入每行歌词
procedure TLyric.ResetLyrics(FTxt:Tstrings);
var i:integer;
function makeOneLyric(CurLyric:string):string;
var p1,p2,p3:integer;
timestr,lyricstr:string;
time1,time2:longint;
isFuSign:boolean;
begin
p1:=pos('[',CurLyric);//第一个‘[’位置
if p1=0 then begin //判断是否非法行
result:= CurLyric; //无 '['
exit;
end;
p2:=pos(']',CurLyric); //第一个‘]’位置
if p2=0 then begin
result:= CurLyric;
exit; //无 ']'
end;
timestr:=copy(curLyric,p1+1,p2-p1-1);
//左右两边为歌词
lyricStr:= copy(curLyric,1,p1-1) + copy(curLyric,p2+1,length(curLyric)-p2) ;
lyricStr:=makeOneLyric(lyricStr);
if copy(Lowercase(timeStr),1,2)='ar' then //作者信息
FAur:= copy(timestr,4,length(timestr)-3)
else if copy(Lowercase(timeStr),1,2)='ti' then //曲目标题
FTi:= copy(timestr,4,length(timestr)-3)
else if copy(Lowercase(timeStr),1,2)='al' then //专辑名
FAl:= copy(timestr,4,length(timestr)-3)
else if copy(Lowercase(timeStr),1,2)='by' then //编辑LRC歌词的人
FBy:= copy(timestr,4,length(timestr)-3)
else if copy(Lowercase(timeStr),1,6)='offset' then //时间补偿值
try
FOffset:= strtoint(copy(timestr,8,length(timestr)-7))
except
FOffset:=0;
end
else //此时为 时间标记
begin
p3:= pos(':',timestr) ;
if p3>0 then begin //判断是否非法行
isFuSign:=false;
try
time1:=strtoint(copy(timestr,1,p3-1))*1000;
if time1<0 then
isFuSign:=true; //记录 该 时间标签 为 负(小于零)
except
//非法歌词行
exit; //分钟有误
end;
try
time2:= trunc( strtofloat(copy(timestr,p3+1,length(timestr)-p3)) *1000);
if isFuSign then
time2:=-time2;
except
exit; //秒 有误
end;
if not ExistTime(time1*60+time2) then
begin
setLength(FLyricArray,length(FLyricArray)+1);
//if trim(lyricStr)=' then
// lyricStr:= '(Music)';
with FLyricArray[length(FLyricArray)-1] do
begin
time :=time1*60+time2;
lystr:=lyricStr;
end;
result:=lyricStr;
end;
end;
end;

end;
begin
SetLength(FLyricArray,0);

//解析歌词各部分
for i:= 0 to FTxt.count-1 do
begin
makeOneLyric(FTxt[i]) ;
end;

FCount:=length(FLyricArray) ;
sortLyric;

{if FTi<>' then FTi:= replaceWithchr(FTi,'&','&&');
if FAur<>' then FAur:= replaceWithchr(FAur,'&','&&');
if FAl<>' then FAl:= replaceWithchr(FAl,'&','&&');
if FBy<>' then FBy:= replaceWithchr(FBy,'&','&&');
}
//根据 整体时间偏移,重新计算每句歌词时间
for i:=0 to length(FLyricArray)-1 do
begin
//FLyricArray[i].lyStr := replaceWithchr(FLyricArray[i].lyStr,'&','&&');

if FLyricArray[i].time >= 0 then
begin
if FLyricArray[i].time - FOffset>=0 then
FLyricArray[i].time:=FLyricArray[i].time - FOffset ;

end
else
FLyricArray[i].time:=0;
end;
end;

procedure TLyric.UnloadLyric(strs:Tstrings);
var i:integer;
begin
SetLength(FLyricArray,strs.Count );
FCount:= strs.Count;
for i:=0 to strs.Count -1 do
begin
FLyricArray[i].time :=0;
FLyricArray[i].lyStr := strs[i];
end;

FTi:='';
FAur:='';
Fal:='';
FBy:='';
FOffset:=0;

end;

destructor TLyric.Destroy;
begin
SetLength(FLyricArray,0);

inherited Destroy;
end;

function TLyric.GetLyric(i:integer): TOneLyric ;
begin
if (i>=0) and (i<length(FLyricArray)) then
result:=FLyricArray[i] ;
end;

procedure TLyric.sortLyric;
var i,j:integer;
tmpLyric:TOneLyric;
begin
for i:=0 to length(FLyricArray)-2 do
begin
for j:=i to length(FLyricArray)-1 do
begin
if FLyricArray[j].time < FLyricArray[i].time then
begin
tmpLyric:= FLyricArray[i];
FLyricArray[i]:= FLyricArray[j];
FLyricArray[j]:= tmpLyric;
end;
end;
end;
end;

function TLyric.ChgOffset(atime:integer):boolean;//提前(正值)或延后(负值)atime毫秒
var i,numberLine:integer;
p1,p2,p3:integer;
timestr,lyricstr,CurLyric,signStr:string;
aOffset:longint;
afind:boolean;
FTxt:Tstrings;
begin
Result:=false;

//修改offset 保存文件
afind:=false;
aOffset:=0;
numberLine:=-1;

FTxt:=TStringlist.create;
try
FTxt.LoadFromFile(FFilename);

for i:=0 to FTxt.Count-1 do
begin
curLyric:=fTxt[i];

p1:=pos('[',CurLyric);//第一个‘[’位置
if p1=0 then begin //判断是否非法行
continue; //无 '['
end;
p2:=pos(']',CurLyric); //第一个‘]’位置
if p2=0 then begin
continue; //无 ']'
end;

timestr:=copy(curLyric,p1+1,p2-p1-1);
//左右两边为歌词
lyricStr:= copy(curLyric,1,p1-1) + copy(curLyric,p2+1,length(curLyric)-p2) ;

if copy(Lowercase(timeStr),1,6)='offset' then //找到 时间补偿串
begin
try
aOffset:= strtoint(copy(timestr,8,length(timestr)-7));
except
continue;
end ;
fTxt[i]:=copy(curLyric,1,p1-1)
+'[offset:'+inttostr(aOffset+aTime) +']'
+copy(curLyric,p2+1,length(curLyric)-p2);

if aOffset+aTime=0 then
FTxt.Delete(i);

fTxt.SaveToFile(FFilename);
afind:=true;
break;
end
else
begin
if numberLine=-1 then
begin
signStr:=copy(Lowercase(timeStr),1,2) ;
if (signStr<>'ar') and (signStr<>'al') and (signStr<>'ti') and (signStr<>'by') then begin
p3:= pos(':',timestr) ;
if p3>0 then //为时间标记
numberLine:=i; //记录行号
end;
end;
end;
end;

if (not afind) and (numberLine<>-1) then
begin
//fTxt.Add('[offset:'+inttostr(aOffset+aTime) +']');
fTxt.Insert(numberline, '[offset:'+inttostr(aOffset+aTime) +']');
fTxt.SaveToFile(FFilename);
end;

//重新载入歌词
loadLyric(FFilename);

result:=true; 

FTxt.Clear;
finally
FTxt.free;
end;
end;

function TLyric.ChgOneLyric(oldTime:longint;aTime:integer):boolean;
var i:integer;
FTxt:Tstrings;
AjustOk:boolean;
thisLyric:string;

function AjustOneLine(var curLyric:string):boolean;
var
isFu:boolean;//该时间是否为负.

p1,p2,p3:integer;
timestr,left_lyric,right_lyric:string; //
time1,time2:longint;
findok:boolean;
isValid:boolean;//

NewTimeLabel:string;
NewTime:longint;

UseMS:boolean;
begin
//---------该串内 是否有标签 ----------
p1:=pos('[',CurLyric);//第一个‘[’位置
if p1=0 then begin //判断是否非法行
Result:=false; //无 '['
exit;
end;
p2:=pos(']',CurLyric); //第一个‘]’位置
if p2=0 then begin
result:= false;
exit; //无 ']'
end;
//==========串内 是否有标签==========

//----------目前标签 是否是 指定时间的 标签----------
timestr:=copy(curLyric,p1+1,p2-p1-1);

Left_lyric:= copy(curLyric,1,p1-1);
Right_lyric:= copy(curLyric,p2+1,length(curLyric)-p2) ;

isValid:=true;
findok:=false;
p3:= pos(':',timestr) ;
if p3>0 then begin //判断是否 合法时间标签
isFu:=false;
try
time1:=strtoint(copy(timestr,1,p3-1))*1000;
if time1<0 then
isFu:=true;
except
//非法歌词行
isValid:=false; //分钟有误
end;

try
if isValid then
begin
time2:= trunc( strtofloat(copy(timestr,p3+1,length(timestr)-p3)) *1000);
if isFu then
time2:=-time2;
end;
except
isValid:=false; //秒 有误
end;

if isValid and (time1*60+time2 - FOffset = oldtime) then //找到 指定时间串
findOk:=true; //找到 啦 啦 啦 ...

end; //非法行 判断结束
//==========是否找到 指定时间标签==========
//-------找到 和 没找到 之后的处理 ----------
if findok then begin
Result:= true;
//根据 老时间标签(timerstr)
//生成 新的时间标签
NewTime:=time1*60+time2 - aTime;
//根据 原来是否使用毫秒 和 目前调整的偏移时间是否属于毫秒级别
// 来决定 是否 使用毫秒
UseMS:= (Pos('.',timestr)>0) or (aTime mod 1000 <>0);
//转化时间为时间串例如: 72秒 ==>> '00:01:12.000'
NewTimeLabel:=ConvertTimeToTimestr(NewTime,0,false,true,UseMS,true);
//返回 新的歌词部分
curLyric := left_Lyric + '[' + NewTimeLabel + ']'+ Right_Lyric;
end
else //还 没找到
begin //在 该行歌词剩余部分 找找看
if AjustOneLine(Right_lyric) then
begin
//在剩余部分内找到了
curLyric:= Left_lyric+ '[' + timestr +']' +Right_lyric ;
Result:=true;
end
//else 剩余部分内 没有的话 ,只好返回 false 啦
// (函数开始处,已经默认=false)
end;
//=========找到 和 没找到 之后的处理========== 
end; //end function AjustOneLine
begin
AjustOk:=false;
Result:=false;
FTxt:=TStringlist.create;
try
FTxt.LoadFromFile(FFilename);
for i:=0 to FTxt.Count-1 do
begin
thisLyric:=FTxt[i];
if AjustOneLine(thisLyric) then
begin
AjustOk:=true;
//更新 新生成 的歌词行
FTxt[i]:=thisLyric;
break;
end;
end;
if AjustOk then
begin
//保存歌词文件
FTxt.SaveToFile(FFilename);
//重新载入歌词
loadLyric(FFilename);
Result:=true;
end;

FTxt.Clear;
finally
FTxt.free;
end;
end;
//保存歌词内容到文件
function TLyric.SaveLyricsToFile(vFileName:string):boolean;
var i:integer;
aTxt:Tstrings ;
begin
result:=false;
if FCount<=0 then exit;
aTxt:=Tstringlist.Create;
try
if FTi <>' then
aTxt.Add('歌名:'+FTi);
if FAur <>' then
aTxt.Add('歌手:'+FAur);
if Fal <>' then
aTxt.Add('专辑:'+Fal);
// if Fby <>' then
// lbxpreview.Items.Add('歌词编辑:'+Fby);
if aTxt.Count >0 then
aTxt.Add('--- --- --- --- --- --- ---');
for i:=0 to FCount-1 do
aTxt.Add(LyricArray[i].lyStr ) ;
aTxt.SaveToFile(vFilename);
Result:=true;
finally
aTxt.Free;
end;
end;
end.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2013-5-14 16:15:42 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-5-14 16:22:25 | 显示全部楼层
从千千静听网站下载歌词的流程为:
1、根据歌手以及歌曲名称找歌词单列表
服务器地址为:
http://ttlrcct2.qianqian.com/dll/lyricsvr.dll?sh?Artist={0}&Title={1}&Flags=0
{0}为歌手名的UNICODE编码字符串
{1}为歌曲名的UNICODE编码字符串
注意
歌手名,歌曲名需要去空格、"'"、转换成小写等操作。
UNICODE编码时需要按字节转换为16进制,而不是按字符。

2、上面的操作获取到类似下面的xml结果。
<?xml version="1.0" encoding="UTF-8"?>
<result>
  <lrc id="70437" artist="胡彦斌" title="男人 KTV"></lrc>
  <lrc id="204568" artist="胡彦斌" title="男人KTV"></lrc>
</result>
3、我们选择其中一个歌词进行下载。
根据选择歌词的ID,artist,title生成一个校验字符串(CODE)根据ID以及CODE去下面的地址获取歌词。
http://ttlrcct2.qianqian.com/dll/lyricsvr.dll?dl?Id={0}&Code={1}
{0}:ID
{1}:CODE

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2014-10-27 16:03:07 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-23 07:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表