歌词

歌词初始化

播放面板左侧展示歌单歌曲,右侧展示当前歌曲歌词,并且实现和左侧相通的滚动条。因此要根据ID获取当前歌曲歌词。

  • song.service.ts
   // 根据ID获取歌曲歌词getLyric (id: number): Observable<Lyric> {const params = new HttpParams().set('id', id.toString());return this.http.get(this.uri + 'lyric', { params }).pipe(map((res: {[key: string]: { lyric: string; }}) => {return {lyric: res.lrc.lyric,tlyric: res.tlyric.lyric,}}))}
  • common.types.ts
// 歌词
export type Lyric = {lyric: string, // 原文tlyric: string // 译文
}

根据api获取当前歌曲需要的部分,并且在common.types.ts中声明Lyric类型,将返回值res处理成需要的键值对格式。

处理歌词

单语歌词

当监听当前歌曲值发生变化时,不仅要重新获取当前歌曲索引还有获取当前歌曲歌词。

  • wy-player-panel.component.ts
    currentLyric: BaseLyricLine[]; // 歌词// 数据监听ngOnChanges (changes: SimpleChanges): void {// 监听当前歌曲变化if (changes['currentSong']) {if (this.currentSong) {this.currentIndex = findIndex(this.songList, this.currentSong);this.updateLyric();if (this.show) {this.scrollToCurrent();}} }}// 根据ID获取歌词private updateLyric () {this.songServe.getLyric(this.currentSong.id).subscribe((res) => {const lyric = new WyLyric(res);this.currentLyric = lyric.lines;});}
  • wy-lyric.ts
import { Lyric } from "src/app/services/data-types/common.types";
// 歌词基类
export interface BaseLyricLine {txt: string;txtCn: string;
}
// 歌词派生类
interface LyricLine extends BaseLyricLine {time: number
}const timeExp = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/;  //正值-匹配 [00:34.910] 类型export class WyLyric {private lrc: Lyric; // 暂存传来的歌词lines: LyricLine[] = [];constructor(lrc: Lyric) {this.lrc = lrc;this.init();}private init () {// 判断是否是外语歌曲if (this.lrc.tlyric) {this.generTLyric();} else {this.generLyric();}}// 解析单语歌词private generLyric () {const lines = this.lrc.lyric.split('\n');lines.forEach(line => this.makeLine(line))}// 解析双语歌词private generTLyric () {}// 处理单行歌词private makeLine (line: string) {const result = timeExp.exec(line);if (result) {const txt = line.replace(timeExp, '').trim();const txtCn = '';if (txt) {const thirdResult = result[3] || '00';const len = thirdResult.length;const _thirdResult = len > 2 ? parseInt(thirdResult) : parseInt(thirdResult) * 10;const time = Number(result[1]) * 60 * 1000 + Number(result[2]) * 60 + _thirdResult;this.lines.push({ txt, txtCn, time })}}}}

当实例化歌词类的时候先暂存传来的歌词,然后判断当前歌词是否是双语,当仅为单语时会将歌词中string类型的原文转为数组,因为每一行歌词前都会有时间提示,所以要通过makeLine方法单独处理每一行。

在处理单行歌词时使用了正则表达式来匹配字符串格式的参数。

RegExpObject.exec(string)
返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。

参数 描述
string 必需。要检索的字符串。

如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。我们可以看得出,在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。

在单行歌词中匹配"[分钟:秒.毫秒]"类型的字符串

如果能匹配到,就在当前单行歌词中将匹配到的字符串置空并去空格,这样就能拿到实际渲染的歌词了。而在时间上是将分钟,秒转换为毫秒并存下来。

  • wy-player-panel.component.html
<!-- 歌词列表 --><app-wy-scroll class=" list-lyric"><ul><li *ngFor="let line of currentLyric">{{line.txt}} <br />{{line?.txtCn}}   </li></ul></app-wy-scroll>


双语歌词

