From f3c70b89beb0b0455af02dcdf1b1a559c2799000 Mon Sep 17 00:00:00 2001 From: N1KO Date: Thu, 12 Dec 2024 21:00:13 +0800 Subject: [PATCH] add qq music --- .../baogutang/music/client/ChannelClient.java | 10 +- .../music/client/NetEaseMusicClient.java | 20 +- .../baogutang/music/client/QQMusicClient.java | 336 ++++++++++++++++++ .../music/config/ExecutorConfig.java | 8 +- .../controller/MusicDownloadController.java | 2 +- .../controller/MusicSearchController.java | 8 +- .../domain/res/download/MusicDownloadRes.java | 2 +- .../res/download/QQMusicDownloadRes.java | 111 ++++++ .../domain/res/search/MusicAlbumRes.java | 6 +- .../domain/res/search/MusicPlaylistRes.java | 6 +- .../domain/res/search/MusicSearchRes.java | 8 +- .../res/search/QQMusicSearchCommonRes.java | 163 +++++++++ .../music/enums/MusicQualityEnum.java | 29 +- .../baogutang/music/enums/SearchTypeEnum.java | 23 +- .../music/properties/QQMusicProperties.java | 29 ++ .../music/service/AbstractMusicService.java | 15 +- .../music/service/IQQMusicService.java | 20 ++ src/main/resources/application.yml | 10 + src/main/resources/templates/music.html | 4 +- 19 files changed, 753 insertions(+), 57 deletions(-) create mode 100644 src/main/java/top/baogutang/music/client/QQMusicClient.java create mode 100644 src/main/java/top/baogutang/music/domain/res/download/QQMusicDownloadRes.java create mode 100644 src/main/java/top/baogutang/music/domain/res/search/QQMusicSearchCommonRes.java create mode 100644 src/main/java/top/baogutang/music/properties/QQMusicProperties.java create mode 100644 src/main/java/top/baogutang/music/service/IQQMusicService.java diff --git a/src/main/java/top/baogutang/music/client/ChannelClient.java b/src/main/java/top/baogutang/music/client/ChannelClient.java index e0d019f..b6050c0 100644 --- a/src/main/java/top/baogutang/music/client/ChannelClient.java +++ b/src/main/java/top/baogutang/music/client/ChannelClient.java @@ -19,15 +19,15 @@ public interface ChannelClient() { }); } @Override - public MusicDetailRes detail(Long id) { - String detailUrl = String.format(netEaseMusicProperties.getDownloadBaseUrl(), id); + public MusicDetailRes detail(String id) { + String detailUrl = String.format(netEaseMusicProperties.getDownloadBaseUrl(), Long.valueOf(id)); return OkHttpUtil.get(detailUrl, null, null, new TypeReference<>() { }); } @Override - public MusicAlbumRes album(Long id) { - String albumUrl = String.format(netEaseMusicProperties.getAlbumBaseUrl(), id); + public MusicAlbumRes album(String id) { + String albumUrl = String.format(netEaseMusicProperties.getAlbumBaseUrl(), Long.valueOf(id)); return OkHttpUtil.get(albumUrl, null, null, new TypeReference<>() { }); } @Override - public MusicArtistRes artist(Long id) { - String albumUrl = String.format(netEaseMusicProperties.getArtistBaseUrl(), id); + public MusicArtistRes artist(String id) { + String albumUrl = String.format(netEaseMusicProperties.getArtistBaseUrl(), Long.valueOf(id)); return OkHttpUtil.get(albumUrl, null, null, new TypeReference<>() { }); } @Override - public MusicDownloadRes download(Long id) { - String downloadUrl = String.format(netEaseMusicProperties.getDownloadBaseUrl(), id); + public MusicDownloadRes download(String id) { + String downloadUrl = String.format(netEaseMusicProperties.getDownloadBaseUrl(), Long.valueOf(id)); MusicDownloadRes res = OkHttpUtil.get(downloadUrl, null, null, new TypeReference<>() { }); if (Objects.nonNull(res)) { diff --git a/src/main/java/top/baogutang/music/client/QQMusicClient.java b/src/main/java/top/baogutang/music/client/QQMusicClient.java new file mode 100644 index 0000000..6c34068 --- /dev/null +++ b/src/main/java/top/baogutang/music/client/QQMusicClient.java @@ -0,0 +1,336 @@ +package top.baogutang.music.client; + +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import top.baogutang.music.annos.ChannelInfo; +import top.baogutang.music.domain.req.search.MusicSearchReq; +import top.baogutang.music.domain.res.download.MusicDownloadRes; +import top.baogutang.music.domain.res.download.QQMusicDownloadRes; +import top.baogutang.music.domain.res.search.*; +import top.baogutang.music.enums.ChannelEnum; +import top.baogutang.music.enums.MusicQualityEnum; +import top.baogutang.music.enums.SearchTypeEnum; +import top.baogutang.music.exceptions.BusinessException; +import top.baogutang.music.processor.AbstractAudioProcessor; +import top.baogutang.music.properties.QQMusicProperties; +import top.baogutang.music.service.IMusicRecordService; +import top.baogutang.music.utils.OkHttpUtil; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 15:00 + */ +@Slf4j +@Component +@ChannelInfo(ChannelEnum.QQ_MUSIC) +public class QQMusicClient implements ChannelClient { + + @Resource + private QQMusicProperties qqMusicProperties; + + @Resource + private IMusicRecordService musicRecordService; + + @Override + public MusicSearchRes search(MusicSearchReq req) { + Integer pageNo = (req.getOffset() / req.getLimit()) + 1; + SearchTypeEnum searchType = SearchTypeEnum.parseQQMusicCode(req.getType()); + if (searchType == null) { + throw new BusinessException("不支持的搜索类型"); + } + String searchUrl = String.format(qqMusicProperties.getQueryBaseUrl(), req.getKeywords(), pageNo, req.getLimit(), searchType.getQqMusicCode()); + switch (searchType) { + case SONG: + return searchSong(searchUrl, pageNo, req.getLimit()); + case ALBUM: + return searchAlbum(searchUrl, pageNo, req.getLimit()); + case PLAYLIST: + return searchPlayList(searchUrl, pageNo, req.getLimit()); + case SINGER: + return searchSinger(searchUrl, pageNo, req.getLimit()); + default: + throw new BusinessException("不支持的搜索类型"); + } + } + + private MusicSearchRes searchSinger(String searchUrl, Integer pageNo, Integer pageSize) { + QQMusicSearchCommonRes qqMusicSearchCommonRes = OkHttpUtil.get(searchUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) { + return null; + } + MusicSearchRes musicSearchRes = new MusicSearchRes(); + musicSearchRes.setCode(200); + MusicSearchRes.SearchResult searchResult = new MusicSearchRes.SearchResult(); + searchResult.setHasMore(pageNo * pageSize < qqMusicSearchCommonRes.getData().getTotal()); + List artistList = qqMusicSearchCommonRes.getData().getList().stream() + .map(singer -> { + MusicSearchRes.Artist artist = new MusicSearchRes.Artist(); + artist.setId(singer.getSingerMId()); + artist.setName(singer.getSingerName()); + artist.setPicUrl(singer.getSingerPic()); + return artist; + }) + .collect(Collectors.toList()); + searchResult.setArtists(artistList); + musicSearchRes.setResult(searchResult); + return musicSearchRes; + } + + private MusicSearchRes searchPlayList(String searchUrl, Integer pageNo, Integer pageSize) { + QQMusicSearchCommonRes qqMusicSearchCommonRes = OkHttpUtil.get(searchUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) { + return null; + } + MusicSearchRes musicSearchRes = new MusicSearchRes(); + musicSearchRes.setCode(200); + MusicSearchRes.SearchResult searchResult = new MusicSearchRes.SearchResult(); + searchResult.setHasMore(pageNo * pageSize < qqMusicSearchCommonRes.getData().getTotal()); + List playLists = qqMusicSearchCommonRes.getData().getList().stream() + .map(songList -> { + MusicSearchRes.PlayList playList = new MusicSearchRes.PlayList(); + playList.setId(songList.getDissId()); + playList.setName(songList.getDissName()); + playList.setCoverImgUrl(songList.getImgUrl()); + return playList; + }) + .collect(Collectors.toList()); + searchResult.setPlaylists(playLists); + musicSearchRes.setResult(searchResult); + return musicSearchRes; + } + + private MusicSearchRes searchAlbum(String searchUrl, Integer pageNo, Integer pageSize) { + QQMusicSearchCommonRes qqMusicSearchCommonRes = OkHttpUtil.get(searchUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) { + return null; + } + MusicSearchRes musicSearchRes = new MusicSearchRes(); + musicSearchRes.setCode(200); + MusicSearchRes.SearchResult searchResult = new MusicSearchRes.SearchResult(); + searchResult.setHasMore(pageNo * pageSize < qqMusicSearchCommonRes.getData().getTotal()); + List albumList = qqMusicSearchCommonRes.getData().getList().stream() + .map(a -> { + MusicSearchRes.Album album = new MusicSearchRes.Album(); + album.setId(a.getAlbumMId()); + album.setName(a.getAlbumName()); + album.setBlurPicUrl(a.getAlbumPic()); + return album; + }) + .collect(Collectors.toList()); + searchResult.setAlbums(albumList); + musicSearchRes.setResult(searchResult); + return musicSearchRes; + } + + private MusicSearchRes searchSong(String searchUrl, Integer pageNo, Integer pageSize) { + QQMusicSearchCommonRes qqMusicSearchCommonRes = OkHttpUtil.get(searchUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) { + return null; + } + MusicSearchRes musicSearchRes = new MusicSearchRes(); + musicSearchRes.setCode(200); + MusicSearchRes.SearchResult searchResult = new MusicSearchRes.SearchResult(); + searchResult.setHasMore(pageNo * pageSize < qqMusicSearchCommonRes.getData().getTotal()); + List songList = qqMusicSearchCommonRes.getData().getList().stream() + .map(s -> { + MusicSearchRes.Song song = new MusicSearchRes.Song(); + song.setId(s.getSongMId()); + song.setName(s.getSongName()); + List artistList = s.getSingerList().stream() + .map(si -> { + MusicSearchRes.Artist artist = new MusicSearchRes.Artist(); + artist.setId(si.getMid()); + artist.setName(si.getName()); + return artist; + }) + .collect(Collectors.toList()); + song.setArtists(artistList); + MusicSearchRes.Album album = new MusicSearchRes.Album(); + album.setId(s.getAlbumMId()); + album.setName(s.getAlbumName()); + song.setAlbum(album); + return song; + }) + .collect(Collectors.toList()); + searchResult.setSongs(songList); + + musicSearchRes.setResult(searchResult); + return musicSearchRes; + } + + @Override + public MusicPlaylistRes playlist(String id) { + String playlistUrl = String.format(qqMusicProperties.getPlaylistBaseUrl(), id); + QQMusicSearchCommonRes qqMusicSearchCommonRes = OkHttpUtil.get(playlistUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) { + return null; + } + List songs = qqMusicSearchCommonRes.getData().getSongList().stream() + .map(s -> { + MusicPlaylistRes.Song song = new MusicPlaylistRes.Song(); + song.setId(s.getSongMId()); + song.setName(s.getSongName()); + List artists = s.getSingerList().stream() + .map(songSinger -> { + MusicPlaylistRes.Artist artist = new MusicPlaylistRes.Artist(); + artist.setId(songSinger.getMid()); + artist.setName(songSinger.getName()); + return artist; + }) + .collect(Collectors.toList()); + song.setAr(artists); + MusicPlaylistRes.Album album = new MusicPlaylistRes.Album(); + album.setId(s.getAlbumMId()); + album.setName(s.getAlbumName()); + song.setAl(album); + return song; + }) + .collect(Collectors.toList()); + MusicPlaylistRes musicPlaylistRes = new MusicPlaylistRes(); + musicPlaylistRes.setCode(200); + musicPlaylistRes.setSongs(songs); + return musicPlaylistRes; + } + + @Override + public MusicDetailRes detail(String id) { + return null; + } + + @Override + public MusicAlbumRes album(String id) { + String albumUrl = String.format(qqMusicProperties.getAlbumBaseUrl(), id); + QQMusicSearchCommonRes qqMusicSearchCommonRes = OkHttpUtil.get(albumUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) { + return null; + } + List songs = qqMusicSearchCommonRes.getData().getList().stream() + .map(albumSong -> { + MusicAlbumRes.Song song = new MusicAlbumRes.Song(); + song.setId(albumSong.getMid()); + song.setName(albumSong.getName()); + List artists = albumSong.getSingerList().stream() + .map(songSinger -> { + MusicAlbumRes.Artist artist = new MusicAlbumRes.Artist(); + artist.setId(songSinger.getMid()); + artist.setName(songSinger.getName()); + return artist; + }) + .collect(Collectors.toList()); + song.setAr(artists); + MusicAlbumRes.Album album = new MusicAlbumRes.Album(); + album.setId(albumSong.getAlbum().getMid()); + album.setName(albumSong.getAlbum().getName()); + song.setAl(album); + return song; + }) + .collect(Collectors.toList()); + MusicAlbumRes musicAlbumRes = new MusicAlbumRes(); + musicAlbumRes.setCode(200); + musicAlbumRes.setSongs(songs); + return musicAlbumRes; + } + + @Override + public MusicArtistRes artist(String id) { + return null; + } + + @Override + public MusicDownloadRes download(String id) { + String downloadUrl = String.format(qqMusicProperties.getDownloadBaseUrl(), id); + QQMusicDownloadRes qqMusicDownloadRes = OkHttpUtil.get(downloadUrl, null, null, new TypeReference<>() { + }); + if (Objects.isNull(qqMusicDownloadRes) || Objects.isNull(qqMusicDownloadRes.getMusicUrlInfo())) { + return null; + } + + MusicDownloadRes musicDownloadRes = new MusicDownloadRes(); + musicDownloadRes.setAlbumName(qqMusicDownloadRes.getSong().getAlbum()); + musicDownloadRes.setArtistName(qqMusicDownloadRes.getSong().getSinger()); + musicDownloadRes.setPic(qqMusicDownloadRes.getSong().getPic()); + musicDownloadRes.setName(qqMusicDownloadRes.getSong().getName()); + QQMusicDownloadRes.MusicUrlInfo musicUrlInfo = qqMusicDownloadRes.getMusicUrlInfo(); + if (Objects.nonNull(musicUrlInfo.getUrlInfoMaster())) { + musicDownloadRes.setUrl(musicUrlInfo.getUrlInfoMaster().getUrl()); + musicDownloadRes.setLevel(musicUrlInfo.getUrlInfoMaster().getBitrate()); + } else if (Objects.nonNull(musicUrlInfo.getUrlInfoAtmos2())) { + musicDownloadRes.setUrl(musicUrlInfo.getUrlInfoAtmos2().getUrl()); + musicDownloadRes.setLevel(musicUrlInfo.getUrlInfoAtmos2().getBitrate()); + } else if (Objects.nonNull(musicUrlInfo.getUrlInfoAtmos51())) { + musicDownloadRes.setUrl(musicUrlInfo.getUrlInfoAtmos51().getUrl()); + musicDownloadRes.setLevel(musicUrlInfo.getUrlInfoAtmos51().getBitrate()); + } else if (Objects.nonNull(musicUrlInfo.getUrlInfoFlac())) { + musicDownloadRes.setUrl(musicUrlInfo.getUrlInfoFlac().getUrl()); + musicDownloadRes.setLevel(musicUrlInfo.getUrlInfoFlac().getBitrate()); + } else if (Objects.nonNull(musicUrlInfo.getUrlInfo320())) { + musicDownloadRes.setUrl(musicUrlInfo.getUrlInfo320().getUrl()); + musicDownloadRes.setLevel(musicUrlInfo.getUrlInfo320().getBitrate()); + } else if (Objects.nonNull(musicUrlInfo.getUrlInfo128())) { + musicDownloadRes.setUrl(musicUrlInfo.getUrlInfo128().getUrl()); + musicDownloadRes.setLevel(musicUrlInfo.getUrlInfo128().getBitrate()); + } + QQMusicDownloadRes.Lyrics lyric = qqMusicDownloadRes.getLyric(); + if (Objects.nonNull(lyric)) { + if (StringUtils.isNotBlank(lyric.getLyric())) { + musicDownloadRes.setLyric(lyric.getLyric()); + } else if (StringUtils.isNotBlank(lyric.getTyLyric())) { + musicDownloadRes.setLyric(lyric.getTyLyric()); + } + } + musicDownloadRes.setId(qqMusicDownloadRes.getSong().getMid()); + return musicDownloadRes; + } + + @Override + public void saveMusic(MusicDownloadRes res) { + musicRecordService.save(res, ChannelEnum.QQ_MUSIC); + + } + + @Override + public void processFile(MusicDownloadRes res) throws IOException { + if (Objects.isNull(res) || Objects.isNull(res.getName()) || Objects.isNull(res.getUrl())) { + return; + } + Path baseDir = Paths.get(qqMusicProperties.getDownloadPath(), res.getName()); + if (!Files.exists(baseDir)) { + Files.createDirectories(baseDir); + } + MusicQualityEnum musicQualityEnum = MusicQualityEnum.parse(res.getLevel()); + if (Objects.isNull(musicQualityEnum)) { + throw new BusinessException("不支持的文件格式"); + } + String fileType = musicQualityEnum.getType(); + AbstractAudioProcessor audioProcessor = AbstractAudioProcessor.getAudioProcessor(fileType); + try (InputStream musicIn = audioProcessor.processAudioTags(new URL(res.getUrl()).openStream(), res)) { + if (Objects.nonNull(musicIn)) { + Files.copy(musicIn, baseDir.resolve(res.getName() + "." + fileType), StandardCopyOption.REPLACE_EXISTING); + } + } + } + +} diff --git a/src/main/java/top/baogutang/music/config/ExecutorConfig.java b/src/main/java/top/baogutang/music/config/ExecutorConfig.java index 44319cc..7e51d5f 100644 --- a/src/main/java/top/baogutang/music/config/ExecutorConfig.java +++ b/src/main/java/top/baogutang/music/config/ExecutorConfig.java @@ -20,16 +20,16 @@ public class ExecutorConfig { @Value("${spring.application.name}") private String appName; - @Value("${thread.pool.core.pool.size:5}") + @Value("${thread.pool.core.pool.size:4}") private Integer corePoolSize; - @Value("${thread.pool.max.pool.size:10}") + @Value("${thread.pool.max.pool.size:8}") private Integer maxPoolSize; - @Value("${thread.pool.keep.alive.second:10}") + @Value("${thread.pool.keep.alive.second:20}") private Integer keepAliveSecond; - @Value("${thread.pool.queue.capacity:200}") + @Value("${thread.pool.queue.capacity:400}") private Integer queueCapacity; @Bean("commonExecutor") diff --git a/src/main/java/top/baogutang/music/controller/MusicDownloadController.java b/src/main/java/top/baogutang/music/controller/MusicDownloadController.java index 0caff5f..cc08b9e 100644 --- a/src/main/java/top/baogutang/music/controller/MusicDownloadController.java +++ b/src/main/java/top/baogutang/music/controller/MusicDownloadController.java @@ -29,7 +29,7 @@ public class MusicDownloadController { @GetMapping public Results download(@RequestParam(name = "channel") Integer channel, - @RequestParam(name = "id") Long id) { + @RequestParam(name = "id") String id) { MusicDownloadRes res = musicService.getMusicService(channel).download(id); return Results.ok(res); } diff --git a/src/main/java/top/baogutang/music/controller/MusicSearchController.java b/src/main/java/top/baogutang/music/controller/MusicSearchController.java index 4aaa5d4..2d7d306 100644 --- a/src/main/java/top/baogutang/music/controller/MusicSearchController.java +++ b/src/main/java/top/baogutang/music/controller/MusicSearchController.java @@ -35,28 +35,28 @@ public class MusicSearchController { @GetMapping("/playlist") public Results playlist(@RequestParam(name = "channel") Integer channel, - @RequestParam(name = "id") Long id) { + @RequestParam(name = "id") String id) { MusicPlaylistRes res = musicService.getMusicService(channel).playList(id); return Results.ok(res); } @GetMapping("/album") public Results album(@RequestParam(name = "channel") Integer channel, - @RequestParam(name = "id") Long id) { + @RequestParam(name = "id") String id) { MusicAlbumRes res = musicService.getMusicService(channel).album(id); return Results.ok(res); } @GetMapping("/artist") public Results artist(@RequestParam(name = "channel") Integer channel, - @RequestParam(name = "id") Long id) { + @RequestParam(name = "id") String id) { MusicArtistRes res = musicService.getMusicService(channel).artist(id); return Results.ok(res); } @GetMapping("/detail") public Results detail(@RequestParam(name = "channel") Integer channel, - @RequestParam(name = "id") Long id) { + @RequestParam(name = "id") String id) { MusicDetailRes res = musicService.getMusicService(channel).detail(id); return Results.ok(res); } diff --git a/src/main/java/top/baogutang/music/domain/res/download/MusicDownloadRes.java b/src/main/java/top/baogutang/music/domain/res/download/MusicDownloadRes.java index ba75d53..543f5bb 100644 --- a/src/main/java/top/baogutang/music/domain/res/download/MusicDownloadRes.java +++ b/src/main/java/top/baogutang/music/domain/res/download/MusicDownloadRes.java @@ -34,7 +34,7 @@ public class MusicDownloadRes extends AbstractMusicRes implements Serializable { private String url; - private Long id; + private String id; private String level; diff --git a/src/main/java/top/baogutang/music/domain/res/download/QQMusicDownloadRes.java b/src/main/java/top/baogutang/music/domain/res/download/QQMusicDownloadRes.java new file mode 100644 index 0000000..2f8ba43 --- /dev/null +++ b/src/main/java/top/baogutang/music/domain/res/download/QQMusicDownloadRes.java @@ -0,0 +1,111 @@ +package top.baogutang.music.domain.res.download; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 19:57 + */ +@Data +public class QQMusicDownloadRes implements Serializable { + + private static final long serialVersionUID = -2144922274595203436L; + + private Song song; + + private Lyrics lyric; + + @JsonProperty("music_urls") + private MusicUrlInfo musicUrlInfo; + + + @Data + public static class Lyrics implements Serializable { + + private static final long serialVersionUID = 1794917161758016855L; + + private String lyric; + + @JsonProperty("tylyric") + private String tyLyric; + + } + + @Data + public static class MusicUrlInfo implements Serializable { + + private static final long serialVersionUID = -997850661214656516L; + + @JsonProperty("128") + private UrlInfo urlInfo128; + + @JsonProperty("320") + private UrlInfo urlInfo320; + + @JsonProperty("aac_48") + private UrlInfo urlInfoAcc48; + + @JsonProperty("aac_96") + private UrlInfo urlInfoAcc96; + + @JsonProperty("aac_192") + private UrlInfo urlInfoAcc192; + + @JsonProperty("ogg_96") + private UrlInfo urlInfoOgg96; + + @JsonProperty("ogg_192") + private UrlInfo urlInfoOgg192; + + @JsonProperty("ogg_320") + private UrlInfo urlInfoOgg320; + + @JsonProperty("ogg_640") + private UrlInfo urlInfoOgg640; + + @JsonProperty("atmos_51") + private UrlInfo urlInfoAtmos51; + + @JsonProperty("atmos_2") + private UrlInfo urlInfoAtmos2; + + @JsonProperty("master") + private UrlInfo urlInfoMaster; + + @JsonProperty("flac") + private UrlInfo urlInfoFlac; + } + + @Data + public static class UrlInfo implements Serializable { + + private static final long serialVersionUID = 6599595524714274175L; + + private String url; + + private String bitrate; + } + + @Data + public static class Song implements Serializable { + + private static final long serialVersionUID = 211886010815586443L; + + private String name; + + private String album; + + private String singer; + + private String pic; + + private String mid; + + } +} diff --git a/src/main/java/top/baogutang/music/domain/res/search/MusicAlbumRes.java b/src/main/java/top/baogutang/music/domain/res/search/MusicAlbumRes.java index 4e6587d..c31b52c 100644 --- a/src/main/java/top/baogutang/music/domain/res/search/MusicAlbumRes.java +++ b/src/main/java/top/baogutang/music/domain/res/search/MusicAlbumRes.java @@ -29,7 +29,7 @@ public class MusicAlbumRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -3111291245613339667L; - private long id; + private String id; private String name; @@ -43,7 +43,7 @@ public class MusicAlbumRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = 1103297822656245236L; - private long id; + private String id; private String name; @@ -55,7 +55,7 @@ public class MusicAlbumRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -5403293880708265600L; - private long id; + private String id; private String name; } diff --git a/src/main/java/top/baogutang/music/domain/res/search/MusicPlaylistRes.java b/src/main/java/top/baogutang/music/domain/res/search/MusicPlaylistRes.java index af68028..b563b90 100644 --- a/src/main/java/top/baogutang/music/domain/res/search/MusicPlaylistRes.java +++ b/src/main/java/top/baogutang/music/domain/res/search/MusicPlaylistRes.java @@ -29,7 +29,7 @@ public class MusicPlaylistRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = 1854475810777692098L; - private long id; + private String id; private String name; @@ -43,7 +43,7 @@ public class MusicPlaylistRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -8238903321545975920L; - private long id; + private String id; private String name; @@ -55,7 +55,7 @@ public class MusicPlaylistRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = 7806822401954161309L; - private long id; + private String id; private String name; } diff --git a/src/main/java/top/baogutang/music/domain/res/search/MusicSearchRes.java b/src/main/java/top/baogutang/music/domain/res/search/MusicSearchRes.java index 15828ab..41b35ac 100644 --- a/src/main/java/top/baogutang/music/domain/res/search/MusicSearchRes.java +++ b/src/main/java/top/baogutang/music/domain/res/search/MusicSearchRes.java @@ -46,7 +46,7 @@ public class MusicSearchRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -266782145902343916L; - private long id; + private String id; private String name; @@ -61,7 +61,7 @@ public class MusicSearchRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -4592741953573940059L; - private long id; + private String id; private String name; @@ -76,7 +76,7 @@ public class MusicSearchRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -8992566914406324393L; - private long id; + private String id; private String name; @@ -88,7 +88,7 @@ public class MusicSearchRes extends AbstractMusicRes implements Serializable { private static final long serialVersionUID = -780326125277012465L; - private long id; + private String id; private String name; diff --git a/src/main/java/top/baogutang/music/domain/res/search/QQMusicSearchCommonRes.java b/src/main/java/top/baogutang/music/domain/res/search/QQMusicSearchCommonRes.java new file mode 100644 index 0000000..f9ddd0c --- /dev/null +++ b/src/main/java/top/baogutang/music/domain/res/search/QQMusicSearchCommonRes.java @@ -0,0 +1,163 @@ +package top.baogutang.music.domain.res.search; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 16:35 + */ +@Data +public class QQMusicSearchCommonRes implements Serializable { + + private static final long serialVersionUID = -2791774281985201020L; + + private Integer result; + + private QQMusicData data; + + @Data + public static class QQMusicData implements Serializable { + + private static final long serialVersionUID = 1464488438086755639L; + + private Integer pageNo; + + private Integer pageSize; + + private Integer total; + + private List list; + + @JsonProperty("songlist") + private List songList; + } + + @Data + public static class AlbumSong implements Serializable { + + private static final long serialVersionUID = -9048864760949525029L; + + private Long id; + + private String mid; + + private String name; + + @JsonProperty("singer") + private List singerList; + + private SongAlbum album; + + + } + + @Data + public static class Song implements Serializable { + + private static final long serialVersionUID = -2124173681110948029L; + + @JsonProperty("songid") + private Long songId; + + @JsonProperty("songmid") + private String songMId; + + @JsonProperty("songname") + private String songName; + + @JsonProperty("albumid") + private Long albumId; + + @JsonProperty("albummid") + private String albumMId; + + @JsonProperty("albumname") + private String albumName; + + @JsonProperty("singer") + private List singerList; + + } + + @Data + public static class SongAlbum implements Serializable { + + private static final long serialVersionUID = 2480081595795584678L; + + private Long id; + + private String mid; + + private String name; + } + + @Data + public static class SongSinger implements Serializable { + + private static final long serialVersionUID = 3969955225404703588L; + + private Long id; + + private String mid; + + private String name; + } + + @Data + public static class SongList implements Serializable { + + private static final long serialVersionUID = -1946329011449068527L; + + @JsonProperty("dissid") + private String dissId; + + @JsonProperty("dissname") + private String dissName; + + @JsonProperty("imgurl") + private String imgUrl; + } + + @Data + public static class Album implements Serializable { + + private static final long serialVersionUID = 3962922926213972575L; + + @JsonProperty("albumID") + private Long albumId; + + @JsonProperty("albumMID") + private String albumMId; + + @JsonProperty("albumName") + private String albumName; + + @JsonProperty("albumPic") + private String albumPic; + } + + @Data + public static class Singer implements Serializable { + + private static final long serialVersionUID = 3969955225404703588L; + + @JsonProperty("singerID") + private Long singerId; + + @JsonProperty("singerMID") + private String singerMId; + + @JsonProperty("singerName") + private String singerName; + + @JsonProperty("singerPic") + private String singerPic; + } +} diff --git a/src/main/java/top/baogutang/music/enums/MusicQualityEnum.java b/src/main/java/top/baogutang/music/enums/MusicQualityEnum.java index 23dbb8b..cd7d6d8 100644 --- a/src/main/java/top/baogutang/music/enums/MusicQualityEnum.java +++ b/src/main/java/top/baogutang/music/enums/MusicQualityEnum.java @@ -26,22 +26,31 @@ public enum MusicQualityEnum { * dolby => 杜比全景声, * jymaster => 超清母带', */ - STANDARD("标准"), - HIGHER("较高"), - EXHIGH("极高"), - LOSSLESS("无损"), - HIRES("Hires音质"), - JYEFFECT("高清环绕声"), - SKY("沉浸环绕声"), - DOLBY("杜比全景声"), - JYMASTER("超清母带"), + STANDARD("标准", null), + HIGHER("较高", null), + EXHIGH("极高", null), + LOSSLESS("无损", null), + HIRES("Hires音质", null), + JYEFFECT("高清环绕声", null), + SKY("沉浸环绕声", null), + DOLBY("杜比全景声", null), + JYMASTER("超清母带", null), + KBPS_128("128kbps", "mp3"), + KBPS_320("320kbps", "mp3"), + ATMOS_5_1("Atmos 5.1", "flac"), + ATMOS_2("Atmos 2", "flac"), + MASTER("Master", "flac"), + FLAC("flac", "flac"), ; private final String desc; - MusicQualityEnum(String desc) { + private final String type; + + MusicQualityEnum(String desc, String type) { this.desc = desc; + this.type = type; } public static MusicQualityEnum parse(String level) { diff --git a/src/main/java/top/baogutang/music/enums/SearchTypeEnum.java b/src/main/java/top/baogutang/music/enums/SearchTypeEnum.java index dd1c79f..fe9b23f 100644 --- a/src/main/java/top/baogutang/music/enums/SearchTypeEnum.java +++ b/src/main/java/top/baogutang/music/enums/SearchTypeEnum.java @@ -2,6 +2,9 @@ package top.baogutang.music.enums; import lombok.Getter; +import java.util.Arrays; +import java.util.Objects; + /** * * @description: @@ -24,20 +27,30 @@ public enum SearchTypeEnum { * 1018:综合, * 2000:声音(搜索声音返回字段格式会不一样) */ - SONG(1, "单曲"), - ALBUM(10, "专辑"), - SINGER(100, "歌手"), - PLAYLIST(1000, "歌单"), + SONG(1, 0, "单曲"), + ALBUM(10, 8, "专辑"), + SINGER(100, 9, "歌手"), + PLAYLIST(1000, 2, "歌单"), ; private final Integer code; + private final Integer qqMusicCode; + private final String desc; - SearchTypeEnum(Integer code, String desc) { + SearchTypeEnum(Integer code, Integer qqMusicCode, String desc) { this.code = code; + this.qqMusicCode = qqMusicCode; this.desc = desc; } + + public static SearchTypeEnum parseQQMusicCode(Integer type) { + return Arrays.stream(SearchTypeEnum.values()) + .filter(searchType -> Objects.equals(searchType.getCode(), type)) + .findFirst() + .orElse(null); + } } diff --git a/src/main/java/top/baogutang/music/properties/QQMusicProperties.java b/src/main/java/top/baogutang/music/properties/QQMusicProperties.java new file mode 100644 index 0000000..4a8a0f7 --- /dev/null +++ b/src/main/java/top/baogutang/music/properties/QQMusicProperties.java @@ -0,0 +1,29 @@ +package top.baogutang.music.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 16:10 + */ +@Data +@Component +@ConfigurationProperties(prefix = "baogutang.qq-music") +public class QQMusicProperties { + + private String queryBaseUrl; + + private String playlistBaseUrl; + + private String albumBaseUrl; + + private String downloadBaseUrl; + + private String downloadPath; + +} diff --git a/src/main/java/top/baogutang/music/service/AbstractMusicService.java b/src/main/java/top/baogutang/music/service/AbstractMusicService.java index 691e2c5..85801b0 100644 --- a/src/main/java/top/baogutang/music/service/AbstractMusicService.java +++ b/src/main/java/top/baogutang/music/service/AbstractMusicService.java @@ -14,6 +14,7 @@ import top.baogutang.music.factory.ChannelClientFactory; import javax.annotation.Resource; import java.io.IOException; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -41,34 +42,38 @@ public abstract class AbstractMusicService channelClient = channelClientFactory.getClient(channelEnum); return channelClient.playlist(id); } - public MusicDetailRes detail(Long id) { + public MusicDetailRes detail(String id) { ChannelEnum channelEnum = getChannelEnum(); ChannelClient channelClient = channelClientFactory.getClient(channelEnum); return channelClient.detail(id); } - public MusicAlbumRes album(Long id) { + public MusicAlbumRes album(String id) { ChannelEnum channelEnum = getChannelEnum(); ChannelClient channelClient = channelClientFactory.getClient(channelEnum); return channelClient.album(id); } - public MusicArtistRes artist(Long id) { + public MusicArtistRes artist(String id) { ChannelEnum channelEnum = getChannelEnum(); ChannelClient channelClient = channelClientFactory.getClient(channelEnum); return channelClient.artist(id); } - public MusicDownloadRes download(Long id) { + public MusicDownloadRes download(String id) { ChannelEnum channelEnum = getChannelEnum(); ChannelClient channelClient = channelClientFactory.getClient(channelEnum); MusicDownloadRes res = channelClient.download(id); + if (Objects.isNull(res)) { + log.error(">>>>>>>>>>query detail error! channel:{},song id:{}<<<<<<<<<<", channelEnum.getDesc(), id); + return null; + } if (StringUtils.isNotBlank(res.getArtistName())) { String[] split = res.getArtistName().split("/"); String artistName = String.join(",", split); diff --git a/src/main/java/top/baogutang/music/service/IQQMusicService.java b/src/main/java/top/baogutang/music/service/IQQMusicService.java new file mode 100644 index 0000000..dea4dba --- /dev/null +++ b/src/main/java/top/baogutang/music/service/IQQMusicService.java @@ -0,0 +1,20 @@ +package top.baogutang.music.service; + +import org.springframework.stereotype.Service; +import top.baogutang.music.enums.ChannelEnum; + +/** + * + * @description: + * + * @author: N1KO + * @date: 2024/12/12 : 17:11 + */ +@Service +public class IQQMusicService extends AbstractMusicService { + + @Override + public ChannelEnum getChannelEnum() { + return ChannelEnum.QQ_MUSIC; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5d1d928..fd7bd3a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -46,4 +46,14 @@ baogutang: 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: /downloads/music +# download-path: /Users/nikooh/Desktop/downloads/music + qq-music: + query-base-url: http://117.72.78.133:5175/search?key=%s&pageNo=%d&pageSize=%d&t=%d + playlist-base-url: http://117.72.78.133:5175/songlist?id=%s + album-base-url: http://117.72.78.133:5175/album/songs?albummid=%s + download-base-url: http://117.72.78.133:5176/song?url=https://y.qq.com/n/ryqq/songDetail/%s + download-path: /downloads/music +# download-path: /Users/nikooh/Desktop/downloads/music + + diff --git a/src/main/resources/templates/music.html b/src/main/resources/templates/music.html index 6cad104..55cbbec 100644 --- a/src/main/resources/templates/music.html +++ b/src/main/resources/templates/music.html @@ -353,7 +353,7 @@ let selectedPlatformCode = null; let selectedSearchTypeCode = null; let offset = 0; - const limit = 50; + const limit = 20; let hasMore = false; let loading = false; @@ -549,7 +549,7 @@ albumItem.innerHTML = ` ${album.name}
${album.name}
-
${album.type}
+
${album.type ? album.type : ''}
`; const albumNameEl = albumItem.querySelector('.album-name');