Posts


Feb. 10, 2019

将歌词处理成电子书

后端的最后一部分。

  1. # coding=utf-8  
  2. import json  
  3. import re  
  4.   
  5.   
  6. class Lyric2Book:  
  7.     support_format = ['txt', 'html']  
  8.     support_ts = ['parallel', 'chunk']  
  9.     html_template = """ 
  10.     <section> 
  11.         <h2 class='header'>%(header)s</h2> 
  12.             <div class='info'> 
  13.                 <div class='album'>%(album)s</div> 
  14.                 <div class='artists'>%(artists)s</div> 
  15.             </div> 
  16.         <div class='content'> 
  17.             %(lyrics)s 
  18.         </div> 
  19.     </section> 
  20.         """  
  21.     html_frame = """<!DOCTYPE html> 
  22.     <html lang="zh-cn"> 
  23.     <head>  
  24.     <meta charset="utf-8"/> 
  25.     <meta name="viewport" content="width=device-width, initial-scale=1" /> 
  26.     <meta name="referrer" content="never" /> 
  27.     <title>%s</title> 
  28.     </head> 
  29.     <body> 
  30.     %s 
  31.     </body> 
  32.     </html> 
  33.     """  
  34.     lyrics_template = "<div class='content-%(ver)d' >%(content)s</div>"  
  35.     txt_template = "%(header)s\n专辑:%(album)s\n作者:%(artists)s\n\n%(lyrics)s\n\n"  
  36.     txt_frame = "%s\n\n%s"  
  37.   
  38.     def __init__(self, file_format='html', title='Lyrics', typesetting='parallel'):  
  39.         self.title = title  
  40.         if file_format in Lyric2Book.support_format:  
  41.             self.format = file_format  
  42.         else:  
  43.             raise Exception('Unsupported format: %s.' % file_format)  
  44.         self.res = ""  
  45.         self.data = ""  
  46.         if typesetting in Lyric2Book.support_ts:  
  47.             self.ts = typesetting  
  48.         else:  
  49.             raise Exception('Unsupported typesetting: %s' % typesetting)  
  50.   
  51.     def chunk(self, lyrics):  
  52.         predlyric = []  
  53.         # 传入的是多个版本的歌词  
  54.         for item in lyrics:  
  55.             lines = []  
  56.             if item is not None:  
  57.                 # 分行处理  
  58.                 for line in item.split('\n'):  
  59.                     line = re.sub('\(\d+,\d+\)', '', line)  
  60.                     time_tag = ''.join(re.findall('\[.*?\]', line))  
  61.                     line = [time_tag, line.strip(time_tag)]  
  62.                     lines.append(line)  
  63.                 predlyric.append(lines)  
  64.         output_section = ''  
  65.         if self.format == 'html':  
  66.             i = 1  
  67.             for item in predlyric:  
  68.                 output_section += "<div class='content-%d'>\n" % i  
  69.                 i += 1  
  70.                 for line in item:  
  71.                     output_section += "<p><span class='timetag'>%s</span>%s</p> \n" % (re.sub('[\[\]]', '-', line[0]), line[1])  
  72.                 output_section += "</div>"  
  73.         elif self.format == 'txt':  
  74.             for item in predlyric:  
  75.                 output_section += ""  
  76.                 for line in item:  
  77.                     format_tag = '-%s- ' % re.sub('[\[\]]', '-', line[0]) if line[0] else ''  
  78.                     output_section += format_tag + line[1] + '\n'  
  79.         return output_section  
  80.   
  81.     def parallel(self, lyrics):  
  82.         unpredlyric = []  
  83.         for item in lyrics:  
  84.             lines = {}  
  85.             if item is not None:  
  86.                 for line in item.split('\n'):  
  87.                     line = re.sub('\(\d+,\d+\)', '', line)  
  88.                     time_tag = ''.join(re.findall('\[.*?\]', line))  
  89.                     lines[time_tag] = line.strip(time_tag)  
  90.                 unpredlyric.append(lines)  
  91.         predlyric = []  
  92.         for group_tag in list(unpredlyric[0].keys()):  
  93.             predlyric += [[group_tag] + [i.get(group_tag, unpredlyric[0][group_tag]) for i in unpredlyric]]  
  94.         dparallels = predlyric  
  95.         output_section = ''  
  96.         if self.format == 'html':  
  97.             for item in dparallels:  
  98.                 output_section += "<div class='content'>\n"  
  99.                 dtimetag = item[0]  
  100.                 dcontent = item[1::]  
  101.                 item_div = "<div class='timetag'>\n<p>{timetag}</p>\n</div>\n<div class='single-lyric'>\n{content}</div>\n"  
  102.                 output_spar = ''.join("<p class='ver-%d'>%s</p>\n" % (c[0], c[1]) for c in enumerate(dcontent, 1))  
  103.                 output_section += item_div.format(timetag=re.sub('[\[\]]', ' - ', dtimetag), content=output_spar) + '</div>'  
  104.         elif self.format == 'txt':  
  105.             for item in dparallels:  
  106.                 dtimetag = item[0]  
  107.                 dcontent = item[1::]  
  108.                 item_div = "{timetag}\n{content}\n"  
  109.                 output_spar = ''.join("%s\n" % c[1] for c in enumerate(dcontent))  
  110.                 output_section += item_div.format(timetag=re.sub('[\[\]]', ' - ', dtimetag), content=output_spar)  
  111.         return output_section  
  112.   
  113.     def doconv(self, sections):  
  114.         last_album = ''  
  115.         output = ''  
  116.         for item in sections:  
  117.             header = item['name']  
  118.             album = item['album']  
  119.             artists = ','.join(item['artists'])  
  120.             a = item['lyric']  
  121.             if a is not None:  
  122.                 ly_res = {}  
  123.                 lyrics = [a['0'], a['1'], a['2']]  
  124.                 if self.ts == 'parallel':  
  125.                     ly_res = self.parallel(lyrics)  
  126.                 elif self.ts == 'chunk':  
  127.                     ly_res = self.chunk(lyrics)  
  128.                 if self.format == 'html':  
  129.                     if last_album != album:  
  130.                         last_album = album  
  131.                         output += '<h1>%s</h1>' % album  
  132.                     output += Lyric2Book.html_template % {'header': header, 'album': album, 'artists': artists, 'lyrics': ly_res}  
  133.                 elif self.format == 'txt':  
  134.                     if last_album != album:  
  135.                         last_album = album  
  136.                         output += album + '\n\n'  
  137.                     output += Lyric2Book.txt_template % {'header': header, 'album': album, 'artists': artists, 'lyrics': ly_res}  
  138.         self.res = output  
  139.   
  140.     def output(self):  
  141.         filename = self.title + '.' + self.format  
  142.         with open(filename, 'w+', encoding='utf-8') as f:  
  143.             res = self.res  
  144.             if self.format == 'html':  
  145.                 res = Lyric2Book.html_frame % (self.title, res)  
  146.             elif self.format == 'txt':  
  147.                 res = Lyric2Book.txt_frame % (self.title, res)  
  148.             f.write(res)  
  149.   
  150.   
  151. if __name__ == '__main__':  
  152.     with open('bbc.txt', 'r', encoding='utf-8') as file:  
  153.         t = Lyric2Book(file_format='thjxt', title='BBC Documentary', typesetting='parallel')  
  154.         content = json.loads(file.read())  
  155.         t.doconv(content['result'])  
  156.         t.output()  

