Compare commits
No commits in common. "483b2793534d4f3440a3bfb4b250b0cb68beedf9" and "b80852e7a09c52e46a7af130458a4d9b4e58b041" have entirely different histories.
483b279353
...
b80852e7a0
|
@ -1,8 +1,6 @@
|
||||||
package com.dengqn.app.lingyinapi.apis;
|
package com.dengqn.app.lingyinapi.apis;
|
||||||
|
|
||||||
import com.dengqn.app.lingyinapi.beans.SeedListItem;
|
import com.dengqn.app.lingyinapi.beans.SeedListItem;
|
||||||
import com.dengqn.app.lingyinapi.beans.api.Page;
|
|
||||||
import com.dengqn.app.lingyinapi.beans.api.Resp;
|
|
||||||
import com.dengqn.app.lingyinapi.config.CookieConfig;
|
import com.dengqn.app.lingyinapi.config.CookieConfig;
|
||||||
import com.dengqn.app.lingyinapi.html.HtmlTool;
|
import com.dengqn.app.lingyinapi.html.HtmlTool;
|
||||||
import com.dengqn.app.lingyinapi.http.HttpTool;
|
import com.dengqn.app.lingyinapi.http.HttpTool;
|
||||||
|
@ -42,27 +40,20 @@ public class Seed {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public ResponseEntity<Resp<Page<SeedListItem>>> getSeedPage(
|
public ResponseEntity<List<SeedListItem>> getSeedPage(
|
||||||
@RequestParam(required = false, defaultValue = "0", name = "inclbookmarked") String inclbookmarked,
|
@RequestParam(required = false, defaultValue = "0", name = "inclbookmarked") String inclbookmarked,
|
||||||
@RequestParam(required = false, defaultValue = "1", name = "incldead") String incldead,
|
@RequestParam(required = false, defaultValue = "1", name = "incldead") String incldead,
|
||||||
@RequestParam(required = false, defaultValue = "0", name = "spstate") String spstate,
|
@RequestParam(required = false, defaultValue = "0", name = "spstate") String spstate,
|
||||||
@RequestParam(required = false, defaultValue = "0", name = "page") String page,
|
@RequestParam(required = false, defaultValue = "1", name = "page") String page
|
||||||
@RequestParam(required = false, defaultValue = "50", name = "size") String size,
|
|
||||||
@RequestParam(required = false, defaultValue = "", name = "search") String search
|
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
String url = "https://pt.soulvoice.club/special.php?inclbookmarked=%s&incldead=%s&spstate=%s&page=%s&search=%s"
|
|
||||||
.formatted(inclbookmarked, incldead, spstate, page, search);
|
String url = "https://pt.soulvoice.club/special.php?inclbookmarked=%s&incldead=%s&spstate=%s&page=%s"
|
||||||
|
.formatted(inclbookmarked, incldead, spstate, page);
|
||||||
String html = HttpTool.getHTML(url, okHttpClient);
|
String html = HttpTool.getHTML(url, okHttpClient);
|
||||||
log.info("html:{}", html);
|
log.info("html:{}", html);
|
||||||
Document doc = Jsoup.parse(html);
|
Document doc = Jsoup.parse(html);
|
||||||
List<SeedListItem> listItem = HtmlTool.getSeedListItem(doc);
|
List<SeedListItem> listItem = HtmlTool.getSeedListItem(doc);
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(listItem);
|
||||||
Resp.ok(Page.<SeedListItem>builder()
|
|
||||||
.page(Integer.valueOf(page))
|
|
||||||
.size(Integer.valueOf(size))
|
|
||||||
.total(HtmlTool.getPageTotal(doc))
|
|
||||||
.list(listItem)
|
|
||||||
.build()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,7 @@ package com.dengqn.app.lingyinapi.beans;
|
||||||
* @author dengqn
|
* @author dengqn
|
||||||
* @since 2025/9/25 18:22
|
* @since 2025/9/25 18:22
|
||||||
*/
|
*/
|
||||||
public record SeedListItem(String seedCover,
|
public record SeedListItem(String seedCover, String seedName, String seedUrl, boolean isFree, boolean isHitAndRun,
|
||||||
String seedName,
|
|
||||||
String seedUrl,
|
|
||||||
String seedDesc,
|
|
||||||
boolean isFree, boolean isHitAndRun,
|
|
||||||
String downloadUrl, String time, String size, String seeders, String views,
|
String downloadUrl, String time, String size, String seeders, String views,
|
||||||
boolean isAnonymous) {
|
boolean isAnonymous) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package com.dengqn.app.lingyinapi.beans.api;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页
|
|
||||||
*
|
|
||||||
* @author dengqn
|
|
||||||
* @since 2025/9/26 10:28
|
|
||||||
*/
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Builder
|
|
||||||
@Data
|
|
||||||
public class Page<T> implements Serializable {
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 7287992347791111742L;
|
|
||||||
private Integer page;
|
|
||||||
private Integer size;
|
|
||||||
private Integer total;
|
|
||||||
private List<T> list;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package com.dengqn.app.lingyinapi.beans.api;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author dengqn
|
|
||||||
* @since 2025/9/26 10:19
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class Resp<T> implements Serializable {
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 3854320483518994111L;
|
|
||||||
|
|
||||||
private Integer code;
|
|
||||||
|
|
||||||
private String msg;
|
|
||||||
|
|
||||||
private T data;
|
|
||||||
|
|
||||||
public static <T> Resp<T> ok(T data) {
|
|
||||||
return ok("ok", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Resp<T> ok(String msg, T data) {
|
|
||||||
return Resp.<T>builder()
|
|
||||||
.code(10000)
|
|
||||||
.msg(msg)
|
|
||||||
.data(data)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Resp<T> error(String msg) {
|
|
||||||
return Resp.<T>builder()
|
|
||||||
.code(10001)
|
|
||||||
.msg(msg)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Resp<T> error(Integer code, String msg) {
|
|
||||||
return Resp.<T>builder()
|
|
||||||
.code(code)
|
|
||||||
.msg(msg)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,9 +5,13 @@ import okhttp3.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -23,11 +27,9 @@ import java.util.Optional;
|
||||||
public class HttpClientConfig {
|
public class HttpClientConfig {
|
||||||
|
|
||||||
private CookieConfig cookieConfig;
|
private CookieConfig cookieConfig;
|
||||||
private final Environment environment;
|
|
||||||
|
|
||||||
public HttpClientConfig(CookieConfig cookieConfig, Environment environment) {
|
public HttpClientConfig(CookieConfig cookieConfig) {
|
||||||
this.cookieConfig = cookieConfig;
|
this.cookieConfig = cookieConfig;
|
||||||
this.environment = environment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -42,15 +44,10 @@ public class HttpClientConfig {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
|
public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
|
||||||
|
|
||||||
String login = environment.getProperty("SECURE_LOGIN", cookieConfig.getSecureLogin());
|
|
||||||
String uid = environment.getProperty("SECURE_UID", cookieConfig.getSecureUid());
|
|
||||||
String pass = environment.getProperty("SECURE_PASS", cookieConfig.getSecurePass());
|
|
||||||
|
|
||||||
return List.of(
|
return List.of(
|
||||||
new Cookie.Builder().domain("pt.soulvoice.club").name("c_secure_login").value(login).build(),
|
new Cookie.Builder().domain("pt.soulvoice.club").name("c_secure_login").value(cookieConfig.getSecureLogin()).build(),
|
||||||
new Cookie.Builder().domain("pt.soulvoice.club").name("c_secure_uid").value(uid).build(),
|
new Cookie.Builder().domain("pt.soulvoice.club").name("c_secure_uid").value(cookieConfig.getSecureUid()).build(),
|
||||||
new Cookie.Builder().domain("pt.soulvoice.club").name("c_secure_pass").value(pass).build()
|
new Cookie.Builder().domain("pt.soulvoice.club").name("c_secure_pass").value(cookieConfig.getSecurePass()).build()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,15 +18,17 @@ import java.util.Objects;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HtmlTool {
|
public class HtmlTool {
|
||||||
public static List<SeedListItem> getSeedListItem(Document doc) {
|
public static List<SeedListItem> getSeedListItem(Document doc) {
|
||||||
|
List<SeedListItem> items = new ArrayList<>();
|
||||||
|
|
||||||
Element torrents;
|
Element torrents;
|
||||||
try {
|
try {
|
||||||
torrents = doc.getElementsByClass("torrents").getFirst();
|
torrents = doc.getElementsByClass("torrents").getFirst();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("搜不到东西:{}", e.getMessage());
|
e.printStackTrace();
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return torrents.select("tr").parallelStream().skip(1)
|
return torrents.select("tr").stream().skip(1)
|
||||||
.map(tr -> {
|
.map(tr -> {
|
||||||
try {
|
try {
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +39,6 @@ public class HtmlTool {
|
||||||
String seedCover = seedNames.get(0).getElementsByTag("img").first().attr("data-src");
|
String seedCover = seedNames.get(0).getElementsByTag("img").first().attr("data-src");
|
||||||
String seedName = seedNames.get(1).getElementsByTag("a").first().attr("title");
|
String seedName = seedNames.get(1).getElementsByTag("a").first().attr("title");
|
||||||
String seedUrl = seedNames.get(1).getElementsByTag("a").first().attr("href");
|
String seedUrl = seedNames.get(1).getElementsByTag("a").first().attr("href");
|
||||||
String seedDesc = seedNames.text().replaceFirst(seedName, "");
|
|
||||||
boolean isFree = seedNames.get(1).getElementsByClass("pro_free").size() > 0;
|
boolean isFree = seedNames.get(1).getElementsByClass("pro_free").size() > 0;
|
||||||
boolean isHitAndRun = seedNames.get(1).getElementsByClass("hitandrun").size() > 0;
|
boolean isHitAndRun = seedNames.get(1).getElementsByClass("hitandrun").size() > 0;
|
||||||
String downloadUrl = seedNames.get(3).getElementsByTag("a").first().attr("href");
|
String downloadUrl = seedNames.get(3).getElementsByTag("a").first().attr("href");
|
||||||
|
@ -53,27 +54,12 @@ public class HtmlTool {
|
||||||
String views = tds.get(7).getElementsByTag("b") == null || tds.get(7).getElementsByTag("b").size() == 0 ? "0" : tds.get(7).getElementsByTag("b").first().text().trim();
|
String views = tds.get(7).getElementsByTag("b") == null || tds.get(7).getElementsByTag("b").size() == 0 ? "0" : tds.get(7).getElementsByTag("b").first().text().trim();
|
||||||
boolean isAnonymous = tds.get(8).text().trim().contains("匿名");
|
boolean isAnonymous = tds.get(8).text().trim().contains("匿名");
|
||||||
|
|
||||||
return new SeedListItem(seedCover, seedName, seedUrl, seedDesc, isFree, isHitAndRun, downloadUrl, time, size, seeders, views, isAnonymous);
|
|
||||||
|
return new SeedListItem(seedCover, seedName, seedUrl, isFree, isHitAndRun, downloadUrl, time, size, seeders, views, isAnonymous);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("解析报错跳过:" + e.getMessage());
|
log.error("解析报错跳过:" + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).filter(Objects::nonNull).toList();
|
}).filter(Objects::nonNull).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getPageTotal(Document document) {
|
|
||||||
Elements paginationEl = document.getElementsByClass("nexus-pagination");
|
|
||||||
if (paginationEl == null) return 0;
|
|
||||||
|
|
||||||
Elements pages = paginationEl.first().getElementsByTag("a");
|
|
||||||
if (pages == null || pages.size() == 0) return 0;
|
|
||||||
|
|
||||||
Element lastA = pages.last();
|
|
||||||
String text = lastA.text();
|
|
||||||
if ("".equalsIgnoreCase(text.trim())) return 0;
|
|
||||||
return Integer.valueOf(text.trim()
|
|
||||||
.replaceAll("\"", "")
|
|
||||||
.replaceAll(" ", "")
|
|
||||||
.split("-")[1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ public class HttpTool {
|
||||||
try {
|
try {
|
||||||
Response response = okHttpClient.newCall(new Request.Builder()
|
Response response = okHttpClient.newCall(new Request.Builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36")
|
|
||||||
.method("GET", null)
|
.method("GET", null)
|
||||||
.build())
|
.build())
|
||||||
.execute();
|
.execute();
|
||||||
|
|
|
@ -580,8 +580,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
<p align="center" class='nexus-pagination'>
|
<p align="center" class='nexus-pagination'><a href="?inclbookmarked=0&incldead=1&spstate=0&page=0"><b
|
||||||
<a href="?inclbookmarked=0&incldead=1&spstate=0&page=0"><b
|
|
||||||
title="Alt+Pageup"><< 上一页</b></a> <a
|
title="Alt+Pageup"><< 上一页</b></a> <a
|
||||||
href="?inclbookmarked=0&incldead=1&spstate=0&page=2"><b
|
href="?inclbookmarked=0&incldead=1&spstate=0&page=2"><b
|
||||||
title="Alt+Pagedown">下一页 >></b></a><br/><a
|
title="Alt+Pagedown">下一页 >></b></a><br/><a
|
||||||
|
@ -591,8 +590,7 @@
|
||||||
href="?inclbookmarked=0&incldead=1&spstate=0&page=3"><b>151 - 200</b></a> | ... | <a
|
href="?inclbookmarked=0&incldead=1&spstate=0&page=3"><b>151 - 200</b></a> | ... | <a
|
||||||
href="?inclbookmarked=0&incldead=1&spstate=0&page=561"><b>28051 - 28100</b></a> | <a
|
href="?inclbookmarked=0&incldead=1&spstate=0&page=561"><b>28051 - 28100</b></a> | <a
|
||||||
href="?inclbookmarked=0&incldead=1&spstate=0&page=562"><b>28101 - 28150</b></a> | <a
|
href="?inclbookmarked=0&incldead=1&spstate=0&page=562"><b>28101 - 28150</b></a> | <a
|
||||||
href="?inclbookmarked=0&incldead=1&spstate=0&page=563"><b>28151 - 28164</b></a>
|
href="?inclbookmarked=0&incldead=1&spstate=0&page=563"><b>28151 - 28164</b></a></p>
|
||||||
</p>
|
|
||||||
<table class="torrents" cellspacing="0" cellpadding="5" width="100%">
|
<table class="torrents" cellspacing="0" cellpadding="5" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="colhead" style="padding: 0px">类型</td>
|
<td class="colhead" style="padding: 0px">类型</td>
|
||||||
|
|
|
@ -17,19 +17,13 @@ import java.util.List;
|
||||||
public class HttpToolTest {
|
public class HttpToolTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetSeedList() throws IOException {
|
public void testGetHtml() throws IOException {
|
||||||
String htmlData = new String(this.getClass().getResourceAsStream("/test-seed-list-page.html").readAllBytes());
|
String htmlData = new String(this.getClass().getResourceAsStream("/test-seed-list-page.html").readAllBytes());
|
||||||
|
// log.info("htmlData: {}", htmlData);
|
||||||
Document parse = Jsoup.parse(htmlData);
|
Document parse = Jsoup.parse(htmlData);
|
||||||
List<SeedListItem> listItem = HtmlTool.getSeedListItem(parse);
|
List<SeedListItem> listItem = HtmlTool.getSeedListItem(parse);
|
||||||
for (SeedListItem seedListItem : listItem) {
|
for (SeedListItem seedListItem : listItem) {
|
||||||
log.info("item-->{}", seedListItem);
|
log.info("item-->{}", seedListItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetSeedTotal() throws IOException {
|
|
||||||
String htmlData = new String(this.getClass().getResourceAsStream("/test-seed-list-page.html").readAllBytes());
|
|
||||||
Document parse = Jsoup.parse(htmlData);
|
|
||||||
Integer pageTotal = HtmlTool.getPageTotal(parse);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue