diff --git a/README.md b/README.md
index 369ac87..100825a 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,10 @@ Pixiv 下载浏览管理器是一个基于 Web 的应用程序,提供以下功
[](https://sywb.top/Staticfiles/p%E6%95%99%E7%A8%8B.mp4)
+观看更新内容(关注于新功能演示,上面的视频主要是登录教学):
+
+[](https://sywb.top/Staticfiles/p%E6%9B%B4%E6%96%B0.mp4)
+
## 🚀 快速开始
### 便携版下载(如果不想自义定或者是懒)
diff --git a/backend/routes/artist.js b/backend/routes/artist.js
index 3fc2d68..c7952ac 100644
--- a/backend/routes/artist.js
+++ b/backend/routes/artist.js
@@ -31,9 +31,6 @@ router.get('/search', async (req, res) => {
name: user.user.name,
account: user.user.account,
profile_image_urls: user.user.profile_image_urls,
- total_illusts: 0,
- total_manga: 0,
- total_followers: 0,
is_followed: user.user.is_followed || false
}));
diff --git a/backend/services/artist.js b/backend/services/artist.js
index a21bfaa..568c90b 100644
--- a/backend/services/artist.js
+++ b/backend/services/artist.js
@@ -8,25 +8,50 @@ class ArtistService {
}
/**
- * 获取作者信息
+ * 获取作者详细信息(用于作者详情页面)
*/
async getArtistInfo(artistId) {
try {
- const response = await this.makeRequest(
- 'GET',
- '/v1/user/detail',
- { user_id: artistId }
- );
+ const response = await this.makeRequest('GET', '/v1/user/detail', { user_id: artistId });
return {
+
success: true,
- data: response.user
+ data: response.user,
};
-
} catch (error) {
return {
success: false,
- error: error.message
+ error: error.message,
+ };
+ }
+ }
+
+ /**
+ * 获取作者简单信息(用于列表页面)
+ */
+ async getArtistBasicInfo(artistId) {
+ try {
+ const response = await this.makeRequest('GET', '/v1/user/detail', { user_id: artistId });
+
+ // 只返回基本信息,不包含统计信息
+ const basicInfo = {
+ id: response.user.id,
+ name: response.user.name,
+ account: response.user.account,
+ profile_image_urls: response.user.profile_image_urls,
+ comment: response.user.comment,
+ is_followed: response.user.is_followed || false
+ };
+
+ return {
+ success: true,
+ data: basicInfo,
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error.message,
};
}
}
@@ -36,24 +61,16 @@ class ArtistService {
*/
async getArtistArtworks(artistId, options = {}) {
try {
- const {
- type = 'art',
- filter = 'for_ios',
- offset = 0,
- limit = 30
- } = options;
+ const { type = 'art', filter = 'for_ios', offset = 0, limit = 30 } = options;
const params = {
user_id: artistId,
type,
filter,
- offset
+ offset,
};
- const response = await this.makeRequest(
- 'GET',
- `/v1/user/illusts?${stringify(params)}`
- );
+ const response = await this.makeRequest('GET', `/v1/user/illusts?${stringify(params)}`);
console.log('Artworks response keys:', Object.keys(response));
console.log('Artworks count:', response.illusts?.length || 0);
@@ -63,14 +80,13 @@ class ArtistService {
success: true,
data: {
artworks: response.illusts,
- next_url: response.next_url
- }
+ next_url: response.next_url,
+ },
};
-
} catch (error) {
return {
success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -80,36 +96,28 @@ class ArtistService {
*/
async getArtistFollowing(artistId, options = {}) {
try {
- const {
- restrict = 'public',
- offset = 0,
- limit = 30
- } = options;
+ const { restrict = 'public', offset = 0, limit = 30 } = options;
const params = {
user_id: artistId,
restrict,
- offset
+ offset,
};
- const response = await this.makeRequest(
- 'GET',
- `/v1/user/following?${stringify(params)}`
- );
+ const response = await this.makeRequest('GET', `/v1/user/following?${stringify(params)}`);
return {
success: true,
data: {
users: response.user_previews,
next_url: response.next_url,
- total: response.user_previews.length
- }
+ total: response.user_previews.length,
+ },
};
-
} catch (error) {
return {
success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -119,34 +127,27 @@ class ArtistService {
*/
async getArtistFollowers(artistId, options = {}) {
try {
- const {
- offset = 0,
- limit = 30
- } = options;
+ const { offset = 0, limit = 30 } = options;
const params = {
user_id: artistId,
- offset
+ offset,
};
- const response = await this.makeRequest(
- 'GET',
- `/v1/user/follower?${stringify(params)}`
- );
+ const response = await this.makeRequest('GET', `/v1/user/follower?${stringify(params)}`);
return {
success: true,
data: {
users: response.user_previews,
next_url: response.next_url,
- total: response.user_previews.length
- }
+ total: response.user_previews.length,
+ },
};
-
} catch (error) {
return {
success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -156,32 +157,29 @@ class ArtistService {
*/
async getFollowingArtists(options = {}) {
try {
- const {
- offset = 0,
- limit = 30
- } = options;
+ const { offset = 0, limit = 30 } = options;
// 检查认证状态
if (!this.auth || !this.auth.accessToken) {
return {
success: false,
- error: '未登录或认证已过期'
+ error: '未登录或认证已过期',
};
}
// 尝试从认证实例获取当前用户ID
let currentUserId = this.auth.user?.id;
-
+
// 如果认证实例中没有用户信息,尝试从状态中获取
if (!currentUserId) {
const status = this.auth.getStatus();
currentUserId = status.user?.id;
}
-
+
if (!currentUserId) {
return {
success: false,
- error: '无法获取当前用户信息,请重新登录'
+ error: '无法获取当前用户信息,请重新登录',
};
}
@@ -189,15 +187,10 @@ class ArtistService {
user_id: currentUserId,
restrict: 'public',
offset,
- limit
+ limit,
};
- console.log('获取关注作者列表,参数:', params);
-
- const response = await this.makeRequest(
- 'GET',
- `/v1/user/following?${stringify(params)}`
- );
+ const response = await this.makeRequest('GET', `/v1/user/following?${stringify(params)}`);
// 转换数据格式以匹配前端期望
const artists = (response.user_previews || []).map(user => ({
@@ -205,52 +198,21 @@ class ArtistService {
name: user.user.name,
account: user.user.account,
profile_image_urls: user.user.profile_image_urls,
- total_illusts: 0, // 这些信息需要通过 /v1/user/detail 获取
- total_manga: 0,
- total_followers: 0,
- is_followed: user.user.is_followed || false
+ is_followed: user.user.is_followed || false,
}));
- // 为前5个用户获取详细信息(避免API调用过多)
- const artistsToFetch = artists.slice(0, 5);
- const detailedArtists = await Promise.all(
- artistsToFetch.map(async (artist) => {
- try {
- const detailResponse = await this.getArtistInfo(artist.id);
- if (detailResponse.success) {
- return {
- ...artist,
- total_illusts: detailResponse.data.total_illusts || 0,
- total_manga: detailResponse.data.total_manga || 0,
- total_followers: detailResponse.data.total_followers || 0
- };
- }
- } catch (error) {
- console.error(`获取用户 ${artist.id} 详细信息失败:`, error.message);
- }
- return artist;
- })
- );
-
- // 合并详细信息和基本信息
- const finalArtists = [
- ...detailedArtists,
- ...artists.slice(5) // 其余用户保持基本信息
- ];
-
return {
success: true,
data: {
- artists: finalArtists,
- total: finalArtists.length
- }
+ artists: artists,
+ total: artists.length,
+ },
};
-
} catch (error) {
console.error('获取关注作者列表失败:', error.message);
return {
success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -262,26 +224,21 @@ class ArtistService {
try {
const data = {
user_id: artistId,
- restrict: 'public'
+ restrict: 'public',
};
const endpoint = action === 'follow' ? '/v1/user/follow/add' : '/v1/user/follow/delete';
-
- const response = await this.makeRequest(
- 'POST',
- endpoint,
- data
- );
+
+ const response = await this.makeRequest('POST', endpoint, data);
return {
success: true,
- data: response
+ data: response,
};
-
} catch (error) {
return {
success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -291,26 +248,17 @@ class ArtistService {
*/
async searchArtists(searchOptions) {
try {
- const {
- keyword,
- sort = 'date_desc',
- duration = 'all',
- offset = 0,
- limit = 30
- } = searchOptions;
+ const { keyword, sort = 'date_desc', duration = 'all', offset = 0, limit = 30 } = searchOptions;
const params = {
word: keyword,
sort,
duration,
offset,
- filter: 'for_ios'
+ filter: 'for_ios',
};
- const response = await this.makeRequest(
- 'GET',
- `/v1/search/user?${stringify(params)}`
- );
+ const response = await this.makeRequest('GET', `/v1/search/user?${stringify(params)}`);
return {
success: true,
@@ -318,14 +266,13 @@ class ArtistService {
users: response.user_previews,
next_url: response.next_url,
search_span_limit: response.search_span_limit,
- total: response.user_previews.length
- }
+ total: response.user_previews.length,
+ },
};
-
} catch (error) {
return {
success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -335,82 +282,26 @@ class ArtistService {
*/
async getRecommendedArtists(options = {}) {
try {
- const {
- offset = 0,
- limit = 30
- } = options;
+ const { offset = 0, limit = 30 } = options;
const params = {
offset,
- filter: 'for_ios'
+ filter: 'for_ios',
};
- const response = await this.makeRequest(
- 'GET',
- `/v1/user/recommended?${stringify(params)}`
- );
+ const response = await this.makeRequest('GET', `/v1/user/recommended?${stringify(params)}`);
return {
success: true,
data: {
users: response.user_previews,
- next_url: response.next_url
- }
+ next_url: response.next_url,
+ },
};
-
} catch (error) {
return {
success: false,
- error: error.message
- };
- }
- }
-
- /**
- * 获取作者统计信息
- */
- async getArtistStats(artistId) {
- try {
- const response = await this.makeRequest(
- 'GET',
- '/v1/user/detail',
- { user_id: artistId }
- );
-
- const user = response.user;
-
- const stats = {
- user_id: user.id,
- total_illusts: user.total_illusts,
- total_manga: user.total_manga,
- total_novels: user.total_novels,
- total_bookmarked_illust: user.total_bookmarked_illust,
- total_following: user.total_following,
- total_followers: user.total_followers,
- total_illust_bookmarks_public: user.total_illust_bookmarks_public,
- total_illust_series: user.total_illust_series,
- total_novel_series: user.total_novel_series,
- background: user.background,
- twitter_account: user.twitter_account,
- twitter_url: user.twitter_url,
- pawoo_url: user.pawoo_url,
- is_followed: user.is_followed,
- is_following: user.is_following,
- is_friend: user.is_friend,
- is_blocking: user.is_blocking,
- is_blocked: user.is_blocked,
- accept_request: user.accept_request
- };
-
- return {
- success: true,
- data: stats
- };
-
- } catch (error) {
- return {
- success: false,
- error: error.message
+ error: error.message,
};
}
}
@@ -420,20 +311,20 @@ class ArtistService {
*/
async makeRequest(method, endpoint, data = null) {
const headers = {
- 'Authorization': `Bearer ${this.auth.accessToken}`,
+ Authorization: `Bearer ${this.auth.accessToken}`,
'Accept-Language': 'en-us',
'App-OS': 'android',
'App-OS-Version': '9.0',
'App-Version': '5.0.234',
- 'User-Agent': 'PixivAndroidApp/5.0.234 (Android 9.0; Pixel 3)'
+ 'User-Agent': 'PixivAndroidApp/5.0.234 (Android 9.0; Pixel 3)',
};
- const config = {
- method,
- url: `${this.baseURL}${endpoint}`,
- headers,
- timeout: 60000 // 增加到60秒
- };
+ const config = {
+ method,
+ url: `${this.baseURL}${endpoint}`,
+ headers,
+ timeout: 60000, // 增加到60秒
+ };
if (data) {
if (method === 'GET') {
@@ -454,11 +345,11 @@ class ArtistService {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
- message: error.message
+ message: error.message,
});
throw error;
}
}
}
-module.exports = ArtistService;
\ No newline at end of file
+module.exports = ArtistService;
diff --git a/backend/services/repository.js b/backend/services/repository.js
index b5d37b4..246dc8f 100644
--- a/backend/services/repository.js
+++ b/backend/services/repository.js
@@ -222,18 +222,80 @@ class RepositoryService {
async getDiskUsage() {
try {
const currentBaseDir = this.getCurrentBaseDir()
- const stats = await fs.statfs(currentBaseDir)
- const total = stats.blocks * stats.bsize
- const free = stats.bavail * stats.bsize
- const used = total - free
- return {
- total,
- used,
- free,
- usagePercent: Math.round((used / total) * 100)
+ // 尝试使用 fs.statfs (Node.js 内置方法)
+ try {
+ const stats = await fs.statfs(currentBaseDir)
+ const total = stats.blocks * stats.bsize
+ const free = stats.bavail * stats.bsize
+ const used = total - free
+
+ return {
+ total,
+ used,
+ free,
+ usagePercent: Math.round((used / total) * 100)
+ }
+ } catch (statfsError) {
+ console.log('fs.statfs 不可用,尝试使用系统命令:', statfsError.message)
+
+ // 如果 fs.statfs 不可用,尝试使用系统命令
+ if (process.platform === 'win32') {
+ // Windows 系统
+ try {
+ const { stdout } = await execAsync('wmic logicaldisk get size,freespace,caption')
+ const lines = stdout.trim().split('\n').slice(1) // 跳过标题行
+
+ for (const line of lines) {
+ const parts = line.trim().split(/\s+/)
+ if (parts.length >= 3) {
+ const caption = parts[0]
+ const freeSpace = parseInt(parts[1])
+ const totalSize = parseInt(parts[2])
+
+ // 检查当前目录是否在这个磁盘上
+ if (currentBaseDir.toUpperCase().startsWith(caption.toUpperCase())) {
+ const used = totalSize - freeSpace
+ return {
+ total: totalSize,
+ used,
+ free: freeSpace,
+ usagePercent: Math.round((used / totalSize) * 100)
+ }
+ }
+ }
+ }
+ } catch (wmicError) {
+ console.log('wmic 命令失败:', wmicError.message)
+ }
+ } else {
+ // Unix/Linux 系统
+ try {
+ const { stdout } = await execAsync(`df -B1 "${currentBaseDir}" | tail -1`)
+ const parts = stdout.trim().split(/\s+/)
+ if (parts.length >= 4) {
+ const total = parseInt(parts[1])
+ const used = parseInt(parts[2])
+ const free = parseInt(parts[3])
+
+ return {
+ total,
+ used,
+ free,
+ usagePercent: Math.round((used / total) * 100)
+ }
+ }
+ } catch (dfError) {
+ console.log('df 命令失败:', dfError.message)
+ }
+ }
+
+ // 如果所有方法都失败,返回默认值
+ console.log('无法获取磁盘使用情况,返回默认值')
+ return { total: 0, used: 0, free: 0, usagePercent: 0 }
}
} catch (error) {
+ console.error('获取磁盘使用情况失败:', error)
return { total: 0, used: 0, free: 0, usagePercent: 0 }
}
}
diff --git a/ui/dist.zip b/ui/dist.zip
index 87930c0..121943e 100644
Binary files a/ui/dist.zip and b/ui/dist.zip differ
diff --git a/ui/src/components/TheWelcome.vue b/ui/src/components/TheWelcome.vue
deleted file mode 100644
index 6092dff..0000000
--- a/ui/src/components/TheWelcome.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
- @{{ artist.account }} 尝试使用不同的关键词搜索 输入作者名称或账号来搜索
-
- More instructions are available in
- README.md.
-
-
-
+
{{ artist.name }}
+ 搜索结果 ({{ filteredResults.length }})
+ 未找到相关作者
+ 搜索作者
+ This is an about page
-
@{{ artist.account }}
-