@@ -10,8 +10,10 @@ use playmatch_client::types::ManualMatchMode::{Admin, Trusted};
1010use playmatch_client:: types:: MetadataProvider :: Igdb ;
1111use playmatch_client:: types:: {
1212 CompanyOrPlatformMatchRequest , CompanyOrPlatformSuggestionRequest , CreateOrGetUserRequest ,
13- GameMatchRequest , GameSuggestionRequest , UpdateUserPermissionsRequest , UserPermissions ,
13+ GameMatchRequest , GameMatchType , GameSuggestionRequest , UpdateUserPermissionsRequest ,
14+ UserPermissions ,
1415} ;
16+ use poise:: CreateReply ;
1517use reqwest:: StatusCode ;
1618use serenity:: all:: {
1719 ButtonStyle , Cache , ChannelId , ComponentInteractionDataKind , CreateEmbedFooter , ShardMessenger ,
@@ -82,6 +84,122 @@ pub async fn list_platforms(ctx: CommandContext<'_>) -> CommandResult {
8284 paginate_playmatch_response ( ctx, companies) . await
8385}
8486
87+ /// Gets metadata for a game on Playmatch by hashes or file name and size.
88+ #[ poise:: command( slash_command, category = "Playmatch" , rename = "game" ) ]
89+ pub async fn get_game_metadata (
90+ ctx : CommandContext < ' _ > ,
91+ md5_hash : Option < String > ,
92+ sha1_hash : Option < String > ,
93+ sha256_hash : Option < String > ,
94+ file_name : String ,
95+ file_size : i64 ,
96+ ) -> CommandResult {
97+ let response = ctx
98+ . data ( )
99+ . playmatch_client
100+ . identify_game_and_relations (
101+ & file_name,
102+ file_size,
103+ md5_hash. as_deref ( ) ,
104+ sha1_hash. as_deref ( ) ,
105+ sha256_hash. as_deref ( ) ,
106+ )
107+ . await ?;
108+
109+ let inner = response. into_inner ( ) ;
110+
111+ if inner. game_match_type == GameMatchType :: NoMatch {
112+ ctx. reply ( "No matching game found for the provided hashes or file name and size." )
113+ . await ?;
114+ return Ok ( ( ) ) ;
115+ }
116+
117+ let game = inner. game . ok_or ( anyhow ! (
118+ "No game found for the provided hashes or file name"
119+ ) ) ?;
120+ let game_files = inner. game_files ;
121+ let platform = inner. platform . ok_or ( anyhow ! (
122+ "No platform found for the provided hashes or file name"
123+ ) ) ?;
124+ let company = inner. company ;
125+ let dat_file = inner. dat_file . ok_or ( anyhow ! (
126+ "No DAT file found for the provided hashes or file name"
127+ ) ) ?;
128+ let signature_group = inner. signature_group . ok_or ( anyhow ! (
129+ "No signature group found for the provided hashes or file name"
130+ ) ) ?;
131+
132+ let files_info = game_files
133+ . iter ( )
134+ . enumerate ( )
135+ . map ( |( i, file) | {
136+ let mut out = format ! ( "**{}. {}**" , i + 1 , file. file_name) ;
137+ if let Some ( size) = file. file_size_in_bytes {
138+ out. push_str ( & format ! ( "Size: `{:.2} MB`" , size as f64 / 1024.0 / 1024.0 ) ) ;
139+ }
140+ if let Some ( serial) = & file. serial {
141+ out. push_str ( & format ! ( "\n Serial: `{}`" , serial) ) ;
142+ }
143+ if let Some ( crc) = & file. crc {
144+ out. push_str ( & format ! ( "\n CRC32: `{}`" , crc) ) ;
145+ }
146+ if let Some ( md5) = & file. md5 {
147+ out. push_str ( & format ! ( "\n MD5: `{}`" , md5) ) ;
148+ }
149+ if let Some ( sha1) = & file. sha1 {
150+ out. push_str ( & format ! ( "\n SHA1: `{}`" , sha1) ) ;
151+ }
152+ if let Some ( sha256) = & file. sha256 {
153+ out. push_str ( & format ! ( "\n SHA256: `{}`" , sha256) ) ;
154+ }
155+ out
156+ } )
157+ . collect :: < Vec < _ > > ( )
158+ . join ( "\n \n " ) ;
159+
160+ let dat_file_value = match dat_file. tags {
161+ None => format ! (
162+ "**{}**\n Current Version: `{}`\n " ,
163+ dat_file. name, dat_file. current_version
164+ ) ,
165+ Some ( tags) => format ! (
166+ "**{}**\n Current Version: `{}`\n Tags: `{}`" ,
167+ dat_file. name,
168+ dat_file. current_version,
169+ tags. join( ", " )
170+ ) ,
171+ } ;
172+
173+ let signature_group_value = match signature_group. website_link {
174+ None => signature_group. name ,
175+ Some ( website_link) => format ! ( "[{}]({})" , signature_group. name, website_link) ,
176+ } ;
177+
178+ // Build the embed
179+ let mut embed = CreateEmbed :: new ( )
180+ . title ( game. name )
181+ . color ( 0x2ecc71 )
182+ . field ( "Match Type" , format ! ( "`{}`" , inner. game_match_type) , true )
183+ . field ( "Platform" , platform. name , true ) ;
184+
185+ if let Some ( c) = company {
186+ embed = embed. field ( "Company" , c. name , true )
187+ }
188+
189+ embed = embed
190+ . field ( "ROM Files" , files_info, false )
191+ . field ( "DAT File" , dat_file_value, true )
192+ . field ( "Signature Group" , signature_group_value, false )
193+ . footer ( CreateEmbedFooter :: new ( format ! (
194+ "Playmatch Game ID: {}" ,
195+ game. id
196+ ) ) ) ;
197+
198+ ctx. send ( CreateReply :: default ( ) . embed ( embed) ) . await ?;
199+
200+ Ok ( ( ) )
201+ }
202+
85203/// Creates a metadata match suggestion for a Game by hashes or name to the IGDB database.
86204#[ poise:: command( slash_command, category = "Playmatch" , rename = "game" , check = is_user_trusted_or_above) ]
87205pub async fn create_game_suggestion (
0 commit comments