Compare commits

...

29 Commits

Author SHA1 Message Date
e74f561ce5 chore: bump version to 1.1.11 2025-01-26 07:40:03 +08:00
9738b41372 chore: update idJson 2025-01-26 07:39:15 +08:00
2d0a5d38bb docs: Stargazers over time 2025-01-05 10:41:22 +08:00
16e01b7a13 chore: bump version to 1.1.10 2024-12-07 16:02:00 +08:00
8f492376a0 chore: update idJson 2024-12-07 16:01:20 +08:00
0642c52db2 chore: bump version to 1.1.9 2024-09-27 21:15:19 +08:00
af256fba7d chore: update idJson 2024-09-27 21:14:44 +08:00
6599fbe6d3 chore: bump version to 1.1.8 2024-09-08 12:23:13 +08:00
a99959e6e5 chore: update idJson 2024-09-08 12:22:27 +08:00
c9c92da926 chore: bump version to 1.1.7 2024-08-21 12:27:56 +08:00
fcff120657 chore: update idJson and add display for idJson version 2024-08-21 12:27:19 +08:00
0ec7cb7c4f fix: winreg compatibility issues
sync with upstream
2024-08-07 17:17:54 +08:00
5a3159d4cb chore: bump version to 1.1.6 2024-08-07 17:08:15 +08:00
38b99bf4dc feat: import export ui layout 2024-08-07 17:07:18 +08:00
0cd9c071d7 chore: bump version to 1.1.5 2024-08-03 23:23:33 +08:00
bf582d0194 fix: update color 2024-08-03 23:19:49 +08:00
5dec6a8273 chore: bump version to 1.1.4 2024-07-29 15:44:10 +08:00
0e429a4762 fix: OS servers log path 2024-07-29 15:43:25 +08:00
5164a17dca style: pylint 2024-07-28 10:13:21 +08:00
a660c03bb5 docs: fix old project name 2024-07-27 15:56:13 +08:00
d7457f2bfb chore: bump version to 1.1.3 2024-07-27 15:50:31 +08:00
223ab899e0 fix(uigf): add bangboo to ID table
close: #5
2024-07-27 15:50:02 +08:00
f62ca1d7e7 chore: bump version to 1.1.2 2024-07-26 10:06:44 +08:00
c034b2e70a feat(uigf): metadata from local db 2024-07-26 10:05:02 +08:00
a2faa86f0c chore: bump version to 1.1.1 2024-07-25 21:45:45 +08:00
510bfdab7a feat: add support for Europe, America, TW,HK,MO servers 2024-07-25 21:44:38 +08:00
f616944755 chore: bump version to 1.1.0 2024-07-25 13:47:37 +08:00
7300c6e719 refactor(i18n): UIGF v4.0 is no longer in beta 2024-07-25 13:26:57 +08:00
6fe12da9be feat(uigf): import UIGFv4.0
BREAKING CHANGES: `region` is no longer stored in/read from local file
2024-07-25 13:25:26 +08:00
15 changed files with 3412 additions and 52 deletions

View File

@ -2,7 +2,7 @@ const fs = require('fs-extra')
const path = require('path')
const crypto = require('crypto')
const AdmZip = require('adm-zip')
const { version } = require('../package.json')
const { version, autoUpdateActive, autoUpdateFrom } = require('../package.json')
const hash = (data, type = 'sha256') => {
const hmac = crypto.createHmac(type, 'nap')
@ -32,9 +32,9 @@ const start = async () => {
await fs.copy(zipPath, path.resolve(outputPath, `${hashName}.zip`))
await fs.remove(zipPath)
await fs.outputJSON(path.join(outputPath, 'manifest.json'), {
active: true,
version,
from: '0.0.1',
active: autoUpdateActive,
version: version,
from: autoUpdateFrom,
name: `${hashName}.zip`,
hash: sha256
})

View File

@ -6,7 +6,7 @@
一个使用 Electron 制作的小工具,需要在 Windows 操作系统上运行。
通过读取游戏日志或者代理模式获取访问游戏跃迁记录 API 所需的 authKey然后再使用获取到的 authKey 来读取游戏跃迁记录。
通过读取游戏日志或者代理模式获取访问游戏调频记录 API 所需的 authKey然后再使用获取到的 authKey 来读取游戏调频记录。
## 其它语言
@ -15,7 +15,7 @@
## 使用说明
1. 下载工具后解压 - 下载地址: [GitHub](https://github.com/earthjasonlin/zzz-signal-search-export/releases/latest/download/ZzzSignalSearchExport.zip) / [123云盘](https://www.123pan.com/s/Vs9uVv-ShhE.html) / [蓝奏云(密码:zzzz](https://www.lanzouh.com/b00eewtvxa)
2. 打开游戏的跃迁详情页面
2. 打开游戏的调频详情页面
![详情页面](/docs/wish-history.jpg)
@ -34,7 +34,11 @@
如果需要导出多个账号的数据,可以点击旁边的加号按钮。
然后游戏切换的新账号,再打开跃迁历史记录,工具再点击“加载数据”按钮。
然后游戏切换的新账号,再打开调频历史记录,工具再点击“加载数据”按钮。
## Stargazers over time
[![Stargazers over time](https://starchart.cc/earthjasonlin/zzz-signal-search-export.svg)](https://starchart.cc/earthjasonlin/zzz-signal-search-export)
## Devlopment

View File

@ -6,7 +6,7 @@ This project is modified from the [star-rail-warp-export](https://github.com/biu
A tool made from Electron that runs on the Windows operating system.
Read the game log or proxy to get the authKey needed to access the game warp history API, and then use the authKey to read the game wish history.
Read the game log or proxy to get the authKey needed to access the game signal search history API, and then use the authKey to read the game wish history.
## Other languages
@ -18,7 +18,7 @@ If you feel that the existing translation is inappropriate, you can send a pull
1. Unzip after downloading the tool - [GitHub](https://github.com/earthjasonlin/zzz-signal-search-export/releases/latest/download/ZzzSignalSearchExport.zip)
2. Open the warp details page of the game
2. Open the signal search details page of the game
![warp details](/docs/wish-history-en.jpg)

View File

@ -1,6 +1,8 @@
{
"name": "zzz-signal-search-export",
"version": "1.0.10",
"version": "1.1.11",
"autoUpdateActive": true,
"autoUpdateFrom": "1.1.0",
"main": "./dist/electron/main/main.js",
"author": "earthjasonlin <https://git.loliquq.cn/earthjasonlin>",
"homepage": "https://github.com/earthjasonlin/zzz-signal-search-export",
@ -108,7 +110,7 @@
"tailwindcss": "^3.0.16",
"vite": "2.7.13",
"vue": "^3.2.29",
"winreg": "^1.2.4",
"winreg": "1.2.4",
"yauzl": "^2.10.0"
},
"keywords": [

View File

@ -3,9 +3,10 @@
"ui.button.load": "Load data",
"ui.button.update": "Update",
"ui.button.directUpdate": "Direct update",
"ui.button.files": "Export Files",
"ui.button.files": "Import/Export",
"ui.button.excel": "Export Excel",
"ui.button.uigf": "Export UIGF (Beta)",
"ui.button.uigf": "Export UIGF",
"ui.button.import": "Import UIGF",
"ui.button.url": "Input URL",
"ui.button.setting": "Settings",
"ui.button.option": "Option",
@ -56,6 +57,7 @@
"ui.setting.fetchFullHistoryHint": "When this option is enabled, click the \"Update Data\" button to get all the card draw records within 6 months. When there are incorrect data within 6 months, this function can be used to repair.",
"ui.setting.closeProxy": "Disable system proxy",
"ui.setting.closeProxyHint": "When you choose proxy mode, if the program crashes it can cause unwanted results that may affect your system. You can click this button to clear the system proxy settings.",
"ui.setting.idVersion": "ID database version",
"ui.about.title": "About",
"ui.about.license": "This software is opensource using MIT license.",
"ui.urlDialog.title": "Input URL manually",

View File

@ -3,9 +3,10 @@
"ui.button.load": "加载数据",
"ui.button.update": "更新数据",
"ui.button.directUpdate": "直接更新",
"ui.button.files": "导出文件",
"ui.button.files": "导入/导出",
"ui.button.excel": "导出Excel",
"ui.button.uigf":"导出UIGF (Beta)",
"ui.button.uigf":"导出UIGF",
"ui.button.import":"导入UIGF",
"ui.button.url": "输入URL",
"ui.button.setting": "设置",
"ui.button.option": "选项",
@ -55,6 +56,7 @@
"ui.setting.fetchFullHistoryHint": "开启时点击“更新数据”按钮会完整获取6个月内所有的抽卡记录当记录里有6个月范围以内的错误数据时可以通过这个功能修复。",
"ui.setting.closeProxy": "关闭系统代理",
"ui.setting.closeProxyHint": "如果使用过代理模式时工具非正常关闭,可能导致系统代理设置没能清除,可以通过这个按钮来清除设置过的系统代理。",
"ui.setting.idVersion": "ID 数据库版本",
"ui.about.title": "关于",
"ui.about.license": "本工具为开源软件,源代码使用 MIT 协议授权",
"ui.urlDialog.title": "手动输入URL",

View File

@ -3,9 +3,10 @@
"ui.button.load": "加載數據",
"ui.button.update": "更新數據",
"ui.button.directUpdate": "直接更新",
"ui.button.files": "導出文件",
"ui.button.files": "導入/匯出",
"ui.button.excel": "導出Excel",
"ui.button.uigf":"導出UIGF (Beta)",
"ui.button.uigf":"導出UIGF",
"ui.button.import":"導入UIGF",
"ui.button.url": "輸入URL",
"ui.button.setting": "設置",
"ui.button.option": "選項",
@ -54,6 +55,7 @@
"ui.setting.fetchFullHistoryHint": "開啟時點擊「更新數據」按鈕會完整獲取6個月內所有的抽卡記錄當記錄裏有6個月範圍以內的錯誤數據時可以通過這個功能修復。",
"ui.setting.closeProxy": "關閉系統代理",
"ui.setting.closeProxyHint": "如果使用過代理模式時工具非正常關閉,可能導致系統代理設置沒能清除,可以通過這個按鈕來清除設置過的系統代理。",
"ui.setting.idVersion": "ID 數據庫版本",
"ui.about.title": "關於",
"ui.about.license": "本工具為開源軟件,源代碼使用 MIT 協議授權",
"ui.urlDialog.title": "手動輸入URL",

3138
src/idJson.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,13 @@
const { app, ipcMain, dialog } = require('electron')
const fs = require('fs-extra')
const path = require('path')
const getData = require('./getData').getData
const { getData, saveData, changeCurrent, convertTimeZone } = require('./getData')
const config = require('./config')
const { name, version } = require('../../package.json')
const i18n = require('./i18n')
const { exit } = require('process')
const { mergeData } = require('./utils/mergeData')
const { sendMsg } = require('./utils')
const idJson = require('../idJson.json')
const getTimeString = () => {
return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2)
@ -16,8 +19,7 @@ const formatDate = (date) => {
let d = `${date.getDate()}`.padStart(2, '0')
return `${y}-${m}-${d} ${date.toLocaleString('zh-cn', { hour12: false }).slice(-8)}`
}
const start = async (uids) => {
const exportUIGF = async (uids) => {
const result = {
info: {
export_timestamp: Math.ceil(Date.now() / 1000),
@ -35,16 +37,7 @@ const start = async (uids) => {
if (!fulldata.length) {
throw new Error('数据为空')
}
const serverTimeZone = new Map([
["prod_gf_cn", 8],
["prod_gf_jp", 8]
])
fulldata.forEach(data => {
let timezone
timezone = serverTimeZone.get(data.region)
if(!timezone) {
throw new Error('不支持此服务器')
}
const listTemp = []
for (let [type, arr] of data.result) {
arr.forEach(log => {
@ -64,7 +57,7 @@ const start = async (uids) => {
listTemp.sort((a, b) => Number(BigInt(a.id) - BigInt(b.id)))
let dataTemp = {
uid: data.uid,
timezone: timezone,
timezone: data.region_time_zone,
lang: data.lang,
list: []
}
@ -87,6 +80,95 @@ const start = async (uids) => {
}
}
const importUIGF = async () => {
const filepath = await dialog.showOpenDialogSync({
properties: ['openFile'],
filters: [
{ name: i18n.uigf.fileType, extensions: ['json'] }
]
})
if (!filepath) return
const { dataMap, current } = await getData()
try {
const jsonData = fs.readJsonSync(filepath[0])
if('info' in jsonData && 'version' in jsonData.info) {
if (jsonData.info.version !== 'v4.0') {
sendMsg('不支持此版本UIGF')
console.error('不支持此版本UIGF')
return
}
} else {
sendMsg('UIGF格式错误')
console.error('UIGF格式错误')
return
}
jsonData.nap.forEach(uidData => {
const resultTemp = []
const isNew = !Boolean(dataMap.has(uidData.uid))
let region_time_zone
if (!isNew) region_time_zone = dataMap.get(uidData.uid).region_time_zone
else region_time_zone = uidData.timezone
let targetLang
if (!isNew) targetLang = dataMap.get(uidData.uid).lang
else targetLang = uidData.lang
if(!idJson[targetLang] && (!uidData.list[0].name || !uidData.list[0].item_type || !uidData.list[0].rank_type)) targetLang = config.lang
let idTargetLangJson = idJson[targetLang]
uidData.list.forEach(recordEntry => {
let rank_type
if (idTargetLangJson?.[recordEntry.item_id].rank_type) rank_type = String(idTargetLangJson[recordEntry.item_id].rank_type)
else rank_type = recordEntry.rank_type
resultTemp.push({
gacha_id: recordEntry.gacha_id,
gacha_type: recordEntry.gacha_type,
item_id: recordEntry.item_id,
count: recordEntry.count ?? "1",
time: convertTimeZone(recordEntry.time, uidData.timezone, region_time_zone),
name: idTargetLangJson?.[recordEntry.item_id].name ?? recordEntry.name,
item_type: idTargetLangJson?.[recordEntry.item_id].item_type ?? recordEntry.item_type,
rank_type: rank_type,
id: recordEntry.id
})
})
const resultTempGrouped = resultTemp.reduce((acc, curr) => {
if (!acc[curr.gacha_type]) {
acc[curr.gacha_type] = []
}
acc[curr.gacha_type].push(curr)
return acc;
}, {})
const resultTempMap = new Map(Object.entries(resultTempGrouped))
const resultMap = { result: resultTempMap, uid: uidData.uid}
let data
const mergedData = mergeData(dataMap.get(uidData.uid), resultMap)
if (isNew) {
data = { result: mergedData, time: Date.now(), uid: uidData.uid, lang: targetLang, region_time_zone: uidData.timezone, deleted: false }
} else {
data = { result: mergedData, time: Date.now(), uid: dataMap.get(uidData.uid).uid, lang: targetLang, region_time_zone: dataMap.get(uidData.uid).region_time_zone, deleted: dataMap.get(uidData.uid).deleted }
}
saveData(data, '')
changeCurrent(uidData.uid)
dataMap.set(uidData.uid, data)
})
return {
dataMap,
current: config.current
}
} catch (error) {
sendMsg(error, 'ERROR')
console.error(error)
}
}
ipcMain.handle('EXPORT_UIGF_JSON', async (event, uids) => {
await start(uids)
await exportUIGF(uids)
})
ipcMain.handle('IMPORT_UIGF_JSON', async () => {
return await importUIGF()
})

View File

@ -29,6 +29,27 @@ const defaultTypeMap = new Map([
['5', '邦布频段']
])
const serverTimeZone = new Map([
["prod_gf_cn", 8],
["prod_gf_jp", 8],
["prod_gf_us", -5],
["prod_gf_eu", 1],
["prod_gf_sg", 8]
])
const convertTimeZone = (dateTimeStr, fromTimeZoneOffset, toTimeZoneOffset) => {
let date = new Date(dateTimeStr.replace(' ', 'T') + 'Z');
let utcDate = new Date(date.getTime() - fromTimeZoneOffset * 60 * 60 * 1000);
let targetDate = new Date(utcDate.getTime() + toTimeZoneOffset * 60 * 60 * 1000);
let year = targetDate.getUTCFullYear();
let month = String(targetDate.getUTCMonth() + 1).padStart(2, '0');
let day = String(targetDate.getUTCDate()).padStart(2, '0');
let hours = String(targetDate.getUTCHours()).padStart(2, '0');
let minutes = String(targetDate.getUTCMinutes()).padStart(2, '0');
let seconds = String(targetDate.getUTCSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
const findDataFiles = async (dataPath, fileMap) => {
const files = await readdir(dataPath)
if (files?.length) {
@ -93,7 +114,7 @@ const changeCurrent = async (uid) => {
const detectGameLocale = async (userPath) => {
let list = []
const lang = app.getLocale()
const arr = ['/miHoYo/绝区零/', '/Cognosphere/Zenless Zone Zero/']
const arr = ['/miHoYo/绝区零/', '/miHoYo/ZenlessZoneZero/']
arr.forEach(str => {
try {
const pathname = path.join(userPath, '/AppData/LocalLow/', str, 'Player.log')
@ -203,7 +224,6 @@ const getGachaLogs = async ({ name, key }, queryString) => {
let logs = []
let uid = ''
let region = ''
let region_time_zone = ''
let endId = '0'
const url = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}`
do {
@ -221,9 +241,6 @@ const getGachaLogs = async ({ name, key }, queryString) => {
if (!region) {
region = res.region
}
if (!region_time_zone) {
region_time_zone = res.region_time_zone
}
list.push(...logs)
page += 1
@ -252,7 +269,7 @@ const getGachaLogs = async ({ name, key }, queryString) => {
}
}
} while (logs.length > 0)
return { list, uid, region, region_time_zone }
return { list, uid, region }
}
const checkResStatus = (res) => {
@ -425,10 +442,25 @@ const fetchData = async (urlOverride) => {
const typeMap = new Map()
const lang = searchParams.get('lang')
let originUid = ''
let originRegion = ''
let originTimeZone = ''
let localTimeZone
for (const type of gachaType) {
const { list, uid, region, region_time_zone } = await getGachaLogs(type, queryString)
const { list, uid, region} = await getGachaLogs(type, queryString)
const region_time_zone = serverTimeZone.get(region)
if(!region_time_zone) {
sendMsg('不支持此服务器')
console.error('不支持此服务器')
return
}
if (localTimeZone === undefined) {
localTimeZone = dataMap.get(uid)?.region_time_zone
if (localTimeZone === undefined) {
localTimeZone = region_time_zone
}
}
localTimeZone === Number(localTimeZone)
list.forEach(item => {
item.time = convertTimeZone(item.time, region_time_zone, localTimeZone)
})
const logs = list.map((item) => {
const { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type, count} = item
return { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type, count }
@ -439,14 +471,8 @@ const fetchData = async (urlOverride) => {
if (!originUid) {
originUid = uid
}
if (!originRegion) {
originRegion = region
}
if (!originTimeZone) {
originTimeZone = region_time_zone
}
}
const data = { result, typeMap, time: Date.now(), uid: originUid, lang, region: originRegion, region_time_zone: originTimeZone }
const data = { result, typeMap, time: Date.now(), uid: originUid, lang, region_time_zone: localTimeZone }
const localData = dataMap.get(originUid)
const mergedResult = mergeData(localData, data)
data.result = mergedResult
@ -527,5 +553,9 @@ exports.getData = () => {
}
}
exports.serverTimeZone = serverTimeZone
exports.getUrl = getUrl
exports.deleteData = deleteData
exports.saveData = saveData
exports.changeCurrent = changeCurrent
exports.convertTimeZone = convertTimeZone

View File

@ -12,6 +12,7 @@
<el-dropdown-menu>
<el-dropdown-item command="excel">{{ui.button.excel}}</el-dropdown-item>
<el-dropdown-item command="uigf-json">{{ui.button.uigf}}</el-dropdown-item>
<el-dropdown-item command="import-json" divided>{{ui.button.import}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@ -272,11 +273,25 @@ const exportUIGFJSON = () => {
});
}
const importData = async () => {
state.status = 'loading'
const data = await ipcRenderer.invoke('IMPORT_UIGF_JSON')
if (data) {
state.dataMap = data.dataMap
state.current = data.current
state.status = 'loaded'
} else {
state.status = 'failed'
}
}
const exportCommand = (type) => {
if (type === 'excel') {
saveExcel()
} else if (type === 'uigf-json') {
exportUIGFJSON()
} else if (type === 'import-json') {
importData()
}
}
const openCacheFolder = async () => {

View File

@ -32,7 +32,7 @@ const props = defineProps({
const chart = ref(null);
const colors = ["#eeaa66", "#fac858", "#ee6666", "#5470c6", "#ba66ee", "#91cc75", "#73c0de"];
const colors = ["#fac858", "#fac858", "#ee6666", "#5470c6", "#5470c6", "#91cc75", "#73c0de"];
const parseData = (detail, type) => {
const text = props.i18n.ui.data;

View File

@ -47,6 +47,7 @@
</el-form-item>
</el-form>
<h3 class="text-lg my-4">{{about.title}}</h3>
<p class="text-gray-600 text-xs mt-1">{{text.idVersion}} {{idJson.version}}</p>
<p class="text-gray-600 text-xs mt-1">{{about.license}}</p>
<p class="text-gray-600 text-xs mt-1">GitHub: <a @click="openGithub" class="cursor-pointer text-blue-400">https://github.com/earthjasonlin/zzz-signal-search-export</a></p>
<p class="text-gray-600 text-xs mt-1 pb-6">UIGF: <a @click="openUIGF" class="cursor-pointer text-blue-400">https://uigf.org/</a></p>
@ -82,6 +83,7 @@
<script setup>
const { ipcRenderer, shell } = require('electron')
import idJson from '../../idJson.json'
import { reactive, onMounted, computed } from 'vue'
const emit = defineEmits(['close', 'changeLang', 'refreshData'])

81
tools/getIdMap.py Normal file
View File

@ -0,0 +1,81 @@
# pylint: disable=C0116, C0103, C0201
"""Download and process data from the Hakushin API"""
import json
import requests
from opencc import OpenCC
# 初始化 OpenCC 转换器
cc = OpenCC('s2t')
# 获取 JSON 数据
weapon_url = 'https://api.hakush.in/zzz/data/weapon.json'
character_url = 'https://api.hakush.in/zzz/data/character.json'
bangboo_url = 'https://api.hakush.in/zzz/data/bangboo.json'
version_url = 'https://api.hakush.in/zzz/new.json'
# 语言映射配置
language_map = {
"zh-cn": "CHS",
"zh-tw": "CHS", # 简体转繁体
"en-us": "EN",
"ja-jp": "JA",
"ko-kr": "KO"
}
# 类型映射配置
type_map = {
"weapon": {"zh-cn": "音擎", "zh-tw": "音擎", "en-us": "W-Engines", "ja-jp": "音動機", "ko-kr": "W-엔진"},
"character": {"zh-cn": "代理人", "zh-tw": "代理人", "en-us": "Agents",
"ja-jp": "エージェント", "ko-kr": "에이전트"},
"bangboo": {"zh-cn": "邦布", "zh-tw": "邦布", "en-us": "Bangboo",
"ja-jp": "ボンプ", "ko-kr": "「Bangboo」"}
}
def fetch_json(url):
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
def transform_data(data, item_type):
transformed = {lang: {} for lang in language_map.keys()}
for id_, item in data.items():
for lang, key in language_map.items():
name = item[key] if lang != 'zh-tw' else cc.convert(item['CHS'])
transformed[lang][id_] = {
"name": name,
"item_type": type_map[item_type][lang],
"rank_type": item['rank']
}
return transformed
def main():
try:
weapon_data = fetch_json(weapon_url)
character_data = fetch_json(character_url)
bangboo_data = fetch_json(bangboo_url)
version_data = fetch_json(version_url)
transformed_data = {lang: {} for lang in language_map.keys()}
transformed_data["version"] = version_data["version"]
weapon_transformed = transform_data(weapon_data, "weapon")
character_transformed = transform_data(character_data, "character")
bangboo_transformed = transform_data(bangboo_data, "bangboo")
for lang in language_map.keys():
transformed_data[lang].update(weapon_transformed[lang])
transformed_data[lang].update(character_transformed[lang])
transformed_data[lang].update(bangboo_transformed[lang])
with open('./src/idJson.json', 'w', encoding='utf-8') as f:
json.dump(transformed_data, f, ensure_ascii=False, indent=2)
print("Data successfully transformed and saved")
except requests.RequestException as e:
print(f"Error fetching data: {e}")
if __name__ == "__main__":
main()

View File

@ -5205,10 +5205,10 @@ window-size@^1.1.1:
define-property "^1.0.0"
is-number "^3.0.0"
winreg@^1.2.4:
winreg@1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=
integrity sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
@ -5326,4 +5326,4 @@ zrender@5.2.1:
resolved "https://registry.npmmirror.com/zrender/download/zrender-5.2.1.tgz#5f4bbda915ba6d412b0b19dc2431beaad05417bb"
integrity sha1-X0u9qRW6bUErCxncJDG+qtBUF7s=
dependencies:
tslib "2.3.0"
tslib "2.3.0"