在拿到国外歌曲的歌词时,会有翻译的文本,这时候就要将原文和译文一句句的对应起来。在WyLyric类中通过对传送进来的歌词类判断,来决定歌词处理的通道是走单语还是双语。

  • wy-lyriv.ts
 // 解析双语歌词private generTLyric () {// 获取原文数组const lines = this.lrc.lyric.split('\n');// 获取译文数组const tLines = this.lrc.tlyric.split('\n').filter(item => timeExp.exec(item) != null);// 判断原文与译文的长度关系const moreLine = lines.length - tLines.length;let tempArr = [];if (moreLine >= 0) {tempArr = [lines, tLines];} else {tempArr = [tLines, lines];}// 获取短的歌词数组中的第一个时间部分const first = timeExp.exec(tempArr[1][0])[0];// 获取长的歌词数组需要跳过的索引const skipIndex = tempArr[0].findIndex(item => {const exec = timeExp.exec(item);if (exec) {return exec[0] === first;}});const _skip = skipIndex === -1 ? 0 : skipIndex;const skipItems = tempArr[0].slice(0, _skip);if (skipItems.length) {skipItems.forEach(line => this.makeLine(line));}let zipLines$;if (moreLine > 0) {zipLines$ = zip(from(lines).pipe(skip(_skip)), from(tLines));} else {zipLines$ = zip(from(lines), from(tLines).pipe(skip(_skip)));}zipLines$.subscribe(([line, tLine]) => this.makeLine(line, tLine))}// 处理单行歌词private makeLine (line: string, tLine = '') {const result = timeExp.exec(line);if (result) {const txt = line.replace(timeExp, '').trim();const txtCn = tLine ? tLine.replace(timeExp, '').trim() : '';if (txt) {const thirdResult = result[3] || '00';const len = thirdResult.length;const _thirdResult = len > 2 ? parseInt(thirdResult) : parseInt(thirdResult) * 10;const time = Number(result[1]) * 60 * 1000 + Number(result[2]) * 60 + _thirdResult;this.lines.push({ txt, txtCn, time })}}}

在通过获取双语歌词回调中,声明局部变量lines和tLines来保存传递过来的歌词的原文和译文部分,api数据中观察到原文和译文可能不对应,因此译文部分要经过一个空值筛选。因为二者不一 一对应,但是在渲染的时候要达到一句原文一句译文,所以需要判断。为了方便取值,声明一个装有原文译文数组的数组,当原文的长度大于等于译文,将原文放在索引0,反之放在索引1。

原文和译文长度可能不同,原文中可能含有一些版权声明和作词作曲介绍,这时候译文可能没有翻译,所以长度不同,这时的逻辑就是一是要全部显示原文歌词,但是还要将原文译文相对应。

此时用正则获取短的歌词数组中第一条数据的时间部分,然后用findIndex在长的歌词数组中寻找该时间部分等于短的歌词数组中的一条的时间部分,拿到索引。

findIndex()

  • 返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
  • 为数组中的每个元素都调用一次函数执行:当数组中的元素在测试条件时返回 true 时, 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。如果没有符合条件的元素返回 -1
    注意: findIndex() 对于空数组,函数是不会执行的。其并没有改变数组的原始值。

所以此时要将返回-1的时候转为0,即原文和译文长度相等,此时不用截取任何数据。截取数据不为空时,在将截取的数据单独提前push到渲染的歌词中。之后便是要处理一一对应的歌词了。

此时判断原文和译文的长度关系,如果原文长,就将原文跳过获取的索引,然后通过zip()来得到一个 [ 原文, 译文 ]observable类型的数组。译文长就将译文跳过获取的索引。然后在将得到的数据订阅处理单行歌词的回调。此时要将之前写死的单条译文写一个判断

总结

其中使用了正则表达式,很显然是一块短板,而且在使用zip()时提示方法不再支持,而是建议使用map来操作,目前为了理解没有修改,后续来调整这一方面!

