@@ -1,9 +1,10 @@
package com.yutou.tools.utils ;
import com.alibaba.fastjson.JSON ;
import com.alibaba.fastjson.JSONObject ;
import com.yutou.tools.home.nas.Data.MusicData ;
import com.yutou.tools.home.nas.MusicController ;
import com.yutou.tools.mybatis.dao.MusicDataDao ;
import com.yutou.tools.mybatis.model.MusicData ;
import com.yutou.tools.mybatis.model.MusicDataExample ;
import com.yutou.tools.utils.Interfaces.MusicToolsService ;
import ealvatag.audio.AudioFile ;
import ealvatag.audio.AudioFileIO ;
import ealvatag.audio.AudioHeader ;
@@ -11,31 +12,44 @@ import ealvatag.audio.exceptions.CannotReadException;
import ealvatag.tag.FieldKey ;
import ealvatag.tag.NullTag ;
import ealvatag.tag.Tag ;
import ealvatag.tag.flac.FlacTag ;
import ealvatag.tag.images.NullArtwork ;
import net.bramp.ffmpeg.FFmpeg ;
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 org.springframework.util.StringUtils ;
import java.io.* ;
import javax.annotation.Resource ;
import java.io.File ;
import java.io.FileOutputStream ;
import java.io.IOException ;
import java.io.OutputStream ;
import java.nio.file.Files ;
import java.nio.file.Paths ;
import java.text.SimpleDateFormat ;
import java.util.* ;
public class MusicTools {
@Service ( " musicToolsService " )
public class MusicTools implements MusicToolsService {
public static final int FIND_TITLE = 1 ;
public static final int FIND_ARTIST = 2 ;
private static MusicTools tools ;
private String musicPath = " /media/yutou/4t/public/音乐 " ;
private final List < MusicData > musicList = new ArrayList < > ( ) ;
private HashMap < String , List < MusicData > > musicMap = new HashMap < String , List < MusicData > > ( ) ;
private boolean isScan = false ;
public static MusicTools getInstance ( ) {
if ( tools = = null ) {
tools = new MusicTools ( ) ;
}
return tools ;
}
@Resource
MusicDataDao musicDataDao ;
private MusicTools ( ) {
}
@Override
public void init ( ) {
musicPath = ( String ) ConfigTools . load ( ConfigTools . CONFIG , " musicDir " ) ;
scanMusic ( ) ;
new Timer ( ) . schedule ( new TimerTask ( ) {
@Override
@@ -49,36 +63,26 @@ public class MusicTools {
} , 0 , 10 * 1000 ) ;
}
public synchronized void scanMusic ( ) {
if ( isScan ) {
@Override
public void scanMusic ( ) {
if ( isScan | | true ) {
return ;
}
System . out . println ( " 执行扫描 " ) ;
musicList . clear ( ) ;
musicMap . clear ( ) ;
musicPath = ( String ) ConfigTools . load ( ConfigTools . CONFIG , " musicDir " ) ;
musicDataDao . truncate ( ) ;
System . out . println ( " 执行扫描: " + musicPath ) ;
new Thread ( ( ) - > {
long startTime = System . currentTimeMillis ( ) ;
QQBotManager . getInstance ( ) . sendMessage ( " 开始扫描音乐夹 " ) ;
isScan = true ;
scan ( new File ( musicPath ) ) ;
isScan = false ;
System . out . println ( " 扫描完成 " ) ;
QQBotManager . getInstance ( ) . sendMessage ( " 音乐扫描完成,共 " + getLength ( ) + " 首歌,耗时: "
+ ( System . currentTimeMillis ( ) - startTime ) ) ;
} ) . start ( ) ;
}
public List < MusicData > scan ( File path , boolean isScanDir ) {
if ( isScanDir ) {
scan ( path ) ;
return musicList ;
} else {
if ( path . exists ( ) & & path . isDirectory ( ) ) {
List < MusicData > list = new ArrayList < > ( ) ;
for ( File file : path . listFiles ( ) ) {
list . add ( getMetadata ( file ) ) ;
}
return list ;
}
}
return null ;
}
private void scan ( File path ) {
if ( path . isFile ( ) ) {
@@ -105,6 +109,7 @@ public class MusicTools {
}
}
/**
* 获取指定目录下的音乐
*
@@ -112,46 +117,48 @@ public class MusicTools {
* @param isDir 是否扫描目录下的所有文件, false则仅为当前目录
* @return 音乐列表
*/
@Override
public List < MusicData > getPath ( String path , boolean isDir ) {
List < MusicData > list = new ArrayList < > ( ) ;
List < MusicData > main ;
MusicDataExample example = new MusicDataExample ( ) ;
String replacement = ConfigTools . load ( ConfigTools . CONFIG , " os " ) . equals ( " windows " ) ? " \\ \\ " : " / " ;
if ( isDir ) {
if ( new File ( path ) . isDirectory ( ) & & ! path . equals ( MusicControl ler . defaultMusicPath ) ) {
for ( Str ing key : musicMap . keySet ( ) ) {
if ( key . startsWith ( path ) ) {
list . addAll ( musicMap . get ( key ) ) ;
}
}
return list ;
}
}
if ( musicMap . containsKey ( path ) ) {
MusicData tmp = musicMap . get ( path ) . isEmpty ( ) ? null : musicMap . get ( path ) . get ( 0 ) ;
if ( tmp ! = null ) {
if ( ! tmp . getFile ( ) . getParent ( ) . equals ( MusicController . defaultMusicPath ) ) {
MusicData t2 = new MusicData ( ) ;
t2 . setTitle ( " 返回 " ) ;
t2 . setFile ( new File ( tmp . getLastDir ( ) ) ) ;
list . add ( t2 ) ;
}
}
getDirList ( path , list ) ;
list . addAll ( musicMap . get ( path ) ) ;
return list ;
example . createCriteria ( ) . andFileLike ( path . replace ( Fi le. separator , replacement ) + " % " ) ;
ma in = musicDataDao . selectByExample ( example ) ;
} else {
if ( path . contains ( MusicControl ler . defaultMusicPath ) ) {
MusicData t2 = new MusicData ( ) ;
t2 . setTitle ( " 返回 " ) ;
t2 . setFile ( new File ( path ) . getParentFile ( ) ) ;
if ( ! path . equals ( MusicController . defaultMusicPath ) ) {
list . add ( t2 ) ;
}
getDirList ( path , list ) ;
return list ;
}
main = musicDataDao . selectByRegexp ( path . replace ( Fi le. separator , replacement ) + replacement + " ([^ " + replacement + " ]+)$ " ) ;
}
return new ArrayList < > ( ) ;
System . out . println ( path + " " + isDir ) ;
if ( ! path . equals ( MusicController . defaultMusicPath ) & & ! path . equals ( " root " ) & & main . size ( ) > 0 ) {
MusicData tmp = main . get ( 0 ) ;
System . out . println ( tmp ) ;
MusicData t2 = new MusicData ( ) ;
t2 . setTitle ( " 返回 " ) ;
t2 . setFile ( new File ( tmp . getLastdir ( ) ) . getAbsolutePath ( ) ) ;
t2 . setIsdir ( 1 ) ;
list . add ( t2 ) ;
}
getDirList ( path , list ) ;
list . addAll ( main ) ;
System . out . println ( list . size ( ) ) ;
return list ;
}
public List < String > getAllAlbum ( ) {
return musicDataDao . selectAllAlbum ( ) ;
}
public List < String > getAllArtist ( ) {
return musicDataDao . selectAllArtist ( ) ;
}
public List < MusicData > selectAlbum ( String album ) {
return musicDataDao . selectAlbum ( album ) ;
}
public List < MusicData > selectArtist ( String artist ) {
return musicDataDao . selectArtist ( artist ) ;
}
private void getDirList ( String path , List < MusicData > list ) {
@@ -160,7 +167,8 @@ public class MusicTools {
if ( listFile . isDirectory ( ) ) {
MusicData data = new MusicData ( ) ;
data . setTitle ( listFile . getName ( ) ) ;
data . setFile ( listFile ) ;
data . setIsdir ( 1 ) ;
data . setFile ( listFile . getAbsolutePath ( ) ) ;
list . add ( data ) ;
}
}
@@ -169,19 +177,28 @@ public class MusicTools {
private void add ( File file ) {
MusicData data = getMetadata ( file ) ;
if ( data ! = null ) {
musicList . add ( data ) ;
String path = file . getAbsolutePath ( ) . replace ( File . separator + file . getName ( ) , " " ) ;
List < MusicData > list ;
if ( musicMap . containsKey ( path ) ) {
list = musicMap . get ( path ) ;
} else {
list = new ArrayList < > ( ) ;
try {
musicDataDao . insert ( data ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
QQBotManager . getInstance ( ) . sendMessage ( " 音乐文件添加失败: " + data . toString ( ) ) ;
}
list . add ( data ) ;
musicMap . put ( path , list ) ;
}
}
@Override
public MusicData getMusicData ( String path ) {
MusicDataExample example = new MusicDataExample ( ) ;
example . createCriteria ( ) . andFileEqualTo ( Tools . base64ToString ( path ) ) ;
List < MusicData > list = musicDataDao . selectByExample ( example ) ;
if ( list ! = null & & list . size ( ) > 0 ) {
return list . get ( 0 ) ;
}
return null ;
}
public MusicData getMetadata ( File file ) {
try {
if ( file . getName ( ) . endsWith ( " .lrc " )
@@ -208,7 +225,7 @@ public class MusicTools {
} catch ( Exception e ) {
}
try {
data . setArtist_s ort ( tag . getFirst ( FieldKey . ARTIST_SORT ) ) ;
data . setArtistS ort ( tag . getFirst ( FieldKey . ARTIST_SORT ) ) ;
} catch ( Exception e ) {
}
try {
@@ -220,7 +237,7 @@ public class MusicTools {
} catch ( Exception e ) {
}
try {
data . setDisc_n o ( tag . getFirst ( FieldKey . DISC_NO ) ) ;
data . setDiscN o ( tag . getFirst ( FieldKey . DISC_NO ) ) ;
} catch ( Exception e ) {
}
try {
@@ -240,30 +257,27 @@ public class MusicTools {
data . setYear ( tag . getFirst ( FieldKey . YEAR ) ) ;
} catch ( Exception e ) {
}
data . setFile ( file ) ;
data . setFile ( file . getAbsolutePath ( ) );
data . setIsdir ( file . isDirectory ( ) ? 1 : 0 ) ;
data . setLastdir ( file . getParentFile ( ) . getParent ( ) ) ;
AudioHeader header = audioFile . getAudioHeader ( ) ;
data . setBitR ate ( header . getBitRate ( ) ) ;
data . setSampleR ate ( header . getSampleRate ( ) ) ;
data . setNoOfS amples ( header . getNoOfSamples ( ) ) ;
data . setChannelC ount ( header . getChannelCount ( ) ) ;
data . setEncodingT ype ( header . getEncodingType ( ) ) ;
data . setDurationAsD ouble ( header . getDurationAsDouble ( ) ) ;
data . setLossless ( header . isLossless ( ) ) ;
data . setVariableB itR ate ( header . isVariableBitRate ( ) ) ;
data . setBitr ate ( header . getBitRate ( ) ) ;
data . setSampler ate ( header . getSampleRate ( ) ) ;
data . setNoofs amples ( header . getNoOfSamples ( ) ) ;
data . setChannelc ount ( header . getChannelCount ( ) ) ;
data . setEncodingt ype ( header . getEncodingType ( ) ) ;
data . setDurationasd ouble ( header . getDurationAsDouble ( ) ) ;
data . setLossless ( header . isLossless ( ) ? 1 : 0 ) ;
data . setVariableb itr ate ( header . isVariableBitRate ( ) ? 1 : 0 ) ;
try {
data . setMd5 ( header . getClass ( ) . getMethod ( " getMd5 " ) . invoke ( header ) . toString ( ) ) ;
} catch ( Exception ignored ) {
data . setMd5 ( Base64 . getEncoder ( ) . encodeToString ( file . getAbsolutePath ( ) . getBytes ( ) ) ) ;
data . setMd5 ( Tools . getFileMD5 ( file ) ) ;
}
return data ;
} catch ( CannotReadException e ) {
MusicData data = getMetadata_jthink ( file ) ;
if ( data = = null )
data = new MusicData ( ) ;
data . setTitle ( file . getName ( ) ) ;
data . setFile ( file ) ;
return data ;
return getMetadata_jthink ( file ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
@@ -284,7 +298,7 @@ public class MusicTools {
} catch ( Exception ignored ) {
}
try {
data . setArtist_s ort ( tag . getFirst ( org . jaudiotagger . tag . FieldKey . ARTIST_SORT ) ) ;
data . setArtistS ort ( tag . getFirst ( org . jaudiotagger . tag . FieldKey . ARTIST_SORT ) ) ;
} catch ( Exception ignored ) {
}
try {
@@ -296,7 +310,7 @@ public class MusicTools {
} catch ( Exception ignored ) {
}
try {
data . setDisc_n o ( tag . getFirst ( org . jaudiotagger . tag . FieldKey . DISC_NO ) ) ;
data . setDiscN o ( tag . getFirst ( org . jaudiotagger . tag . FieldKey . DISC_NO ) ) ;
} catch ( Exception ignored ) {
}
try {
@@ -316,60 +330,166 @@ public class MusicTools {
data . setYear ( tag . getFirst ( org . jaudiotagger . tag . FieldKey . YEAR ) ) ;
} catch ( Exception ignored ) {
}
data . setFile ( file ) ;
data . setFile ( file . getAbsolutePath ( ) );
data . setIsdir ( file . isDirectory ( ) ? 1 : 0 ) ;
data . setLastdir ( file . getParentFile ( ) . getParent ( ) ) ;
org . jaudiotagger . audio . AudioHeader header = audioFile . getAudioHeader ( ) ;
data . setBitR ate ( Integer . parseInt ( header . getBitRate ( ) ) ) ;
data . setSampleR ate ( Integer . parseInt ( header . getSampleRate ( ) ) ) ;
data . setNoOfS amples ( header . getSampleRateAsNumber ( ) ) ;
data . setChannelC ount ( Integer . parseInt ( header . getChannels ( ) ) ) ;
data . setEncodingT ype ( header . getEncodingType ( ) + " " ) ;
data . setDurationAs Double ( header . getTrackLength ( ) ) ;
data . setLossless ( header . isLossless ( ) ) ;
data . setVariableB itR ate ( header . isVariableBitRate ( ) ) ;
data . setBitr ate ( Integer . parseInt ( header . getBitRate ( ) ) ) ;
data . setSampler ate ( Integer . parseInt ( header . getSampleRate ( ) ) ) ;
data . setNoofs amples ( Long . parseLong ( header. getSampleRateAsNumber ( ) + " " ) ) ;
data . setChannelc ount ( Integer . parseInt ( header . getChannels ( ) ) ) ;
data . setEncodingt ype ( header . getEncodingType ( ) + " " ) ;
data . setDurationasdouble ( Double . parse Double ( header . getTrackLength ( ) + " " ) ) ;
data . setLossless ( header . isLossless ( ) ? 1 : 0 ) ;
data . setVariableb itr ate ( header . isVariableBitRate ( ) ? 1 : 0 ) ;
try {
data . setMd5 ( header . getClass ( ) . getMethod ( " getMd5 " ) . invoke ( header ) . toString ( ) ) ;
} catch ( Exception ignored ) {
data . setMd5 ( Base64 . getEncoder ( ) . encodeToString ( file . getAbsolutePath ( ) . getBytes ( ) ) ) ;
data . setMd5 ( Tools . getFileMD5 ( file ) ) ;
}
return data ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
return getMetadataOfFFmpeg ( file ) ;
}
return null ;
}
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 ) ) ;
}
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 ) {
return find ( title , FIND_TITLE ) ;
}
@Override
public List < MusicData > findOfArtist ( String by ) {
return find ( by , FIND_ARTIST ) ;
}
public List < MusicData > getMusicList ( ) {
return musicList ;
return musicDataDao . selectByExample ( new MusicDataExample ( ) ) ;
}
@Override
public int getLength ( ) {
return tools . musicList . size ( ) ;
return musicDataDao . selectByExample ( new MusicDataExample ( ) ) . size ( ) ;
}
@Override
public boolean isScan ( ) {
return isScan ;
}
private List < MusicData > find ( String title , int type ) {
List < MusicData > list = new ArrayList < > ( ) ;
for ( MusicData data : m usicList ) {
if ( data . getTitle ( ) . contains ( title ) ) {
list . add ( data ) ;
}
List < MusicData > list ;
MusicDataExample example = new M usicDataExample ( ) ;
if ( type = = FIND_TITLE ) {
example . createCriteria ( ) . andTitleEqualTo ( title ) ;
} else if ( type = = FIND_ARTIST ) {
example . createCriteria ( ) . andArtistEqualTo ( title ) ;
}
list = musicDataDao . selectByExample ( example ) ;
return list ;
}
@Override
public String getMusicPath ( ) {
return musicPath ;
}
@@ -378,26 +498,40 @@ public class MusicTools {
this . musicPath = musicPath ;
}
private void saveImage ( MusicData data ) {
try {
File file = new File ( d ata . getTitle ( ) + " .jpg " ) ;
if ( ! file . exists ( ) ) {
if ( ! f ile . c reateNewFile ( ) ) {
return ;
@Override
public byte [ ] readImage ( String path ) throws Exception {
File file = new File ( p ath ) ;
AudioFile audioFile = null ;
audioFile = AudioF ileIO . 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 ;
}
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文件 " ) ;
}
}
OutputStream outputStream = new FileOutputStream ( file ) ;
outputStream . write ( data . readImage ( ) ) ;
outputStream . flush ( ) ;
outputStream . close ( ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return Files . readAllBytes ( Paths . get ( img . getAbsolutePath ( ) ) ) ;
}
public static void main ( String [ ] args ) throws Exception {
File file = new File ( " Z: \\ 音乐 \\ 总之就是非常酸 \\ ED \\ カノエラナ - 月と星空 \\ カノエラナ.wav " ) ;
System . out . println ( new MusicTools ( ) . getMetadata ( file ) ) ;
file = new File ( " Z: \\ 音乐 \\ 终将成为你 \\ [OP]君にふれて \\ rise.flac " ) ;
// file = new File("Z:\\音乐\\周董\\2012 十二新作\\03 公公偏头痛.ape");
System . out . println ( new MusicTools ( ) . getMetadataOfFFmpeg ( file ) ) ;
}