鱼C论坛

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

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

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

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

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

x

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

小甲鱼最新课程 -> https://ilovefishc.com
 楼主| 发表于 2013-3-18 08:57:18 | 显示全部楼层
是用delphi的
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2013-3-27 14:03:12 | 显示全部楼层
下来学习学习!!!!!!
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2013-5-14 15:55:49 | 显示全部楼层
本帖最后由 aminghanhua 于 2013-5-14 16:13 编辑
  1. procedure TForm1.Lv1DblClick(Sender: TObject);
  2. begin
  3. if Lv1.Items.Count <> 0 then
  4. begin
  5.    if Lv.ItemIndex <> -1 then
  6.     begin
  7.     form1.mp1.URL:=Lv1.Selected.Caption;
  8.     form1.mp1.controls.play;
  9.     end;
  10. end;
  11. end;
复制代码
  1. unit lyric;//歌词显示单元
  2. interface
  3. uses Classes,SysUtils;
  4. type
  5. TOneLyric=Record
  6. time:longint;
  7. lyStr:string;
  8. end;
  9. TLyric=class
  10. private
  11. FFilename:string;
  12. FOffset:integer; //时间补偿值 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
  13. FAur:string; //艺人名
  14. FBy:string; //编者(指编辑LRC歌词的人)
  15. FAl:string; //专辑名
  16. FTi:string; //曲名
  17. FCount:integer;
  18. FLyricArray : array of TOneLyric;
  19. function GetLyric(i:integer): TOneLyric ;
  20. function ExistTime(vTime:longint):boolean;
  21. procedure sortLyric;
  22. procedure ResetLyrics(FTxt:Tstrings);
  23. protected
  24. public
  25. constructor Create;
  26. destructor Destroy; override;
  27. procedure loadLyric(afilename:string);
  28. procedure SetTxt(aLyrics:Tstrings);
  29. procedure UnloadLyric(strs:Tstrings);
  30. //整体提前(正值)或整体延后(负值)atime毫秒
  31. function ChgOffset(atime:integer):boolean;
  32. //提前(正值)/延后(负值)某一句歌词 aTime毫秒
  33. function ChgOneLyric(oldTime:longint;aTime:integer):boolean;
  34. //保存歌词内容到文件
  35. function SaveLyricsToFile(vFileName:string):boolean;
  36. property filename:string read ffilename;
  37. property Ar:string read FAur;
  38. property By:string read FBy;
  39. property Al:string read FAl;
  40. property Ti:string read FTi;
  41. property Offset :integer read FOffset;
  42. property LyricArray[i:integer]: TOneLyric read GetLyric ;
  43. property Count:integer read FCount;
  44. end;
  45. implementation
  46. constructor TLyric.Create;
  47. begin
  48. inherited Create;
  49. FTi:='';
  50. FAur:='';
  51. Fal:='';
  52. FBy:='';
  53. FOffset:=0;
  54. end;
  55. function TLyric.ExistTime(vTime:longint):boolean;
  56. var i:integer;
  57. begin
  58. result:=false;
  59. for i:=0 to length(FLyricArray) -1 do
  60. if FLyricArray[i].time =vTime then
  61. begin
  62. result:=true;
  63. break;
  64. end;
  65. end;
  66. procedure TLyric.loadLyric(afilename:string);
  67. var
  68. FTxt:Tstrings;
  69. begin
  70. FTi:='';
  71. FAur:='';
  72. Fal:='';
  73. FBy:='';
  74. FOffset:=0;
  75. FFilename:=afilename;
  76. //载入歌词
  77. FTxt:=TStringlist.create;
  78. FTxt.LoadFromFile(Ffilename);
  79. ResetLyrics(FTxt);
  80. FTxt.Clear;
  81. FTxt.free;
  82. end;
  83. procedure TLyric.SetTxt(aLyrics:Tstrings);
  84. begin
  85. FTi:='';
  86. FAur:='';
  87. Fal:='';
  88. FBy:='';
  89. FOffset:=0;
  90. //载入歌词
  91. ResetLyrics(aLyrics);
  92. end;
  93. //根据歌词文件 载入每行歌词
  94. procedure TLyric.ResetLyrics(FTxt:Tstrings);
  95. var i:integer;
  96. function makeOneLyric(CurLyric:string):string;
  97. var p1,p2,p3:integer;
  98. timestr,lyricstr:string;
  99. time1,time2:longint;
  100. isFuSign:boolean;
  101. begin
  102. p1:=pos('[',CurLyric);//第一个‘[’位置
  103. if p1=0 then begin //判断是否非法行
  104. result:= CurLyric; //无 '['
  105. exit;
  106. end;
  107. p2:=pos(']',CurLyric); //第一个‘]’位置
  108. if p2=0 then begin
  109. result:= CurLyric;
  110. exit; //无 ']'
  111. end;
  112. timestr:=copy(curLyric,p1+1,p2-p1-1);
  113. //左右两边为歌词
  114. lyricStr:= copy(curLyric,1,p1-1) + copy(curLyric,p2+1,length(curLyric)-p2) ;
  115. lyricStr:=makeOneLyric(lyricStr);
  116. if copy(Lowercase(timeStr),1,2)='ar' then //作者信息
  117. FAur:= copy(timestr,4,length(timestr)-3)
  118. else if copy(Lowercase(timeStr),1,2)='ti' then //曲目标题
  119. FTi:= copy(timestr,4,length(timestr)-3)
  120. else if copy(Lowercase(timeStr),1,2)='al' then //专辑名
  121. FAl:= copy(timestr,4,length(timestr)-3)
  122. else if copy(Lowercase(timeStr),1,2)='by' then //编辑LRC歌词的人
  123. FBy:= copy(timestr,4,length(timestr)-3)
  124. else if copy(Lowercase(timeStr),1,6)='offset' then //时间补偿值
  125. try
  126. FOffset:= strtoint(copy(timestr,8,length(timestr)-7))
  127. except
  128. FOffset:=0;
  129. end
  130. else //此时为 时间标记
  131. begin
  132. p3:= pos(':',timestr) ;
  133. if p3>0 then begin //判断是否非法行
  134. isFuSign:=false;
  135. try
  136. time1:=strtoint(copy(timestr,1,p3-1))*1000;
  137. if time1<0 then
  138. isFuSign:=true; //记录 该 时间标签 为 负(小于零)
  139. except
  140. //非法歌词行
  141. exit; //分钟有误
  142. end;
  143. try
  144. time2:= trunc( strtofloat(copy(timestr,p3+1,length(timestr)-p3)) *1000);
  145. if isFuSign then
  146. time2:=-time2;
  147. except
  148. exit; //秒 有误
  149. end;
  150. if not ExistTime(time1*60+time2) then
  151. begin
  152. setLength(FLyricArray,length(FLyricArray)+1);
  153. //if trim(lyricStr)=' then
  154. // lyricStr:= '(Music)';
  155. with FLyricArray[length(FLyricArray)-1] do
  156. begin
  157. time :=time1*60+time2;
  158. lystr:=lyricStr;
  159. end;
  160. result:=lyricStr;
  161. end;
  162. end;
  163. end;

  164. end;
  165. begin
  166. SetLength(FLyricArray,0);

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

  172. FCount:=length(FLyricArray) ;
  173. sortLyric;

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

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

  187. end
  188. else
  189. FLyricArray[i].time:=0;
  190. end;
  191. end;

  192. procedure TLyric.UnloadLyric(strs:Tstrings);
  193. var i:integer;
  194. begin
  195. SetLength(FLyricArray,strs.Count );
  196. FCount:= strs.Count;
  197. for i:=0 to strs.Count -1 do
  198. begin
  199. FLyricArray[i].time :=0;
  200. FLyricArray[i].lyStr := strs[i];
  201. end;

  202. FTi:='';
  203. FAur:='';
  204. Fal:='';
  205. FBy:='';
  206. FOffset:=0;

  207. end;

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

  211. inherited Destroy;
  212. end;

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

  218. procedure TLyric.sortLyric;
  219. var i,j:integer;
  220. tmpLyric:TOneLyric;
  221. begin
  222. for i:=0 to length(FLyricArray)-2 do
  223. begin
  224. for j:=i to length(FLyricArray)-1 do
  225. begin
  226. if FLyricArray[j].time < FLyricArray[i].time then
  227. begin
  228. tmpLyric:= FLyricArray[i];
  229. FLyricArray[i]:= FLyricArray[j];
  230. FLyricArray[j]:= tmpLyric;
  231. end;
  232. end;
  233. end;
  234. end;

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

  244. //修改offset 保存文件
  245. afind:=false;
  246. aOffset:=0;
  247. numberLine:=-1;

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

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

  254. p1:=pos('[',CurLyric);//第一个‘[’位置
  255. if p1=0 then begin //判断是否非法行
  256. continue; //无 '['
  257. end;
  258. p2:=pos(']',CurLyric); //第一个‘]’位置
  259. if p2=0 then begin
  260. continue; //无 ']'
  261. end;

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

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

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

  277. fTxt.SaveToFile(FFilename);
  278. afind:=true;
  279. break;
  280. end
  281. else
  282. begin
  283. if numberLine=-1 then
  284. begin
  285. signStr:=copy(Lowercase(timeStr),1,2) ;
  286. if (signStr<>'ar') and (signStr<>'al') and (signStr<>'ti') and (signStr<>'by') then begin
  287. p3:= pos(':',timestr) ;
  288. if p3>0 then //为时间标记
  289. numberLine:=i; //记录行号
  290. end;
  291. end;
  292. end;
  293. end;

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

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

  302. result:=true;

  303. FTxt.Clear;
  304. finally
  305. FTxt.free;
  306. end;
  307. end;

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

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

  316. p1,p2,p3:integer;
  317. timestr,left_lyric,right_lyric:string; //
  318. time1,time2:longint;
  319. findok:boolean;
  320. isValid:boolean;//

  321. NewTimeLabel:string;
  322. NewTime:longint;

  323. UseMS:boolean;
  324. begin
  325. //---------该串内 是否有标签 ----------
  326. p1:=pos('[',CurLyric);//第一个‘[’位置
  327. if p1=0 then begin //判断是否非法行
  328. Result:=false; //无 '['
  329. exit;
  330. end;
  331. p2:=pos(']',CurLyric); //第一个‘]’位置
  332. if p2=0 then begin
  333. result:= false;
  334. exit; //无 ']'
  335. end;
  336. //==========串内 是否有标签==========

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

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

  341. isValid:=true;
  342. findok:=false;
  343. p3:= pos(':',timestr) ;
  344. if p3>0 then begin //判断是否 合法时间标签
  345. isFu:=false;
  346. try
  347. time1:=strtoint(copy(timestr,1,p3-1))*1000;
  348. if time1<0 then
  349. isFu:=true;
  350. except
  351. //非法歌词行
  352. isValid:=false; //分钟有误
  353. end;

  354. try
  355. if isValid then
  356. begin
  357. time2:= trunc( strtofloat(copy(timestr,p3+1,length(timestr)-p3)) *1000);
  358. if isFu then
  359. time2:=-time2;
  360. end;
  361. except
  362. isValid:=false; //秒 有误
  363. end;

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

  366. end; //非法行 判断结束
  367. //==========是否找到 指定时间标签==========
  368. //-------找到 和 没找到 之后的处理 ----------
  369. if findok then begin
  370. Result:= true;
  371. //根据 老时间标签(timerstr)
  372. //生成 新的时间标签
  373. NewTime:=time1*60+time2 - aTime;
  374. //根据 原来是否使用毫秒 和 目前调整的偏移时间是否属于毫秒级别
  375. // 来决定 是否 使用毫秒
  376. UseMS:= (Pos('.',timestr)>0) or (aTime mod 1000 <>0);
  377. //转化时间为时间串例如: 72秒 ==>> '00:01:12.000'
  378. NewTimeLabel:=ConvertTimeToTimestr(NewTime,0,false,true,UseMS,true);
  379. //返回 新的歌词部分
  380. curLyric := left_Lyric + '[' + NewTimeLabel + ']'+ Right_Lyric;
  381. end
  382. else //还 没找到
  383. begin //在 该行歌词剩余部分 找找看
  384. if AjustOneLine(Right_lyric) then
  385. begin
  386. //在剩余部分内找到了
  387. curLyric:= Left_lyric+ '[' + timestr +']' +Right_lyric ;
  388. Result:=true;
  389. end
  390. //else 剩余部分内 没有的话 ,只好返回 false 啦
  391. // (函数开始处,已经默认=false)
  392. end;
  393. //=========找到 和 没找到 之后的处理==========
  394. end; //end function AjustOneLine
  395. begin
  396. AjustOk:=false;
  397. Result:=false;
  398. FTxt:=TStringlist.create;
  399. try
  400. FTxt.LoadFromFile(FFilename);
  401. for i:=0 to FTxt.Count-1 do
  402. begin
  403. thisLyric:=FTxt[i];
  404. if AjustOneLine(thisLyric) then
  405. begin
  406. AjustOk:=true;
  407. //更新 新生成 的歌词行
  408. FTxt[i]:=thisLyric;
  409. break;
  410. end;
  411. end;
  412. if AjustOk then
  413. begin
  414. //保存歌词文件
  415. FTxt.SaveToFile(FFilename);
  416. //重新载入歌词
  417. loadLyric(FFilename);
  418. Result:=true;
  419. end;

  420. FTxt.Clear;
  421. finally
  422. FTxt.free;
  423. end;
  424. end;
  425. //保存歌词内容到文件
  426. function TLyric.SaveLyricsToFile(vFileName:string):boolean;
  427. var i:integer;
  428. aTxt:Tstrings ;
  429. begin
  430. result:=false;
  431. if FCount<=0 then exit;
  432. aTxt:=Tstringlist.Create;
  433. try
  434. if FTi <>' then
  435. aTxt.Add('歌名:'+FTi);
  436. if FAur <>' then
  437. aTxt.Add('歌手:'+FAur);
  438. if Fal <>' then
  439. aTxt.Add('专辑:'+Fal);
  440. // if Fby <>' then
  441. // lbxpreview.Items.Add('歌词编辑:'+Fby);
  442. if aTxt.Count >0 then
  443. aTxt.Add('--- --- --- --- --- --- ---');
  444. for i:=0 to FCount-1 do
  445. aTxt.Add(LyricArray[i].lyStr ) ;
  446. aTxt.SaveToFile(vFilename);
  447. Result:=true;
  448. finally
  449. aTxt.Free;
  450. end;
  451. end;
  452. end.
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
 楼主| 发表于 2013-5-14 16:15:42 | 显示全部楼层
小甲鱼最新课程 -> https://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

小甲鱼最新课程 -> https://ilovefishc.com
发表于 2014-10-27 16:03:07 | 显示全部楼层
学习
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-18 20:36

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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