diff --git a/src/main/java/com/ping/study/controller/tx/LiveInfoController.java b/src/main/java/com/ping/study/controller/tx/LiveInfoController.java index 766ad25..6b0edce 100644 --- a/src/main/java/com/ping/study/controller/tx/LiveInfoController.java +++ b/src/main/java/com/ping/study/controller/tx/LiveInfoController.java @@ -1,6 +1,7 @@ package com.ping.study.controller.tx; import com.ping.study.service.tx.LiveInfoService; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,4 +22,12 @@ public class LiveInfoController { public String getLiveInfo(@PathVariable String cnlid) { return liveInfoService.getLiveInfo(cnlid); } + + //定时执行更新直播链接 + //定时任务 从北京时间凌晨到12点,每过半个小时执行一次 + @Scheduled(cron = "0 0/30 0-11 * * ?") + @RequestMapping("/live/refresh") + public String refreshLiveInfo() { + return liveInfoService.refreshLiveInfo(); + } } diff --git a/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java b/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java index 2b40fbc..6c2494d 100644 --- a/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java +++ b/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java @@ -3,6 +3,7 @@ package com.ping.study.controller.tx; import com.ping.study.service.tx.TxSportTokenRefreshService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -14,7 +15,8 @@ public class TokenRefreshController { private TxSportTokenRefreshService txSportTokenRefreshService; - @RequestMapping("/refresh") + + @RequestMapping("/cookie/refresh") public Boolean refreshToken() { return txSportTokenRefreshService.refreshCookies(); diff --git a/src/main/java/com/ping/study/mapper/UrlsMapper.java b/src/main/java/com/ping/study/mapper/UrlsMapper.java index 88d445c..dbb5277 100644 --- a/src/main/java/com/ping/study/mapper/UrlsMapper.java +++ b/src/main/java/com/ping/study/mapper/UrlsMapper.java @@ -36,4 +36,7 @@ public interface UrlsMapper { void deleteUrlById(Integer id); //删除所有url void deleteAllUrls(); + + //更新比赛直播链接 + void updateUrlsWithGameId(String gameId, String s); } diff --git a/src/main/java/com/ping/study/model/vo/live/LiveInfoResponse.java b/src/main/java/com/ping/study/model/vo/live/LiveInfoResponse.java new file mode 100644 index 0000000..ae50692 --- /dev/null +++ b/src/main/java/com/ping/study/model/vo/live/LiveInfoResponse.java @@ -0,0 +1,18 @@ +package com.ping.study.model.vo.live; + +import lombok.Data; + +import java.util.List; + +@Data +public class LiveInfoResponse { + private int retcode; + private List play_list; + // 其他需要的字段... + + @Data + public static class PlayItem { + private List urls; + // 其他需要的字段... + } +} diff --git a/src/main/java/com/ping/study/service/tx/LiveInfoService.java b/src/main/java/com/ping/study/service/tx/LiveInfoService.java index a827be4..79c244b 100644 --- a/src/main/java/com/ping/study/service/tx/LiveInfoService.java +++ b/src/main/java/com/ping/study/service/tx/LiveInfoService.java @@ -1,9 +1,15 @@ package com.ping.study.service.tx; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ping.study.mapper.GamesMapper; +import com.ping.study.mapper.UrlsMapper; import com.ping.study.model.dto.tx.LiveInfoRequest; +import com.ping.study.model.vo.live.LiveInfoResponse; +import com.ping.study.pojo.Games; import com.ping.study.utils.tx.CKeyGenerator; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.StringRedisTemplate; @@ -14,6 +20,8 @@ import reactor.core.publisher.Mono; import java.time.DayOfWeek; import java.time.Instant; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -23,6 +31,10 @@ public class LiveInfoService { private final WebClient webClient; private final CKeyGenerator cKeyGenerator; + @Autowired + private GamesMapper gamesMapper; + @Autowired + private UrlsMapper urlsMapper; private StringRedisTemplate stringRedisTemplate; @@ -69,9 +81,45 @@ public class LiveInfoService { .queryParam("tm", Instant.now().getEpochSecond()) .queryParam("cnlid", cnlid) .build()) - .header("Cookie", "pgv_pvid=67939534; fqm_pvqid=5e0a1a80-2ffb-42c9-8878-99ef08c0bd21; RK=dudkRjOGUW; ptcz=d9e319494b15cb621d9f54a8e03a1b55fb6c6c3564ff6c4985d1ff7b4797ce4e; video_platform=2; qq_domain_video_guid_verify=119f9c981e9ffd34; _qimei_uuid42=184170b170810037e9eacb93c4fe35a57c7df28f38; _qimei_q36=; _qimei_h38=215914e0566ee066f810eb4b0200000e81840b; video_guid=119f9c981e9ffd34; tvfe_boss_uuid=d41b10b066856291; eas_sid=E1i7L1k4j4D7q1D0Q5J894p636; livelink_pvid=7900946432; check_16=584445b5d815fd331bb7206205f8c603; o2_uin=941039061; uin_cookie=o0941039061; ied_qq=o0941039061; o_cookie=941039061; pac_uid=0_ePEHB57t75p7c; LW_sid=31h7T2M8f3O5O280q0K0L365H2; LW_uid=P1J7P2i8S3R5a2r0j020t3n543; ptui_loginuin=1131302745; qq_nick=A; qq_head=https://tvpic.gtimg.cn/head/dbb128053992612c0c1327e8e32e95f8da39a3ee5e6b4b0d3255bfef95601890afd80709/346; vqq_refresh_token=; vqq_next_refresh_time=6505; vqq_login_time_init=1745154214; _qimei_fingerprint=829539b60aaa7ed28f0e5f604c391a63; main_login=qq; vqq_appid=101481799; vqq_openid=2E6A77E3002C87A9CA68908FB058D4E5; vqq_access_token=308C7CAFBC867AF65212034AC90E71D9; vqq_vuserid=3468482246; vqq_vusession=H1-ZxeRN0vDUVk4_wKLkyA.N") + .header("Cookie", "_qimei_q32=b6ff8aedc45c2d93874747a3e7f5e3dd; ptui_loginuin=1131302745; vqq_access_token=308C7CAFBC867AF65212034AC90E71D9; lcad_appuser=CCC4A35B6047F544; tvfe_boss_uuid=d41b10b066856291; _qimei_uuid42=184170b170810037e9eacb93c4fe35a57c7df28f38; LW_sid=31h7T2M8f3O5O280q0K0L365H2; o_cookie=941039061; lcad_LDERturn=503; last_nick=%E8%85%BE%E8%AE%AF%E7%BD%91%E5%8F%8B; uin_cookie=o0941039061; lcad_LPDFturn=43; spt_uid=1829817828670177361; RK=dudkRjOGUW; ied_qq=o0941039061; lcad_LPVLturn=470; lcad_o_minduid=OCcytZR6an_BFYcypXv6ZzuBX65okAHc; pgv_pvid=67939534; lcad_LVINturn=636; pgv_info=ssid=s6516917000; last_main_login=qq; eas_sid=E1i7L1k4j4D7q1D0Q5J894p636; fqm_pvqid=5e0a1a80-2ffb-42c9-8878-99ef08c0bd21; last_avatar=https://mat1.gtimg.com/sports/sportapp/default_profile_big_after_v1_4.png; lcad_LPPBturn=28; lcad_LPSJturn=135; livelink_pvid=7900946432; LW_uid=P1J7P2i8S3R5a2r0j020t3n543; o2_uin=941039061; pac_uid=0_ePEHB57t75p7c; ptcz=d9e319494b15cb621d9f54a8e03a1b55fb6c6c3564ff6c4985d1ff7b4797ce4e; qq_domain_video_guid_verify=119f9c981e9ffd34; vqq_appid=101481799; vqq_openid=2E6A77E3002C87A9CA68908FB058D4E5; vqq_vuserid=3468482246; _qimei_fingerprint=aaf3a442da56251083fbe4352a04dc72; _qimei_q36=09d3b683102573c400e0b201300015518b19; _qimei_h38=fdedada2b12cacb7c731c46802000004418b19; vqq_vusession=jjtKD6NC-SPkVdItUGl3Sg.N; ts_last=sports.qq.com/kbsweb/mycenter.htm; ts_uid=9292458684; ukey=174520991101356433; boss_user=loginType=1&nbaVipType=0&qq=&wxOpenId=2E6A77E3002C87A9CA68908FB058D4E5&wxAppId=101481799&uKey=174520991101356433; ptag=film_video_qq_com|; main_login=qq; spt_session=CLuygiIQ7MONwAYY8ZWXwAYg1wE; spt_token=roxqAw5zstnrHn4H7DMOSbTeSkCVC0JjQGPz6Lp5Jx1-rxtW6mfo-wgg8jq41xEi; next_refresh_time=1745216492421; bossv2_isvip=-1") .retrieve() .bodyToMono(String.class) .block(); } + + public List extractPlayUrls(String liveInfoJson) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + LiveInfoResponse response = mapper.readValue(liveInfoJson, LiveInfoResponse.class); + + List urls = new ArrayList<>(); + if (response.getPlay_list() != null) { + for (LiveInfoResponse.PlayItem item : response.getPlay_list()) { + if (item.getUrls() != null) { + urls.addAll(item.getUrls()); + } + } + } + + return urls; + } + + public String refreshLiveInfo() { + List gamesList = gamesMapper.selectAll(); + for (Games games : gamesList) { + String playId = games.getPlayId(); + String liveInfo = getLiveInfo(playId); + log.info("获取到的直播信息: {}", liveInfo); + try { + List urls = extractPlayUrls(liveInfo); + log.info("提取到的播放URL: {}", urls); + urlsMapper.updateUrlsWithGameId(games.getGameId(), urls.get(0)); + // 这里可以保存urls到数据库或其他处理 + } catch (Exception e) { + log.error("解析直播信息失败"); + } + } + return "刷新完成"; + } + + } \ No newline at end of file diff --git a/src/main/java/com/ping/study/service/tx/TxSportTokenRefreshService.java b/src/main/java/com/ping/study/service/tx/TxSportTokenRefreshService.java index 17ad8b7..72fad2b 100644 --- a/src/main/java/com/ping/study/service/tx/TxSportTokenRefreshService.java +++ b/src/main/java/com/ping/study/service/tx/TxSportTokenRefreshService.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.ping.study.model.vo.live.LiveInfoResponse; +import jakarta.annotation.PostConstruct; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.StringRedisTemplate; @@ -30,6 +32,12 @@ public class TxSportTokenRefreshService { this.redisTemplate = redisTemplate; } + @PostConstruct + public void initBaseCookies() { + String baseCookies = "pgv_pvid=67939534; fqm_pvqid=5e0a1a80-2ffb-42c9-8878-99ef08c0bd21; RK=dudkRjOGUW; ptcz=d9e319494b15cb621d9f54a8e03a1b55fb6c6c3564ff6c4985d1ff7b4797ce4e; video_platform=2; qq_domain_video_guid_verify=119f9c981e9ffd34; _qimei_uuid42=184170b170810037e9eacb93c4fe35a57c7df28f38; _qimei_q36=; _qimei_h38=215914e0566ee066f810eb4b0200000e81840b; video_guid=119f9c981e9ffd34; tvfe_boss_uuid=d41b10b066856291; eas_sid=E1i7L1k4j4D7q1D0Q5J894p636; livelink_pvid=7900946432; check_16=584445b5d815fd331bb7206205f8c603; _qimei_fingerprint=3c06d28104a1e802703470a164d81dca; ptui_loginuin=1131302745"; + redisTemplate.opsForValue().set(REDIS_COOKIE_KEY, baseCookies, 30, TimeUnit.DAYS); + } + /** * 刷新Cookie并存储到Redis */ @@ -37,11 +45,8 @@ public class TxSportTokenRefreshService { public boolean refreshCookies() { try { // 1. 从Redis获取基础登录态Cookie(首次需手动初始化) - String baseCookie = redisTemplate.opsForValue().get("tx_base_cookies"); - if (baseCookie == null) { - baseCookie = "pgv_pvid=67939534; ptui_loginuin=1131302745; ..."; // 你的浏览器完整Cookie - } - + String baseCookie = redisTemplate.opsForValue().get(REDIS_COOKIE_KEY); + log.info("当前Cookie: {}", baseCookie); // 2. 携带基础Cookie发起请求 String response = webClient.get() .uri("/init/refresh?os=web") @@ -49,7 +54,6 @@ public class TxSportTokenRefreshService { .retrieve() .bodyToMono(String.class) .block(); - // 3. 合并新旧Cookie(保留基础登录态) JsonNode data = new ObjectMapper().readTree(response).path("data"); String newCookie = extractNewCookies(data); // 提取spt_token等 @@ -57,7 +61,7 @@ public class TxSportTokenRefreshService { // 4. 存储到Redis redisTemplate.opsForValue().set( - "tx_sports_cookies", + REDIS_COOKIE_KEY, finalCookie, Long.parseLong(data.path("tokenTTL").asText()), TimeUnit.SECONDS @@ -68,6 +72,27 @@ public class TxSportTokenRefreshService { return false; } } + /** + * 从腾讯API响应中提取新的Cookie信息 + */ + private String extractNewCookies(JsonNode dataNode) { + if (dataNode == null || !dataNode.has("cookie")) { + return ""; + } + + StringBuilder cookieStr = new StringBuilder(); + Iterator cookies = dataNode.path("cookie").elements(); + + while (cookies.hasNext()) { + JsonNode cookie = cookies.next(); + cookieStr.append(cookie.path("name").asText()) + .append("=") + .append(cookie.path("value").asText()) + .append("; "); + } + + return cookieStr.toString(); + } // 合并Cookie的工具方法 @@ -94,15 +119,19 @@ public class TxSportTokenRefreshService { /** * 定时刷新任务(每1小时执行一次) */ -// @Scheduled(fixedRate = 3600000) // 单位:毫秒 -// public void scheduledRefresh() { -// if (!refreshCookies()) { -// log.warn("定时刷新Cookie失败,将重试..."); -// // 失败后延迟5分钟重试 +// @Scheduled(fixedRate = 3600000) + public void scheduledRefresh() { + if (!refreshCookies()) { + log.warn("首次刷新失败,尝试重新初始化基础Cookie..."); + initBaseCookies(); // try { -// Thread.sleep(300000); -// refreshCookies(); -// } catch (InterruptedException ignored) {} -// } -// } +// Thread.sleep(30000); // 等待30秒后重试 +// if (!refreshCookies()) { +// log.error("重试刷新仍然失败"); +// } +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } + } + } } \ No newline at end of file diff --git a/src/main/resources/mapper/GamesMapper.xml b/src/main/resources/mapper/GamesMapper.xml index 5cdee35..f6e3130 100644 --- a/src/main/resources/mapper/GamesMapper.xml +++ b/src/main/resources/mapper/GamesMapper.xml @@ -128,4 +128,5 @@ delete from games + diff --git a/src/main/resources/mapper/UrlsMapper.xml b/src/main/resources/mapper/UrlsMapper.xml index 8c8d3a2..5063ecd 100644 --- a/src/main/resources/mapper/UrlsMapper.xml +++ b/src/main/resources/mapper/UrlsMapper.xml @@ -94,4 +94,8 @@ delete from urls + + + update urls set url = #{s},type = 'tx' where game_id = #{gameId} +