forked from fayharinn/StoreLocalizer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvite.config.js
More file actions
139 lines (126 loc) · 4.9 KB
/
Copy pathvite.config.js
File metadata and controls
139 lines (126 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
// Custom plugin to handle Play Store scraping in dev mode
const playstoreScraperPlugin = () => ({
name: 'playstore-scraper',
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
if (!req.url?.startsWith('/api/googleplay/playstore/dev/')) {
return next()
}
const match = req.url.match(/\/playstore\/dev\/(\d+)/)
if (!match) {
res.statusCode = 400
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ error: 'Invalid developer ID' }))
return
}
const developerId = match[1]
const storeUrl = `https://play.google.com/store/apps/dev?id=${developerId}&hl=en`
try {
const response = await fetch(storeUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Accept': 'text/html',
}
})
if (!response.ok) {
res.statusCode = response.status
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ error: `Failed to fetch: ${response.status}` }))
return
}
const html = await response.text()
// Extract package names
const packageRegex = /\/store\/apps\/details\?id=([a-zA-Z0-9._]+)/g
const packages = new Set()
let packageMatch
while ((packageMatch = packageRegex.exec(html)) !== null) {
packages.add(packageMatch[1])
}
// Extract app names and icons
const apps = []
for (const pkg of packages) {
// Try to find app name
const nameRegex = new RegExp(`aria-label="([^"]+)"[^>]*href="[^"]*\\/store\\/apps\\/details\\?id=${pkg.replace(/\./g, '\\.')}`, 'i')
const nameMatch = html.match(nameRegex)
// Try to find icon URL - look for img src near the app link
// Icons are typically in format: https://play-lh.googleusercontent.com/...
const iconRegex = new RegExp(`<img[^>]*src="(https://play-lh\\.googleusercontent\\.com/[^"]+)"[^>]*>[^<]*<[^>]*href="[^"]*\\/store\\/apps\\/details\\?id=${pkg.replace(/\./g, '\\.')}`, 'i')
const iconMatch = html.match(iconRegex)
// Alternative: look for srcset patterns
let iconUrl = iconMatch ? iconMatch[1] : null
if (!iconUrl) {
const srcsetRegex = new RegExp(`srcset="(https://play-lh\\.googleusercontent\\.com/[^"\\s]+)[^"]*"[^>]*>[^<]*<[^>]*href="[^"]*\\/store\\/apps\\/details\\?id=${pkg.replace(/\./g, '\\.')}`, 'i')
const srcsetMatch = html.match(srcsetRegex)
iconUrl = srcsetMatch ? srcsetMatch[1] : null
}
apps.push({
packageName: pkg,
name: nameMatch ? nameMatch[1] : pkg,
icon: iconUrl,
storeUrl: `https://play.google.com/store/apps/details?id=${pkg}`
})
}
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ developerId, apps, count: apps.length }))
} catch (error) {
res.statusCode = 500
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ error: error.message }))
}
})
}
})
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss(), playstoreScraperPlugin()],
// Set VITE_BASE_PATH=/xcstrings-localizer/ for GitHub Pages, otherwise defaults to /
base: process.env.VITE_BASE_PATH || '/',
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
build: {
outDir: 'dist',
sourcemap: false,
},
server: {
proxy: {
'/api/appstoreconnect': {
target: 'https://api.appstoreconnect.apple.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/appstoreconnect/, ''),
secure: true,
},
'/api/googleplay/androidpublisher': {
target: 'https://androidpublisher.googleapis.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/googleplay/, ''),
secure: true,
},
'/api/itunes': {
target: 'https://itunes.apple.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/itunes/, ''),
secure: true,
},
'/api/astro': {
target: 'http://127.0.0.1:8089',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/astro/, ''),
},
// AppCompete MCP (Rank Tracker / ASO) — /api/appcompete/mcp → https://appcompete.com/api/mcp
'/api/appcompete': {
target: 'https://appcompete.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/appcompete/, '/api'),
secure: true,
},
},
},
})