mirror of
https://github.com/exverge-0/yuzu-games-parser.git
synced 2024-12-22 12:42:01 +00:00
Merge branch master of https://git.suyu.dev/Exverge/yuzu-games-parser into master
This commit is contained in:
commit
3095e1fe0f
7 changed files with 350 additions and 3 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
src/US.en.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
33
Cargo.toml
Normal file
33
Cargo.toml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# MIT License
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Exverge (exverge@exverge.xyz)
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "yuzu-games-parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
|
serde_json = "1.0.115"
|
||||||
|
anyhow = "1.0.81"
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Exverge (exverge@exverge.xyz)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
28
README.md
28
README.md
|
@ -1,8 +1,30 @@
|
||||||
|
<!--
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Exverge (exverge@exverge.xyz)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
-->
|
||||||
|
|
||||||
# yuzu-games-parser
|
# yuzu-games-parser
|
||||||
Parser for yuzu's games compatibility API into another per-game format
|
Parser for yuzu's games compatibility API into another per-game format
|
||||||
|
|
||||||
`yuzu-games-parser <game_id>`
|
`yuzu-games-parser <game_id>`
|
||||||
|
|
||||||
Originally to be used for the suyu website, however this can be used for anything (assuming you follow the license)
|
Originally to be used for the suyu website, however this can be used for anything. (assuming you follow the license)
|
||||||
|
|
||||||
You need a copy of the eShop title metadata, you can get a version of it [here](https://raw.githubusercontent.com/blawar/titledb/master/US.en.json).
|
|
||||||
|
|
192
src/main.rs
Normal file
192
src/main.rs
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Exverge (exverge@exverge.xyz)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE. */
|
||||||
|
|
||||||
|
mod serialize;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let games: Vec<Game> = serde_json::from_str(include_str!("websiteFeed"))?; // must be in src folder
|
||||||
|
let eshop: Value = serde_json::from_str(include_str!("US.en.json"))?; // must be in src folder
|
||||||
|
let id = std::env::args().nth(1).unwrap();
|
||||||
|
|
||||||
|
let mut result: Option<Game> = None;
|
||||||
|
|
||||||
|
if id != "all" {
|
||||||
|
for game in games {
|
||||||
|
if game.id == id {
|
||||||
|
result = Some(game);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
use std::fs::*;
|
||||||
|
use std::path::Path;
|
||||||
|
create_dir(Path::new("result")).expect("Failed to create dir");
|
||||||
|
for game in games {
|
||||||
|
write(
|
||||||
|
Path::new(format!("result/{}.json", game.id).as_str()),
|
||||||
|
get_and_serialize(&game, &eshop),
|
||||||
|
)
|
||||||
|
.expect(format!("failed to write game {}", game.id).as_str());
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if result.is_none() {
|
||||||
|
eprintln!("id not found");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
let result = result.unwrap();
|
||||||
|
println!("{}", get_and_serialize(&result, &eshop));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_and_serialize(result: &Game, eshop: &Value) -> String {
|
||||||
|
let title_id = result.releases.get(0).unwrap().id.clone();
|
||||||
|
|
||||||
|
let mut eshop_id = String::new();
|
||||||
|
for (str, title) in eshop.as_object().unwrap() {
|
||||||
|
let id = title.get("id").unwrap().as_str();
|
||||||
|
if id.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if id.unwrap().to_string() == title_id {
|
||||||
|
eshop_id = str.clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if eshop_id.is_empty() {
|
||||||
|
eprintln!("eshop id not found");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(result, &eshop, eshop_id, title_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize(result: &Game, eshop: &Value, eshop_id: String, title_id: String) -> String {
|
||||||
|
println!("{}", eshop_id);
|
||||||
|
serde_json::to_string_pretty(&serialize::Game {
|
||||||
|
name: result.title.clone(),
|
||||||
|
description: eshop
|
||||||
|
.get(&eshop_id)
|
||||||
|
.unwrap()
|
||||||
|
.get("description")
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.unwrap_or("null")
|
||||||
|
.to_string(),
|
||||||
|
title_id,
|
||||||
|
img: eshop
|
||||||
|
.get(&eshop_id)
|
||||||
|
.unwrap()
|
||||||
|
.get("iconUrl")
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.unwrap_or("null")
|
||||||
|
.to_string(),
|
||||||
|
tests: result
|
||||||
|
.testcases
|
||||||
|
.iter()
|
||||||
|
.map(|x| serialize::testcase_to_test(x))
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct Game {
|
||||||
|
id: String,
|
||||||
|
title: String,
|
||||||
|
wiki_override: Option<String>,
|
||||||
|
// this is only used in certain pokémon games
|
||||||
|
wiki_markdown: Option<String>,
|
||||||
|
compatibility: i8,
|
||||||
|
releases: Vec<Release>,
|
||||||
|
testcase_date: Option<String>,
|
||||||
|
testcases: Vec<TestCase>,
|
||||||
|
issues: Vec<Issue>,
|
||||||
|
savefiles: Vec<Savefile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct Release {
|
||||||
|
id: String,
|
||||||
|
region: Option<String>,
|
||||||
|
// this is always null
|
||||||
|
release_date: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
enum OS {
|
||||||
|
Windows,
|
||||||
|
Linux,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct TestCase {
|
||||||
|
id: String,
|
||||||
|
author: Option<String>,
|
||||||
|
#[serde(rename = "buildDate")]
|
||||||
|
build_date: String,
|
||||||
|
#[serde(rename = "buildName")]
|
||||||
|
build_name: String,
|
||||||
|
version: String,
|
||||||
|
compatibility: i8,
|
||||||
|
cpu: String,
|
||||||
|
gpu: String,
|
||||||
|
date: String,
|
||||||
|
os: OS,
|
||||||
|
program_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct Issue {
|
||||||
|
created_at: String,
|
||||||
|
id: u16,
|
||||||
|
// there can't be more than 65,535 yuzu & suyu issues... right?
|
||||||
|
owner_username: String,
|
||||||
|
state: IssueState,
|
||||||
|
tags: Option<String>,
|
||||||
|
// either null, array encased in a string, or just a singular string
|
||||||
|
title: String,
|
||||||
|
updated_at: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct Savefile {
|
||||||
|
author: String,
|
||||||
|
basename: String,
|
||||||
|
description: String,
|
||||||
|
id: String,
|
||||||
|
title: String,
|
||||||
|
title_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
enum IssueState {
|
||||||
|
#[serde(rename = "closed")]
|
||||||
|
Closed,
|
||||||
|
#[serde(rename = "open")]
|
||||||
|
Open,
|
||||||
|
}
|
73
src/serialize.rs
Normal file
73
src/serialize.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Exverge (exverge@exverge.xyz)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE. */
|
||||||
|
use crate::{TestCase, OS};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Game {
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) description: String,
|
||||||
|
#[serde(rename = "titleId")]
|
||||||
|
pub(crate) title_id: String,
|
||||||
|
pub(crate) img: String,
|
||||||
|
pub(crate) tests: Vec<Test>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Test {
|
||||||
|
pub tester: Option<String>,
|
||||||
|
pub rating: i8,
|
||||||
|
pub details: Option<String>,
|
||||||
|
pub test_date: String,
|
||||||
|
pub cpu: String,
|
||||||
|
pub gpu: String,
|
||||||
|
pub version: String,
|
||||||
|
pub os: String,
|
||||||
|
pub from_yuzu: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn testcase_to_test(case: &TestCase) -> Test {
|
||||||
|
Test {
|
||||||
|
tester: case.author.clone(),
|
||||||
|
rating: match case.compatibility {
|
||||||
|
0 => 6,
|
||||||
|
1 => 5,
|
||||||
|
2 => 4,
|
||||||
|
3 => 3,
|
||||||
|
4 => 2,
|
||||||
|
5 => 1,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
details: None,
|
||||||
|
test_date: case.date.clone(),
|
||||||
|
cpu: case.cpu.clone(),
|
||||||
|
gpu: case.gpu.clone(),
|
||||||
|
version: case.version.clone(),
|
||||||
|
os: match case.os {
|
||||||
|
OS::Windows => "Windows",
|
||||||
|
OS::Linux => "Linux",
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
from_yuzu: true,
|
||||||
|
}
|
||||||
|
}
|
1
src/websiteFeed
Normal file
1
src/websiteFeed
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue