iphone-xudale 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.eslintrc.json +3 -0
  2. package/app/(pages)/options/page.tsx +720 -0
  3. package/app/(pages)/popup/page.tsx +166 -0
  4. package/app/(pages)/tips/page.tsx +40 -0
  5. package/app/components/DropListBox.tsx +157 -0
  6. package/app/components/SVGPlay.tsx +14 -0
  7. package/app/favicon.ico +0 -0
  8. package/app/globals.css +27 -0
  9. package/app/layout.tsx +15 -0
  10. package/app/page.tsx +3 -0
  11. package/app/scripts/content/checkoutSteps.ts +341 -0
  12. package/app/scripts/content/doFroApplePages.ts +206 -0
  13. package/app/scripts/content/getPageInitInfo.ts +49 -0
  14. package/app/scripts/content/getStoreCanPickInfo.ts +251 -0
  15. package/app/scripts/content/goOrderSteps.ts +179 -0
  16. package/app/scripts/content/index.ts +56 -0
  17. package/app/scripts/content/playSystemNotifacation.ts +39 -0
  18. package/app/scripts/content/sendSelfNotificatioin.ts +27 -0
  19. package/app/scripts/inject/index.ts +18 -0
  20. package/app/shared/constants.ts +236 -0
  21. package/app/shared/interface.ts +25 -0
  22. package/app/shared/location/city.json +1774 -0
  23. package/app/shared/location/county.json +17115 -0
  24. package/app/shared/location/province.json +94 -0
  25. package/app/shared/util.ts +93 -0
  26. package/buildAfter.js +86 -0
  27. package/bunBuild.ts +54 -0
  28. package/extension/content-script.js +7 -0
  29. package/extension/favicon.ico +0 -0
  30. package/extension/icons/icon128.png +0 -0
  31. package/extension/icons/icon16.png +0 -0
  32. package/extension/icons/icon19-disable.png +0 -0
  33. package/extension/icons/icon19.png +0 -0
  34. package/extension/icons/icon32.png +0 -0
  35. package/extension/icons/icon38.png +0 -0
  36. package/extension/icons/icon48.png +0 -0
  37. package/extension/inject-script.js +1 -0
  38. package/extension/manifest.json +38 -0
  39. package/extension/service-worker.js +62 -0
  40. package/extension.next.config.js +25 -0
  41. package/icon_generator.py +30 -0
  42. package/middleware.ts +21 -0
  43. package/next.config.js +15 -0
  44. package/package.json +67 -0
  45. package/postcss.config.js +6 -0
  46. package/public/assets/images/SCR-20230916-nbkz.png +0 -0
  47. package/public/assets/images/SCR-20230916-nbyv.png +0 -0
  48. package/public/assets/images/SCR-20230916-ncte.png +0 -0
  49. package/public/assets/images/SCR-20230916-ndgw.png +0 -0
  50. package/public/assets/images/SCR-20230916-ndks.png +0 -0
  51. package/public/assets/images/SCR-20230916-neaa.png +0 -0
  52. package/public/assets/images/SCR-20230916-neeq.jpeg +0 -0
  53. package/public/assets/images/SCR-20230916-nfkt.png +0 -0
  54. package/public/assets/images/SCR-20230919-ulfn.png +0 -0
  55. package/public/assets/images/SCR-20230919-ulzd.png +0 -0
  56. package/public/assets/images/SCR-20230919-uocr.png +0 -0
  57. package/public/icon_original.png +0 -0
  58. package/public/next.svg +1 -0
  59. package/public/vercel.svg +1 -0
  60. package/tailwind.config.ts +20 -0
  61. package/tsconfig.json +27 -0
  62. package/types/global.d.ts +19 -0
