您的位置:首页 > 编程语言 > Java开发

Hub Player播放器 Java mp3播放器

2015-10-11 14:17 429 查看
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.player;

import java.io.File;

import java.io.IOException;

import java.net.ConnectException;

import java.net.HttpURLConnection;

import java.net.URISyntaxException;

import java.net.URL;

import java.util.Timer;

import java.util.TimerTask;

import javax.sound.sampled.AudioFormat;

import javax.sound.sampled.AudioInputStream;

import javax.sound.sampled.AudioSystem;

import javax.sound.sampled.DataLine;

import javax.sound.sampled.DataLine.Info;

import javax.sound.sampled.FloatControl;

import javax.sound.sampled.LineUnavailableException;

import javax.sound.sampled.SourceDataLine;

import javax.sound.sampled.UnsupportedAudioFileException;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import org.jaudiotagger.audio.AudioFile;

import org.jaudiotagger.audio.AudioFileIO;

import org.jaudiotagger.audio.AudioHeader;

import org.jaudiotagger.audio.exceptions.CannotReadException;

import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;

import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;

import org.jaudiotagger.tag.TagException;

import com.hubPlayer.ui.tool.TimeProgressBar;

/**

* 底层播放器,主要控制播放

*

* @date 2014-10-18

*/

public class BasicPlayer {

public SourceDataLine sourceDataLine;

private AudioInputStream audioInputStream;

public URL audio;

public boolean HTTPFlag;

public Thread playThread;

public boolean IsPause = true;// 是否停止播放状态

public boolean NeedContinue;// 当播放同一首歌曲 是否继续播放状态

public boolean IsComplete;

public boolean IsEnd;

// 检测输入流是否阻塞

private boolean IsChoke;

private Timer checkConnection;

// 音量控制

private FloatControl floatVoiceControl;

public TimeProgressBar timerProgressBar;

public synchronized void play() {

try {

// 获取网络音频输入流

if (HTTPFlag) {

try {

HttpURLConnection urlConnection = (HttpURLConnection) audio

.openConnection();

audioInputStream = AudioSystem

.getAudioInputStream(urlConnection.getInputStream());

// 用计时器监测歌曲连接状态 初始启动计时器

checkConnectionSchedule();

} catch (ConnectException e) {

// 进度条清零

timerProgressBar.cleanTimer();

// 连接超时

JOptionPane.showMessageDialog(null, "网络资源连接异常", "",

JOptionPane.PLAIN_MESSAGE);

return;

}

}

//

else

// 获取本地音频输入流

audioInputStream = AudioSystem.getAudioInputStream(audio);

// 获取音频编码格式

AudioFormat audioFormat = audioInputStream.getFormat();

// MPEG1L3转PCM_SIGNED

if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {

audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,

audioFormat.getSampleRate(), 16,

audioFormat.getChannels(),

audioFormat.getChannels() * 2,

audioFormat.getSampleRate(), false);

audioInputStream = AudioSystem.getAudioInputStream(audioFormat,

audioInputStream);

}

// 根据上面的音频格式获取输出设备信息

DataLine.Info info = new Info(SourceDataLine.class, audioFormat);

// 获取输出设备对象

sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);

// 打开输出管道

sourceDataLine.open();

// 允许此管道执行数据 I/O

sourceDataLine.start();

// 获取总音量的控件

floatVoiceControl = (FloatControl) sourceDataLine

.getControl(FloatControl.Type.MASTER_GAIN);

// 音量minValue -80 maxValue 6

// 设合适的初始音量

floatVoiceControl.setValue(-20);

byte[] buf = new byte[1024];

int onceReadDataSize = 0;

while ((onceReadDataSize = audioInputStream

.read(buf, 0, buf.length)) != -1) {

// 输入流没有阻塞

IsChoke = false;

if (IsEnd) {

return;

}

// 是否暂停

if (IsPause)

pause();

// 将数据写入混频器中 至输出端口写完前阻塞

sourceDataLine.write(buf, 0, onceReadDataSize);

// 预设输入流阻塞

IsChoke = true;

}

IsChoke = false;

// 冲刷缓冲区数据

sourceDataLine.drain();

sourceDataLine.close();

audioInputStream.close();

if (checkConnection != null) {

checkConnection.cancel();

checkConnection.purge();

checkConnection = null;

// System.out.println("EndTimeOutControl");

}

} catch (UnsupportedAudioFileException | IOException

| LineUnavailableException | InterruptedException e) {

e.printStackTrace();

}

}

public void load(URL url) {

this.audio = url;

}

public void checkConnectionSchedule() {

checkConnection = new Timer(true);

checkConnection.schedule(new TimerTask() {

// 阻塞计数

int times = 0;

@Override

public void run() {

if (IsChoke) {

times++;

// 如果检测到阻塞次数有20次

if (times == 20) {

try {

// 进度条清零

timerProgressBar.cleanTimer();

// 使playThread自然执行完

IsEnd = false;

// 输入流关闭

audioInputStream.close();

JOptionPane.showMessageDialog(null, "连接异常中断", "",

JOptionPane.PLAIN_MESSAGE);

} catch (Exception e) {

e.printStackTrace();

}

}

} else

times = 0;

// System.out.println(times);

}

}, 2000, 500);

}

public synchronized void resume() {

IsPause = false;

NeedContinue = false;

this.notify();

}

private synchronized void pause() throws InterruptedException {

NeedContinue = true;

this.wait();

}

public void end() {

try {

if (playThread == null)

return;

IsPause = true;

NeedContinue = false;

IsComplete = false;

IsEnd = true;

// 关闭当前数据输入管道

sourceDataLine.close();

audioInputStream.close();

playThread = null;

} catch (Exception e) {

System.out.println("中断播放当前歌曲");

IsPause = true;

NeedContinue = false;

IsComplete = false;

IsEnd = true;

}

}

// 获取音频文件的长度 秒数

public int getAudioTrackLength(URL url) {

try {

// 只能获得本地歌曲文件的信息

AudioFile file = AudioFileIO.read(new File(url.toURI()));

// 获取音频文件的头信息

AudioHeader audioHeader = file.getAudioHeader();

// 文件长度 转换成时间

return audioHeader.getTrackLength();

} catch (CannotReadException | IOException | TagException

| ReadOnlyFileException | InvalidAudioFrameException

| URISyntaxException e) {

e.printStackTrace();

return -1;

}

}

public String getAudioTotalTime(int sec) {

String time = "0:00";

if (sec <= 0)

return time;

int minute = sec / 60;

int second = sec % 60;

int hour = minute / 60;

if (second < 10)

time = minute + ":0" + second;

else

time = minute + ":" + second;

if (hour != 0)

time = hour + ":" + time;

return time;

}

public SourceDataLine getSourceDataLine() {

return sourceDataLine;

}

public FloatControl getFloatControl() {

return floatVoiceControl;

}

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.player;

import java.io.File;

import java.net.MalformedURLException;

import java.net.URL;

import javax.swing.JButton;

import javax.swing.JLabel;

import javax.swing.JOptionPane;

import javax.swing.JTree;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.TreeNode;

import javax.swing.tree.TreePath;

import com.hubPlayer.song.SongNode;

import com.hubPlayer.ui.tool.TimeProgressBar;

/**

* 高层播放器 主要控制与外部信息交互

*

* @date 2014-10-18

*/

