diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 63ca34f..c1d5207 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,12 @@ spring-boot-starter-thymeleaf + + net.jthink + jaudiotagger + 3.0.1 + + diff --git a/src/main/java/top/baogutang/music/client/NetEaseMusicClient.java b/src/main/java/top/baogutang/music/client/NetEaseMusicClient.java index 94e58ad..a8580b0 100644 --- a/src/main/java/top/baogutang/music/client/NetEaseMusicClient.java +++ b/src/main/java/top/baogutang/music/client/NetEaseMusicClient.java @@ -8,6 +8,7 @@ import top.baogutang.music.domain.req.search.MusicSearchReq; import top.baogutang.music.domain.res.download.MusicDownloadRes; import top.baogutang.music.domain.res.search.*; import top.baogutang.music.enums.ChannelEnum; +import top.baogutang.music.processor.AbstractAudioProcessor; import top.baogutang.music.properties.NetEaseMusicProperties; import top.baogutang.music.service.IMusicRecordService; import top.baogutang.music.utils.OkHttpUtil; @@ -101,19 +102,13 @@ public class NetEaseMusicClient implements ChannelClient StringUtils.equalsIgnoreCase(fileType, f.name())) + .findFirst() + .orElse(OTHERS); + } +} diff --git a/src/main/java/top/baogutang/music/processor/AbstractAudioProcessor.java b/src/main/java/top/baogutang/music/processor/AbstractAudioProcessor.java new file mode 100644 index 0000000..1bd1a9b --- /dev/null +++ b/src/main/java/top/baogutang/music/processor/AbstractAudioProcessor.java @@ -0,0 +1,85 @@ +package top.baogutang.music.processor; + +import lombok.extern.slf4j.Slf4j; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.CannotWriteException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.tag.TagException; +import top.baogutang.music.domain.res.download.MusicDownloadRes; +import top.baogutang.music.enums.AudioFileTypeEnum; +import top.baogutang.music.exceptions.BusinessException; + +import java.io.*; +import java.net.URL; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 12:15 + */ +@Slf4j +public abstract class AbstractAudioProcessor { + + public static AbstractAudioProcessor getAudioProcessor(String fileType) { + AudioFileTypeEnum fileTypeEnum = AudioFileTypeEnum.parse(fileType); + switch (fileTypeEnum) { + case FLAC: + return new FlacAudioProcessor(); + case MP3: + return new Mp3AudioProcessor(); + default: + throw new BusinessException("不支持文件格式"); + } + } + + public InputStream processAudioTags(InputStream inputStream, MusicDownloadRes res) { + File file = null; + try { + file = convertInputStreamToTempFile(inputStream); + return process(file, res); + } catch (Exception e) { + log.error(">>>>>>>>>>processAudioTags error:{}<<<<<<<<<<", e.getMessage(), e); + return null; + } finally { + if (file != null && file.exists()) { + file.delete(); + } + } + } + + abstract InputStream process(File file, MusicDownloadRes res) throws TagException, CannotWriteException, IOException, CannotReadException, InvalidAudioFrameException, ReadOnlyFileException; + + + protected byte[] fetchImageData(String imageUrl) { + try (InputStream inputStream = new URL(imageUrl).openStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + return outputStream.toByteArray(); + } catch (IOException e) { + log.error("Error downloading image from URL: {}", imageUrl, e); + return new byte[0]; + } + } + + + private File convertInputStreamToTempFile(InputStream inputStream) throws IOException { + // 创建临时文件 + File tempFile = File.createTempFile("tempFile", ".tmp"); + // 写入 InputStream 数据到临时文件 + try (FileOutputStream outputStream = new FileOutputStream(tempFile)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + } + return tempFile; + } +} diff --git a/src/main/java/top/baogutang/music/processor/FlacAudioProcessor.java b/src/main/java/top/baogutang/music/processor/FlacAudioProcessor.java new file mode 100644 index 0000000..d31f0a0 --- /dev/null +++ b/src/main/java/top/baogutang/music/processor/FlacAudioProcessor.java @@ -0,0 +1,49 @@ +package top.baogutang.music.processor; + +import lombok.extern.slf4j.Slf4j; +import org.jaudiotagger.audio.AudioFile; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.CannotWriteException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.audio.flac.FlacFileReader; +import org.jaudiotagger.audio.flac.FlacFileWriter; +import org.jaudiotagger.tag.FieldDataInvalidException; +import org.jaudiotagger.tag.FieldKey; +import org.jaudiotagger.tag.Tag; +import org.jaudiotagger.tag.TagException; +import org.jaudiotagger.tag.images.StandardArtwork; +import top.baogutang.music.domain.res.download.MusicDownloadRes; + +import java.io.*; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 10:40 + */ +@Slf4j +public class FlacAudioProcessor extends AbstractAudioProcessor { + + + @Override + InputStream process(File file, MusicDownloadRes res) throws TagException, CannotWriteException, IOException, CannotReadException, InvalidAudioFrameException, ReadOnlyFileException { + FlacFileReader flacFileReader = new FlacFileReader(); + AudioFile audioFile = flacFileReader.read(file); + Tag tag = audioFile.getTag(); + tag.setField(FieldKey.TITLE, res.getName()); + tag.setField(FieldKey.ALBUM, res.getAlbumName()); + tag.setField(FieldKey.ARTIST, res.getArtistName()); + tag.setField(FieldKey.LYRICS, res.getLyric()); + StandardArtwork artwork = new StandardArtwork(); + artwork.setImageUrl(res.getPic()); + artwork.setBinaryData(fetchImageData(res.getPic())); + tag.setField(artwork); + FlacFileWriter flacFileWriter = new FlacFileWriter(); + flacFileWriter.write(audioFile); + return new FileInputStream(file); + } +} + diff --git a/src/main/java/top/baogutang/music/processor/Mp3AudioProcessor.java b/src/main/java/top/baogutang/music/processor/Mp3AudioProcessor.java new file mode 100644 index 0000000..5acdec3 --- /dev/null +++ b/src/main/java/top/baogutang/music/processor/Mp3AudioProcessor.java @@ -0,0 +1,48 @@ +package top.baogutang.music.processor; + +import lombok.extern.slf4j.Slf4j; +import org.jaudiotagger.audio.AudioFile; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.CannotWriteException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.audio.flac.FlacFileWriter; +import org.jaudiotagger.audio.mp3.MP3FileReader; +import org.jaudiotagger.tag.FieldKey; +import org.jaudiotagger.tag.Tag; +import org.jaudiotagger.tag.TagException; +import org.jaudiotagger.tag.images.StandardArtwork; +import top.baogutang.music.domain.res.download.MusicDownloadRes; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 13:32 + */ +@Slf4j +public class Mp3AudioProcessor extends AbstractAudioProcessor { + @Override + InputStream process(File file, MusicDownloadRes res) throws TagException, CannotWriteException, IOException, CannotReadException, InvalidAudioFrameException, ReadOnlyFileException { + MP3FileReader fileReader = new MP3FileReader(); + AudioFile audioFile = fileReader.read(file); + Tag tag = audioFile.getTag(); + tag.setField(FieldKey.TITLE, res.getName()); + tag.setField(FieldKey.ALBUM, res.getAlbumName()); + tag.setField(FieldKey.ARTIST, res.getArtistName()); + tag.setField(FieldKey.LYRICS, res.getLyric()); + StandardArtwork artwork = new StandardArtwork(); + artwork.setImageUrl(res.getPic()); + artwork.setBinaryData(fetchImageData(res.getPic())); + tag.setField(artwork); + FlacFileWriter flacFileWriter = new FlacFileWriter(); + flacFileWriter.write(audioFile); + return new FileInputStream(file); + } +} diff --git a/src/main/java/top/baogutang/music/service/AbstractMusicService.java b/src/main/java/top/baogutang/music/service/AbstractMusicService.java index 1b5b917..691e2c5 100644 --- a/src/main/java/top/baogutang/music/service/AbstractMusicService.java +++ b/src/main/java/top/baogutang/music/service/AbstractMusicService.java @@ -1,6 +1,7 @@ package top.baogutang.music.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import top.baogutang.music.client.ChannelClient; import top.baogutang.music.domain.req.AbstractMusicReq; import top.baogutang.music.domain.req.search.MusicSearchReq; @@ -68,21 +69,28 @@ public abstract class AbstractMusicService channelClient = channelClientFactory.getClient(channelEnum); MusicDownloadRes res = channelClient.download(id); - channelClient.saveMusic(res); -// CompletableFuture.runAsync(() -> { -// try { -// channelClient.processFile(res); -// } catch (IOException e) { -// log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e); -// throw new BusinessException("下载异常"); -// } -// }, commonExecutor); - try { - channelClient.processFile(res); - } catch (IOException e) { - log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e); - throw new BusinessException("下载异常"); + if (StringUtils.isNotBlank(res.getArtistName())) { + String[] split = res.getArtistName().split("/"); + String artistName = String.join(",", split); + res.setArtistName(artistName); } + + channelClient.saveMusic(res); + CompletableFuture.runAsync(() -> { + try { + channelClient.processFile(res); + log.info(">>>>>>>>>>download file:{} success<<<<<<<<<<", res.getName()); + } catch (IOException e) { + log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e); + throw new BusinessException("下载异常"); + } + }, commonExecutor); +// try { +// channelClient.processFile(res); +// } catch (IOException e) { +// log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e); +// throw new BusinessException("下载异常"); +// } return res; } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0a65245..556eb77 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -45,5 +45,5 @@ baogutang: album-base-url: http://117.72.78.133:5173/album?id=%d artist-base-url: http://117.72.78.133:5173/artists?id=%d download-base-url: https://api.sooooooooooooooooootheby.top/Netease_url/Song_V1?level=jymaster&type=json&ids=%d - download-path: /baogutang-music/download/music + download-path: /Users/nikooh/Desktop/Download