@@ -0,0 +1,251 @@
1
+ import { IPHONEORDER_CONFIG } from '@/app/shared/interface'
2
+ import { applePageUrl, iPhoneModels, fetchHeaders, defaultAres } from '@/app/shared/constants'
3
+ import { sleep, randomSleep } from '@/app/shared/util'
4
+ import crossfetch from 'cross-fetch'
5
+ import { each as _each, map as _map } from 'lodash'
6
+
7
+ const fetch = crossfetch.bind(this)
8
+
9
+ /*
10
+ * @partNumber iPhone 型号
11
+ * @isNoWait 是否等待,不等待表示纯粹调用接口
12
+ */
13
+ interface IGetStoreCanPickInfoProps {
14
+ x_aos_stk: string
15
+ partNumber: string
16
+ isNoWait?: boolean
17
+ iPhoneOrderConfig: IPHONEORDER_CONFIG
18
+ }
19
+ const getStoreCanPickInfo = async ({
20
+ x_aos_stk,
21
+ partNumber,
22
+ isNoWait,
23
+ iPhoneOrderConfig,
24
+ }: IGetStoreCanPickInfoProps) => {
25
+ storeSearchInPage({ iPhoneOrderConfig })
26
+ let pickupStoreInfo: Record<string, any> = {}
27
+ const { host, protocol } = window.location || {}
28
+ // let url = `${protocol}//www.apple.com.cn/shop/fulfillment-messages`
29
+ let url = `/shop/checkoutx?_a=search&_m=checkout.fulfillment.pickupTab.pickup.storeLocator`
30
+
31
+ const districtName = iPhoneOrderConfig.districtName || defaultAres.districtName
32
+ const provinceName = iPhoneOrderConfig.provinceName || defaultAres.provinceName
33
+ const cityName = iPhoneOrderConfig.cityName || defaultAres.cityName
34
+ let reqQuery = {
35
+ 'parts.0': partNumber, // 型号 `MQ8G3CH/A`,
36
+ 'mts.0': `regular`,
37
+ pl: true,
38
+ location: `${provinceName} ${cityName} ${districtName}`,
39
+ geoLocated: false,
40
+ state: provinceName,
41
+ city: cityName,
42
+ district: districtName,
43
+ }
44
+
45
+ const querystring = _map(reqQuery, (value, key) => {
46
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
47
+ }).join(`&`)
48
+
49
+ let dataString = '',
50
+ data = []
51
+ const provinceCityDistrict =
52
+ provinceName == cityName ? cityName + ' ' + districtName : provinceName + ' ' + cityName + ' ' + districtName
53
+ data = [
54
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.showAllStores=false`,
55
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.selectStore=`,
56
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.searchInput=${encodeURIComponent(
57
+ provinceName + ' ' + cityName + ' ' + districtName
58
+ )}`,
59
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.city=${encodeURIComponent(
60
+ cityName
61
+ )}`,
62
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.state=${encodeURIComponent(
63
+ provinceName
64
+ )}`,
65
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.provinceCityDistrict=${encodeURIComponent(
66
+ provinceCityDistrict
67
+ )}`,
68
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.countryCode=CN`,
69
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.district=${encodeURIComponent(
70
+ districtName
71
+ )}`,
72
+ ]
73
+ dataString = data.join(`&`)
74
+
75
+ let options = {
76
+ method: 'POST',
77
+ headers: {
78
+ ...fetchHeaders,
79
+ referer: applePageUrl.buyiPhone,
80
+ 'X-Aos-Model-Page': 'checkoutPage',
81
+ 'X-Aos-Stk': x_aos_stk,
82
+ },
83
+ credentials: 'include' as RequestCredentials,
84
+ body: dataString,
85
+ }
86
+
87
+ console.log(`getStoreCanPickInfo options`, options)
88
+ try {
89
+ let resResult = (await fetch(url, options)) as Record<string, any>
90
+
91
+ let pickupResults: any = {}
92
+
93
+ // 如果请求失败, 表示被封禁
94
+ if (![200, 301, 302].includes(Number(resResult?.status))) {
95
+ if (!isNoWait) {
96
+ console.log(`********** GMfetch failed, stepWait add 1 sec **********`)
97
+ const resText = await resResult.text()
98
+ // console.log(`resText`, resText)
99
+ iPhoneOrderConfig.stepWait = iPhoneOrderConfig.stepWait + 1
100
+ if (resText?.indexOf(`503 Service Temporarily Unavailable`) > -1) {
101
+ console.log(`********** and wait 1 min **********`)
102
+ // 换一个型号调用,让apple认为是正常请求
103
+ const iPhoneProAll = iPhoneModels.iPhone15Pro
104
+ const randomPartNumberiPhonePro =
105
+ iPhoneProAll[Math.floor(Math.random() * iPhoneProAll.length)]?.model
106
+ await getStoreCanPickInfo({
107
+ x_aos_stk,
108
+ partNumber: randomPartNumberiPhonePro,
109
+ isNoWait: true,
110
+ iPhoneOrderConfig,
111
+ })
112
+ await sleep(60)
113
+ }
114
+ } else {
115
+ console.log(`********** GMfetch failed, NoWait failed **********`)
116
+ }
117
+ } else {
118
+ const resJson = await resResult.json()
119
+ console.log(`resJson`, resJson)
120
+ pickupResults =
121
+ resJson?.body?.checkout?.fulfillment?.pickupTab?.pickup?.storeLocator?.searchResults?.d || {}
122
+ }
123
+
124
+ let partPickupStores = pickupResults?.retailStores || [],
125
+ pickupNumbers = ''
126
+ _each(partPickupStores, store => {
127
+ const {
128
+ retailAddress,
129
+ storeDisabled,
130
+ pickupMessages,
131
+ availability,
132
+ storeId: storeNumber,
133
+ storeName,
134
+ } = store || {}
135
+ const { availableNowForAllLines } = availability || {}
136
+ const { city } = retailAddress || {}
137
+ // 有时候会搜出周边城市,这里用于排除周边城市
138
+ const isInCity = city == cityName
139
+ if (isInCity && pickupMessages?.length && (!storeDisabled || availableNowForAllLines)) {
140
+ pickupStoreInfo = {
141
+ ...pickupStoreInfo,
142
+ storeNumber,
143
+ storeName,
144
+ availableNowForAllLines,
145
+ }
146
+ return false
147
+ }
148
+ })
149
+ } catch (e) {
150
+ console.log(e)
151
+ if (!isNoWait) {
152
+ console.log(`********** GMfetch failed, stepWait add 1 sec, and wait 1 min **********`)
153
+ iPhoneOrderConfig.stepWait = iPhoneOrderConfig.stepWait + 1
154
+ // 换一个型号调用,让apple认为是正常请求
155
+ const iPhoneProAll = iPhoneModels.iPhone15Pro
156
+ const randomPartNumberiPhonePro = iPhoneProAll[Math.floor(Math.random() * iPhoneProAll.length)]?.model
157
+ await getStoreCanPickInfo({
158
+ x_aos_stk,
159
+ partNumber: randomPartNumberiPhonePro,
160
+ isNoWait: true,
161
+ iPhoneOrderConfig,
162
+ })
163
+ await sleep(10)
164
+ } else {
165
+ console.log(`********** GMfetch failed, NoWait failed **********`)
166
+ }
167
+ }
168
+
169
+ console.log(`pickupStoreInfo`, pickupStoreInfo)
170
+ return pickupStoreInfo
171
+ }
172
+
173
+ export default getStoreCanPickInfo
174
+
175
+ interface IStoreSearchInPageProps {
176
+ iPhoneOrderConfig: IPHONEORDER_CONFIG
177
+ }
178
+
179
+ const randomRange = 3
180
+ const storeSearchInPage = async ({ iPhoneOrderConfig }: IStoreSearchInPageProps) => {
181
+ const storeSearchDataAutom = `fulfillment-pickup-store-search-button`
182
+ const storeSearchBtn = document.querySelector(`button[data-autom="${storeSearchDataAutom}"]`)
183
+ if (!storeSearchBtn) return
184
+ const { cityName, districtName, provinceName } = iPhoneOrderConfig
185
+
186
+ if (!cityName || !districtName || !provinceName) return
187
+
188
+ // 已纠正的情况下,不需要重复点击了
189
+ if (storeSearchBtn.textContent) {
190
+ if (storeSearchBtn.textContent.includes(districtName) && storeSearchBtn.textContent.includes(provinceName)) {
191
+ return
192
+ }
193
+ }
194
+
195
+ await randomSleep({ min: 0, max: randomRange })
196
+ const isSelectionOpen = document.querySelectorAll(`li[role="listitem"]>button`)?.length > 0
197
+
198
+ if (!isSelectionOpen) {
199
+ ;(storeSearchBtn as HTMLButtonElement).click()
200
+ }
201
+
202
+ await randomSleep({ min: 0, max: randomRange })
203
+
204
+ const provinceTabBtn = document.getElementById(
205
+ 'checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.state'
206
+ )
207
+ provinceTabBtn?.click()
208
+
209
+ let hasTheProvince = false
210
+ if (provinceName) {
211
+ const provinceItems = document.querySelectorAll(`li[role="listitem"]>button`)
212
+ _each(provinceItems, p_item => {
213
+ if (p_item?.textContent?.includes(provinceName)) {
214
+ ;(p_item as HTMLButtonElement)?.click()
215
+ hasTheProvince = true
216
+ return false
217
+ }
218
+ })
219
+ await randomSleep({ min: 0, max: randomRange })
220
+ }
221
+
222
+ const cityTabBtn = document.getElementById(
223
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.city`
224
+ )
225
+ cityTabBtn?.click()
226
+ if (hasTheProvince && cityName && cityName != provinceName && cityTabBtn) {
227
+ const cityItems = document.querySelectorAll(`li[role="listitem"]>button`)
228
+ _each(cityItems, p_item => {
229
+ if (p_item?.textContent?.includes(cityName)) {
230
+ ;(p_item as HTMLButtonElement)?.click()
231
+ return false
232
+ }
233
+ })
234
+ await randomSleep({ min: 0, max: randomRange })
235
+ }
236
+
237
+ const districtTabBtn = document.getElementById(
238
+ `checkout.fulfillment.pickupTab.pickup.storeLocator.address.stateCitySelectorForCheckout.district`
239
+ )
240
+ districtTabBtn?.click()
241
+ if (districtName && districtTabBtn) {
242
+ const districtItems = document.querySelectorAll(`li[role="listitem"]>button`)
243
+ _each(districtItems, p_item => {
244
+ if (p_item?.textContent?.includes(districtName)) {
245
+ ;(p_item as HTMLButtonElement)?.click()
246
+ return false
247
+ }
248
+ })
249
+ await randomSleep({ min: 0, max: randomRange })
250
+ }
251
+ }
@@ -0,0 +1,179 @@
1
+ import getStoreCanPickInfo from './getStoreCanPickInfo'
2
+ import checkoutSteps from './checkoutSteps'
3
+ import type { IPHONEORDER_CONFIG } from '@/app/shared/interface'
4
+ import { CHECKOUT_STEPS, BILL_OPTIONS_TYPE } from '@/app/shared/constants'
5
+ import { sleep } from '@/app/shared/util'
6
+ import { isEmpty as _isEmpty, each as _each, some as _some } from 'lodash'
7
+ import { iframeMessagePass } from '@/app/shared/constants'
8
+
9
+ interface IGoOrderSteps {
10
+ partNumber: string
11
+ x_aos_stk: string
12
+ count?: number
13
+ iPhoneOrderConfig: IPHONEORDER_CONFIG
14
+ }
15
+
16
+ const goOrderSteps = async ({ partNumber, x_aos_stk, count, iPhoneOrderConfig }: IGoOrderSteps) => {
17
+ count = count || 1 // 重试次数
18
+ const { afterCountThenReload = 50 } = iPhoneOrderConfig || {}
19
+ // ********** 发送消息给 tips page **********
20
+ const iframeWindow = (document?.getElementById(iframeMessagePass.iframeID) as HTMLIFrameElement)?.contentWindow
21
+ const message = { action: iframeMessagePass.messageAction, count: count, beforeReload: afterCountThenReload }
22
+ iframeWindow?.postMessage(message, '*')
23
+
24
+ // 获取可以提货的商店信息
25
+ let pickupStoreInfo = await getStoreCanPickInfo({ x_aos_stk, partNumber, iPhoneOrderConfig })
26
+
27
+ const { storeNumber, availableNowForAllLines } = pickupStoreInfo || {}
28
+ const { host, protocol } = location || {}
29
+
30
+ if (storeNumber) {
31
+ // 走第一步, 选店,获取提货时间
32
+ let canPickupTime = await checkoutSteps({
33
+ step: CHECKOUT_STEPS.selectStore,
34
+ x_aos_stk,
35
+ stepInfo: {
36
+ storeNumber,
37
+ },
38
+ iPhoneOrderConfig,
39
+ })
40
+ console.log(`firstStep:`, canPickupTime)
41
+
42
+ const timeSlot = canPickupTime?.timeSlot as Record<string, any>
43
+ const noNeedTimeSlot = canPickupTime?.noNeedTimeSlot
44
+ const canPickup = canPickupTime?.isSuccess
45
+ if (!canPickup) return
46
+
47
+ if (noNeedTimeSlot) {
48
+ // 所有时间可取货,直接走 checkoutFulfillment
49
+ let canCheckout = await checkoutSteps({
50
+ noNeedTimeSlot,
51
+ step: CHECKOUT_STEPS.checkoutFulfillment,
52
+ x_aos_stk,
53
+ stepInfo: {
54
+ storeNumber,
55
+ },
56
+ iPhoneOrderConfig,
57
+ })
58
+
59
+ if (!canCheckout?.isSuccess) return
60
+ } else {
61
+ // 第二步, 选日期时间
62
+ let pickupTimeInStore = await checkoutSteps({
63
+ step: CHECKOUT_STEPS.selectPickupTime,
64
+ noNeedTimeSlot,
65
+ x_aos_stk,
66
+ stepInfo: {
67
+ storeNumber,
68
+ ...timeSlot,
69
+ },
70
+ iPhoneOrderConfig,
71
+ })
72
+
73
+ if (!pickupTimeInStore?.isSuccess) return
74
+ }
75
+ // 第三步 填写证件信息
76
+ let addContactResult = await checkoutSteps({
77
+ step: CHECKOUT_STEPS.pickupContact,
78
+ x_aos_stk,
79
+ stepInfo: {
80
+ lastName: iPhoneOrderConfig.lastName,
81
+ firstName: iPhoneOrderConfig.firstName,
82
+ emailAddress: iPhoneOrderConfig.appleId,
83
+ fullDaytimePhone: iPhoneOrderConfig.mobile,
84
+ nationalIdSelf: iPhoneOrderConfig.last4code,
85
+ },
86
+ iPhoneOrderConfig,
87
+ })
88
+ const { allBillingOptions } = addContactResult || {}
89
+
90
+ if (!addContactResult?.isSuccess) return
91
+
92
+ let selectBillType = BILL_OPTIONS_TYPE[iPhoneOrderConfig.payBill] || BILL_OPTIONS_TYPE.alipay
93
+ let selectBillValue = 'ALIPAY'
94
+
95
+ if (!_isEmpty(allBillingOptions)) {
96
+ _each(allBillingOptions, bill_option => {
97
+ const { label, labelImageAlt, a11yLabel, value } = bill_option || {}
98
+ const labelText = label || labelImageAlt || a11yLabel || ''
99
+ if (labelText.indexOf(selectBillType) > -1) {
100
+ selectBillValue = value || 'ALIPAY'
101
+ return false
102
+ }
103
+ })
104
+ }
105
+ // 第四步一, 选择付款方式
106
+ let addBill = await checkoutSteps({
107
+ step: CHECKOUT_STEPS.selectBill,
108
+ x_aos_stk,
109
+ stepInfo: {
110
+ billOption: selectBillValue,
111
+ billInstallment: iPhoneOrderConfig.payInstallment, // 分期
112
+ },
113
+ iPhoneOrderConfig,
114
+ })
115
+
116
+ if (!addBill?.isSuccess) return
117
+
118
+ if (iPhoneOrderConfig.payInstallment && iPhoneOrderConfig.payInstallment > 0) {
119
+ const { installmentOptions = [] } = addBill || {}
120
+ // 判断传入的分期是否合法
121
+ let isPayInstallmentValidated = _some(installmentOptions, item => {
122
+ return item?.value == iPhoneOrderConfig.payInstallment
123
+ })
124
+ if (!isPayInstallmentValidated) {
125
+ iPhoneOrderConfig.payInstallment = installmentOptions[installmentOptions?.length - 1]?.value || 0
126
+ }
127
+ }
128
+
129
+ let confirmBillStepsInfo: Record<string, any> = {
130
+ billOption: selectBillValue,
131
+ }
132
+ if (iPhoneOrderConfig.payInstallment) {
133
+ confirmBillStepsInfo = {
134
+ ...confirmBillStepsInfo,
135
+ billInstallment: iPhoneOrderConfig.payInstallment, // 分期
136
+ }
137
+ }
138
+ // 第四步二,确认付款方式
139
+ let confirmBill = await checkoutSteps({
140
+ step: CHECKOUT_STEPS.checkoutBill,
141
+ x_aos_stk,
142
+ stepInfo: {
143
+ ...confirmBillStepsInfo,
144
+ },
145
+ iPhoneOrderConfig,
146
+ })
147
+
148
+ if (!confirmBill?.isSuccess) return
149
+
150
+ // 最后下单
151
+ let placeOrderRes = await checkoutSteps({
152
+ step: CHECKOUT_STEPS.placeOrder,
153
+ x_aos_stk,
154
+ stepInfo: {},
155
+ iPhoneOrderConfig,
156
+ })
157
+
158
+ if (placeOrderRes?.isSuccess) {
159
+ let jumpUrl = `${protocol}//${host}/shop/checkout/interstitial`
160
+ if (placeOrderRes?.url) {
161
+ // `${protocol}//${host}/shop/checkout/status`
162
+ jumpUrl = `${protocol}//${host}${placeOrderRes.url || ''}`
163
+ }
164
+
165
+ location.href = jumpUrl
166
+ }
167
+ } else if (count >= afterCountThenReload) {
168
+ await sleep(1, `goOrderSteps failed over ${afterCountThenReload} times, then reload page`)
169
+ location.reload()
170
+ } else {
171
+ await sleep(
172
+ iPhoneOrderConfig.stepWait,
173
+ `goOrderSteps again, count: ${count}, limit times: ${afterCountThenReload}`
174
+ )
175
+ await goOrderSteps({ partNumber, x_aos_stk, count: count + 1, iPhoneOrderConfig })
176
+ }
177
+ }
178
+
179
+ export default goOrderSteps
@@ -0,0 +1,56 @@
1
+ import doFroApplePages from './doFroApplePages'
2
+ import { iframeMessagePass } from '@/app/shared/constants'
3
+ import playSystemNotification from './playSystemNotifacation'
4
+
5
+ // @ts-ignore
6
+ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
7
+ const { data, voiceInfo } = message || {}
8
+ const { text } = voiceInfo || {}
9
+ if (data == 'playSystemNotification' && text) {
10
+ playSystemNotification({ voiceInfo: voiceInfo })
11
+ }
12
+ })
13
+
14
+ const addTipsToPage = () => {
15
+ var extensionId = chrome.runtime.id
16
+ const iframe = document.createElement('iframe')
17
+ iframe.id = iframeMessagePass.iframeID
18
+ iframe.style.cssText = `
19
+ right: 0;
20
+ top: 50%;
21
+ width: 250px;
22
+ height: 160px;
23
+ `
24
+ iframe.src = `chrome-extension://${extensionId}/dist/tips.html`
25
+ document.documentElement.appendChild(iframe)
26
+ iframe.style.position = 'fixed'
27
+ console.log(`addTipsToPage`)
28
+ }
29
+
30
+ console.log(`this is content`)
31
+ const contentRun = async () => {
32
+ addTipsToPage()
33
+
34
+ // const orderEnabled = !!(await restoreFromStorage(storeKeys.orderEnabled))
35
+ // console.log(`orderEnabled`, orderEnabled)
36
+ // if (!orderEnabled) return
37
+ await doFroApplePages()
38
+ }
39
+
40
+ contentRun()
41
+
42
+ window.addEventListener('message', function (event) {
43
+ if (event.source === window && event.data.action === 'doFroApplePages') {
44
+ // 在这里执行你的方法逻辑
45
+ doFroApplePages(event.data.url)
46
+ }
47
+ })
48
+
49
+ // 监听页面的加载完成事件, 注入自定义脚本到页面中
50
+ window.addEventListener('load', function injectCustomScript() {
51
+ var script = document.createElement('script')
52
+ var extensionId = chrome.runtime.id
53
+ console.log(extensionId)
54
+ script.src = `chrome-extension://${extensionId}/inject-script.js`
55
+ document.documentElement.appendChild(script)
56
+ })
@@ -0,0 +1,39 @@
1
+ import { VOICE_OBJ } from '@/app/shared/interface'
2
+
3
+ const defaultVoiceInfo = {
4
+ text: `抢到了`,
5
+ times: 1,
6
+ }
7
+
8
+ const playSystemNotification = async ({ voiceInfo }: { voiceInfo: VOICE_OBJ }) => {
9
+ let extensionId
10
+ if (typeof chrome !== 'undefined' && chrome?.runtime) {
11
+ extensionId = chrome.runtime.id
12
+ chrome.runtime.sendMessage({ data: 'bellring', extensionId, voiceInfo })
13
+ }
14
+
15
+ // 检查浏览器是否支持 Web Notifications API
16
+ if ('Notification' in window) {
17
+ const icon = extensionId ? `chrome-extension://${extensionId}/icons/icon38.png` : undefined
18
+ // 请求权限显示通知
19
+ Notification.requestPermission().then(permission => {
20
+ if (permission === 'granted') {
21
+ // 创建通知对象
22
+ const notification = new Notification('提醒', {
23
+ body: voiceInfo?.text || defaultVoiceInfo.text,
24
+ icon,
25
+ })
26
+
27
+ // 将通知点击时的行为处理逻辑添加在这里
28
+ notification.onclick = function () {
29
+ // 处理通知点击事件
30
+ console.log('通知被点击了')
31
+ }
32
+ }
33
+ })
34
+ } else {
35
+ console.log(`notification fail`)
36
+ }
37
+ }
38
+
39
+ export default playSystemNotification
@@ -0,0 +1,27 @@
1
+ import { sleep } from '@/app/shared/util'
2
+
3
+ const sendSelfNotificatioin = async ({ url }: { url?: string }) => {
4
+ if (!url) return
5
+
6
+ return Promise.race([
7
+ sleep(5),
8
+ new Promise((resolve, reject) => {
9
+ const img = new Image()
10
+ img.src = url
11
+ img.style.display = 'none'
12
+ img.style.width = '1px'
13
+ img.style.height = '1px'
14
+ document.body.appendChild(img)
15
+ img.addEventListener('load', function () {
16
+ console.log('请求成功')
17
+ resolve(true)
18
+ })
19
+ img.addEventListener('error', function () {
20
+ console.log('请求失败')
21
+ resolve(false)
22
+ })
23
+ }),
24
+ ])
25
+ }
26
+
27
+ export default sendSelfNotificatioin
@@ -0,0 +1,18 @@
1
+ ;(function (history) {
2
+ var originalPushState = history.pushState
3
+
4
+ history.pushState = function (state, title, url) {
5
+ if (typeof history.onpushstate == 'function') {
6
+ history.onpushstate({ state: state })
7
+ }
8
+
9
+ // @ts-ignore
10
+ url = url && url.search(/^http/) > -1 ? url : ''
11
+
12
+ window.postMessage({ action: 'doFroApplePages', url: url }, '*')
13
+ // 调用原生的 history.pushState 方法
14
+ // @ts-ignore
15
+ return originalPushState.apply(history, arguments)
16
+ }
17
+ console.log(history.pushState)
18
+ })(history)