add qq music
This commit is contained in:
parent
eacd618cd1
commit
f3c70b89be
@ -19,15 +19,15 @@ public interface ChannelClient<Q extends AbstractMusicReq, S extends AbstractMus
|
||||
|
||||
MusicSearchRes search(MusicSearchReq req);
|
||||
|
||||
MusicPlaylistRes playlist(Long id);
|
||||
MusicPlaylistRes playlist(String id);
|
||||
|
||||
MusicDetailRes detail(Long id);
|
||||
MusicDetailRes detail(String id);
|
||||
|
||||
MusicAlbumRes album(Long id);
|
||||
MusicAlbumRes album(String id);
|
||||
|
||||
MusicArtistRes artist(Long id);
|
||||
MusicArtistRes artist(String id);
|
||||
|
||||
MusicDownloadRes download(Long id);
|
||||
MusicDownloadRes download(String id);
|
||||
|
||||
void saveMusic(MusicDownloadRes res);
|
||||
|
||||
|
||||
@ -50,36 +50,36 @@ public class NetEaseMusicClient implements ChannelClient<MusicSearchReq, MusicSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public MusicPlaylistRes playlist(Long id) {
|
||||
String playlistUrl = String.format(netEaseMusicProperties.getPlaylistBaseUrl(), id);
|
||||
public MusicPlaylistRes playlist(String id) {
|
||||
String playlistUrl = String.format(netEaseMusicProperties.getPlaylistBaseUrl(), Long.valueOf(id));
|
||||
return OkHttpUtil.get(playlistUrl, null, null, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
|
||||
@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)) {
|
||||
|
||||
336
src/main/java/top/baogutang/music/client/QQMusicClient.java
Normal file
336
src/main/java/top/baogutang/music/client/QQMusicClient.java
Normal file
@ -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<MusicSearchReq, MusicSearchRes> {
|
||||
|
||||
@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.Singer> 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<MusicSearchRes.Artist> 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.SongList> 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<MusicSearchRes.PlayList> 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.Album> 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<MusicSearchRes.Album> 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.Song> 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<MusicSearchRes.Song> songList = qqMusicSearchCommonRes.getData().getList().stream()
|
||||
.map(s -> {
|
||||
MusicSearchRes.Song song = new MusicSearchRes.Song();
|
||||
song.setId(s.getSongMId());
|
||||
song.setName(s.getSongName());
|
||||
List<MusicSearchRes.Artist> 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.Song> qqMusicSearchCommonRes = OkHttpUtil.get(playlistUrl, null, null, new TypeReference<>() {
|
||||
});
|
||||
if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) {
|
||||
return null;
|
||||
}
|
||||
List<MusicPlaylistRes.Song> songs = qqMusicSearchCommonRes.getData().getSongList().stream()
|
||||
.map(s -> {
|
||||
MusicPlaylistRes.Song song = new MusicPlaylistRes.Song();
|
||||
song.setId(s.getSongMId());
|
||||
song.setName(s.getSongName());
|
||||
List<MusicPlaylistRes.Artist> 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.AlbumSong> qqMusicSearchCommonRes = OkHttpUtil.get(albumUrl, null, null, new TypeReference<>() {
|
||||
});
|
||||
if (Objects.isNull(qqMusicSearchCommonRes) || Objects.isNull(qqMusicSearchCommonRes.getData())) {
|
||||
return null;
|
||||
}
|
||||
List<MusicAlbumRes.Song> songs = qqMusicSearchCommonRes.getData().getList().stream()
|
||||
.map(albumSong -> {
|
||||
MusicAlbumRes.Song song = new MusicAlbumRes.Song();
|
||||
song.setId(albumSong.getMid());
|
||||
song.setName(albumSong.getName());
|
||||
List<MusicAlbumRes.Artist> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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")
|
||||
|
||||
@ -29,7 +29,7 @@ public class MusicDownloadController {
|
||||
|
||||
@GetMapping
|
||||
public Results<MusicDownloadRes> 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);
|
||||
}
|
||||
|
||||
@ -35,28 +35,28 @@ public class MusicSearchController {
|
||||
|
||||
@GetMapping("/playlist")
|
||||
public Results<MusicPlaylistRes> 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<MusicAlbumRes> 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<MusicArtistRes> 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<MusicDetailRes> 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);
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ public class MusicDownloadRes extends AbstractMusicRes implements Serializable {
|
||||
|
||||
private String url;
|
||||
|
||||
private Long id;
|
||||
private String id;
|
||||
|
||||
private String level;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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<T extends Serializable> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2791774281985201020L;
|
||||
|
||||
private Integer result;
|
||||
|
||||
private QQMusicData<T> data;
|
||||
|
||||
@Data
|
||||
public static class QQMusicData<T extends Serializable> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1464488438086755639L;
|
||||
|
||||
private Integer pageNo;
|
||||
|
||||
private Integer pageSize;
|
||||
|
||||
private Integer total;
|
||||
|
||||
private List<T> list;
|
||||
|
||||
@JsonProperty("songlist")
|
||||
private List<Song> 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<SongSinger> 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<SongSinger> 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;
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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<Q extends AbstractMusicReq, S extends
|
||||
return channelClient.search(req);
|
||||
}
|
||||
|
||||
public MusicPlaylistRes playList(Long id) {
|
||||
public MusicPlaylistRes playList(String id) {
|
||||
ChannelEnum channelEnum = getChannelEnum();
|
||||
ChannelClient<Q, S> channelClient = channelClientFactory.getClient(channelEnum);
|
||||
return channelClient.playlist(id);
|
||||
}
|
||||
|
||||
public MusicDetailRes detail(Long id) {
|
||||
public MusicDetailRes detail(String id) {
|
||||
ChannelEnum channelEnum = getChannelEnum();
|
||||
ChannelClient<Q, S> channelClient = channelClientFactory.getClient(channelEnum);
|
||||
return channelClient.detail(id);
|
||||
}
|
||||
|
||||
public MusicAlbumRes album(Long id) {
|
||||
public MusicAlbumRes album(String id) {
|
||||
ChannelEnum channelEnum = getChannelEnum();
|
||||
ChannelClient<Q, S> channelClient = channelClientFactory.getClient(channelEnum);
|
||||
return channelClient.album(id);
|
||||
}
|
||||
|
||||
public MusicArtistRes artist(Long id) {
|
||||
public MusicArtistRes artist(String id) {
|
||||
ChannelEnum channelEnum = getChannelEnum();
|
||||
ChannelClient<Q, S> channelClient = channelClientFactory.getClient(channelEnum);
|
||||
return channelClient.artist(id);
|
||||
}
|
||||
|
||||
public MusicDownloadRes download(Long id) {
|
||||
public MusicDownloadRes download(String id) {
|
||||
ChannelEnum channelEnum = getChannelEnum();
|
||||
ChannelClient<Q, S> 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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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 = `
|
||||
<img src="${album.blurPicUrl}" class="album-cover" alt="${album.name}" />
|
||||
<div class="album-name" data-id="${album.id}">${album.name}</div>
|
||||
<div class="album-type">${album.type}</div>
|
||||
<div class="album-type">${album.type ? album.type : ''}</div>
|
||||
`;
|
||||
|
||||
const albumNameEl = albumItem.querySelector('.album-name');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user