Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fetching user followings #44

Merged
merged 4 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions apps/monkey/src/Config.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ const dateRange = computed({
clearable
/>

<div class="center flex-wrap justify-start gap-2">
<div
v-if="!config.followingsOnly"
class="center flex-wrap justify-start gap-2"
>
<n-checkbox
v-model:checked="config.largePic"
label="导出原图"
Expand Down Expand Up @@ -65,6 +68,7 @@ const dateRange = computed({
</template>
默认开始前都会清空之前的状态
</n-tooltip>

<button
class="py-1 text-3.5 btn bg-#18a058! hover:bg-green-7!"
@click="() => {
Expand All @@ -74,7 +78,11 @@ const dateRange = computed({
重置为所有微博
</button>
</div>

<n-checkbox
v-model:checked="config.followingsOnly"
label="只导出关注列表"
size="small"
/>
<div
v-show="config.hasComment"
class="flex items-center gap-4"
Expand Down
67 changes: 42 additions & 25 deletions apps/monkey/src/Ctrl.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<script setup lang="ts">
import { useMessage } from 'naive-ui'
import { saveAs } from 'file-saver'
import { storeToRefs } from 'pinia'

import { exportData } from '@core/utils'
import { fetchFollowings } from '@core/services'
import { useConfigStore, usePostStore } from './stores'
import Config from './Config.vue'

Expand All @@ -15,37 +14,31 @@ const configStore = useConfigStore()
const isStart = ref(false)
const isStop = ref(false)
const isFinish = ref(false)
const isFetchingFollowings = ref(false)

const { config } = storeToRefs(configStore)

const percentage = computed(() => config.value.fetchedCount / postStore.total * 100)
const progressText = computed(() => () => `${config.value.fetchedCount}/${postStore.total} 条`)

/**
* 导出数据
*/
async function exportDatas() {
const posts = await postStore.getAll()
console.log('导出的数量:', posts.length)

const res = await exportData(posts, postStore.userInfo)
if (!res)
return
const scripts = 'https://github.com/Chilfish/Weibo-archiver/raw/monkey/scripts.zip'
saveAs(scripts, 'scripts.zip')
}

const { pause, start } = fetchPosts({
fetchOptions: () => ({
...config.value,
savePost: post => postStore.add(post),
}),
setTotal: total => postStore.total = total,
onFinish: async () => {
message.success('获取完毕~,正在获取关注列表')
isFetchingFollowings.value = true
await fetchFollowings(
config.value.uid,
async data => postStore.addFollowings(data),
)
await postStore.exportDatas()

isStart.value = false
isFinish.value = true
config.value.curPage--
exportDatas()
},
})

Expand All @@ -55,18 +48,32 @@ async function startFetch() {
})

postStore.setDB()
await postStore.setCount()
isStart.value = true
isFinish.value = false
isStop.value = false
isFetchingFollowings.value = false

// 如果只获取关注列表
if (config.value.followingsOnly) {
isFetchingFollowings.value = true
await fetchFollowings(
config.value.uid,
async data => postStore.addFollowings(data),
)
await postStore.exportFollowings()
isStart.value = false
isFinish.value = true
return
}

// 如果是重新开始,不保留上次 fetch 的状态
if (!config.value.restore || !config.value.isFetchAll)
await postStore.reset()

await postStore.setCount()
await postStore.setUser()

isStart.value = true
isFinish.value = false
isStop.value = false
start()
await start()
}

window.$message = message
Expand Down Expand Up @@ -94,6 +101,16 @@ function toggleStop() {
else
start()
}

const startButtonText = computed(() => {
if (config.value.followingsOnly)
return '获取关注列表'

if (isStop.value)
return `重新开始获取 ${config.value.isFetchAll ? '全部' : '部分'} 微博`

return `开始获取 ${config.value.isFetchAll ? '全部' : '部分'} 微博`
})
</script>

<template>
Expand Down Expand Up @@ -141,14 +158,14 @@ function toggleStop() {
v-show="!isStart || isStop"
@click="startFetch"
>
{{ isStop ? '重新' : '' }}开始获取 <strong>{{ config.isFetchAll ? '全部' : '部分' }}</strong> 微博
{{ startButtonText }}
</button>

<div
v-show="isStart && !isFinish && !isStop"
class="center"
>
获取中~
正在获取{{ isFetchingFollowings ? '关注列表' : '微博' }} ~
</div>

<button
Expand All @@ -160,7 +177,7 @@ function toggleStop() {

<button
v-show="isFinish || isStop"
@click="exportDatas"
@click="postStore.exportDatas"
>
导出
</button>
Expand Down
1 change: 1 addition & 0 deletions apps/monkey/src/stores/configStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const useConfigStore = defineStore('config', () => {
hasComment: true,
hasFavorite: true,
commentCount: 6,
followingsOnly: false,
dateRange: [now, now],
}

Expand Down
33 changes: 32 additions & 1 deletion apps/monkey/src/stores/postStore.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineStore, storeToRefs } from 'pinia'
import type { Post, UID, UserInfo } from '@types'
import type { Post, UID, UserBio, UserInfo } from '@types'
import { EmptyIDB, IDB } from '@core/utils/storage'
import saveAs from 'file-saver'
import { useConfigStore } from './configStore'

export const usePostStore = defineStore('post', () => {
Expand Down Expand Up @@ -84,6 +85,33 @@ export const usePostStore = defineStore('post', () => {
await idb.value.setUserInfo(user)
}

async function addFollowings(followings: UserBio[]) {
await waitIDB()
await idb.value.addFollowings(followings)
}

async function exportFollowings() {
await waitIDB()
const data = await idb.value.getFollowings()
return await exportData([], userInfo.value, data)
}

/**
* 导出数据
*/
async function exportDatas() {
const posts = await getAll()
console.log('导出的数量:', posts.length)

const followings = await idb.value.getFollowings()

const res = await exportData(posts, userInfo.value, followings)
if (!res)
return
const scripts = 'https://github.com/Chilfish/Weibo-archiver/raw/monkey/scripts.zip'
saveAs(scripts, 'scripts.zip')
}

return {
total,
pageSize,
Expand All @@ -95,5 +123,8 @@ export const usePostStore = defineStore('post', () => {
getAll,
setCount,
setUser,
exportDatas,
addFollowings,
exportFollowings,
}
})
68 changes: 67 additions & 1 deletion packages/core/src/services/userService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { UserInfo } from '@types'
import type { UserBio, UserInfo } from '@types'
import { weiFetch } from '../utils/fetch'
import { parseFollowing } from '../utils'

export async function userInfo(
{ id, name }: { id?: string, name?: string },
Expand Down Expand Up @@ -55,3 +56,68 @@ export async function userDetail(
...detail,
}
}

export async function getFollowings(
uid: string,
page: number,
) {
const { users, total_number } = await weiFetch<{
users: any[]
total_number: number
}>('/friendships/friends', {
params: {
uid,
page,
},
})

return {
users: users.map(parseFollowing),
total: total_number,
}
}

export async function getMyFollowings(
page: number,
) {
const { data } = await weiFetch<{ data: {
follows: { users: any[] }
total_number: number
} }>('/profile/followContent', {
params: {
page,
},
})

return {
users: data.follows.users.map(parseFollowing),
total: data.total_number,
}
}

export function isMe(uid: string) {
// 获取头像的链接
const links = Array.from(document.querySelector('[role=navigation]')?.querySelectorAll('a') || [])
const matched = links[links.length - 1]?.href.match(/\d+/)?.[0] || ''

return matched === uid
}

export async function fetchFollowings(
uid: string,
saveData: (users: UserBio[], total: number) => Promise<void>,
) {
let page = 1
const _isMe = isMe(uid)
while (true) {
await delay(3000)
const { users, total } = _isMe
? await getMyFollowings(page)
: await getFollowings(uid, page)

await saveData(users, total)
page += 1
if (users.length === 0)
break
}
}
18 changes: 17 additions & 1 deletion packages/core/src/stores/post.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { defineStore } from 'pinia'
import { useRoute, useRouter } from 'vue-router'
import type { Post, UID, UserInfo } from '@types'
import type { Post, UID, UserBio, UserInfo } from '@types'
import { EmptyIDB, IDB } from '../utils/storage'

export const usePostStore = defineStore('post', () => {
const publicStore = usePublicStore()
const followings = shallowRef<UserBio[]>([])

const idb = ref(new EmptyIDB())
watchImmediate(() => publicStore.curUid, async (uid) => {
Expand All @@ -16,6 +17,8 @@ export const usePostStore = defineStore('post', () => {

idb.value = new IDB(wrappedUid)
await updateTotal()

followings.value = await getFollowings()
})

const route = useRoute()
Expand Down Expand Up @@ -72,10 +75,14 @@ export const usePostStore = defineStore('post', () => {
async function set(
data: Post[],
user: UserInfo,
followings?: UserBio[],
isReplace = false,
) {
await waitIDB()

if (followings && followings.length)
await idb.value.addFollowings(followings)

const { count, search } = await idb.value.addDBPosts(data, isReplace)
totalDB.value = count
total.value = count
Expand Down Expand Up @@ -196,12 +203,20 @@ export const usePostStore = defineStore('post', () => {
return posts
}

async function getFollowings() {
await waitIDB()
return await idb.value
.getFollowings()
.then(data => data.sort((a, b) => a.name.localeCompare(b.name)))
}

return {
total,
totalDB,
pages,
pageSize,
curPage,
followings,

get,
set,
Expand All @@ -226,5 +241,6 @@ export const usePostStore = defineStore('post', () => {
getByTime,
searchPost,
searchAndTime,
getFollowings,
}
})
9 changes: 7 additions & 2 deletions packages/core/src/stores/public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ export const usePublicStore = defineStore('public', () => {
})

function addUser(user: UserInfo | null | undefined) {
if (!user || users.value.find(u => u.uid === user.uid))
if (!user)
return

users.value.push(user)
const idx = users.value.findIndex(u => u.uid === user.uid)

if (idx < 0)
users.value.push(user)
else
users.value.splice(idx, 1, user)
}

function rmUser() {
Expand Down
Loading