Feb. 6, 2019

寻找孤独

2019年的春节只有5天,二十八放假,初三上课。

放假前几分钟,我在想我能够做什么做什么,把计划中的事,未做完的事,未计划的事统统完成,大部分都是课外的事。

我确实完成了一些,但有些我却总也走不下去。歌词工具从十月份开始有想法,十一月份真正开始,到现在有三四个月了。借着这个想法我才真正熟悉了Python,后台逻辑其实一个月以前就结束了,一些改进的想法也决定搁置,没有再重构;前端最关键的部分也测试证明可行,然后我就不走了。

More...

Nov. 11, 2018

Python小工具:批量下载网易云音乐歌单/专辑中的歌词

最近想把网易云音乐中的英语听力下载到播放器中,方便随时听。但是只下载音频的话就少了些什么,最好连听力的歌词也下载进去。于是乎写了个小工具,可以批量下载歌单或者专辑中的音乐的歌词,可以省很多时间。

netease-lyric.py

  1. #coding=utf-8  
  2. import requests  
  3. from bs4 import BeautifulSoup  
  4. import json  
  5. import re,os  
  6. from spider import *  
  7. def get_html(url):  
  8.     headers = {  
  9.         'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',  
  10.         'Referer':'http://music.163.com',  
  11.         'Host':'music.163.com'  
  12.     }  
  13.     try:  
  14.         response = requests.get(url,headers=headers)  
  15.         html = response.text  
  16.         return html  
  17.     except:  
  18.         print('request error')  
  19.         pass  
  20.   
  21. def get_lyric(song_id):  
  22.     url = 'http://music.163.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=1&kv=1&tv=-1'  
  23.     html = get_html(url)  
  24.     json_obj = json.loads(html)  
  25.     print(json_obj)  
  26.     lyric = json_obj['lrc']['lyric']  
  27.     return lyric  
  28.   
  29. def get_details(song_id):  
  30.     url = 'http://music.163.com/api/song/detail/?' + 'id=' + str(song_id) + '&ids=%5B' + str(song_id) + '%5D'  
  31.     html = get_html(url)  
  32.     print(html)  
  33.     json_obj = json.loads(html)  
  34.     song_name = json_obj['songs'][0]['name']  
  35.     song_artist = json_obj['songs'][0]['artists'][0]['name']  
  36.     return song_name,song_artist  
  37.   
  38. def output_file(song_id):  
  39.     song_name,song_artist = get_details(song_id)  
  40.     lyric = get_lyric(song_id)  
  41.     file_name = song_name + ' - ' + song_artist + '.lrc'  
  42.     #替换歌曲名中的斜杠  
  43.     file_name = file_name.replace('/','/')  
  44.     file = open(file_name,"w+",encoding="utf-8")  
  45.     file.writelines(lyric)  
  46.     file.close()  
  47.   
  48. url = "https://music.163.com/album?id=2817001"  
  49. id_list = get_songlist(url)  
  50. print(id_list)  
  51.   
  52. for iterm in id_list:  
  53.     output_file(iterm)  

