Skip to content

Commit 955d52b

Browse files
committed
Add toast for click 'like' button when account is banned; Close #81
Assisted-by: Grok 4.5
1 parent 7679c14 commit 955d52b

3 files changed

Lines changed: 104 additions & 1 deletion

File tree

src/constants/globalEvents.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export const DRAWER_VIDEO_ENTER_PAGE_FULL = 'drawerVideoEnterPageFull'
55
export const DRAWER_VIDEO_EXIT_PAGE_FULL = 'drawerVideoExitPageFull'
66
export const IFRAME_PAGE_SWITCH_BEWLY = 'iframePageSwitchBewly'
77
export const IFRAME_PAGE_SWITCH_BILI = 'iframePageSwitchBili'
8+
export const BEWLY_API_TOAST = 'bewlyApiToast'

src/contentScripts/views/App.vue

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script setup lang="ts">
22
import { useEventListener, useThrottleFn, useToggle } from '@vueuse/core'
33
import type { Ref } from 'vue'
4+
import { useToast } from 'vue-toastification'
45
56
import type { BewlyAppProvider } from '~/composables/useAppProvider'
67
import { useDark } from '~/composables/useDark'
78
import { useWebFullscreen } from '~/composables/useWebFullscreen'
8-
import { BEWLY_MOUNTED, DRAWER_VIDEO_ENTER_PAGE_FULL, DRAWER_VIDEO_EXIT_PAGE_FULL, IFRAME_PAGE_SWITCH_BEWLY, IFRAME_PAGE_SWITCH_BILI, OVERLAY_SCROLL_BAR_SCROLL } from '~/constants/globalEvents'
9+
import { BEWLY_API_TOAST, BEWLY_MOUNTED, DRAWER_VIDEO_ENTER_PAGE_FULL, DRAWER_VIDEO_EXIT_PAGE_FULL, IFRAME_PAGE_SWITCH_BEWLY, IFRAME_PAGE_SWITCH_BILI, OVERLAY_SCROLL_BAR_SCROLL } from '~/constants/globalEvents'
910
import { AppPage } from '~/enums/appEnums'
1011
import { settings } from '~/logic'
1112
import { type DockItem, useMainStore } from '~/stores/mainStore'
@@ -20,6 +21,23 @@ const mainStore = useMainStore()
2021
const settingsStore = useSettingsStore()
2122
const { isDark } = useDark()
2223
const [showSettings, toggleSettings] = useToggle(false)
24+
const toast = useToast()
25+
26+
useEventListener(window, BEWLY_API_TOAST, ((event: CustomEvent<{ message?: string, type?: string }>) => {
27+
const message = event.detail?.message
28+
if (!message)
29+
return
30+
31+
const type = event.detail?.type || 'error'
32+
if (type === 'warning')
33+
toast.warning(message)
34+
else if (type === 'info')
35+
toast.info(message)
36+
else if (type === 'success')
37+
toast.success(message)
38+
else
39+
toast.error(message)
40+
}) as EventListener)
2341
2442
// Get the 'page' query parameter from the URL
2543
function getPageParam(): AppPage | null {

src/inject/index.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,90 @@ function setupClipboardInterceptor() {
120120

121121
setupClipboardInterceptor()
122122

123+
function isReplyActionUrl(url) {
124+
if (!url)
125+
return false
126+
try {
127+
const parsed = new URL(url, location.href)
128+
const path = parsed.pathname.replace(/\/+$/, '')
129+
return parsed.hostname === 'api.bilibili.com'
130+
&& path === '/x/v2/reply/action'
131+
}
132+
catch {
133+
return /api\.bilibili\.com\/x\/v2\/reply\/action(?:\?|$|\/)/.test(String(url))
134+
}
135+
}
136+
137+
let lastReplyActionToastKey = ''
138+
let lastReplyActionToastAt = 0
139+
140+
function notifyReplyActionError(data) {
141+
if (!data || typeof data !== 'object')
142+
return
143+
if (data.code === 0 || data.code === '0')
144+
return
145+
146+
const message = data.message || data.msg
147+
if (!message || message === '0')
148+
return
149+
150+
const text = String(message)
151+
const now = Date.now()
152+
if (text === lastReplyActionToastKey && now - lastReplyActionToastAt < 800)
153+
return
154+
lastReplyActionToastKey = text
155+
lastReplyActionToastAt = now
156+
157+
window.dispatchEvent(new CustomEvent('bewlyApiToast', {
158+
detail: { message: text, type: 'error' },
159+
}))
160+
}
161+
162+
function setupReplyActionInterceptor() {
163+
if (typeof window.fetch === 'function') {
164+
const originalFetch = window.fetch.bind(window)
165+
window.fetch = function (...args) {
166+
const input = args[0]
167+
let url = ''
168+
if (typeof input === 'string')
169+
url = input
170+
else if (input && typeof input.url === 'string')
171+
url = input.url
172+
173+
return originalFetch(...args).then((response) => {
174+
if (isReplyActionUrl(url)) {
175+
response.clone().json().then(notifyReplyActionError).catch(() => {})
176+
}
177+
return response
178+
})
179+
}
180+
}
181+
182+
if (typeof XMLHttpRequest !== 'undefined') {
183+
const originalOpen = XMLHttpRequest.prototype.open
184+
const originalSend = XMLHttpRequest.prototype.send
185+
186+
XMLHttpRequest.prototype.open = function (method, url, ...rest) {
187+
this.__bewlyReplyActionUrl = typeof url === 'string' ? url : String(url ?? '')
188+
return originalOpen.call(this, method, url, ...rest)
189+
}
190+
191+
XMLHttpRequest.prototype.send = function (...args) {
192+
this.addEventListener('load', function onLoad() {
193+
if (!isReplyActionUrl(this.__bewlyReplyActionUrl))
194+
return
195+
try {
196+
notifyReplyActionError(JSON.parse(this.responseText))
197+
}
198+
catch {}
199+
})
200+
return originalSend.apply(this, args)
201+
}
202+
}
203+
}
204+
205+
setupReplyActionInterceptor()
206+
123207
window.___inject = true
124208

125209
// History.prototype.pushState = history.pushState

0 commit comments

Comments
 (0)