public class HigherPlayer extends BasicPlayer {

private JTree tree;

private SongNode loadSong;

private SongNode playingSong;

private String loadSongName;// 与loadSong对应

private String playingSongName;// 与playedSong对应

// 当前播放歌曲所在的目录

private TreePath currentListPath;

private JButton play;

private JLabel songNameLabel;

private JLabel audioTotalTimeLabel;

// 播放模式

public int mode;

public boolean IsPlayNextSong;

// 当前音频的总时间

public int audioTotalTime;

public HigherPlayer() {

}

// 本地资源

public void load(TreeNode node) {

this.loadSong = (SongNode) node;

DefaultMutableTreeNode mutablenode = (DefaultMutableTreeNode) node;

File songFile = (File) mutablenode.getUserObject();

loadSongName = songFile.getName();

try {

audio = songFile.toURI().toURL();

this.HTTPFlag = false;

} catch (MalformedURLException e) {

e.printStackTrace();

}

}

// 网络资源

public void load(SongNode song, String dataURL) {

try {

if (dataURL==null || dataURL.length() == 0) {

JOptionPane.showMessageDialog(null, "没有找到歌曲资源链接地址", "",

JOptionPane.PLAIN_MESSAGE);

loadSongName = null;

return;

}

loadSongName = song.toString();

loadSong = song;

audio = new URL(dataURL);

this.HTTPFlag = true;

} catch (MalformedURLException e) {

e.printStackTrace();

}

}

public void open() {

playingSongName = loadSongName;

playingSong = loadSong;

IsComplete = false;

// 网络资源播放时间

if (playingSong.getHTTPFlag())

audioTotalTime = playingSong.getTotalTime();

// 本地资源播放时间

else

audioTotalTime = getAudioTrackLength(audio);

audioTotalTimeLabel.setText(getAudioTotalTime(audioTotalTime));

// 重置计时器

timerProgressBar.cleanTimer();

// 启动新的计时器

timerProgressBar.setAudioTotalTime(audioTotalTime);

timerProgressBar.setCurrentPlayedSongLrcInfo(playingSong.getLrcInfo());

timerProgressBar.startTimer();

// 因为要与播放面板交互 所以让监听歌曲状态的线程在高层播放器初始化

playThread = new Thread(() -> {

// 播放结束前, 线程在此阻塞 不能解码的歌曲 这不阻塞

super.play();

if (IsEnd) {

IsEnd = false;

return;

}

// 播放结束 play按钮显示"播放"状态

play.doClick();

// 播放模式决定接着进行地播放

playSwitch();

});

playThread.start();

}

private void playSwitch() {

IsComplete = true;

// 初始化播放状态

switch (mode) {

// 单曲播放

case 0:

return;

// 单曲循环

case 1:

break;

// 顺序播放 当触发播放按钮时,因为要播放新歌曲 所以进入

// if(!player.getAfterSong().equals(player.getCurrentSong())) {}

// 使得当前线程被终止,往下的播放操作被终止

case 2:

IsPlayNextSong = true;

next();

break;

// 列表播放 情况同顺序播放

case 3:

cycle();

break;

// 随机播放 情况同顺序播放

case 4:

random();

break;

}

play.doClick();

}

// 接着进行地播放

public void next() {

DefaultMutableTreeNode list = (DefaultMutableTreeNode) playingSong

.getParent();

SongNode songNode = null;

if (!IsPlayNextSong) {

songNode = (SongNode) list.getChildBefore(playingSong);

} else {

songNode = (SongNode) list.getChildAfter(playingSong);

}

if (songNode == null) {

IsPause = false;

return;

}

// 在当前所在的歌曲列表路径中加入待播放的歌曲 形成待播放歌曲的路径

TreePath songPath = currentListPath.pathByAddingChild(songNode);

tree.setSelectionPath(songPath);

if (songNode.getHTTPFlag())

load(songNode, songNode.getDataURL());

else

load(songNode);

}

// 列表循环播放

private void cycle() {

DefaultMutableTreeNode list = (DefaultMutableTreeNode) playingSong

.getParent();

SongNode songNode = null;

songNode = (SongNode) list.getChildAfter(playingSong);

if (songNode == null) {

songNode = (SongNode) list.getFirstChild();

}

// 在当前所在的歌曲列表路径中加入待播放的歌曲 形成待播放歌曲的路径

TreePath songPath = currentListPath.pathByAddingChild(songNode);

tree.setSelectionPath(songPath);

if (songNode.getHTTPFlag())

load(songNode, songNode.getDataURL());

else

load(songNode);

}

// 随机播放

private void random() {

DefaultMutableTreeNode list = (DefaultMutableTreeNode) playingSong

.getParent();

int songnum = list.getChildCount();

// 随机歌曲

int songindex = (int) Math.round(Math.random() * songnum) - 1;

if (songindex < 0)

songindex = 0;

SongNode songNode = (SongNode) list.getChildAt(songindex);

// 在当前所在的歌曲列表路径中加入待播放的歌曲 形成待播放歌曲的路径

TreePath songPath = currentListPath.pathByAddingChild(songNode);

tree.setSelectionPath(songPath);

if (songNode.getHTTPFlag())

load(songNode, songNode.getDataURL());

else

load(songNode);

}

// 提供网络资源加入列表及播放的接口

public void setSelectTreeNodeInCurrentList(SongNode songNode, String dataURL) {

TreePath songPath = currentListPath.pathByAddingChild(songNode);

tree.setSelectionPath(songPath);

load(songNode, dataURL);

}

public void end() {

super.end();

timerProgressBar.cleanTimer();

}

public TreeNode getloadSong() {

return loadSong;

}

public TreeNode getPlayingSong() {

return playingSong;

}

public String getPlayingSongName() {

return playingSongName;

}

public void setPlayingSongName(String song) {

playingSongName = song;

}

public String getLoadSongName() {

return loadSongName;

}

public JButton getPlayButton() {

return play;

}

public void setPlayButton(JButton button) {

this.play = button;

}

public void setCurrentListPath(TreePath currentListPath) {

this.currentListPath = currentListPath;

}

public void setJTree(JTree tree) {

this.tree = tree;

}

public JTree getJTree() {

return this.tree;

}

public JLabel getSongNameLabel() {

return songNameLabel;

}

public void setSongNameLabel(JLabel songNameLabel) {

this.songNameLabel = songNameLabel;

}

public void setVoiceValue(float voiceValue) {

super.getFloatControl().setValue(voiceValue);

}

public float getVoiceValue() {

return getFloatControl().getValue();

}

public void setAudioTotalTimeLabel(JLabel label) {

audioTotalTimeLabel = label;

}

public void setCurrentTimeCountLabel(JLabel label) {

}

public void setTimerProgressBar(TimeProgressBar timerProgressBar) {

this.timerProgressBar = timerProgressBar;

}

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.search;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Vector;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

import javax.swing.JOptionPane;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

import com.hubPlayer.song.SongInfos;

/**

* 利用JSoup解析百度音乐 从中得到搜索的歌曲信息(SongInfos)

*

* @date 2014-11-06

*/

public class SearchSong {

// http://music.baidu.com/search/song?s=1&key=key&start=00&size=20
// 上面是百度音乐搜索地址形式, key是关键字,start是以库中的第几条歌曲开始,size为页面显示的歌曲数目(最大为20)

// 搜索地址及网页编码集 百度音乐是以utf-8编码

private static final String baseUrl = "http://music.baidu.com";

private String encode = "utf-8";

// 歌曲集合

private Map<String, List<SongInfos>> songLibraryMap;

private int songNumber;

// 与搜索和展示面板交互

private String key;

private int start;

private int page;

// boolean flag;

public SearchSong() {

// songLibraryMap = new HashMap<String, List<SongInfos>>();

// 第一页

page = 1;

// 第一首歌序号

start = 0;

songNumber =20;

}

/**

* 打开搜索地址,获取HTML

*/

public boolean openConnection() {

if (key == null)

return false;

// 拼接搜索地址

String searchUrl = "";

if ("百度音乐新歌榜/月榜".equals(key)) {

// 百度音乐新歌榜/月榜地址

searchUrl = "http://music.baidu.com/top/new/month/";

} else {

String keyEncode = "";

// 将key关键字转成URL编码

try {

keyEncode = URLEncoder.encode(key, encode);

} catch (UnsupportedEncodingException e1) {

e1.printStackTrace();

}

searchUrl = baseUrl + "/search/song?s=1&key=" + keyEncode

+ "&start=" + start + "&size=20";

}

try {

// 打开链接,获取HTML文 档

// 功能用URLConnection一样,下面被注释了的代码

Document document = Jsoup.connect(searchUrl).get();

parseHtml(document);

// // 打开连接

// URLConnection connection = new URL(searchUrl).openConnection();

//

//

// // 打开输入流

// BufferedReader reader = new BufferedReader(new InputStreamReader(

// connection.getInputStream(), encode));

//

// // 获取HTML

// StringBuffer stringbuffer = new StringBuffer();

// String line;

// while ((line = reader.readLine()) != null) {

// stringbuffer.append(line + "\n");

// }

return true;

} catch (IOException e) {

e.printStackTrace();

JOptionPane.showMessageDialog(null, "网络连接超时", "",

JOptionPane.PLAIN_MESSAGE);

return false;

}

}

/**

* 解析HTML 获取信息:歌曲、歌手、专辑名及歌曲所在的地址

*

* @param document

* HTML文档

*/

private void parseHtml(Document document) {

// 获取HTML中的歌曲列表区域块

// 获取搜索歌曲数目

songNumber = 20;

Element e = document.select("span[class=number]").first();

if (e != null) {

String number = e.text();

songNumber = Integer.parseInt(number);

}

// 每个歌曲的区域块

Elements songDiv = null;

// 新歌榜 的关键字不一样

if ("百度音乐新歌榜/月榜".equals(key))

songDiv = document.select("div[class=song-item]");

else

songDiv = document.select("div[class^=song-item clearfix]");

List<SongInfos> temporaryList = new Vector<SongInfos>();

// 遍历每个歌曲块

for (Element aSongNode : songDiv) {

// 选择class等于以song-title开头的span标签

Element songTitle = aSongNode.select("span[class^=song-title]")

.first().select("a[href^=/song]").first();

if (songTitle == null)

continue;

// 获取歌曲所在的绝对地址

String songUrl = songTitle.attr("abs:href");

// 获取歌曲名

String songName = songTitle.text();

// 搜索列表保存歌曲信息

temporaryList.add(getSongInfos(songName, songUrl));

}

if (songLibraryMap.get(key) == null)

songLibraryMap.put(key, temporaryList);

else

songLibraryMap.get(key).addAll(temporaryList);

}

// 深度爬取歌曲信息

private SongInfos getSongInfos(String songName, String songUrl) {

SongInfos songInfos = new SongInfos(songName);

try {

// 打开歌曲链接,获取其HTML代码

Document document = Jsoup.connect(songUrl).get();

// 歌曲资源地址

// 格式 http://music.baidu.com/song/7319923
// String songID = songUrl.substring(28, songUrl.length());

// String dataUrl =

// "http://music.baidu.com/data/music/file?link=&song_id="

// + songID;

// 歌手名

String singer = "";

Element SingerElement = document.select("span[class^=author_list]")

.first();

if (SingerElement != null) {

singer = SingerElement.text();

// 如果歌手名格式形如"x1/x2"则转成"x1、x2"

if (singer.contains("/")) {

String[] singers = singer.split("/");

singer = "";

for (String s : singers) {

singer = singer + "、" + s;

}

singer = singer.substring(1);

}

}

// 获取专辑信息 格式-所属专辑:album

String album = "";

Element albumElement = document.select("li[class^=clearfix]")

.first();

if (albumElement != null)

album = albumElement.text();

// 去除"所属专辑:"

if (album.length() >= 5)

album = album.substring(5);

searchDataURL(songInfos, singer, songName);

// 百度音乐改版 此节点已经找不到

// 获取其下载链接,在下载页面获取不到这个地址

// String downloadUrl = "";

// Element downloadElement = document.select("a[data_url]").first();

// if (downloadElement != null)

// downloadUrl = downloadElement.attr("data_url");

// if (!flag) {

// findDataUrl("陈奕迅", "苦瓜");

// flag = true;

// }

// 百度音乐改版 此节点已经找不到

// // 获取歌曲文件长度

// int dataSize = 0;

// // 播放时长

// int totalTime = 0;

//

// Element dataSizeElement =

// document.select("a[data_size]").first();

// if (dataSizeElement != null) {

// // 大概的时间

// String size = dataSizeElement.attr("data_size");

// dataSize = Integer.parseInt(size);

// totalTime = dataSize * 8 / songInfos.getBitRate();

// }

// 获取歌词文件地址

String lrcUrl = "";

Element lrcUrlElement = document.select("a[data-lyricdata]")

.first();

if (lrcUrlElement != null) {

lrcUrl = lrcUrlElement.attr("data-lyricdata");

// 正则匹配

Pattern pattern = Pattern.compile("(/.*\\.lrc)");

Matcher matcher = pattern.matcher(lrcUrl);

if (matcher.find())

lrcUrl = baseUrl + matcher.group();

else

lrcUrl = "";

}

// 保存歌曲信息

songInfos.setSinger(singer);

songInfos.setAlbum(album);

songInfos.setLrcUrl(lrcUrl);

// System.out.println("--------A song item--------");

// System.out.println("song: " + songName + " singer: " + singer

// + " album: " + songInfos.getAlbum() + " dataSize: "

// + songInfos.getDataSize() + " bitRate: "

// + songInfos.getBitRate());

// System.out.println("songDataUrl: " + songInfos.getSongDataUrl());

// System.out.println("lrcUrl: " + songInfos.getLrcUrl());

// System.out.println("---------------------------");

} catch (IOException e) {

e.printStackTrace();

// JOptionPane.showMessageDialog(null, "歌曲地址: " + songUrl +

// "\n歌曲名: "

// + songName + " 读取数据异常", "", JOptionPane.PLAIN_MESSAGE);

}

return songInfos;

}

/**

* 由于受百度音乐改版的影响,这里不直接去获取歌曲资源地址和文件总字节数 百度音乐用了登陆和JS加密这个地址

* 我们用百度音乐盒http://box.zhangmen.baidu.com/的xml文件间接获取

*

*

*/

private void searchDataURL(SongInfos songInfos, String singer, String song) {

String songBoxUrl = "http://box.zhangmen.baidu.com/x?op=12&count=1&title="

+ song + "$$" + singer + "$$";

Document document = null;

try {

document = Jsoup.connect(songBoxUrl).get();

} catch (IOException e) {

e.printStackTrace();

return;

}

/**

* 提取durl节点中的encode节点的字符串与decode节点的字符串拼接歌曲资源地址

**/

String dataUrl = "";

Elements durlNodes = document.select("durl");

for (Element durlNode : durlNodes) {

Element encode = durlNode.select("encode").first();

Element decode = durlNode.select("decode").first();

if (encode == null || decode == null)

continue;

String encodeText = encode.text();

String decodeText = decode.text();

encodeText = encodeText.substring(0,

encodeText.lastIndexOf("/") + 1);

dataUrl = encodeText + decodeText;

}

/**

* 获取歌曲文件长度和比特率

**/

int dataSize = 0;

int totalTime = 0;

Element p2p = document.select("p2p").first();

if (p2p != null) {

// 文件总字节数

String dataSizeText = p2p.select("size").first().text();

// 比特率

int bitRate = Integer.parseInt(p2p.select("bitrate").text()) * 1000;

dataSize = Integer.parseInt(dataSizeText);

totalTime = dataSize * 8 / bitRate;

songInfos.setBitRate(bitRate);

}

songInfos.setSongDataUrl(dataUrl);

songInfos.setDataSize(dataSize);

songInfos.setTotalTime(totalTime);

}

/**

* 清除已解析的歌曲信息等

*/

public void clear() {

start = 0;

key = "";

page = 1;

songNumber = 20;

}

/**

* 设置搜索的关键字 之后需调用search方法进行搜索

*

* @param key

* 关键字

* @return SearchSong this

*/

public SearchSong setKey(String key) {

this.key = key;

return this;

}

public String getKey() {

return key;

}

/**

* 设置当前页面

*

* @param start

* 设置当前页面第一首歌曲在库中的序号,

* @return SearchSong this

*/

public SearchSong setPage(int page) {

this.page = page;

start = (page - 1) * 20;

return this;

}

// 设置页面

public int getPage() {

return page;

}

public void setSongLibraryMap(Map<String, List<SongInfos>> songLibraryMap) {

this.songLibraryMap = songLibraryMap;

}

public int getSongNumber() {

return songNumber;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.search;

import java.io.Serializable;

import java.util.HashMap;

/**

* 歌曲库集合 保存到本地

*

* @param <V>

* String searchKey

* @param <K>

* List<SongInfos> songList

*

* @date 2014-12-6

*/

public class SongLibraryMap<K, V> extends HashMap<K, V> implements Serializable {

// 歌曲缓存时间

private Long bufferedDatetime;

public long getBufferedDateTime() {

return bufferedDatetime;

}

public void setBufferedDateTime(long bufferedDatetime) {

this.bufferedDatetime = bufferedDatetime;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.song;

import java.io.File;

import java.io.FileFilter;

import java.util.StringTokenizer;

/**

* AFilter 过滤器 歌曲类型 MP3 WAV MID 歌词类型 LRC

*

* @date 2014-10-15

*/

public class AFilter implements FileFilter {

private String description;

public AFilter(String description) {

this.description = description;

}

public boolean accept(File f) {

String name = f.getName();

StringTokenizer token = new StringTokenizer(description, ",;");

while (token.hasMoreTokens()) {

if (name.toLowerCase().endsWith(token.nextToken().toLowerCase()))

return true;

}

return false;

}

public String getDescription() {

return description;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.song;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/**

* 歌词信息:标题/歌手/专辑/时间-歌词文本组

*

* @date 2014-10-31

*/

public class LrcInfos {

private String title;

private String singer;

private String album;

private int totalTime;

private List<Integer> timeList;

private Map<Integer, String> infos;

private String regex;

private Pattern pattern;

public LrcInfos() {

infos = new HashMap<Integer, String>();

timeList = new ArrayList<Integer>();

regex = "\\[\\d{2}:\\d{2}\\.\\d{2}\\]";

pattern = Pattern.compile(regex);

}

// 读入本地歌词文件

public void read(File file) {

try {

BufferedReader reader = new BufferedReader(new InputStreamReader(

new FileInputStream(file), "utf-8"));

String line = "";

while ((line = reader.readLine()) != null) {

match(line);

}

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

// 读入网络资源

public void read(String lrcUrl) {

try {

HttpURLConnection urlConnection = (HttpURLConnection) new URL(

lrcUrl).openConnection();

BufferedReader reader = new BufferedReader(new InputStreamReader(

urlConnection.getInputStream(), "utf-8"));

String line = "";

while ((line = reader.readLine()) != null) {

match(line);

}

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

// 匹配一行字符

private void match(String line) {

// 判断当前行是否为歌手、标题、专辑 不是 满足

if (!line.endsWith("]")) {

// 匹配当前的时间格式

Matcher matcher = pattern.matcher(line);

int endIndex = 0;

// 满足则

while (matcher.find()) {

// 获取内容

String group = matcher.group();

group = group.substring(1, group.length() - 1);

timeList.add(toCurrentTime(group));

endIndex = matcher.end();

}

String strInfos = line.substring(endIndex, line.length());

timeList.forEach(each -> infos.put(each, strInfos));

timeList.clear();

} else if (line.startsWith("[ti:")) {

title = line.substring(4, line.length() - 1);

} else if (line.startsWith("[ar:")) {

singer = line.substring(4, line.length() - 1);

} else if (line.startsWith("[al:")) {

album = line.substring(4, line.length() - 1);

}

}

// 解析当前信息时间 秒制

private int toCurrentTime(String time) {

int currentTime = 0;

String[] spliter = time.split(":");

currentTime += Integer.parseInt(spliter[0]) * 60;

spliter = spliter[1].split("\\.");

currentTime += Integer.parseInt(spliter[0]);

if (Integer.parseInt(spliter[1]) >= 50)

currentTime++;

if (totalTime < currentTime)

totalTime = currentTime;

return currentTime;

}

public String getTitle() {

return title;

}

public String getSinger() {

return singer;

}

public String getAlbum() {

return album;

}

public int getTotalTime() {

return totalTime;

}

public Map<Integer, String> getInfos() {

return infos;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.song;

import java.io.Serializable;

/**

* 网络爬取得 歌曲信息:歌曲名、歌手、专辑、播放时间、歌词地址、资源地址

*

* @date 2014-11-06

*/

public class SongInfos implements Serializable{

private String song;

private String singer;

private String album;

// 时间=文件长度/比特率*8

private int totalTime;

private int dataSize;

private String songDataUrl;

private String lrcUrl;

// 大概的比特率

private int bitRate;

public SongInfos(String song) {

this.song = song;

totalTime = 0;

lrcUrl = "";

bitRate = 128000;

}

public SongInfos(String song, String singer) {

this(song);

this.singer = singer;

}

public SongInfos(String song, String singer, String album) {

this(song, singer);

this.album = album;

}

public SongInfos(String song, String singer, String album,

String songDataUrl) {

this(song, singer, album);

this.songDataUrl = songDataUrl;

}

public String getSong() {

return song;

}

public void setSong(String song) {

this.song = song;

}

public String getAlbum() {

return album;

}

public void setAlbum(String album) {

this.album = album;

}

public String getSinger() {

return singer;

}

public void setSinger(String singer) {

this.singer = singer;

}

public String getSongDataUrl() {

return songDataUrl;

}

public void setSongDataUrl(String songDataUrl) {

this.songDataUrl = songDataUrl;

}

public int getTotalTime() {

return totalTime;

}

public void setTotalTime(int totalTime) {

this.totalTime = totalTime;

}

public String getLrcUrl() {

return lrcUrl;

}

public void setLrcUrl(String lrcUrl) {

this.lrcUrl = lrcUrl;

}

public int getBitRate() {

return bitRate;

}

public void setBitRate(int bitRate) {

this.bitRate = bitRate;

}

public int getDataSize() {

return dataSize;

}

public void setDataSize(int dataSize) {

this.dataSize = dataSize;

}

public String toString() {

return "Song: " + song + " Singer: " + singer + " Album: " + album

+ "\ndownload URL: " + songDataUrl;

}

public boolean equals(Object object) {

if (this == object)

return true;

if (getClass() != object.getClass())

return false;

SongInfos objectSongInfos = (SongInfos) object;

if (songDataUrl == null)

return song.equals(objectSongInfos.getSong())

&& singer.equals(objectSongInfos.getSinger())

&& album.equals(objectSongInfos.getAlbum());

return songDataUrl.equals(objectSongInfos.getSongDataUrl());

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.song;

import java.io.File;

import javax.swing.tree.DefaultMutableTreeNode;

/**

* SongNode 显示歌曲名字 不显示歌曲路径

*

* @date 2014-10-15

*/

public class SongNode extends DefaultMutableTreeNode {

private File song;

private String dataUrl;

// 标记歌曲是否为网络资源

private boolean HTTPFlag;

// 播放时长

private int totalTime;

// 文件长度

private int dataSize;

// 本地与网络歌词资源

private File lrcFile;

// 解析的歌曲信息

private LrcInfos lrcInfo;

// 歌曲的上级路径

private String parentPath;

// 无扩展名的歌曲名

private String songName;

public SongNode(File song) {

super(song, false);

this.song = song;

parentPath = song.getParent();

songName = song.getName();

songName = songName.substring(0, songName.lastIndexOf("."));

File f = new File(parentPath + "\\" + songName + ".lrc");

lrcInfo = new LrcInfos();

if (f.exists()) {

lrcFile = f;

lrcInfo.read(lrcFile);

}

}

// 网络资源

public SongNode(String songName, int totalTime, int dataSize,

String lrcUrl, String dataUrl) {

try {

song = new File(dataUrl);

} catch (NullPointerException e) {

song = null;

}

this.dataUrl = dataUrl;

this.songName = songName;

this.dataSize = dataSize;

HTTPFlag = true;

// 大概的播放时间 真正播放时长大概是算出的时间-3

this.totalTime = totalTime - 3;

lrcInfo = new LrcInfos();

// 存在歌曲链接

if (lrcUrl.length() > 0) {

lrcInfo.read(lrcUrl);

// 利用歌词来得到精确的播放时间

int time = lrcInfo.getTotalTime();

if (this.totalTime < time) {

this.totalTime = time;

}

}

}

public int getTotalTime() {

return totalTime;

}

public void setLrc(File lrcFile) {

this.lrcFile = lrcFile;

lrcInfo.read(lrcFile);

}

public File getLrc() {

return lrcFile;

}

public LrcInfos getLrcInfo() {

return lrcInfo;

}

public String getSongName() {

return songName;

}

public File getSong() {

return song;

}

public String getDataURL() {

return dataUrl;

}

public boolean getHTTPFlag() {

return HTTPFlag;

}

public int getDataSize() {

return dataSize;

}

@Override

public String toString() {

if (HTTPFlag)

return songName + ".mp3";

return song.getName();

}

public boolean equals(Object object) {

if (this == object)

return true;

if (object == null)

return false;

if (getClass() != object.getClass())

return false;

if (song == null)

return false;

SongNode objectNode = (SongNode) object;

return song.equals(objectNode.getSong());

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui;

import java.awt.Container;

import java.awt.Dimension;

import java.awt.Point;

import java.awt.Toolkit;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.util.Date;

import java.util.List;

import javax.swing.Box;

import javax.swing.BoxLayout;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JToolBar;

import javax.swing.JTree;

import com.hubPlayer.player.HigherPlayer;

import com.hubPlayer.search.SongLibraryMap;

import com.hubPlayer.song.SongInfos;

import com.hubPlayer.ui.tool.ButtonToolBar;

import com.hubPlayer.ui.tool.IconButton;

/**

* 以 KuGou布局为框架

*

* @date 2014-10-1

*/

public class HubFrame extends JFrame {

private static final int InitialWidth;

private static final int InitialHeight;

private static final Point InitialPoint;

private static final int ChangedWidth;

private static final String savaPath;

private static final double bufferedTime;

private PlayPanel playPanel;

private PlayListPanel playListPanel;

private SearchPanel searchPanel;

private ShowPanel showPanel;

private ButtonToolBar toolBar;

private SongLibraryMap<String, List<SongInfos>> songLibrary;

static {

Dimension dime = Toolkit.getDefaultToolkit().getScreenSize();

InitialWidth = 975;

InitialHeight = 670;

ChangedWidth = 365;

InitialPoint = new Point((dime.width - InitialWidth) / 2,

(dime.height - InitialHeight) / 2);

savaPath = "E:/Hub/download";

bufferedTime = 2 * Math.pow(10, 8);

}

public HubFrame() {

setTitle("Hub");

setSize(InitialWidth, InitialHeight);

setLocation(InitialPoint);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 保存下载歌曲文件夹

File savefolder = new File(savaPath);

// 创建已下载歌曲的存储文件夹

if (!savefolder.exists())

savefolder.mkdirs();

readSongLibrary();

buildPanel();

setVisible(true);

requestFocus();

}

private void buildPanel() {

playPanel = new PlayPanel();

// ToolBar:the left of the Frame

toolBar = new ButtonToolBar(JToolBar.VERTICAL, 4);

JButton[] toolBarButtons = new JButton[] {

new IconButton("本地列表", "icon/note.png"),

new IconButton("网络收藏", "icon/clouds.png"),

new IconButton("我的下载", "icon/download.png"),

new IconButton("更多", "icon/app.png") };

toolBar.addButtons(toolBarButtons);

playListPanel = new PlayListPanel(toolBar.getButtons(), this);

searchPanel = new SearchPanel();

showPanel = new ShowPanel();

// 传递给各面板的属性

JTree[] listTree = playListPanel.deliverTree();

HigherPlayer player = playPanel.getHigherPlayer();

// 沟通播放面板与歌曲列表面板

playPanel.setTrees(listTree);

player.setJTree(listTree[0]);

playListPanel.deliverHigherPlayer(player);

// 沟通乐库面板与歌曲列表面板

showPanel.setListTree(listTree);

// 沟通搜索面板与展示面板

searchPanel.setShowPanel(showPanel);

// 沟通搜索面板与本地

searchPanel.setSongLibraryMap(songLibrary);

// 沟通播放面板与歌词面板

playPanel.setLrcPanelTextArea(showPanel.getTextArea());

// 沟通乐库面板与播放面板

showPanel.setPlayer(player);

playPanel.setParentFrame(this);

// Set the preferredSize of those panels

playPanel.setPreferredSize(new Dimension(350, 115));

playListPanel.setPreferredSize(new Dimension(305, 520));

toolBar.setPreferredSize(new Dimension(47, 520));

searchPanel.setPreferredSize(new Dimension(610, 115));

showPanel.setPreferredSize(new Dimension(610, 520));

buildLayout();

setAction();

}

private void setAction() {

// 设置最大化事件 即展开窗体

this.addWindowStateListener(event -> {

if (event.getNewState() == JFrame.MAXIMIZED_BOTH) {

searchPanel.setVisible(true);

showPanel.setVisible(true);

setSize(InitialWidth, InitialHeight);

setLocation(InitialPoint);

setVisible(true);

}

});

// 折叠窗体

searchPanel.getCollapseButton().addActionListener(event -> {

searchPanel.setVisible(false);

showPanel.setVisible(false);

setSize(ChangedWidth, InitialHeight);

setVisible(true);

});

this.addWindowListener(new WindowAdapter() {

@Override

public void windowClosing(WindowEvent e) {

saveSongLibrary();

System.exit(0);

}

});

}

private void buildLayout() {

Box topBox = Box.createHorizontalBox();

topBox.add(playPanel);

topBox.add(searchPanel);

Box bottomBox = Box.createHorizontalBox();

bottomBox.add(toolBar);

bottomBox.add(playListPanel);

bottomBox.add(showPanel);

Container mainPanel = getContentPane();

mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));

mainPanel.add(topBox);

mainPanel.add(bottomBox);

mainPanel.add(Box.createVerticalStrut(15));

}

@SuppressWarnings({ "unchecked" })

private void readSongLibrary() {

File library = new File("E:/Hub/SongLibrary.dat");

if (!library.exists()) {

songLibrary = new SongLibraryMap<String, List<SongInfos>>();

} else {

try {

ObjectInputStream inputStream = new ObjectInputStream(

new FileInputStream(library));

songLibrary = (SongLibraryMap<String, List<SongInfos>>) inputStream

.readObject();

// 歌曲库缓存超过约两天,将清除

long bufferedDateTime = songLibrary.getBufferedDateTime();

if ((new Date().getTime() - bufferedDateTime) > bufferedTime) {

songLibrary.clear();

}

inputStream.close();

} catch (IOException | ClassNotFoundException e) {

songLibrary = new SongLibraryMap<String, List<SongInfos>>();

e.printStackTrace();

}

}

}

private void saveSongLibrary() {

if (songLibrary != null) {

songLibrary.setBufferedDateTime(new Date().getTime());

try {

ObjectOutputStream outputStream = new ObjectOutputStream(

new FileOutputStream(new File("E:/Hub/SongLibrary.dat")));

outputStream.writeObject(songLibrary);

outputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui;

import java.awt.CardLayout;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import com.hubPlayer.player.HigherPlayer;

import com.hubPlayer.ui.tool.AppPanel;

import com.hubPlayer.ui.tool.SongListPanel;

/**

* 播放列表面板

*

* @date 2014-10-12

*/

public class PlayListPanel extends JPanel {

private SongListPanel songListPanel;

private SongListPanel cloudsPanel;

private SongListPanel downloadPanel;

private JScrollPane appPanel;

private JButton[] buttons;

private JFrame parent;

private CardLayout card;

public PlayListPanel(JButton[] buttons, JFrame parent) {

setOpaque(false);

card = new CardLayout();

setLayout(card);

this.buttons = buttons;

this.parent = parent;

initPanel();

}

private void initPanel() {

songListPanel = new SongListPanel("默认列表");

songListPanel.addPopupMenuToTree();

cloudsPanel = new SongListPanel("默认列表", "我喜欢");

cloudsPanel.addPopupMenuToTree();

downloadPanel = new SongListPanel("下载中", "已下载");

appPanel = new JScrollPane(new AppPanel(parent));

add(songListPanel, "0");

add(cloudsPanel, "1");

add(downloadPanel, "2");

add(appPanel, "3");

setAction();

}

private void setAction() {

for (int i = 0; i < buttons.length; i++) {

int k = i;

buttons[i].addActionListener(event -> {

card.show(this, "" + k);

});

}

}

public void deliverHigherPlayer(HigherPlayer HigherPlayer) {

songListPanel.setPlayer(HigherPlayer);

cloudsPanel.setPlayer(HigherPlayer);

downloadPanel.setPlayer(HigherPlayer);

}

public JTree[] deliverTree() {

return new JTree[] { songListPanel.getTree(), cloudsPanel.getTree(),

downloadPanel.getTree() };

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui;

import java.awt.Component;

import java.awt.Dimension;

import java.awt.event.KeyEvent;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.net.HttpURLConnection;

import javax.swing.DefaultComboBoxModel;

import javax.swing.GroupLayout;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JComboBox;

import javax.swing.JLabel;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JSlider;

import javax.swing.JTextArea;

import javax.swing.JTree;

import javax.swing.LayoutStyle;

import javax.swing.SwingConstants;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.JFrame;

import com.hubPlayer.player.HigherPlayer;

import com.hubPlayer.song.SongNode;

import com.hubPlayer.ui.tool.IconButton;

import com.hubPlayer.ui.tool.TimeProgressBar;

/*

* To change this license header, choose License Headers in Project Properties.

* To change this template file, choose Tools | Templates

* and open the template in the editor.

*/

/**

* 播放面板 使用NetBean Matisse构建.面板包含:3个标签,7个按钮,1个进度条,1个组合框和1个滑块条

*

* @date 2014-10-9

*/

public class PlayPanel extends JPanel {

/**

* Creates new form HubPlayPanel

*/

public PlayPanel() {

initComponents();

initPlayer();

}

/**

* This method is called from within the constructor to initialize the form.

* WARNING: Do NOT modify this code. The content of this method is always

* regenerated by the Form Editor.

*/

@SuppressWarnings("unchecked")

// <editor-fold defaultstate="collapsed" desc="Generated Code">

private void initComponents() {

songName = new JLabel("Music");

download = new IconButton("下载", "icon/download.png");

mark = new IconButton("我喜欢", "icon/heart.png");

share = new IconButton("分享", "icon/share.png");

timerProgressBar = new TimeProgressBar();

mode = new JComboBox<>();

backPlay = new IconButton("上一首", "icon/back.png");

play = new IconButton("播放", "icon/play.png");

play.setSelectedIcon(new ImageIcon("icon/pause.png"));

play.setDisabledSelectedIcon(new ImageIcon("icon/play.png"));

play.setMnemonic(KeyEvent.VK_ENTER);

frontPlay = new IconButton("下一首", "icon/front.png");

voiceControl = new IconButton("静音", "icon/voice.png");

voiceAdjust = new JSlider(minVoice, maxVoice);

voiceAdjust.setValue(suitableVoice);

audioTotalTimeLabel = new JLabel("4:00");

currentTimeCountLabel = new JLabel("0:00");

setOpaque(false);

setPreferredSize(new Dimension(360, 110));

download.setMaximumSize(new Dimension(3030, 3030));

download.setMinimumSize(new Dimension(30, 30));

download.setPreferredSize(new Dimension(30, 30));

mark.setPreferredSize(new Dimension(30, 30));

share.setPreferredSize(new Dimension(30, 30));

timerProgressBar.setPreferredSize(new Dimension(340, 7));

mode.setModel(new DefaultComboBoxModel(new String[] { "单曲播放", "单曲循环",

"顺序播放", "列表循环", "随机播放" }));

backPlay.setPreferredSize(new Dimension(30, 30));

play.setPreferredSize(new Dimension(30, 30));

frontPlay.setPreferredSize(new Dimension(30, 30));

voiceControl.setPreferredSize(new Dimension(30, 30));

voiceAdjust.setPreferredSize(new Dimension(50, 20));

audioTotalTimeLabel.setText("0:00");

currentTimeCountLabel.setText("0:00");

GroupLayout layout = new GroupLayout(this);

this.setLayout(layout);

layout.setHorizontalGroup(layout

.createParallelGroup(GroupLayout.Alignment.LEADING)

.addGroup(

layout.createSequentialGroup()

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.LEADING)

.addGroup(

layout.createSequentialGroup()

.addGap(12, 12,

12)

.addComponent(

songName,

GroupLayout.PREFERRED_SIZE,

230,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addComponent(

download,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addComponent(

mark,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addComponent(

share,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE))

.addGroup(

layout.createSequentialGroup()

.addGap(10, 10,

10)

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.LEADING)

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.TRAILING,

false)

.addGroup(

layout.createSequentialGroup()

.addComponent(

currentTimeCountLabel)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED,

GroupLayout.DEFAULT_SIZE,

Short.MAX_VALUE)

.addComponent(

audioTotalTimeLabel))

.addComponent(

timerProgressBar,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE))

.addGroup(

layout.createSequentialGroup()

.addComponent(

mode,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED,

33,

Short.MAX_VALUE)

.addComponent(

backPlay,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addComponent(

play,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addComponent(

frontPlay,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addGap(28,

28,

28)

.addComponent(

voiceControl,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addComponent(

voiceAdjust,

GroupLayout.PREFERRED_SIZE,

81,

GroupLayout.PREFERRED_SIZE)

.addGap(1,

1,

1)))))

.addGap(0, 7, Short.MAX_VALUE)));

layout.linkSize(SwingConstants.HORIZONTAL, new Component[] { download,

mark, share });

layout.setVerticalGroup(layout

.createParallelGroup(GroupLayout.Alignment.LEADING)

.addGroup(

layout.createSequentialGroup()

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.LEADING)

.addGroup(

layout.createSequentialGroup()

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.LEADING)

.addGroup(

layout.createSequentialGroup()

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.LEADING)

.addGroup(

layout.createSequentialGroup()

.addGap(10,

10,

10)

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.BASELINE)

.addComponent(

download,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addComponent(

mark,

GroupLayout.PREFERRED_SIZE,

20,

GroupLayout.PREFERRED_SIZE)

.addComponent(

share,

GroupLayout.PREFERRED_SIZE,

20,

GroupLayout.PREFERRED_SIZE))

.addGap(6,

6,

6))

.addGroup(

GroupLayout.Alignment.TRAILING,

layout.createSequentialGroup()

.addContainerGap()

.addComponent(

songName,

GroupLayout.PREFERRED_SIZE,

20,

GroupLayout.PREFERRED_SIZE)

.addPreferredGap(

LayoutStyle.ComponentPlacement.UNRELATED)))

.addComponent(

timerProgressBar,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE))

.addGroup(

layout.createSequentialGroup()

.addGap(55,

55,

55)

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.CENTER)

.addComponent(

currentTimeCountLabel)

.addComponent(

audioTotalTimeLabel))))

.addPreferredGap(

LayoutStyle.ComponentPlacement.RELATED)

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.CENTER)

.addComponent(

play,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addComponent(

backPlay,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addComponent(

frontPlay,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)))

.addGroup(

layout.createSequentialGroup()

.addGap(76, 76,

76)

.addComponent(

voiceControl,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE))

.addGroup(

GroupLayout.Alignment.CENTER,

layout.createSequentialGroup()

.addGap(80, 80,

80)

.addGroup(

layout.createParallelGroup(

GroupLayout.Alignment.LEADING)

.addComponent(

voiceAdjust,

GroupLayout.Alignment.CENTER,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE)

.addComponent(

mode,

GroupLayout.Alignment.CENTER,

GroupLayout.PREFERRED_SIZE,

GroupLayout.DEFAULT_SIZE,

GroupLayout.PREFERRED_SIZE))))

.addContainerGap(GroupLayout.DEFAULT_SIZE,

Short.MAX_VALUE)));

layout.linkSize(SwingConstants.VERTICAL, new Component[] { download,

mark, share });

}

private void initPlayer() {

player = new HigherPlayer();

player.setPlayButton(play);

player.setSongNameLabel(songName);

player.setAudioTotalTimeLabel(audioTotalTimeLabel);

player.setCurrentTimeCountLabel(currentTimeCountLabel);

player.setTimerProgressBar(timerProgressBar);

timerProgressBar.setTimerControl(player.IsPause);

timerProgressBar.setCurrentTimeCountLabel(currentTimeCountLabel);

setButtonsAction();

setOtherAction();

}

public HigherPlayer getHigherPlayer() {

return player;

}

public void setButtonsAction() {

// 播放 按钮

play.addActionListener(event -> {

if (player.getLoadSongName() == null) {

return;

}

// 在第一次播放时 为了不进入下面一个if判断

// 如果PlayingSongName==null时,则进入,终止当前歌曲播放,可是当前播放线程还没有实例 报异常

if (player.getPlayingSongName() == null) {

player.setPlayingSongName(player.getLoadSongName());

}

// 在播放过程切换歌曲

if (!player.getLoadSongName().equals(player.getPlayingSongName())

&& !player.IsComplete) {

// 终止当前歌曲播放

player.end();

player.setPlayingSongName(player.getLoadSongName());

}

// 是暂停 则播放

if (player.IsPause) {

if (player.NeedContinue) {

// 继续播放

player.resume();

// 进度条的控制

timerProgressBar.setTimerControl(false);

timerProgressBar.resumeTimer();

play.setIcon(play.getSelectedIcon());

play.setToolTipText("暂停");

return;

}

// 进度条的控制 不阻塞

timerProgressBar.setTimerControl(false);

// 播放歌曲

player.open();

// 声音控制

voiceAdjust.setValue(suitableVoice);

songName.setText(player.getPlayingSongName());

play.setIcon(play.getSelectedIcon());

play.setToolTipText("暂停");

player.IsPause = false;

} else {

// 是播放 则暂停

player.IsPause = true;

timerProgressBar.setTimerControl(true);

play.setIcon(play.getDisabledSelectedIcon());

play.setToolTipText("播放");

}

songName.updateUI();

play.updateUI();

parentFrame.setVisible(true);

});

//前一首按钮

backPlay.addActionListener(event -> {

if (player.getLoadSongName() == null) {

return;

}

player.IsPlayNextSong = false;

player.next();

play.doClick();

});

// 后一首按钮

frontPlay.addActionListener(event -> {

if (player.getLoadSongName() == null) {

return;

}

player.IsPlayNextSong = true;

player.next();

play.doClick();

});

//声音控制按钮

voiceControl.addActionListener(event -> {

if (!player.IsPause) {

if (voiceAdjust.getValue() != minVoice) {

player.setVoiceValue(minVoice);

voiceAdjust.setValue(minVoice);

} else {

player.setVoiceValue(suitableVoice);

voiceAdjust.setValue(suitableVoice);

}

}

});

// 下载歌曲按钮

download.addActionListener(event -> {

// 无载入歌时

if (player.getLoadSongName() == null) {

return;

}

if (!player.audio.toString().startsWith("http://")) {

JOptionPane.showMessageDialog(null, "播放中歌曲是本地资源,无需下载 ", "",

JOptionPane.PLAIN_MESSAGE);

return;

}

SongNode playedSong = (SongNode) player.getPlayingSong();

// 下载面板"下载中"列表添加播放中的歌曲

addSongNodeToTreeList(trees[2], 0, playedSong);

JOptionPane.showMessageDialog(null, "已成功添加到下载列表", null,

JOptionPane.PLAIN_MESSAGE, null);

download(playedSong);

});

// 标记按钮

mark.addActionListener(event -> {

if (player.getLoadSongName() == null) {

return;

}

SongNode playedSong = (SongNode) player.getPlayingSong();

// 加入标记列表

addSongNodeToTreeList(trees[1], 1, playedSong);

JOptionPane.showMessageDialog(null, "已成功添加到收藏列表", null,

JOptionPane.PLAIN_MESSAGE, null);

});

}

public void setOtherAction() {

timerProgressBar.addChangeListener(event -> {

});

voiceAdjust.addChangeListener(event -> {

if (!player.IsPause) {

player.setVoiceValue(voiceAdjust.getValue());

}

});

mode.addActionListener(event -> {

player.mode = mode.getSelectedIndex();

});

}

// 下载歌曲

public void download(SongNode songNode) {

new Thread(

() -> {

try {

// 打开资源链接

HttpURLConnection httpURLConnection = (HttpURLConnection) player.audio

.openConnection();

// 开启IO流 读写数据

BufferedInputStream inputStream = new BufferedInputStream(

httpURLConnection.getInputStream());

BufferedOutputStream outputStream = new BufferedOutputStream(

new FileOutputStream(new File("E:/Hub/download/"

+ player.getLoadSongName())));

byte[] buff = new byte[1024];

int onceRead = 0;

while ((onceRead = inputStream.read(buff, 0,

buff.length))!=-1) {

outputStream.write(buff, 0, onceRead);

}

outputStream.flush();

outputStream.close();

inputStream.close();

// 下载中列表移除节点

removeSongNodeInTreeList(trees[2], 0, songNode);

// 下载完成列表加入节点

addSongNodeToTreeList(trees[2], 1, songNode);

JOptionPane.showMessageDialog(null, "下载完成,文件存至E:/Hub/download",

"", JOptionPane.PLAIN_MESSAGE);

} catch (Exception e) {

e.printStackTrace();

}

}).start();

}

public void addSongNodeToTreeList(JTree tree, int index, SongNode songNode) {

DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel()

.getRoot();

DefaultMutableTreeNode list = (DefaultMutableTreeNode) root

.getChildAt(index);

list.add(songNode);

// 列表名更新

String listName = (String) list.getUserObject();

listName = listName.substring(0, listName.lastIndexOf("[")) + "["

+ list.getChildCount() + "]";

list.setUserObject(listName);

// 如果这里不更新树的话 会不正确显示

tree.updateUI();

}

public void removeSongNodeInTreeList(JTree tree, int index,

SongNode songNode) {

DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel()

.getRoot();

DefaultMutableTreeNode list = (DefaultMutableTreeNode) root

.getChildAt(index);

list.remove(songNode);

// 列表名更新

String listName = (String) list.getUserObject();

listName = listName.substring(0, listName.lastIndexOf("[")) + "["

+ list.getChildCount() + "]";

list.setUserObject(listName);

// 如果这里不更新树的话 会不正确显示

tree.updateUI();

}

public void setTrees(JTree[] trees) {

this.trees = trees;

}

public void setLrcPanelTextArea(JTextArea textArea) {

timerProgressBar.setLrcPanelTextArea(textArea);

}

public void setParentFrame(JFrame frame) {

this.parentFrame = frame;

}

// Variables declaration - do not modify

private JLabel songName;

private JButton download;

private JButton mark;

private JButton share;

private TimeProgressBar timerProgressBar;

private JLabel currentTimeCountLabel;

private JLabel audioTotalTimeLabel;

private JComboBox<String> mode;

private JButton backPlay;

private JButton play;

private JButton frontPlay;

private JSlider voiceAdjust;

private JButton voiceControl;

private JTree[] trees;

private JFrame parentFrame;

private HigherPlayer player;

// 由FloatControl.Type.MASTER_GAIN得到的数据

private final int minVoice = -80;

private final int maxVoice = 6;

private final int suitableVoice = -20;

// End of variables declaration

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui;

import java.awt.BorderLayout;

import java.awt.CardLayout;

import java.awt.Dimension;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.swing.Box;

import javax.swing.JButton;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JScrollBar;

import javax.swing.JTextField;

import javax.swing.JToolBar;

import com.hubPlayer.search.SearchSong;

import com.hubPlayer.song.SongInfos;

import com.hubPlayer.ui.tool.ButtonToolBar;

import com.hubPlayer.ui.tool.IconButton;

import com.hubPlayer.ui.tool.LibraryPanel;

import com.hubPlayer.ui.tool.LibraryTableModel;

/**

* 搜索功能面板

*

* @date 2014-10-26

*/

public class SearchPanel extends JPanel {

// 搜索功能相关

private JTextField textField;

private JButton searchButton;

// 记录前一次输入的文本

private String beforeKey;

// 解析由关键字产生的搜索网页

private SearchSong searchSong;

private Thread searchThread;

private JButton userButton;

// 主要用于切换展示面板页面

private ButtonToolBar hubToolBar;

private JButton[] toolBarButtons;

// 与展示面板相关

private ShowPanel showPanel;

private CardLayout cardLayout;

private LibraryPanel libraryPanel;

private LibraryTableModel libraryTableModel;

// 最大搜索页数

private int maxPage;

// 音乐库数据集

private Map<String, List<SongInfos>> songLibraryMap;

public SearchPanel() {

setLayout(new BorderLayout());

setOpaque(false);

init();

setAction();

createLayout();

}

private void init() {

textField = new JTextField();

textField.setPreferredSize(new Dimension(200, 30));

searchButton = new IconButton("搜索", "icon/search.png");

userButton = new IconButton("用户", "icon/user.png");

searchButton.setPreferredSize(new Dimension(50, 30));

userButton.setPreferredSize(new Dimension(50, 30));

hubToolBar = new ButtonToolBar(JToolBar.HORIZONTAL, 6);

hubToolBar.setPreferredSize(new Dimension(300, 65));

toolBarButtons = new JButton[6];

toolBarButtons[0] = new IconButton("折叠", "icon/collapse.png");

toolBarButtons[1] = new IconButton("乐库");

toolBarButtons[1].setText("乐库");

toolBarButtons[2] = new IconButton("MV");

toolBarButtons[2].setText("MV");

toolBarButtons[3] = new IconButton("歌词");

toolBarButtons[3].setText("歌词");

toolBarButtons[4] = new IconButton("电台");

toolBarButtons[4].setText("电台");

toolBarButtons[5] = new IconButton("直播");

toolBarButtons[5].setText("直播");

hubToolBar.addButtons(toolBarButtons);

searchSong = new SearchSong();

maxPage = 100;

}

private void createLayout() {

Box Box1 = Box.createHorizontalBox();

Box1.add(Box.createHorizontalStrut(10));

Box1.add(userButton);

Box1.add(Box.createHorizontalStrut(20));

Box1.add(textField);

Box1.add(Box.createHorizontalStrut(5));

Box1.add(searchButton);

Box1.add(Box.createHorizontalStrut(10));

Box Box2 = Box.createVerticalBox();

Box2.add(Box.createVerticalStrut(7));

Box2.add(Box1);

Box2.add(Box.createVerticalStrut(5));

add(Box2, BorderLayout.NORTH);

add(hubToolBar, BorderLayout.CENTER);

}

private void setAction() {

for (int i = 1; i < toolBarButtons.length; i++) {

int k = i;

toolBarButtons[i].addActionListener(event -> {

cardLayout.show(showPanel, String.valueOf(k));

});

}

searchButton.addActionListener(event -> {

String key = textField.getText();

if (!prejudgeForSearchButton(key))

return;

searchThread = new Thread(() -> {

searchForSearchButton(key);

});

searchThread.start();

});

// 初始显示百度音乐新歌

// textField.setText("百度音乐新歌榜/月榜");

// searchButton.doClick();

}

private void setMoreSearchAction(JButton moreSearch) {

moreSearch.addActionListener(event -> {

String key = textField.getText();

if (!prejudgeForMoreSearch(key))

return;

if (!key.equals(beforeKey)) {

textField.setText(beforeKey);

key = beforeKey;

}

// 判断歌曲库映射是否包含此关键字,没有则进行searchButton的搜索

if (songLibraryMap.containsKey(key)) {

int searchPage = searchSong.getPage() + 1;

if (searchPage > maxPage) {

JOptionPane.showMessageDialog(null, "已经没有更多数据", "",

JOptionPane.PLAIN_MESSAGE);

return;

}

String searchKey = key;

searchThread = new Thread(() -> {

searchForMoreSearch(searchKey, searchPage);

});

searchThread.start();

}

else {

searchButton.doClick();

}

});

}

// 计算歌曲分页

private int countPage(int songNumber) {

int page = songNumber / 20;

if (songNumber % 20 != 0)

page++;

return page;

}

// 预判搜索关键字

private boolean prejudgeForSearchButton(String key) {

if (searchThread != null && searchThread.isAlive()) {

JOptionPane.showMessageDialog(null, "正在搜索数据中,请耐心等待", "",

JOptionPane.PLAIN_MESSAGE);

return false;

}

if (key == null || key.length() == 0)

return false;

// 搜索关键字没变且不是要进行分页搜索

if (key.equals(beforeKey))

return false;

return true;

}

// 预判搜索关键字

private boolean prejudgeForMoreSearch(String key) {

// 正在搜索中

if (searchThread != null && searchThread.isAlive()) {

JOptionPane.showMessageDialog(null, "正在搜索数据中,请耐心等待", "",

JOptionPane.PLAIN_MESSAGE);

return false;

}

if (beforeKey == null || beforeKey.length() == 0)

return false;

return true;

}

// 搜索过程

private void searchForSearchButton(String key) {

// <-----------搜索数据------------>

if (!songLibraryMap.containsKey(key)) {

// 清除前次解析的信息

searchSong.clear();

// 设置关键字 进行此次解析

if (!searchSong.setKey(key).openConnection()) {

// 连接失败

beforeKey = "";

return;

}

if (songLibraryMap.containsKey(key)) {

// 获取它的上限页数

maxPage = countPage(searchSong.getSongNumber());

}

}

// <-----------数据加入表格------------>

// 表格选中数据和取消选中,是为了去掉一个Bug:在当前页面操作单元格时,当换新页时,那个被操作的单元格数据不更新

libraryPanel.getDataTable().selectAll();

// 表格数据清空

libraryTableModel.deleteTableData();

List<SongInfos> songList = songLibraryMap.get(key);

int addSongNum = songList.size();

// 更新乐库表格数据

songList.subList(0, addSongNum).forEach(

each -> libraryTableModel.updateData(each));

libraryPanel.getDataTable().clearSelection();

// 保留此次搜索的关键字

beforeKey = key;

int page = countPage(addSongNum);

searchSong.setPage(page);

}

// 搜索过程

private void searchForMoreSearch(String key, int page) {

searchSong.setPage(page);

List<SongInfos> songList = songLibraryMap.get(key);

int songNum = songList.size();

// 设置关键字 进行此次解析

if (!searchSong.setKey(key).openConnection()) {

// 连接失败

return;

}

maxPage = countPage(searchSong.getSongNumber());

songList.subList(songNum, songList.size()).forEach(

each -> libraryTableModel.updateData(each));

// libraryPanel.getTableScrollBar()

// .setValue(

// libraryPanel.getTableScrollBar().getMaximum()+1);

}

public void setShowPanel(ShowPanel showPanel) {

this.showPanel = showPanel;

this.cardLayout = (CardLayout) showPanel.getLayout();

// 沟通乐库面板与搜索歌曲信息

libraryPanel = showPanel.getLibraryPanel();

libraryTableModel = libraryPanel.getLibraryTableModel();

setMoreSearchAction(libraryPanel.getMoreSearch());

}

// HubFrame传进来的歌曲库集合

public void setSongLibraryMap(Map<String, List<SongInfos>> songLibraryMap) {

this.songLibraryMap = songLibraryMap;

searchSong.setSongLibraryMap(songLibraryMap);

}

// 折叠面板按钮

public JButton getCollapseButton() {

return toolBarButtons[0];

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui;

import java.awt.CardLayout;

import java.awt.Font;

import java.awt.GridLayout;

import java.awt.Insets;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTextArea;

import javax.swing.JTree;

import com.hubPlayer.player.HigherPlayer;

import com.hubPlayer.ui.tool.LibraryPanel;

/**

* 展示面板

*

* @date 2014-10-26

*

*/

public class ShowPanel extends JPanel {

private LibraryPanel libraryPanel;

// 歌词面板相关

private JPanel lrcPanel;

private JTextArea textArea;

// 其他面板

private JScrollPane MVPanel;

private JScrollPane radioPanel;

private JScrollPane livePanel;

public ShowPanel() {

setLayout(new CardLayout());

init();

createLayout();

}

private void init() {

libraryPanel = new LibraryPanel();

// 歌词面板处理

lrcPanel = new JPanel(new GridLayout());

textArea = new JTextArea();

// 文本域设置不可编辑、透明、左间距、自动换行

textArea.setEditable(false);

textArea.setLineWrap(true);

textArea.setMargin(new Insets(0, 175, 0, 0));

textArea.setOpaque(false);

textArea.setFont(new Font("PLAN", Font.PLAIN, 14));

lrcPanel.add(textArea);

// 其他面板

MVPanel = new JScrollPane(new JLabel("MV"));

radioPanel = new JScrollPane(new JLabel("电台"));

livePanel = new JScrollPane(new JLabel("直播"));

}

private void createLayout() {

add(libraryPanel, "1");

add(MVPanel, "2");

add(lrcPanel, "3");

add(radioPanel, "4");

add(livePanel, "5");

}

public JTextArea getTextArea() {

return textArea;

}

public LibraryPanel getLibraryPanel() {

return libraryPanel;

}

public void setListTree(JTree[] trees) {

libraryPanel.setListTree(trees);

}

public void setPlayer(HigherPlayer player) {

libraryPanel.setPlayer(player);

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import java.awt.GridLayout;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JPanel;

import com.hubPlayer.expansion.game_2048.My2048;

import com.hubPlayer.expansion.game_snake.MySnake;

import view.ChessFrame;

/**

* 拓展功能面板,为播放器增加一些游戏程序

*

* @date 2014-10-13

*

*/

public class AppPanel extends JPanel {

private JButton game2048;

private JButton gameSnake;

private JButton gameGobang;

private JFrame parent;

public AppPanel(JFrame parent) {

this.parent = parent;

setLayout(new GridLayout(3, 3));

setSize(300, 500);

addButtons();

setButtonsAction();

}

private void addButtons() {

game2048 = new IconButton("2048", "icon/item.png");

add(game2048);

gameSnake = new IconButton("贪吃蛇", "icon/item.png");

add(gameSnake);

gameGobang = new IconButton("网络五子棋", "icon/item.png");

add(gameGobang);

add(new IconButton(null, "icon/item.png"));

add(new IconButton(null, "icon/item.png"));

add(new IconButton(null, "icon/item.png"));

add(new IconButton(null, "icon/item.png"));

add(new IconButton(null, "icon/item.png"));

add(new IconButton(null, "icon/item.png"));

}

private void setButtonsAction() {

game2048.addActionListener(event -> {

new My2048(parent);

});

gameSnake.addActionListener(event -> {

new MySnake(parent);

});

gameGobang.addActionListener(event -> {

new ChessFrame(parent);

});

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import java.awt.GridLayout;

import java.awt.Insets;

import javax.swing.JButton;

import javax.swing.JToolBar;

/**

* The HubToolBar is on the left of the HubFrame. It extends JToolBar. There are

* four HubButtons (note\download\application\clouds) in the ToolBar

*

* @date 2014-10-1

*/

public class ButtonToolBar extends JToolBar {

private JButton[] buttons;

public ButtonToolBar() {

setBorderPainted(false);

setMargin(new Insets(0, 5, 5, 5));

setFloatable(false);

setOpaque(false);

setBorderPainted(false);

}

public ButtonToolBar(int orentation, int buttonNum) {

this();

setOrientation(orentation);

if (orentation == JToolBar.VERTICAL)

setLayout(new GridLayout(buttonNum, 1));

else

setLayout(new GridLayout(1, buttonNum));

}

public void addButtons(JButton[] buttons) {

this.buttons = buttons;

for (int i = 0; i < buttons.length; i++) {

add(buttons[i]);

}

}

public JButton[] getButtons() {

return buttons;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import javax.swing.ImageIcon;

import javax.swing.JButton;

/**

* 图片按钮

*

* @date 2014-10-7

*/

public class IconButton extends JButton {

public IconButton(String tip) {

setToolTipText(tip);

setBorderPainted(false);

setOpaque(false);

setContentAreaFilled(false);

}

public IconButton(String tip, String imgUrl) {

this(tip);

setIcon(new ImageIcon(imgUrl));

}

public String toString() {

return getToolTipText();

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.net.HttpURLConnection;

import java.net.URL;

import javax.swing.Box;

import javax.swing.BoxLayout;

import javax.swing.JButton;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JTable;

import javax.swing.JTree;

import javax.swing.tree.DefaultMutableTreeNode;

import com.hubPlayer.player.HigherPlayer;

import com.hubPlayer.song.SongInfos;

import com.hubPlayer.song.SongNode;

/**

* HubLibraryOperation处理外层交互 乐库数据表格中的操作面板(OperationPanel),主要包含3个按钮:播放,加到列表,下载

*

* @date 2014-11-07

*/

public class LibraryOperation {

private JTree[] trees;

// 播放器

private HigherPlayer player;

// 下载完成提示 只为第一次下载作提示

private static boolean TipFlag = true;

private final static String savePath = "E:/Hub/download";

public void setListTree(JTree[] trees) {

this.trees = trees;

}

public void setPlayer(HigherPlayer player) {

this.player = player;

}

public class OperationPanel extends JPanel {

private JButton play;

private JButton toList;

private JButton download;

private String song;

private String singer;

private String dataURL;

private SongNode songNode;

public OperationPanel() {

initComponent();

setAction();

}

// 接收歌曲信息

public OperationPanel(SongInfos songInfos) {

this();

song = songInfos.getSong();

singer = songInfos.getSinger();

dataURL = songInfos.getSongDataUrl();

songNode = new SongNode(singer + "-" + song,

songInfos.getTotalTime(), songInfos.getDataSize(),

songInfos.getLrcUrl(), dataURL);

}

private void initComponent() {

play = new IconButton("播放", "icon/note2.png");

toList = new IconButton("添加到列表", "icon/add.png");

download = new IconButton("下载", "icon/download2.png");

setLayout(new BoxLayout(this, BoxLayout.X_AXIS));

Box box = Box.createHorizontalBox();

box.add(play);

box.add(toList);

box.add(download);

add(Box.createHorizontalStrut(40));

add(box);

}

private void setAction() {

// 播放

play.addActionListener(event -> {

// 选中默认播放列表

trees[0].setSelectionRow(0);

addTreeList(trees[0], 0);

player.setSelectTreeNodeInCurrentList(songNode, dataURL);

// 播放按钮播放

player.getPlayButton().doClick();

});

// 加到播放列表

toList.addActionListener(event -> {

addTreeList(trees[0], 0);

});

// 下载

download.addActionListener(event -> {

if (dataURL == null || dataURL.length() == 0) {

JOptionPane.showMessageDialog(null, "没有找到资源相应的下载链接", "",

JOptionPane.PLAIN_MESSAGE);

return;

}

new Thread(() -> {

try {

// 打开资源链接

HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(

dataURL).openConnection();

// 开启IO流 读写数据

BufferedInputStream inputStream = new BufferedInputStream(

httpURLConnection.getInputStream());

String songName = savePath + "/" + singer + "-" + song;

if (!songName.endsWith(".mp3"))

songName += ".mp3";

BufferedOutputStream outputStream = new BufferedOutputStream(

new FileOutputStream(new File(songName)));

// 加入到下载面板 的"下载中"节点

addTreeList(trees[2], 0);

byte[] buff = new byte[1024];

int onceRead = 0;

while ((onceRead = inputStream.read(buff, 0,

buff.length)) != -1) {

outputStream.write(buff, 0, onceRead);

}

outputStream.flush();

outputStream.close();

inputStream.close();

// 移除"下载中"的歌曲信息

removeSongNodeInTreeList(trees[2], 0);

// 将歌曲信息移入"已下载"

addTreeList(trees[2], 1);

// 下载完成提示

if (TipFlag) {

JOptionPane.showMessageDialog(null, "下载完成,文件存至 "

+ savePath, "", JOptionPane.PLAIN_MESSAGE);

TipFlag = false;

}

} catch (IOException e) {

e.printStackTrace();

}

}).start();

});

}

public void addTreeList(JTree tree, int index) {

DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree

.getModel().getRoot();

DefaultMutableTreeNode list = (DefaultMutableTreeNode) root

.getChildAt(index);

list.add(songNode);

// 列表名更新

String listName = (String) list.getUserObject();

listName = listName.substring(0, listName.lastIndexOf("[")) + "["

+ list.getChildCount() + "]";

list.setUserObject(listName);

// 如果这里不更新树的话 会不正确显示

tree.updateUI();

}

public void removeSongNodeInTreeList(JTree tree, int index) {

DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree

.getModel().getRoot();

DefaultMutableTreeNode list = (DefaultMutableTreeNode) root

.getChildAt(index);

list.remove(songNode);

// 列表名更新

String listName = (String) list.getUserObject();

listName = listName.substring(0, listName.lastIndexOf("[")) + "["

+ list.getChildCount() + "]";

list.setUserObject(listName);

// 如果这里不更新树的话 会不正确显示

tree.updateUI();

}

public void setSong(String song) {

this.song = song;

}

public void setSinger(String singer) {

this.singer = singer;

}

public void setDataURL(String dataURL) {

this.dataURL = dataURL;

}

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.Component;

import java.awt.Dimension;

import javax.swing.AbstractCellEditor;

import javax.swing.BorderFactory;

import javax.swing.Box;

import javax.swing.BoxLayout;

import javax.swing.JButton;

import javax.swing.JPanel;

import javax.swing.JScrollBar;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.JToolBar;

import javax.swing.JTree;

import javax.swing.ListSelectionModel;

import javax.swing.ScrollPaneConstants;

import javax.swing.SwingConstants;

import javax.swing.table.DefaultTableCellRenderer;

import javax.swing.table.TableCellEditor;

import com.hubPlayer.player.HigherPlayer;

/*

* To change this license header, choose License Headers in Project Properties.

* To change this template file, choose Tools | Templates

* and open the template in the editor.

*/

/**

* netBean 构建 乐库面板

*

* @date 2014-11-8

*/

public class LibraryPanel extends JPanel {

/**

* Creates new form HubLibraryPanel

*/

public LibraryPanel() {

initComponents();

}

/**

* This method is called from within the constructor to initialize the form.

* WARNING: Do NOT modify this code. The content of this method is always

* regenerated by the Form Editor.

*/

@SuppressWarnings({ "unchecked", "serial" })

// <editor-fold defaultstate="collapsed" desc="Generated Code">

private void initComponents() {

aScrollPanel = new JScrollPane();

dataTable = new JTable();

libraryTableModel = new LibraryTableModel();

libraryOperation = new LibraryOperation();

aToolBar = new JToolBar();

moreSearch = new JButton();

setLayout(new BorderLayout());

aScrollPanel

.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

aScrollPanel

.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);

aScrollPanel.setMaximumSize(new Dimension(615, 481));

// 设置20行空数据

dataTable.setModel(libraryTableModel);

libraryTableModel.setLibraryOperation(libraryOperation);

// 定义"操作栏"的渲染器 显示按钮

dataTable.getColumn("操作").setCellRenderer(

new DefaultTableCellRenderer() {

@Override

public Component getTableCellRendererComponent(

JTable table, Object value, boolean isSelected,

boolean hasFocus, int row, int column) {

return value instanceof JPanel ? (JPanel) value : super

.getTableCellRendererComponent(table, value,

isSelected, hasFocus, row, column);

}

});

// 定义"操作栏"的编辑器 响应按钮事件

dataTable.getColumn("操作").setCellEditor(new CellEditor());

dataTable.setColumnSelectionAllowed(true);

dataTable.setRowHeight(23);

aScrollPanel.setViewportView(dataTable);

dataTable.getColumnModel().getSelectionModel()

.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

add(aScrollPanel, BorderLayout.CENTER);

aToolBar.setFloatable(false);

aToolBar.setRollover(true);

aToolBar.setOpaque(false);

moreSearch.setText("更多数据");

moreSearch.setFocusable(false);

moreSearch.setHorizontalTextPosition(SwingConstants.CENTER);

moreSearch.setVerticalTextPosition(SwingConstants.BOTTOM);

// moreSearch.setEnabled(false);

aToolBar.add(moreSearch);

Box box = Box.createVerticalBox();

box.setBorder(BorderFactory.createLineBorder(Color.BLACK));

box.setOpaque(true);

box.add(aToolBar);

add(box, BorderLayout.SOUTH);

}// </editor-fold>

// 传给搜索面板,用以展示搜索结果

public LibraryTableModel getLibraryTableModel() {

return libraryTableModel;

}

public JTable getDataTable() {

return dataTable;

}

public JScrollBar getTableScrollBar() {

return aScrollPanel.getVerticalScrollBar();

}

public JButton getMoreSearch() {

return moreSearch;

}

public void setListTree(JTree[] trees) {

libraryOperation.setListTree(trees);

}

public void setPlayer(HigherPlayer player) {

libraryOperation.setPlayer(player);

}

// Variables declaration - do not modify

private JScrollPane aScrollPanel;

private JTable dataTable;

private LibraryTableModel libraryTableModel;

private LibraryOperation libraryOperation;

private JToolBar aToolBar;

private JButton moreSearch;

// End of variables declaration

}

class CellEditor extends AbstractCellEditor implements TableCellEditor {

private JPanel panel;

// 当单元格从编辑状态退出时,调用此方法,将此单元渲染器的value设为这个Object,即显示这个Object

@Override

public Object getCellEditorValue() {

return panel;

}

// 当需要编辑单元格时,调用此方法,编辑的是返回的组件对象

@Override

public Component getTableCellEditorComponent(JTable table, Object value,

boolean isSelected, int row, int column) {

return value instanceof JPanel ? panel = (JPanel) value : null;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import javax.swing.JPanel;

import javax.swing.table.DefaultTableModel;

import com.hubPlayer.song.SongInfos;

/**

* 一个歌曲信息表格模型,继续默认表格模式DefaultTableModel,实现单元格渲染器TableCellRenderer

* 表格头为歌曲(String),歌手(String),专辑(String),操作(JPanel) 定义渲染器显示操作面板

* 其中操作面板包含3个按钮:播放,加入列表,下载

*

* @date 2014-11-7

*/

public class LibraryTableModel extends DefaultTableModel {

// 标题栏

private static final String[] title = new String[] { "歌曲", "歌手", "专辑", "操作" };

// 标题栏对应的数据类型

private static final Class[] types = new Class[] { String.class,

String.class, String.class, Object.class };

// 标题栏对应的可编辑状态

private static final boolean[] canEdit = new boolean[] { false, false,

false, true };

// 表格初始数据

private static final Object[][] initData = new Object[][] {

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null },

{ null, null, null, null }, { null, null, null, null } };

// 操作面板

private LibraryOperation libraryOperation;

public LibraryTableModel() {

super(initData, title);

}

public void deleteTableData() {

// 通知表格,数据要改变

fireTableDataChanged();

// 清除表格行

for (int i = getRowCount() - 1; i >= 0; i--) {

removeRow(i);

}

// 清除表格数据

getDataVector().clear();

// 垃圾回收

try {

this.finalize();

} catch (Throwable e) {

e.printStackTrace();

}

}

// 检测每列对应数据类型

public Class getColumnClass(int columnIndex) {

return types[columnIndex];

}

// 检测单元格对应的可编辑状态

public boolean isCellEditable(int rowIndex, int columnIndex) {

return canEdit[columnIndex];

}

public void updateData(SongInfos songInfos) {

String song = songInfos.getSong();

String singer = songInfos.getSinger();

String album = songInfos.getAlbum();

// 操作面板,接受歌曲信息

JPanel panel = libraryOperation.new OperationPanel(songInfos);

Object[] data = new Object[] { song, singer, album, panel };

addRow(data);

}

public void setLibraryOperation(LibraryOperation libraryOperation) {

this.libraryOperation = libraryOperation;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import java.awt.event.KeyAdapter;

import java.awt.event.KeyEvent;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.io.File;

import java.util.Enumeration;

import java.util.List;

import java.util.Vector;

import javax.swing.JFileChooser;

import javax.swing.JMenu;

import javax.swing.JMenuItem;

import javax.swing.JOptionPane;

import javax.swing.JPopupMenu;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.filechooser.FileNameExtensionFilter;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.TreeNode;

import javax.swing.tree.TreePath;

import com.hubPlayer.player.HigherPlayer;

import com.hubPlayer.song.AFilter;

import com.hubPlayer.song.SongNode;

/**

* 歌曲列表面板:播放列表,标记列表、下载列表

*

* @date 2014-10-12

*/

public class SongListPanel extends JScrollPane {

// 菜单项相关

private JMenuItem newList;

private JMenuItem removeList;

private JMenuItem cleanList;

private JMenuItem addSongFile;

private JMenuItem addSongFolder;

private JMenuItem removeSong;

private JMenuItem addLrcFile;

private JMenuItem addLrcFloder;

private JPopupMenu popupMenu;

// 歌曲、歌词列表相关

private JTree tree;

private DefaultMutableTreeNode topNode;

private int defaultNodes;

private List<SongNode> songlist;

// 文件对话框相关

private JFileChooser fileChooser;

private FileNameExtensionFilter songFilter;

private FileNameExtensionFilter lrcFilter;

// 播放器

private HigherPlayer higherPlayer;

public SongListPanel(String... defaultNodes) {

this.defaultNodes = defaultNodes.length;

initComponent(defaultNodes);

createPopupmenu();

createAction();

}

private void initComponent(String... defaultNodes) {

// 树组件

topNode = new DefaultMutableTreeNode();

// node表默认的列表 [0]表示列表中的歌曲数

for (int i = 0; i < defaultNodes.length; i++) {

DefaultMutableTreeNode node = new DefaultMutableTreeNode(

defaultNodes[i] + "[0]");

topNode.add(node);

}

tree = new JTree(topNode);

// tree.setPreferredSize(new Dimension(290, 400));

tree.startEditingAtPath(new TreePath(new Object[] { topNode,

topNode.getFirstChild() }));

// 隐藏根节点

tree.setRootVisible(false);

getViewport().add(tree);

// 文件选择器处理

fileChooser = new JFileChooser();

songFilter = new FileNameExtensionFilter("音频文件(*.mid;*.mp3;*.wav)",

"mid", "MID", "mp3", "MP3", "wav", "WAV");

lrcFilter = new FileNameExtensionFilter("歌词文件(*.lrc)", "lrc", "LRC");

songlist = new Vector<SongNode>();

}

private void createPopupmenu() {

popupMenu = new JPopupMenu();

newList = new JMenuItem("新建列表");

removeList = new JMenuItem("移除列表");

cleanList = new JMenuItem("清空列表");

addSongFile = new JMenuItem("添加本地歌曲");

addSongFolder = new JMenuItem("添加本地歌曲文件夹");

JMenu addSong = new JMenu("添加歌曲");

addSong.add(addSongFile);

addSong.add(addSongFolder);

addLrcFile = new JMenuItem("添加本地歌词");

addLrcFloder = new JMenuItem("添加本地歌词文件夹");

addLrcFile.setEnabled(false);

addLrcFloder.setEnabled(false);

JMenu addLrc = new JMenu("添加歌词");

addLrc.add(addLrcFile);

addLrc.add(addLrcFloder);

removeSong = new JMenuItem("删除歌曲");

popupMenu.add(newList);

popupMenu.add(removeList);

popupMenu.add(cleanList);

popupMenu.addSeparator();

popupMenu.add(addSong);

popupMenu.addSeparator();

popupMenu.add(addLrc);

popupMenu.addSeparator();

popupMenu.add(removeSong);

}

private void createAction() {

// 新建列表

newList.addActionListener(event -> {

String listName = JOptionPane.showInputDialog(this, "请输入新建列表的名称",

null, JOptionPane.DEFAULT_OPTION);

if (listName == null || listName.length() == 0)

return;

addList(listName);

});

// 移除列表

removeList

.addActionListener(event -> {

TreePath path = tree.getSelectionPath();

if (path == null)

return;

DefaultMutableTreeNode node = (DefaultMutableTreeNode) path

.getLastPathComponent();

// 判断是否在歌曲上触发事件 是返回此歌曲的目录

if (path.getPathCount() == 3) {

node = (DefaultMutableTreeNode) node.getParent();

}

// 该目录是否为默认目录

int nodeIndex = topNode.getIndex(node);

if (nodeIndex < defaultNodes && nodeIndex != -1)

return;

// 该目录是否含歌曲 不含则返回true

if (node.isLeaf())

node.removeFromParent();

// 改模录含有歌曲 询问是否移除

else if (JOptionPane

.showConfirmDialog(this, "列表内包含歌曲,是否删除?", null,

JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {

// 终止当前歌曲播放

TreeNode playedSong = higherPlayer.getPlayingSong();

if (playedSong != null

&& node.getIndex(playedSong) != -1

&& playedSong != null) {

higherPlayer.end();

// 触发下播放按钮 使它处于待播放状态

higherPlayer.IsPause = false;

higherPlayer.getPlayButton().doClick();

higherPlayer.getSongNameLabel().setText("");

}

// 清空集合中的歌曲

Enumeration<SongNode> e = node.children();

while (e.hasMoreElements()) {

songlist.remove(e.nextElement());

}

if (songlist.isEmpty()) {

addLrcFile.setEnabled(false);

addLrcFloder.setEnabled(false);

}

node.removeFromParent();

}

tree.updateUI();

});

// 清空列表

cleanList.addActionListener(event -> {

// 返回选中节点的路径

TreePath path = tree.getSelectionPath();

if (path == null)

return;

DefaultMutableTreeNode node = (DefaultMutableTreeNode) path

.getLastPathComponent();

if (node.getChildCount() == 0)

node = (DefaultMutableTreeNode) node.getParent();

if (node == topNode)

return;

// 终止当前歌曲播放

TreeNode playedSong = higherPlayer.getPlayingSong();

if (playedSong != null && node.getIndex(playedSong) != -1

&& playedSong != null) {

higherPlayer.end();

higherPlayer.IsPause = false;

higherPlayer.getPlayButton().doClick();

higherPlayer.getSongNameLabel().setText("");

}

Enumeration<SongNode> e = node.children();

while (e.hasMoreElements()) {

songlist.remove(e.nextElement());

}

if (songlist.isEmpty()) {

addLrcFile.setEnabled(false);

addLrcFloder.setEnabled(false);

}

node.removeAllChildren();

// 设歌曲列表的歌曲数为0

updateSongNumInList(node);

tree.updateUI();

});

// 删除歌曲

removeSong.addActionListener(event -> {

TreePath path = tree.getSelectionPath();

if (path == null)

return;

DefaultMutableTreeNode node = (DefaultMutableTreeNode) path

.getLastPathComponent();

// 该选中节点是歌曲目录

if (path.getPathCount() == 2)

return;

// 获取当前歌曲的列表 用于更新列表中歌曲数

DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node

.getParent();

// 终止当前歌曲播放

if (node == higherPlayer.getPlayingSong()

&& higherPlayer.playThread != null) {

higherPlayer.end();

higherPlayer.IsPause = false;

higherPlayer.getPlayButton().doClick();

higherPlayer.getSongNameLabel().setText("");

}

songlist.remove(node);

if (songlist.isEmpty()) {

addLrcFile.setEnabled(false);

addLrcFloder.setEnabled(false);

}

node.removeFromParent();

updateSongNumInList(parent);

tree.updateUI();

});

// 增加本地歌曲

addSongFile.addActionListener(event -> {

TreePath path = tree.getSelectionPath();

if (path == null)

return;

DefaultMutableTreeNode node = (DefaultMutableTreeNode) path

.getLastPathComponent();

// 选中节点是第3级

if (path.getPathCount() == 3)

node = (DefaultMutableTreeNode) node.getParent();

// 设置JFileChooser可多选音频文件

fileChooser.setMultiSelectionEnabled(true);

fileChooser.setFileFilter(songFilter);

fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)

return;

File[] files = fileChooser.getSelectedFiles();

addSongs(node, files);

});

// 增加本地歌曲文件夹

addSongFolder.addActionListener(event -> {

// JTree的处理和"增加本地歌曲"一样

TreePath path = tree.getSelectionPath();

if (path == null)

return;

DefaultMutableTreeNode node = (DefaultMutableTreeNode) path

.getLastPathComponent();

// 选中节点是第3级

if (path.getPathCount() == 3)

node = (DefaultMutableTreeNode) node.getParent();

// 设置JFileChooser只选文件夹

fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

fileChooser.setMultiSelectionEnabled(false);

if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)

return;

// 获取选中的文件夹

File directory = fileChooser.getSelectedFile();

// 获取文件夹中的文件,以SongFilter过滤

File[] files = directory

.listFiles(new AFilter(".mid;.mp3;.wav"));

if (files.length == 0)

return;

addSongs(node, files);

});

// 歌词文件

addLrcFile

.addActionListener(event -> {

fileChooser.setMultiSelectionEnabled(true);

fileChooser.setFileFilter(lrcFilter);

fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)

return;

File[] files = fileChooser.getSelectedFiles();

addLrcs(files);

});

// 歌词文件夹

addLrcFloder

.addActionListener(event -> {

fileChooser

.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

fileChooser.setMultiSelectionEnabled(false);

if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)

return;

// 获取选中的文件夹

File directory = fileChooser.getSelectedFile();

// 获取文件夹中的文件,以SongFilter过滤

File[] files = directory.listFiles(new AFilter(".lrc"));

if (files.length == 0)

return;

addLrcs(files);

});

tree.addMouseListener(new MouseAdapter() {

@Override

public void mousePressed(MouseEvent e) {

// 右击选中歌曲

if (e.getButton() == MouseEvent.BUTTON3) {

// 获得一个最接近点击点的节点路径

TreePath path = tree.getPathForLocation(e.getX(), e.getY());

if (path != null)

tree.setSelectionPath(path);

}

}

@Override

public void mouseClicked(MouseEvent e) {

// 鼠标左击两次 播放歌曲

if (e.getButton() == MouseEvent.BUTTON1

&& e.getClickCount() == 2) {

TreePath path = tree.getSelectionPath();

// 该选中节点是否为歌曲

if (path != null && path.getPathCount() == 3) {

SongNode songNode = (SongNode) path

.getLastPathComponent();

if (!tree.equals(higherPlayer.getJTree())) {

higherPlayer.setJTree(tree);

}

// 如果此歌曲节点是网络资源,则载入其URL

if (songNode.getHTTPFlag())

higherPlayer.load(songNode, songNode.getDataURL());

else

higherPlayer.load(songNode);

higherPlayer.getPlayButton().doClick();

}

}

}

});

tree.addTreeSelectionListener(event -> {

TreePath path = tree.getSelectionPath();

// 选中的节点是列表

if (path.getPathCount() == 2) {

// 从当前选中的列表开始操作

higherPlayer.setCurrentListPath(path);

tree.startEditingAtPath(path);

}

});

tree.addKeyListener(new KeyAdapter() {

@Override

public void keyPressed(KeyEvent e) {

if (KeyEvent.VK_SPACE == e.getKeyCode())

higherPlayer.getPlayButton().doClick();

}

});

}

public DefaultMutableTreeNode addList(String listName) {

listName = listName + "[0]";

DefaultMutableTreeNode songList = new DefaultMutableTreeNode(listName);

topNode.add(songList);

tree.updateUI();

return songList;

}

public void addSongs(DefaultMutableTreeNode parent, File... files) {

for (File f : files) {

if (!f.exists())

continue;

SongNode node = new SongNode(f);

// 如果当前列表存在此首歌,count不等于0,则不加入当前列表

// songList存放了所有歌曲列表中的歌曲

long count = songlist.stream()

.filter(each -> parent.equals(each.getParent()))

.filter(each -> each.equals(node)).count();

// 不用判断 if(parent.isNodeChild(node))

// 因为前面new了一个节点,同时TreeNode没调用它子节点的equals判断

if (count != 0)

continue;

parent.add(node);

// 歌曲集合加入文件

songlist.add(node);

}

if (!songlist.isEmpty()) {

addLrcFile.setEnabled(true);

addLrcFloder.setEnabled(true);

}

updateSongNumInList(parent);

tree.updateUI();

}

public void addLrcs(File... files) {

for (File f : files) {

if (!f.exists())

continue;

String name = f.getName();

String lrcName = name.substring(0, name.lastIndexOf("."));

// 当前歌曲集合中转成流式,选出那些与歌词名相同的歌曲作为一个子集合,设置子集合中歌曲的歌词

songlist.stream()

.filter(each -> each.getSongName().equals(lrcName))

.forEach(each -> {

if (each.getLrc() == null)

each.setLrc(f);

});

}

}

// 设置列表中的歌曲数

private void updateSongNumInList(DefaultMutableTreeNode node) {

String listName = (String) node.getUserObject();

listName = listName.substring(0, listName.lastIndexOf("[")) + "["

+ node.getChildCount() + "]";

node.setUserObject(listName);

}

public void addPopupMenuToTree() {

tree.setComponentPopupMenu(popupMenu);

tree.updateUI();

}

public void setPlayer(HigherPlayer player) {

this.higherPlayer = player;

}

public JTree getTree() {

return tree;

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package com.hubPlayer.ui.tool;

import java.util.Map;

import java.util.Timer;

import java.util.TimerTask;

import javax.swing.JLabel;

import javax.swing.JProgressBar;

import javax.swing.JTextArea;

import javax.swing.text.BadLocationException;

import com.hubPlayer.song.LrcInfos;

/**

* 播放面板的进度条,绑定一个计时器 计时打印歌词

*

* @date 2014-10-23

*/

public class TimeProgressBar extends JProgressBar {

private boolean timerPause;

private int audioTotalTime;

private int counter;

private Timer timer;

private Task task;

private JLabel currentTimeCountLabel;

private LrcInfos lrcInfos;

private Map<Integer, String> lrcInfosMap;

private int nextLrcTime;

// 歌词面板

private JTextArea textArea;

public TimeProgressBar() {

counter = 0;

setMinimum(0);

setStringPainted(false);

}

// 启动计时器

public void startTimer() {

// 初始显示23条歌词

if (lrcInfosMap.size() != 0)

printNextLrcInTheTime(0, 23);

timer = new Timer(true);

task = new Task();

timer.schedule(task, 500, 1000);

}

// 重启计时器

public void resumeTimer() {

synchronized (timer) {

timer.notify();

}

}

// 重置计时器

public void cleanTimer() {

counter = 0;

if (timer != null) {

timer.cancel();

timer.purge();

}

currentTimeCountLabel.setText("0:00");

this.setValue(0);

textArea.setText("\n");

}

public void setAudioTotalTime(int n) {

audioTotalTime = n;

super.setMaximum(n);

}

public void setTimerControl(boolean IsPause) {

this.timerPause = IsPause;

}

public void setCurrentTimeCountLabel(JLabel currentTimeCountLabel) {

this.currentTimeCountLabel = currentTimeCountLabel;

}

public void setCurrentPlayedSongLrcInfo(LrcInfos lrcInfos) {

this.lrcInfos = lrcInfos;

lrcInfosMap = lrcInfos.getInfos();

}

public void setLrcPanelTextArea(JTextArea textArea) {

this.textArea = textArea;

}

/**

* 打印time时间后的line条歌词 audioTotalTime当前播放歌曲的时长 nextLrcTime搜寻下一条歌词的开始时间

*/

private void printNextLrcInTheTime(int time, int line) {

for (int i = 0; i < line && time <= audioTotalTime; time++) {

String content = lrcInfos.getInfos().get(time);

if (content != null) {

textArea.append(content + "\n");

nextLrcTime = time + 1;

i++;

}

}

}

class Task extends TimerTask {

@Override

public void run() {

synchronized (timer) {

if (counter == audioTotalTime) {

// 终止计数器 但当前任务还会被执行

cleanTimer();

return;

}

if (timerPause) {

try {

timer.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

try {

if (lrcInfosMap.size() != 0) {

String content = lrcInfosMap.get(counter);

if (content != null) {

// 剪去第一行歌词,同时整体上移

textArea.select(textArea.getLineStartOffset(1),

textArea.getLineEndOffset(textArea

.getLineCount() - 1));

textArea.setText(textArea.getSelectedText());

// 显示最后一条歌词的下一条

printNextLrcInTheTime(nextLrcTime, 1);

}

}

} catch (BadLocationException e) {

e.printStackTrace();

}

counter += 1;

TimeProgressBar.this.setValue(counter);

TimeProgressBar.this.currentTimeCountLabel

.setText(getCurrentTime(counter));

}

}

// 转换时间

public String getCurrentTime(int sec) {

String time = "0:00";

if (sec <= 0)

return time;

int minute = sec / 60;

int second = sec % 60;

int hour = minute / 60;

if (second < 10)

time = minute + ":0" + second;

else

time = minute + ":" + second;

if (hour != 0)

time = hour + ":" + time;

return time;

}

}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: