add music pic query

This commit is contained in:
N1KO 2025-01-23 16:11:27 +08:00
parent 9ac028a5f9
commit 7f4be753b2
7 changed files with 296 additions and 0 deletions

View File

@ -0,0 +1,18 @@
package top.baogutang.music.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 连接超时
factory.setReadTimeout(5000); // 读取超时
return new RestTemplate(factory);
}
}

View File

@ -19,5 +19,7 @@ public class CacheKey {
public static final String KEY_USER_LEVEL_PREFIX = "baogutang-music:user:level:id:";
public static final String KEY_MUSIC_TAG_TOKEN_PREFIX = "baogutang-music:music-tag:token:";
}

View File

@ -0,0 +1,35 @@
package top.baogutang.music.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import top.baogutang.music.service.IMusicInfoService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
/**
*
* @description:
*
* @author: N1KO
* @date: 2025/01/23 : 14:45
*/
@Slf4j
@RestController
@RequestMapping("/api/v1/music/info")
public class MusicInfoController {
@Resource
private IMusicInfoService musicInfoService;
@GetMapping("/cover")
public void getMusicCover(@RequestParam(name = "title", required = false) String title,
@RequestParam(name = "artist", required = true) String artist,
@RequestParam(name = "album", required = false) String album,
HttpServletResponse response) {
musicInfoService.getCover(title, artist, album, response);
}
}

View File

@ -0,0 +1,16 @@
package top.baogutang.music.service;
import javax.servlet.http.HttpServletResponse;
/**
*
* @description:
*
* @author: N1KO
* @date: 2025/01/23 : 14:53
*/
public interface IMusicInfoService {
void getCover(String title, String artist, String album, HttpServletResponse response);
}

View File

@ -21,4 +21,6 @@ public interface IMusicRecordService extends IService<MusicRecordEntity> {
MusicRecordEntity queryByChannelAndPlatform(ChannelEnum channel, String platformId);
List<MusicRecordEntity> queryByPlatformIdList(List<String> platformIdList);
MusicRecordEntity queryByNameOrAlbumOrArtist(String title, String album, String artist);
}

View File

@ -0,0 +1,211 @@
package top.baogutang.music.service.impl;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import top.baogutang.music.dao.entity.MusicRecordEntity;
import top.baogutang.music.exceptions.BusinessException;
import top.baogutang.music.service.IMusicInfoService;
import top.baogutang.music.service.IMusicRecordService;
import top.baogutang.music.utils.CacheUtil;
import top.baogutang.music.utils.OkHttpUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import static top.baogutang.music.constants.CacheKey.KEY_MUSIC_TAG_TOKEN_PREFIX;
/**
*
* @description:
*
* @author: N1KO
* @date: 2025/01/23 : 14:53
*/
@Slf4j
@Service
public class MusicInfoServiceImpl implements IMusicInfoService {
@Resource
private IMusicRecordService musicRecordService;
@Resource
private RestTemplate restTemplate;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource(name = "commonExecutor")
private Executor commonExecutor;
@Override
public void getCover(String title, String artist, String album, HttpServletResponse response) {
MusicRecordEntity musicRecord = musicRecordService.queryByNameOrAlbumOrArtist(title, album, artist);
if (Objects.nonNull(musicRecord) && StringUtils.isNotBlank(musicRecord.getPic())) {
this.downloadPicAndResponse(musicRecord.getPic(), response);
return;
}
// 获取三方token
String token = CacheUtil.cacheOrSupply(KEY_MUSIC_TAG_TOKEN_PREFIX,
1L,
TimeUnit.DAYS,
redisTemplate,
this::geneToken,
new TypeReference<>() {
});
Map<String, String> headers = new HashMap<>();
headers.put("authorization", "jwt " + token);
headers.put("Content-Type", "application/json");
Map<String, Object> params = new HashMap<>();
if (StringUtils.isBlank(title)) {
params.put("title", album);
} else {
params.put("title", title);
}
params.put("artist", artist);
params.put("album", album);
InfoRes<List<MusicInfoRes>> res = this.queryInfo(headers, params);
if (Objects.isNull(res) || !Boolean.TRUE.equals(res.getResult()) || CollectionUtils.isEmpty(res.getData())) {
log.error("<<<<<<<<<<query info error>>>>>>>>>>");
return;
}
MusicInfoRes musicInfoRes = res.getData().get(0);
this.downloadPicAndResponse(musicInfoRes.getAlbumImg(), response);
}
private InfoRes<List<MusicInfoRes>> queryInfo(Map<String, String> headers, Map<String, Object> params) {
InfoRes<List<MusicInfoRes>> res = null;
try {
params.put("resource", "qmusic");
res = OkHttpUtil.post("http://114.96.87.132:8002/apimt/fetch_id3_by_title/", headers, params, new TypeReference<>() {
});
if (Objects.isNull(res) || !Boolean.TRUE.equals(res.getResult()) || CollectionUtils.isEmpty(res.getData())) {
params.put("resource", "netease");
res = OkHttpUtil.post("http://114.96.87.132:8002/apimt/fetch_id3_by_title/", headers, params, new TypeReference<>() {
});
}
} catch (Exception e) {
log.error("query music info error:{}", e.getMessage(), e);
return null;
}
return res;
}
private String geneToken() {
Map<String, String> params = new HashMap<>();
params.put("username", "admin");
params.put("password", "admin");
TokenRes tokenRes = null;
try {
tokenRes = OkHttpUtil.post("http://114.96.87.132:8002/apimt/token/", params, new TypeReference<>() {
});
} catch (Exception e) {
log.error("<<<<<<<<<<获取token异常{}>>>>>>>>>>", e.getMessage(), e);
throw new BusinessException("获取token异常!");
}
if (Objects.nonNull(tokenRes) && Boolean.TRUE.equals(tokenRes.getResult())) {
return tokenRes.getToken();
}
throw new BusinessException("获取token异常!");
}
private void downloadPicAndResponse(String picUrl, HttpServletResponse response) {
// 获取响应实体
ResponseEntity<org.springframework.core.io.Resource> responseEntity = restTemplate.exchange(
picUrl,
HttpMethod.GET,
null,
org.springframework.core.io.Resource.class
);
// 设置Content-Type
MediaType contentType = responseEntity.getHeaders().getContentType();
if (contentType != null) {
response.setContentType(contentType.toString());
} else {
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
}
// 设置Content-Length如果可用
List<String> contentLength = responseEntity.getHeaders().get(HttpHeaders.CONTENT_LENGTH);
if (contentLength != null && !contentLength.isEmpty()) {
response.setHeader(HttpHeaders.CONTENT_LENGTH, contentLength.get(0));
}
if (Objects.isNull(responseEntity.getBody())) {
log.error("<<<<<<<<<<getCover error! url:{} response body is null>>>>>>>>>>", picUrl);
return;
}
try (InputStream inputStream = responseEntity.getBody().getInputStream();
OutputStream outputStream = response.getOutputStream()) {
// 数据传输
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
} catch (Exception e) {
log.error("getCover error!picUrl:{},message:{}", picUrl, e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
@Data
static class TokenRes {
private String token;
private Boolean result;
}
@Data
static class InfoRes<T> {
private Boolean result;
private String code;
private T data;
}
@Data
static class MusicInfoRes {
private String mid;
private String extra;
private String notice;
private String title;
private String singer;
private String album;
@JsonProperty("album_img")
private String albumImg;
private String artist;
}
}

View File

@ -3,6 +3,7 @@ package top.baogutang.music.service.impl;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import top.baogutang.music.dao.entity.MusicRecordEntity;
import top.baogutang.music.dao.mapper.MusicRecordMapper;
@ -76,4 +77,15 @@ public class MusicRecordServiceImpl extends ServiceImpl<MusicRecordMapper, Music
.list();
}
@Override
public MusicRecordEntity queryByNameOrAlbumOrArtist(String title, String album, String artist) {
return new LambdaQueryChainWrapper<>(baseMapper)
.like(StringUtils.isNotBlank(title), MusicRecordEntity::getName, title + "%")
.like(StringUtils.isNotBlank(album), MusicRecordEntity::getAlbumName, album + "%")
.like(StringUtils.isNotBlank(artist), MusicRecordEntity::getArtistName, artist + "%")
.orderByDesc(MusicRecordEntity::getId)
.last(" limit 1")
.one();
}
}