feat: 支持搜索关注的 UP 主 (#588)
This commit is contained in:
@@ -82,6 +82,7 @@ pub struct FollowedCollectionsRequest {
|
|||||||
pub struct FollowedUppersRequest {
|
pub struct FollowedUppersRequest {
|
||||||
pub page_num: Option<i32>,
|
pub page_num: Option<i32>,
|
||||||
pub page_size: Option<i32>,
|
pub page_size: Option<i32>,
|
||||||
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Validate)]
|
#[derive(Deserialize, Validate)]
|
||||||
|
|||||||
@@ -153,7 +153,9 @@ pub async fn get_followed_uppers(
|
|||||||
let credential = &VersionedConfig::get().read().credential;
|
let credential = &VersionedConfig::get().read().credential;
|
||||||
let me = Me::new(bili_client.as_ref(), credential);
|
let me = Me::new(bili_client.as_ref(), credential);
|
||||||
let (page_num, page_size) = (params.page_num.unwrap_or(1), params.page_size.unwrap_or(20));
|
let (page_num, page_size) = (params.page_num.unwrap_or(1), params.page_size.unwrap_or(20));
|
||||||
let bili_uppers = me.get_followed_uppers(page_num, page_size).await?;
|
let bili_uppers = me
|
||||||
|
.get_followed_uppers(page_num, page_size, params.name.as_deref())
|
||||||
|
.await?;
|
||||||
|
|
||||||
let bili_uid: Vec<_> = bili_uppers.list.iter().map(|upper| upper.mid).collect();
|
let bili_uid: Vec<_> = bili_uppers.list.iter().map(|upper| upper.mid).collect();
|
||||||
|
|
||||||
|
|||||||
@@ -60,21 +60,31 @@ impl<'a> Me<'a> {
|
|||||||
Ok(serde_json::from_value(resp["data"].take())?)
|
Ok(serde_json::from_value(resp["data"].take())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_followed_uppers(&self, page_num: i32, page_size: i32) -> Result<FollowedUppers> {
|
pub async fn get_followed_uppers(
|
||||||
|
&self,
|
||||||
|
page_num: i32,
|
||||||
|
page_size: i32,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> Result<FollowedUppers> {
|
||||||
ensure!(
|
ensure!(
|
||||||
!self.mid().is_empty(),
|
!self.mid().is_empty(),
|
||||||
"未获取到用户 ID,请确保填写设置中的 B 站认证信息"
|
"未获取到用户 ID,请确保填写设置中的 B 站认证信息"
|
||||||
);
|
);
|
||||||
let mut resp = self
|
let url = if name.is_some() {
|
||||||
|
"https://api.bilibili.com/x/relation/followings/search"
|
||||||
|
} else {
|
||||||
|
"https://api.bilibili.com/x/relation/followings"
|
||||||
|
};
|
||||||
|
let mut request = self
|
||||||
.client
|
.client
|
||||||
.request(
|
.request(Method::GET, url, self.credential)
|
||||||
Method::GET,
|
|
||||||
"https://api.bilibili.com/x/relation/followings",
|
|
||||||
self.credential,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.query(&[("vmid", self.mid())])
|
.query(&[("vmid", self.mid())])
|
||||||
.query(&[("pn", page_num), ("ps", page_size)])
|
.query(&[("pn", page_num), ("ps", page_size)]);
|
||||||
|
if let Some(name) = name {
|
||||||
|
request = request.query(&[("name", name)]);
|
||||||
|
}
|
||||||
|
let mut resp = request
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
.error_for_status()?
|
.error_for_status()?
|
||||||
|
|||||||
@@ -199,11 +199,13 @@ class ApiClient {
|
|||||||
|
|
||||||
async getFollowedUppers(
|
async getFollowedUppers(
|
||||||
pageNum?: number,
|
pageNum?: number,
|
||||||
pageSize?: number
|
pageSize?: number,
|
||||||
|
name?: string
|
||||||
): Promise<ApiResponse<UppersResponse>> {
|
): Promise<ApiResponse<UppersResponse>> {
|
||||||
const params = {
|
const params = {
|
||||||
page_num: pageNum,
|
page_num: pageNum,
|
||||||
page_size: pageSize
|
page_size: pageSize,
|
||||||
|
name: name
|
||||||
};
|
};
|
||||||
return this.get<UppersResponse>('/me/uppers', params as Record<string, unknown>);
|
return this.get<UppersResponse>('/me/uppers', params as Record<string, unknown>);
|
||||||
}
|
}
|
||||||
@@ -294,8 +296,8 @@ const api = {
|
|||||||
getCreatedFavorites: () => apiClient.getCreatedFavorites(),
|
getCreatedFavorites: () => apiClient.getCreatedFavorites(),
|
||||||
getFollowedCollections: (pageNum?: number, pageSize?: number) =>
|
getFollowedCollections: (pageNum?: number, pageSize?: number) =>
|
||||||
apiClient.getFollowedCollections(pageNum, pageSize),
|
apiClient.getFollowedCollections(pageNum, pageSize),
|
||||||
getFollowedUppers: (pageNum?: number, pageSize?: number) =>
|
getFollowedUppers: (pageNum?: number, pageSize?: number, name?: string) =>
|
||||||
apiClient.getFollowedUppers(pageNum, pageSize),
|
apiClient.getFollowedUppers(pageNum, pageSize, name),
|
||||||
insertFavorite: (request: InsertFavoriteRequest) => apiClient.insertFavorite(request),
|
insertFavorite: (request: InsertFavoriteRequest) => apiClient.insertFavorite(request),
|
||||||
insertCollection: (request: InsertCollectionRequest) => apiClient.insertCollection(request),
|
insertCollection: (request: InsertCollectionRequest) => apiClient.insertCollection(request),
|
||||||
insertSubmission: (request: InsertSubmissionRequest) => apiClient.insertSubmission(request),
|
insertSubmission: (request: InsertSubmissionRequest) => apiClient.insertSubmission(request),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import SubscriptionCard from '$lib/components/subscription-card.svelte';
|
import SubscriptionCard from '$lib/components/subscription-card.svelte';
|
||||||
import Pagination from '$lib/components/pagination.svelte';
|
import Pagination from '$lib/components/pagination.svelte';
|
||||||
|
import SearchBar from '$lib/components/search-bar.svelte';
|
||||||
import { setBreadcrumb } from '$lib/stores/breadcrumb';
|
import { setBreadcrumb } from '$lib/stores/breadcrumb';
|
||||||
import api from '$lib/api';
|
import api from '$lib/api';
|
||||||
import type { Followed, ApiError } from '$lib/types';
|
import type { Followed, ApiError } from '$lib/types';
|
||||||
@@ -11,13 +12,14 @@
|
|||||||
let totalCount = 0;
|
let totalCount = 0;
|
||||||
let currentPage = 0;
|
let currentPage = 0;
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
let searchQuery = '';
|
||||||
|
|
||||||
const pageSize = 50;
|
const pageSize = 50;
|
||||||
|
|
||||||
async function loadUppers(page: number = 0) {
|
async function loadUppers(page: number = 0, name?: string) {
|
||||||
loading = true;
|
loading = true;
|
||||||
try {
|
try {
|
||||||
const response = await api.getFollowedUppers(page + 1, pageSize); // API 使用 1 基索引
|
const response = await api.getFollowedUppers(page + 1, pageSize, name || undefined); // API 使用 1 基索引
|
||||||
uppers = response.data.uppers;
|
uppers = response.data.uppers;
|
||||||
totalCount = response.data.total;
|
totalCount = response.data.total;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -32,12 +34,18 @@
|
|||||||
|
|
||||||
function handleSubscriptionSuccess() {
|
function handleSubscriptionSuccess() {
|
||||||
// 重新加载数据以获取最新状态
|
// 重新加载数据以获取最新状态
|
||||||
loadUppers(currentPage);
|
loadUppers(currentPage, searchQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handlePageChange(page: number) {
|
async function handlePageChange(page: number) {
|
||||||
currentPage = page;
|
currentPage = page;
|
||||||
await loadUppers(page);
|
await loadUppers(page, searchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSearch(query: string) {
|
||||||
|
searchQuery = query;
|
||||||
|
currentPage = 0;
|
||||||
|
await loadUppers(0, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
@@ -53,6 +61,10 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<div class="mb-4 flex items-center justify-between">
|
||||||
|
<SearchBar placeholder="搜索 UP 主.." value={searchQuery} onSearch={handleSearch}></SearchBar>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-6 flex items-center justify-between">
|
<div class="mb-6 flex items-center justify-between">
|
||||||
<div class="flex items-center gap-6">
|
<div class="flex items-center gap-6">
|
||||||
{#if !loading}
|
{#if !loading}
|
||||||
|
|||||||
Reference in New Issue
Block a user