1use core::fmt;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 errors::{ErrorHandle, PublishedFileServiceError},
9 macros::{do_http, optional_argument},
10 steam_id::{de_steamid_from_str, SteamId},
11 Steam, BASE,
12};
13
14use super::INTERFACE;
15
16const ENDPOINT: &str = "QueryFiles";
17const VERSION: &str = "1";
18
19#[derive(Debug)]
21pub enum PublishedFileQueryType {
22 RankedByVote,
24 RankedByPublicationDate,
26 AcceptedForGameRankedByAcceptanceDate,
28 RankedByTrend,
30 FavoritedByFriendsRankedByPublicationDate,
32 CreatedByFriendsRankedByPublicationDate,
34 RankedByNumTimesReported,
36 CreatedByFollowedUsersRankedByPublicationDate,
38 NotYetRated,
40 RankedByTotalUniqueSubscriptions,
42 RankedByTotalVotesAsc,
44 RankedByVotesUp,
46 RankedByTextSearch,
48 RankedByPlaytimeTrend,
50 RankedByTotalPlaytime,
52 RankedByAveragePlaytimeTrend,
54 RankedByLifetimeAveragePlaytime,
56 RankedByPlaytimeSessionsTrend,
58 RankedByLifetimePlaytimeSessions,
60 RankedByInappropriateContentRating,
62 RankedByBanContentCheck,
64 RankedByLastUpdatedDate,
66}
67
68impl fmt::Display for PublishedFileQueryType {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 let value = match self {
71 PublishedFileQueryType::RankedByVote => 0,
72 PublishedFileQueryType::RankedByPublicationDate => 1,
73 PublishedFileQueryType::AcceptedForGameRankedByAcceptanceDate => 2,
74 PublishedFileQueryType::RankedByTrend => 3,
75 PublishedFileQueryType::FavoritedByFriendsRankedByPublicationDate => 4,
76 PublishedFileQueryType::CreatedByFriendsRankedByPublicationDate => 5,
77 PublishedFileQueryType::RankedByNumTimesReported => 6,
78 PublishedFileQueryType::CreatedByFollowedUsersRankedByPublicationDate => 7,
79 PublishedFileQueryType::NotYetRated => 8,
80 PublishedFileQueryType::RankedByTotalUniqueSubscriptions => 9,
81 PublishedFileQueryType::RankedByTotalVotesAsc => 10,
82 PublishedFileQueryType::RankedByVotesUp => 11,
83 PublishedFileQueryType::RankedByTextSearch => 12,
84 PublishedFileQueryType::RankedByPlaytimeTrend => 13,
85 PublishedFileQueryType::RankedByTotalPlaytime => 14,
86 PublishedFileQueryType::RankedByAveragePlaytimeTrend => 15,
87 PublishedFileQueryType::RankedByLifetimeAveragePlaytime => 16,
88 PublishedFileQueryType::RankedByPlaytimeSessionsTrend => 17,
89 PublishedFileQueryType::RankedByLifetimePlaytimeSessions => 18,
90 PublishedFileQueryType::RankedByInappropriateContentRating => 19,
91 PublishedFileQueryType::RankedByBanContentCheck => 20,
92 PublishedFileQueryType::RankedByLastUpdatedDate => 21,
93 };
94 write!(f, "{}", value)
95 }
96}
97
98#[derive(Debug)]
100pub enum PublishedFileInfoMatchingFileType {
101 Items,
103 Collections,
105 Art,
107 Videos,
109 Screenshots,
111 CollectionEligible,
113 Games,
115 Software,
117 Concepts,
119 GreenlightItems,
121 AllGuides,
123 WebGuides,
125 IntegratedGuides,
127 UsableInGame,
129 Merch,
131 ControllerBindings,
133 SteamworksAccessInvites,
135 ItemsMtx,
137 ItemsReadyToUse,
139 WorkshopShowcase,
141 GameManagedItems,
143}
144
145impl fmt::Display for PublishedFileInfoMatchingFileType {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 let value = match self {
148 PublishedFileInfoMatchingFileType::Items => 0,
149 PublishedFileInfoMatchingFileType::Collections => 1,
150 PublishedFileInfoMatchingFileType::Art => 2,
151 PublishedFileInfoMatchingFileType::Videos => 3,
152 PublishedFileInfoMatchingFileType::Screenshots => 4,
153 PublishedFileInfoMatchingFileType::CollectionEligible => 5,
154 PublishedFileInfoMatchingFileType::Games => 6,
155 PublishedFileInfoMatchingFileType::Software => 7,
156 PublishedFileInfoMatchingFileType::Concepts => 8,
157 PublishedFileInfoMatchingFileType::GreenlightItems => 9,
158 PublishedFileInfoMatchingFileType::AllGuides => 10,
159 PublishedFileInfoMatchingFileType::WebGuides => 11,
160 PublishedFileInfoMatchingFileType::IntegratedGuides => 12,
161 PublishedFileInfoMatchingFileType::UsableInGame => 13,
162 PublishedFileInfoMatchingFileType::Merch => 14,
163 PublishedFileInfoMatchingFileType::ControllerBindings => 15,
164 PublishedFileInfoMatchingFileType::SteamworksAccessInvites => 16,
165 PublishedFileInfoMatchingFileType::ItemsMtx => 17,
166 PublishedFileInfoMatchingFileType::ItemsReadyToUse => 18,
167 PublishedFileInfoMatchingFileType::WorkshopShowcase => 19,
168 PublishedFileInfoMatchingFileType::GameManagedItems => 20,
169 };
170 write!(f, "{}", value)
171 }
172}
173
174#[derive(Serialize, Deserialize, Debug, Clone)]
176pub struct Preview {
177 #[serde(rename = "previewid")]
179 pub preview_id: String,
180 #[serde(rename = "sortorder")]
182 pub sort_order: u16,
183 pub url: Option<String>,
185 pub size: Option<u32>,
187 #[serde(rename = "filename")]
189 pub file_name: Option<String>,
190 pub preview_type: u8,
192}
193
194#[derive(Serialize, Deserialize, Debug, Clone)]
196pub struct Tag {
197 pub tag: String,
199 pub display_name: String,
201}
202
203#[derive(Serialize, Deserialize, Debug, Clone)]
205pub struct VoteData {
206 pub score: f32,
208}
209
210#[derive(Serialize, Deserialize, Debug, Clone)]
212pub struct PlaytimeStats {
213 pub playtime_seconds: String,
215 pub num_sessions: String,
217}
218
219#[derive(Serialize, Deserialize, Debug, Clone)]
221pub struct File {
222 pub result: u64,
224 #[serde(rename = "publishedfileid")]
226 pub published_file_id: String,
227 #[serde(deserialize_with = "de_steamid_from_str")]
229 pub creator: SteamId,
230 pub creator_appid: u32,
232 pub consumer_appid: u32,
234 pub consumer_shortcutid: u32,
236 #[serde(rename = "filename")]
238 pub file_name: String,
239 pub file_size: String,
241 pub preview_file_size: String,
243 pub preview_url: String,
245 pub url: String,
247 pub hcontent_file: Option<String>,
249 pub hcontent_preview: String,
251 pub title: String,
253 pub short_description: String,
255 pub time_created: u32,
257 pub time_updated: u32,
259 pub visibility: u8,
261 pub flags: u32,
263 pub workshop_file: bool,
265 pub workshop_accepted: bool,
267 pub show_subscribe_all: bool,
269 pub num_comments_public: u64,
271 pub banned: bool,
273 pub ban_reason: String,
275 pub banner: String,
277 pub can_be_deleted: bool,
279 pub app_name: String,
281 pub file_type: u8,
283 pub can_subscribe: bool,
285 pub subscriptions: u64,
287 pub favorited: u64,
289 pub followers: u64,
291 pub lifetime_subscriptions: u64,
293 pub lifetime_favorited: u64,
295 pub lifetime_followers: u64,
297 pub lifetime_playtime: String,
299 pub lifetime_playtime_sessions: String,
301 pub views: u64,
303 pub num_children: u32,
305 pub num_reports: u32,
307 pub previews: Vec<Preview>,
309 pub tags: Vec<Tag>,
311 pub vote_data: VoteData,
313 pub playtime_stats: PlaytimeStats,
315 pub language: u32,
317 pub maybe_inappropriate_sex: bool,
319 pub maybe_inappropriate_violence: bool,
321 pub revision_change_number: String,
323 pub revision: u32,
325 pub available_revisions: Vec<u32>,
327 pub ban_text_check_result: u32,
329}
330
331#[derive(Serialize, Deserialize, Debug, Clone)]
333pub struct PublishedFiles {
334 pub total: u64,
336 #[serde(rename = "publishedfiledetails")]
338 pub published_file_details: Vec<File>,
339}
340
341#[derive(Serialize, Deserialize, Debug)]
342struct Response {
343 response: PublishedFiles,
344}
345
346impl Steam {
347 pub async fn query_files(
382 &self,
383 query_type: PublishedFileQueryType,
384 page: u32,
385 cursor: &str,
386 numperpage: Option<u32>, creator_app_id: u32,
388 app_id: u32,
389 required_tags: &str,
390 excluded_tags: &str,
391 match_all_tags: Option<bool>,
392 required_flags: &str,
393 omitted_flags: &str,
394 search_text: &str,
395 file_type: PublishedFileInfoMatchingFileType,
396 child_published_file_id: u64,
397 days: u32,
398 include_recent_votes_only: bool,
399 cache_max_age_seconds: Option<u32>,
400 language: Option<i32>,
401 required_kv_tags: &str, total_only: bool,
403 ids_only: bool,
404 return_vote_data: bool,
405 return_tags: bool,
406 return_kv_tags: bool,
407 return_previews: bool,
408 return_children: bool,
409 return_short_description: bool,
410 return_for_sale_data: bool,
411 return_metadata: Option<bool>,
412 return_playtime_stats: u32,
413 ) -> Result<PublishedFiles, PublishedFileServiceError> {
414 let query = vec![
415 format!("?key={}", &self.api_key),
416 format!("&query_type={}", query_type),
417 format!("&page={}", page),
418 format!("&cursor={}", cursor),
419 format!("&creator_appid={}", creator_app_id),
420 format!("&appid={}", app_id),
421 format!("&requiredtags={}", required_tags),
422 format!("&excludedtags={}", excluded_tags),
423 format!("&required_flags={}", required_flags),
424 format!("&omitted_flags={}", omitted_flags),
425 format!("&search_text={}", search_text),
426 format!("&filetype={}", file_type),
427 format!("&child_publishedfileid={}", child_published_file_id),
428 format!("&days={}", days),
429 format!("&include_recent_votes_only={}", include_recent_votes_only),
430 format!("&required_kv_tags={}", required_kv_tags),
431 format!("&totalonly={}", total_only),
432 format!("&ids_only={}", ids_only),
433 format!("&return_vote_data={}", return_vote_data),
434 format!("&return_tags={}", return_tags),
435 format!("&return_kv_tags={}", return_kv_tags),
436 format!("&return_previews={}", return_previews),
437 format!("&return_children={}", return_children),
438 format!("&return_short_description={}", return_short_description),
439 format!("&return_for_sale_data={}", return_for_sale_data),
440 format!("&return_playtime_stats={}", return_playtime_stats),
441 optional_argument!(numperpage),
442 optional_argument!(match_all_tags),
443 optional_argument!(cache_max_age_seconds),
444 optional_argument!(language),
445 optional_argument!(return_metadata),
446 ];
447
448 let url = format!(
449 "{}/{}/{}/v{}/{}",
450 BASE,
451 INTERFACE,
452 ENDPOINT,
453 VERSION,
454 query.concat()
455 );
456
457 let response = do_http!(
458 url,
459 Response,
460 ErrorHandle,
461 PublishedFileServiceError::QueryFiles
462 );
463
464 Ok(response.response)
465 }
466}