[Angular实战网易云]——15、歌词渲染相关推荐

  1. [Angular实战网易云]——10、滑块进度条

    场景 首页主体样式大致实现,底部样式还有所欠缺,所以底部应加上个别信息与播放的进度条,这个进度条类似Zorro的滑块,点击与滑动,其中包括事件的绑定与组件的嵌套.其中进度条不仅仅实现在歌曲进度上,在音 ...

  2. [Angular实战网易云]——20、歌单详情

    歌单详情 场景 在首页和歌单列表页,点击歌单图片能够查看当前歌单的详细信息,包括歌单内的歌曲 创建新模块 ng g m sheet-info --routingng g c sheet-info ap ...

  3. [Angular实战网易云]——13、底部信息与功能(一)

    场景 在点击播放音乐之后,歌曲的信息也要渲染到DOM中,其中关于歌曲的时长以及播放的时长也要添加上去.在信息渲染之后还要增加底部的功能,上/下一曲,播放/暂停,以及音量调节和播放模式等 步骤 歌曲显示 ...

  4. python3爬取网易云歌单数据清洗_如何利用Python网络爬虫爬取网易云音乐歌词

    赵雷的歌曲 本文以民谣歌神赵雷为数据采集对象,专门采集他的歌曲歌词,其他歌手的歌词采集方式可以类推,下图展示的是<成都>歌词. 赵雷歌曲---<成都> 一般来说,网页上显示的U ...

  5. python爬取歌词_利用Python网络爬虫抓取网易云音乐歌词

    今天小编给大家分享网易云音乐歌词爬取方法. 本文的总体思路如下: 找到正确的URL,获取源码: 利用bs4解析源码,获取歌曲名和歌曲ID: 调用网易云歌曲API,获取歌词: 将歌词写入文件,并存入本地 ...

  6. 重磅!python获取同步输出的桌面网易云音乐歌词(内存偏移获取)

    最喜欢研究跟音乐相关的东西了,就像有的人爱喝酒吗,我离不开音乐,撸代码的时候,来点音乐,状态飙升,就跟晚上有人喜欢自己买点花生米小酌一下. 一直想做一个歌词输出的屏幕,心里暗暗合计了好一阵了,无非大致 ...

  7. 如何用Python网络爬虫爬取网易云音乐歌词

    前几天小编给大家分享了数据可视化分析,在文尾提及了网易云音乐歌词爬取,今天小编给大家分享网易云音乐歌词爬取方法. 本文的总体思路如下: 找到正确的URL,获取源码: 利用bs4解析源码,获取歌曲名和歌 ...

  8. 一款网易云音乐歌词制作软件

    好吧,随便百度一个软件都可以用. 我之前没接触过.. http://www.aiqisoft.com/download/download.php?aid=2&id=211 都是导入歌曲,导入歌 ...

  9. 利用Python网络爬虫实现对网易云音乐歌词爬取

    今天小编给大家分享网易云音乐歌词爬取方法. 本文的总体思路如下: 找到正确的URL,获取源码: 利用bs4解析源码,获取歌曲名和歌曲ID: 调用网易云歌曲API,获取歌词: 将歌词写入文件,并存入本地 ...

最新文章

  1. 语言毕业设计选题及源代码_区块链毕业设计论文「11」
  2. ASP.NET 之异步处理一(Session处理)
  3. Oracle学习:分组数据(group by)与笛卡尔积
  4. C和指针之函数之实现阶乘和斐波那契数(递归和非递归)
  5. python中空格属于字符吗_举例说明python中空格是属于字符
  6. linux脚本怎怎么屏蔽段落,怎么写shell脚本才能不耍流氓?
  7. kmeans聚类算法matlab代码,K-Means算法实现(Matlab)
  8. 粤嵌GE6818实现识别触摸坐标的识别
  9. 深度 | EB级规模大数据平台核心技术揭秘(下)
  10. 18、DQL(分页查询:limt)
  11. LeetCode_1677_数组中重复的数字
  12. 像游戏一样办公,赋能OA系统转型
  13. 小程序中maring-top、maring-left、maring-right、maring-bottom失效/没有用的原因及解决方案
  14. 农村没网络怎样安监控,家里没有wifi安哪种监控器
  15. 安卓游戏时禁止状态栏下拉_Android手机屏蔽状态栏下拉
  16. Linux 常用服务搭建笔记(精简笔记)
  17. 使用frontpage下载整站
  18. Zemax学习笔记——多重结构配置的激光扩束镜
  19. Win10家庭版使用远程桌面连接失败
  20. 几种室内定位技术的简要介绍

热门文章

  1. 了解源代码管理工具——Github
  2. 普通话测试app怎么样可以不交钱_和小首一起好好说普通话!
  3. John F. Kennedy的就职演说(在线收听)
  4. 凡拓数字通过注册:年营收7亿 伍穗颖夫妇控制43%股权
  5. mysql实现两列数据或者两行数据相减
  6. 赛博朋克小建筑系列模型
  7. 微信开发者工具 Source Map 的使用
  8. ISE 下按键消抖实验
  9. 怎么解决运行时输入错误,请重新输入以及专业无法输入的问题
  10. Word插入高亮格式化代码