Files
nas-service/src/main/java/com/yutou/nas/Services/impl/MusicToolsServiceImpl.java
2022-12-08 16:20:34 +08:00

624 lines
23 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.yutou.nas.Services.impl;
import com.yutou.nas.Datas.AppData;
import com.yutou.nas.Services.IMusicToolsService;
import com.yutou.nas.mybatis.dao.MusicDataDao;
import com.yutou.nas.mybatis.model.MusicData;
import com.yutou.nas.mybatis.model.MusicDataExample;
import com.yutou.nas.utils.*;
import ealvatag.audio.AudioFile;
import ealvatag.audio.AudioFileIO;
import ealvatag.audio.AudioHeader;
import ealvatag.tag.FieldKey;
import ealvatag.tag.NullTag;
import ealvatag.tag.Tag;
import ealvatag.tag.images.NullArtwork;
import net.bramp.ffmpeg.FFprobe;
import net.bramp.ffmpeg.probe.FFmpegFormat;
import net.bramp.ffmpeg.probe.FFmpegProbeResult;
import net.bramp.ffmpeg.probe.FFmpegStream;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.Collator;
import java.util.*;
@Service("MusicToolsService")
public class MusicToolsServiceImpl implements IMusicToolsService {
public static final int FIND_TITLE = 1;
public static final int FIND_ARTIST = 2;
private String musicPath = "/media/yutou/disk_lvm/public/音乐";
private boolean isScan = false;
@Resource
MusicDataDao musicDataDao;
@Override
public void init() {
musicPath = (String) ConfigTools.load(ConfigTools.CONFIG, "musicDir");
scanMusic();
}
@Override
public void scanMusic() {
if (isScan) {
return;
}
if (!ConfigTools.load(ConfigTools.CONFIG, "musicScan", boolean.class, false)) {
return;
}
musicPath = (String) ConfigTools.load(ConfigTools.CONFIG, "musicDir");
com.yutou.nas.utils.Log.i("执行扫描:" + musicPath);
new Thread(() -> {
long startTime = System.currentTimeMillis();
QQBotManager.getInstance().sendMessage("开始扫描音乐夹");
musicDataDao.truncate();
isScan = true;
scan(new File(musicPath));
isScan = false;
Log.i("扫描完成");
QQBotManager.getInstance().sendMessage("音乐扫描完成,共" + getLength() + "首歌,耗时:"
+ (System.currentTimeMillis() - startTime));
}).start();
}
private void scan(File path) {
if (!path.exists()) {
Log.i("MusicScan", "文件夹不存在,取消扫描");
return;
}
if (path.isFile()) {
add(path);
} else if (path.isDirectory()) {
for (File file : Objects.requireNonNull(path.listFiles())) {
if (file.isDirectory()) {
scan(file);
} else {
add(file);
}
}
}
}
public void getPathOrDir(String path, List<MusicData> list) {
File files = new File(path);
for (File file : Objects.requireNonNull(files.listFiles())) {
if (file.isFile()) {
list.add(getMetadata(file));
} else {
getPathOrDir(file.getAbsolutePath(), list);
}
}
}
@Override
public List<MusicData> getPath(String path, boolean isDir, boolean delPath) {
return getPath(path, isDir, delPath, false);
}
/**
* 获取指定目录下的音乐
*
* @param path 指定目录
* @param isDir 是否扫描目录下的所有文件false则仅为当前目录
* @return 音乐列表
*/
@Override
public List<MusicData> getPath(String path, boolean isDir, boolean delPath, boolean filter) {
List<MusicData> list = new ArrayList<>();
List<MusicData> main = new ArrayList<>();
MusicDataExample example = new MusicDataExample();
String replacement = "windows".equals(ConfigTools.load(ConfigTools.CONFIG, "os")) ? "\\\\" : "/";
String tmpPath = path;
if (StringUtils.isEmpty(path)) {
tmpPath = AppData.defaultMusicPath;
}
if (isDir) {
example.createCriteria().andFileLike(tmpPath.replace(File.separator, replacement) + "%");
main = musicDataDao.selectByExample(example, delPath);
}else {
tmpPath = tmpPath.replace(File.separator, replacement)
.replace("+", "\\+")
.replace("[", "\\[")
.replace("(", "\\(")
.replace(")", "\\)")
.replace("]", "\\]");
main = new ArrayList<>(musicDataDao.selectByRegexp(tmpPath + replacement + "([^" + replacement + "]+)$", delPath));
}
if (!path.equals(AppData.defaultMusicPath) && !"root".equals(path)) {
MusicData t2 = new MusicData();
t2.setTitle("返回");
t2.setTrack("-1");
if (main.isEmpty()) {
t2.setFile("root");
} else {
t2.setFile(new File(path).getParent());
}
com.yutou.nas.utils.Log.i("查询地址:" + path + " 设置返回地址:" + t2.getFile());
t2.setIsdir(1);
list.add(t2);
}
getDirList(path, list);
list.addAll(main);
list.sort((o1, o2) -> {
if ("返回".equals(o2.getTitle())) {
return 1;
}
Comparator<Object> compare = Collator.getInstance(Locale.CHINA);
return compare.compare(o1.getTitle(), o2.getTitle());
});
if (filter) {
list.removeIf(data -> data.getTitle().toLowerCase().contains("instrumental"));
}
return list;
}
public List<MusicData> getAllAlbum() {
return musicDataDao.selectAllAlbum();
}
public List<MusicData> getAllArtist() {
return musicDataDao.selectAllArtist();
}
public List<MusicData> selectAlbum(String album, boolean isDelFile) {
return musicDataDao.selectAlbum(album, isDelFile);
}
public List<MusicData> selectArtist(String artist, boolean isDelFile) {
return musicDataDao.selectArtist(artist, isDelFile);
}
private void getDirList(String path, List<MusicData> list) {
File file = new File(path);
com.yutou.nas.utils.Log.i("扫描文件:" + path);
if (file.isDirectory()) {
for (File listFile : Objects.requireNonNull(file.listFiles())) {
if (listFile.isDirectory()) {
MusicData data = new MusicData();
data.setTitle(listFile.getName());
data.setIsdir(1);
data.setFile(listFile.getAbsolutePath());
list.add(data);
}
}
} else {
MusicData data = new MusicData();
data.setTitle(file.getName());
data.setIsdir(0);
data.setFile(file.getAbsolutePath());
list.add(data);
}
}
private void add(File file) {
MusicData data = getMetadata(file);
if (data != null) {
try {
if (getMusicData(file.getAbsolutePath(), false) == null) {
// System.out.println(data);
musicDataDao.insert(data);
}
} catch (Exception e) {
e.printStackTrace();
QQBotManager.getInstance().sendMessage("音乐文件添加失败:" + data);
}
}
}
@Override
public MusicData getMusicData(String path, boolean delFile) {
MusicDataExample example = new MusicDataExample();
example.createCriteria().andFileEqualTo(path);
List<MusicData> list = musicDataDao.selectByExample(example, delFile);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
@Override
public MusicData getMusicDataOfMd5(String md5, boolean isDelFile) {
MusicDataExample example = new MusicDataExample();
example.createCriteria().andMd5EqualTo(md5);
List<MusicData> list = musicDataDao.selectByExample(example, isDelFile);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
public MusicData getMetadata(File file) {
try {
if (file.getName().endsWith(".lrc")
|| file.getName().endsWith(".jpg")
|| file.getName().endsWith(".ini")
|| file.getName().endsWith(".png")
|| file.getName().endsWith(".torrent")
|| file.getName().endsWith(".log")
|| file.getName().endsWith(".mkv")
|| file.getName().endsWith(".dff")
|| file.getName().endsWith(".cue")
|| file.getName().endsWith(".m3u")
|| file.getName().endsWith(".txt")
|| file.getName().endsWith(".db")
) {
return null;
}
AudioFile audioFile = AudioFileIO.read(file);
Tag tag = audioFile.getTag().or(NullTag.INSTANCE);
MusicData data = new MusicData();
try {
data.setAlbum(tag.getFirst(FieldKey.ALBUM));
} catch (Exception ignored) {
}
try {
data.setArtist(tag.getFirst(FieldKey.ARTIST));
} catch (Exception ignored) {
}
try {
data.setArtistSort(tag.getFirst(FieldKey.ARTIST_SORT));
} catch (Exception ignored) {
}
try {
data.setComment(tag.getFirst(FieldKey.COMMENT));
} catch (Exception ignored) {
}
try {
data.setComposer(tag.getFirst(FieldKey.COMPOSER));
} catch (Exception ignored) {
}
try {
data.setDiscNo(tag.getFirst(FieldKey.DISC_NO));
} catch (Exception ignored) {
}
try {
if (StringUtils.isEmpty(tag.getFirst(FieldKey.TITLE))) {
data.setTitle(file.getName());
} else {
data.setTitle(tag.getFirst(FieldKey.TITLE));
}
} catch (Exception e) {
data.setTitle(file.getName());
}
try {
data.setTrack(tag.getFirst(FieldKey.TRACK));
} catch (Exception ignored) {
}
try {
data.setYear(tag.getFirst(FieldKey.YEAR));
} catch (Exception ignored) {
}
data.setFile(file.getAbsolutePath());
data.setIsdir(file.isDirectory() ? 1 : 0);
data.setLastdir(file.getParentFile().getParent());//这里是设置上一级目录
AudioHeader header = audioFile.getAudioHeader();
data.setBitrate(header.getBitRate());
data.setSamplerate(header.getSampleRate());
data.setNoofsamples(header.getNoOfSamples());
data.setChannelcount(header.getChannelCount());
data.setEncodingtype(header.getEncodingType());
data.setDurationasdouble(header.getDurationAsDouble());
data.setLossless(header.isLossless() ? 1 : 0);
data.setVariablebitrate(header.isVariableBitRate() ? 1 : 0);
try {
data.setMd5(header.getClass().getMethod("getMd5").invoke(header).toString());
if(data.getMd5().startsWith("00000")&&data.getMd5().endsWith("00000")){
throw new NullPointerException("md5 is null");
}
} catch (Exception ignored) {
data.setMd5(Tools.getFileMD5(file));
}
return data;
} catch (IOException e) {
return getMetadata_jthink(file);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public MusicData getMetadata_jthink(File file) {
try {
org.jaudiotagger.audio.AudioFile audioFile = org.jaudiotagger.audio.AudioFileIO.read(file);
org.jaudiotagger.tag.Tag tag = audioFile.getTag();
MusicData data = new MusicData();
try {
data.setAlbum(tag.getFirst(org.jaudiotagger.tag.FieldKey.ALBUM));
} catch (Exception ignored) {
}
try {
data.setArtist(tag.getFirst(org.jaudiotagger.tag.FieldKey.ARTIST));
} catch (Exception ignored) {
}
try {
data.setArtistSort(tag.getFirst(org.jaudiotagger.tag.FieldKey.ARTIST_SORT));
} catch (Exception ignored) {
}
try {
data.setComment(tag.getFirst(org.jaudiotagger.tag.FieldKey.COMMENT));
} catch (Exception ignored) {
}
try {
data.setComposer(tag.getFirst(org.jaudiotagger.tag.FieldKey.COMPOSER));
} catch (Exception ignored) {
}
try {
data.setDiscNo(tag.getFirst(org.jaudiotagger.tag.FieldKey.DISC_NO));
} catch (Exception ignored) {
}
try {
if (StringUtils.isEmpty(tag.getFirst(org.jaudiotagger.tag.FieldKey.TITLE))) {
data.setTitle(file.getName());
} else {
data.setTitle(tag.getFirst(org.jaudiotagger.tag.FieldKey.TITLE));
}
} catch (Exception e) {
data.setTitle(file.getName());
}
try {
data.setTrack(tag.getFirst(org.jaudiotagger.tag.FieldKey.TRACK));
} catch (Exception ignored) {
}
try {
data.setYear(tag.getFirst(org.jaudiotagger.tag.FieldKey.YEAR));
} catch (Exception ignored) {
}
data.setFile(file.getAbsolutePath());
data.setIsdir(file.isDirectory() ? 1 : 0);
data.setLastdir(file.getParentFile().getParent());
org.jaudiotagger.audio.AudioHeader header = audioFile.getAudioHeader();
data.setBitrate(Integer.parseInt(header.getBitRate()));
data.setSamplerate(Integer.parseInt(header.getSampleRate()));
data.setNoofsamples(Long.parseLong(header.getSampleRateAsNumber() + ""));
data.setChannelcount(Integer.parseInt(header.getChannels()));
data.setEncodingtype(header.getEncodingType() + "");
data.setDurationasdouble(Double.parseDouble(header.getTrackLength() + ""));
data.setLossless(header.isLossless() ? 1 : 0);
data.setVariablebitrate(header.isVariableBitRate() ? 1 : 0);
try {
data.setMd5(header.getClass().getMethod("getMd5").invoke(header).toString());
if(data.getMd5().startsWith("00000")&&data.getMd5().endsWith("00000")){
throw new NullPointerException("md5 is null");
}
} catch (Exception ignored) {
data.setMd5(Tools.getFileMD5(file));
}
return data;
} catch (Exception e) {
return getMetadataOfFFmpeg(file);
}
}
private MusicData getMetadataOfFFmpeg(File file) {
MusicData data;
try {
data = new MusicData();
FFprobe fFprobe = new FFprobe((String) ConfigTools.load(ConfigTools.CONFIG, "ffprobe"));
FFmpegProbeResult result = fFprobe.probe(file.getAbsolutePath());
FFmpegFormat format = result.getFormat();
FFmpegStream stream = null;
for (FFmpegStream tmp : result.getStreams()) {
if (tmp.index == 0) {
stream = tmp;
}
}
Map<String, String> tag = format.tags;
data.setTitle(getTitle(tag));
data.setAlbum(getAlbum(tag));
data.setArtist(getArtist(tag));
data.setDiscNo(tag.get("disc") == null ? tag.get("disc".toUpperCase()) : tag.get("disc"));
data.setTrack(tag.get("track") == null ? tag.get("track".toUpperCase()) : tag.get("track"));
data.setYear(getYear(tag));
data.setArtistSort(tag.get("album_artist") == null ? tag.get("album_artist".toUpperCase()) : tag.get("album_artist"));
data.setDurationasdouble(format.duration);
data.setBitrate((int) (format.bit_rate / 1000));
if (stream != null) {
if (data.getBitrate() == 0) {
data.setBitrate((int) (stream.bit_rate / 1000));
}
data.setChannelcount(stream.channels);
data.setLossless(0);
data.setSamplerate(stream.sample_rate);
data.setNoofsamples(stream.duration_ts);
}
data.setEncodingtype(format.format_long_name);
data.setComment("");
data.setComposer("");
data.setVariablebitrate(0);
data.setFile(file.getAbsolutePath());
data.setLastdir(file.getParentFile().getParent());
data.setIsdir(file.isDirectory() ? 1 : 0);
if (data.getYear() == null) {
data.setYear("0000");
}
data.setMd5(Tools.getFileMD5(file));
} catch (Exception e) {
e.printStackTrace();
data = new MusicData();
data.setTitle(file.getName());
data.setFile(file.getAbsolutePath());
data.setIsdir(file.isDirectory() ? 1 : 0);
data.setLastdir(file.getParentFile().getParent());
data.setMd5(Tools.getFileMD5(file));
QQBotManager.getInstance().sendMessage("添加音乐文件失败:\n" + data + "\n" + Tools.getExceptionString(e));
}
return data;
}
private String getTitle(Map<String, String> tag) {
String title = tag.get("title");
if (StringUtils.isEmpty(title)) {
title = tag.get("TITLE");
if (StringUtils.isEmpty(title)) {
title = tag.get("Title");
}
}
return title;
}
private String getArtist(Map<String, String> tag) {
String title = tag.get("artist");
if (StringUtils.isEmpty(title)) {
title = tag.get("ARTIST");
if (StringUtils.isEmpty(title)) {
title = tag.get("Artist");
}
}
return title;
}
private String getAlbum(Map<String, String> tag) {
String title = tag.get("album");
if (StringUtils.isEmpty(title)) {
title = tag.get("ALBUM");
if (StringUtils.isEmpty(title)) {
title = tag.get("Album");
}
}
return title;
}
private String getYear(Map<String, String> tag) {
String title = tag.get("year");
if (StringUtils.isEmpty(title)) {
title = tag.get("YEAR");
if (StringUtils.isEmpty(title)) {
title = tag.get("Year");
}
}
return title;
}
@Override
public List<MusicData> findOfTitle(String title, boolean delFile) {
return find(title, FIND_TITLE, delFile);
}
@Override
public List<MusicData> findOfArtist(String by, boolean delFile) {
return find(by, FIND_ARTIST, delFile);
}
@Override
public List<MusicData> getMusicList(boolean delFile) {
return musicDataDao.selectByExample(new MusicDataExample(), delFile);
}
@Override
public int getLength() {
return musicDataDao.selectByExample(new MusicDataExample(), true).size();
}
@Override
public boolean isScan() {
return isScan;
}
private List<MusicData> find(String title, int type, boolean delFile) {
List<MusicData> list;
MusicDataExample example = new MusicDataExample();
if (type == FIND_TITLE) {
example.createCriteria().andTitleEqualTo(title);
} else if (type == FIND_ARTIST) {
example.createCriteria().andArtistEqualTo(title);
}
list = musicDataDao.selectByExample(example, delFile);
return list;
}
@Override
public String getMusicPath() {
return musicPath;
}
public void setMusicPath(String musicPath) {
this.musicPath = musicPath;
}
@Override
public byte[] readImage(String path) throws Exception {
File file = new File(path);
AudioFile audioFile;
audioFile = AudioFileIO.read(file);
Tag tag = audioFile.getTag().or(NullTag.INSTANCE);
byte[] bytes = tag.getFirstArtwork().or(NullArtwork.INSTANCE).getBinaryData();
if (bytes.length == 0) {
return readImageFile(file);
}
return bytes;
}
@Override
public File getMusicOfMd5(String md5, boolean delFile) {
MusicDataExample example = new MusicDataExample();
example.createCriteria().andMd5EqualTo(md5);
List<MusicData> list = musicDataDao.selectByExample(example, delFile);
Log.i("Music Size", list.size());
if (!list.isEmpty()) {
Log.i("Music File", list.get(0).toString());
return new File(list.get(0).getFile());
}
return null;
}
@Override
public File getMusicLrcMd5(String md5) {
MusicDataExample example = new MusicDataExample();
example.createCriteria().andMd5EqualTo(md5);
List<MusicData> list = musicDataDao.selectByExample(example, false);
if (!list.isEmpty()) {
String fileName = list.get(0).getFile();
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".")), ".lrc");
System.out.println("fileName = " + fileName);
File file = new File(fileName);
if (file.exists()) {
return file;
}
}
return null;
}
private byte[] readImageFile(File file) throws Exception {
String path = file.getAbsolutePath().replace(file.getName(), "");
File img = new File(path, "cover.jpg");
if (!img.exists()) {
img = new File(path, "Cover.jpg");
if (!img.exists()) {
img = new File(path, "COVER.jpg");
if (!img.exists()) {
throw new NullPointerException("没有cover文件");
}
}
}
return Files.readAllBytes(Paths.get(img.getAbsolutePath()));
}
public static void main(String[] args) throws Exception {
File file = new File("Z:\\音乐\\总之就是非常酸\\ED\\カノエラナ - 月と星空\\カノエラナ.wav");
file = new File("Z:\\音乐\\终将成为你\\[OP]君にふれて\\rise.flac");
// file = new File("Z:\\音乐\\周董\\2012 十二新作\\03 公公偏头痛.ape");
com.yutou.nas.utils.Log.i(new MusicToolsServiceImpl().getMetadataOfFFmpeg(file));
new MusicToolsServiceImpl().getMusicLrcMd5("84d3180883e6447c3b86bfc55b05608e");
}
}