日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

javafx音乐播放器----歌词同步实时显示(包含获取酷我歌词方式,歌词同步方法)

發布時間:2023/12/29 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javafx音乐播放器----歌词同步实时显示(包含获取酷我歌词方式,歌词同步方法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 首先我是爬蟲獲取的酷我的音源,因此歌詞也是通過爬蟲獲取的,下面這個方法可以獲取到歌曲對應的歌詞信息。簡單說下,在搜索歌曲之后會返回一個歌曲列表,查看源代碼是包含在li標簽里面的,這個li標簽里面就有請求播放頁面的地址,拿到這個地址請求單個歌曲頁面播放的時候響應的html里面的js就包含了歌詞信息,然后大致是var lrcList = [{"time": "1.8","lineLyric": "九張機-(網劇《雙世寵妃》主題曲) - 葉炫清 "}這種格式的,我將每一時間段歌詞轉換為KuwoLyric對象:
public List<KuwoLyric> getLyric(KuwoLiLabel label) {String url = null;if (StringUtil.isEmpty(label.getNewPlayUrl())) {if (StringUtil.isEmpty(label.getOldPlayUrl())) {throw new MarsException("獲取不到播放頁面的url地址!");}url = label.getOldPlayUrl();} else {url = label.getNewPlayUrl();}HttpGet get = new HttpGet(url);CloseableHttpClient client = HttpClients.createDefault();CloseableHttpResponse response = null;try {response = client.execute(get);String lrcHtml = EntityUtils.toString(response.getEntity(), "utf-8");Elements elements = Jsoup.parse(lrcHtml).select("head script");Pattern pattern = Pattern.compile("\\[.*?\\]");Matcher matcher = pattern.matcher(elements.html());if (matcher.find()) {String jsonLrc = matcher.group();return JSON.parseArray(jsonLrc, KuwoLyric.class);}} catch (Exception e) {System.out.println("獲取歌詞信息出錯 對應的歌曲是:"+label.getNewMusicName());e.printStackTrace();}return null;}@AllArgsConstructor @Getter @ToString public class KuwoLyric {private String time;private String lineLyric;}
  • 獲取到了歌詞信息就是展示了,肯定是需要另外開一個線程來同步顯示歌詞的,歌詞同步采用while循環的方式:

? ? ?期間遇到問題如下

? ? ? ? ?1.歌曲停止再次播放的時候就會再開一個線程,這樣下去線程就會越來越多。解決方式是:(1)可以定義一個volatile 修飾的線程終止變量,當停止再播放的時候需要先結束之前的歌詞同步線程再啟動新線程,結束線程就改變一下停止變量就行了(有個缺點就是時效性不高,當歌詞線程還在睡眠中時是不會調到if里面去終止線程的,這時候切歌前面的歌詞同步線程并沒有關閉)。(2)采用中斷線程的操作,這樣線程會立即中斷,在捕獲到線程被中斷之后立馬結束當前線程。

? ? ? ? ?2.運行程序,切歌時內存和cpu占用率會成倍增加。經排查成倍增加是因為每次切歌我是直接調用顯示歌詞線程,因此每次切都會成倍增加,解決辦法仍然是第一個問題中方法,在每次切歌之前需要先終止之前歌詞線程。

? ? ? ? ?3.播放歌曲cpu占用率穩定,但是很高,經排查,由于我是通過while(true)一直比較當前播放時間和歌詞時間,來顯示歌詞的,所以cpu一直占用高,解決辦法是,先取出第一段歌詞,計算和當前播放時間差值,之后再使歌詞線程睡這個差值時間,之后再次進行判斷,這樣while就不會持續占用cpu資源。

?

顯示歌詞代碼如下(采用中斷操作):TextField是顯示歌詞的文本框,KuwoPojo是音樂實體類。先得到歌詞集合再遍歷每個小段歌詞對象,拿出時間和播放器的當前時間比較,當播放時間接近歌詞時間時候就顯示當前對應的歌詞。

public class LyricShowUtil {// 必須設置為volatile才能改變線程狀態public volatile boolean isStop = false;public Thread lyricThread;// enum PlayStatus {}public void readyLyric(TextField lrcText, KuwoPojo nowMusic, MediaPlayer player) {// 得到每段歌詞組成的列表List<KuwoLyric> lyric = KuwoMusic.obj.getLyric(nowMusic.getLabel());System.out.println("歌詞列表:" + lyric);lrcText.setText("**********wait**********");for (KuwoLyric kuwoLyric : lyric) {String time = kuwoLyric.getTime();while (true) {if (this.isStop) {System.out.println("**********結束歌詞顯示線程**********");return;} ;Double temp=Double.valueOf(time).doubleValue()*1000- player.getCurrentTime().toMillis();//單位是毫秒ms// 設置歌詞顯示精度if ( temp< 0.1) {System.out.println("======顯示歌詞" + Double.valueOf(time).doubleValue() + " "+ player.getCurrentTime().toSeconds());System.out.println(lrcText + " " + kuwoLyric + " " + kuwoLyric.getLineLyric());lrcText.setText(kuwoLyric.getLineLyric());break;}else {try {TimeUnit.MILLISECONDS.sleep(temp.longValue());} catch (InterruptedException e) {System.out.println("歌詞顯示線程readyLyric出錯");e.printStackTrace();}}}}}public void showLyricInfo(TextField lrcText, KuwoPojo nowMusic, MediaPlayer player) {// 之前可能中斷過線程,因此每次調用需要重新設值this.isStop = false;lyricThread = new Thread(() -> {try {readyLyric(lrcText, nowMusic, player);} catch (InterruptedException e) {System.out.println("歌詞顯示線程被中斷 " + e.getMessage());return;}}, "歌詞展示線程");lyricThread.start();} }

點擊播放按鈕觸發的方法如下:該方法在Controller里面,selectMusic是當前選中的音樂,nowMusic是當前播放的音樂,player是MediaPlayer對象。

public void play(ActionEvent event) {if (player!=null&&selectMusic == nowMusic) {// 暫停/停止 再播放同一首歌的時候if (player.getStatus().toString().equals("STOPPED")) {//停止再播放 同一首歌lyricShowUtil.lyricThread.interrupt();// 停止之前歌詞同步線程lyricShowUtil.showLyricInfo(lrcText, nowMusic, player);}else {//暫停-->播放System.out.println("暫停---》播放");}} if (player == null||selectMusic!=nowMusic) {// 第一次播放的時候 or 切歌,播放當前選中的歌曲if (player==null) {lyricShowUtil = new LyricShowUtil();}else {lyricShowUtil.lyricThread.interrupt();// 停止之前歌詞同步線程player.dispose();}// 獲取當前選中的labelnowMusic = musicList.getSelectionModel().getSelectedItem();Media media = new Media(nowMusic.getMp3PlayUrl());player = new MediaPlayer(media);System.out.println("====正在播放=======" + nowMusic);lyricShowUtil.showLyricInfo(lrcText, nowMusic, player);}

完整音樂播放器代碼請見github:https://github.com/MrLawrenc/MarsTools? 在music包里面有完整的音樂播放器代碼

總結

以上是生活随笔為你收集整理的javafx音乐播放器----歌词同步实时显示(包含获取酷我歌词方式,歌词同步方法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。