抓取歌单中的歌曲信息,获得id spider.py

More...

Oct. 20, 2018

我与Esport S8四分之一决赛后 【有的人不配赢】

首先恭喜IG击败LCK头号种子KT,打入四强。

然后,让我们用最饱满的热情恭喜夺冠热门RNG喜提八强,提前回家。

怎么说呢,IG赢KT我的确想到过,但是没有想到IG怎么做才能打赢KT。我曾经想过如果IG能赢KT我要吹IG一辈子,因为今天不仅是S8的四分之一决赛日,也是我的18岁生日。那么现在就是我兑现诺言的时候了。

More...

Oct. 3, 2018

使用Calibre制作书籍目录 Kindle上阅读是章节名始终固定在第一个的问题

最近遇到了几首很好听的歌曲,为了方便,就打算将歌词编辑出来放到Kindle。大概的步骤是先在Word上排好。然后用Calibre转换成Kindle能识别的格式。最初效果很好,抱着Kindle唱歌感觉非常有B格。后来同学也让我查几首歌的歌词放上去,这样歌曲从原来的两三首增加到八首,这样一页一页的翻找就比较费力,于是乎我用Calibre编辑功能为它自动生成了目录,一切和想象中的一样顺利,但是选择目录时却遇到了一件尴尬的事:

More...

Oct. 1, 2018

感冒中度过的混乱的一周

秋凉猛袭,世界似乎在一夜之间变得萧索了,早上出门,迎面而来的是阵阵凉意。夏和秋的分界线变得格外清晰,只是一个晚上,寒流就横扫大地,劫掠走夏天的最后几丝热量,然后君临天下,好不壮阔。接下来,便是阴雨、落叶和阴雨。

More...

Aug. 24, 2018

最后的吟唱

我在忙最后一件事,这几天一直在采购东西,为这最后一件事。

一块2.5寸机械硬盘,已经无力回天,但是控制电路和电机都能用的硬盘。把它拆开,可以看到光洁的盘片,通上电还能盘片还能转动,磁头也能动。浓浓的机械的美感。

More...

Aug. 9, 2018

用Python为树莓派制作一个GPIO控制的音乐播放器

话说最近真是干啥啥不行。

先说背景

手机被收了,只能用树莓派听歌,不过我的派并没有配屏幕……所以最初的方法是:打开电脑->连上VNC->打开树莓派的浏览器访问网易云,虽然能听,但是切歌、调音量都得通过电脑调,很麻烦,而且开着Chromium树莓派发热恐怖。

More...

Jul. 27, 2018

制作Arduino 超声波雷达

关于这个用Arduino做超声波雷达的项目,我在Create Arduino上见过很多次,这里就自己做出来试试。 主要原理是利用超声波测距,然后使用Processing在屏幕上绘制出雷达图,总体比较简单。

成品

More...

Jul. 26, 2018

《我不是药神》的美中不足和国产电影

作为国产片中难得一见的高分电影,《我不是药神》可谓获誉无数。接着出门旅游晚上的空闲,在当地一家影院观赏了这部作品。

一说到国产电影,我对看《让子弹飞》时那种被强行喂屎一般的感觉还让我心有余悸,对国产电影一直敬而远之,不知从什么时候开始,“国产电影”就和“烂片”定下了不解之缘。《我不是药神》总算动摇了这段孽缘。因为我已很久没有看电影了,加上之前在网络上已经看过很多关于《我不是药神》的影评,即使处处小心也被剧透得差不多了,所以这里就不再在演员演技或其他方面说太多了,我和大部分人的观点基本一致。写这篇文章是为了说说《我不是药神》美中不足的一点。

More...