Add stock info, fix sunrise sorting

This commit is contained in:
NGnius (Graham) 2023-02-12 14:57:42 -05:00
parent 3d0cf7dafb
commit 6ddf5d7201
7 changed files with 66 additions and 10 deletions

View file

@ -70,6 +70,7 @@ impl MusicSearchStore for ProStudioMasters {
},
}).into(),
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown },
stock: crate::StoreStock::Available,
});
}
}

View file

@ -161,7 +161,8 @@ impl std::convert::Into<StoreEntry> for ArtistSearchResult {
image: Some(self.image)
}).into(),
store: "7digital".to_owned(),
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown }
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown },
stock: crate::StoreStock::Available,
}
}
}
@ -200,7 +201,8 @@ impl std::convert::Into<StoreEntry> for ReleaseSearchResult {
}
}).into(),
store: "7digital".to_owned(),
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown }
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown },
stock: crate::StoreStock::Available,
}
}
}
@ -255,7 +257,8 @@ impl std::convert::Into<StoreEntry> for TrackSearchResult {
}),
}).into(),
store: "7digital".to_owned(),
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown }
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown },
stock: crate::StoreStock::Available,
}
}
}

View file

@ -31,6 +31,8 @@ pub struct StoreEntry {
pub extra: StoreExtra,
/// Price information
pub price: StorePrice,
/// Stock information
pub stock: StoreStock,
}
/// A store identifier
@ -61,6 +63,50 @@ impl std::fmt::Display for StoreId {
}
}
/// Stock of a search result
pub enum StoreStock {
/// Out of stock
SoldOut,
/// In stock, but amount unknown or not applicable (for digital items)
Available,
/// In stock with <count> available
Count(u64),
/// Stock is unknown
Unknown,
}
impl StoreStock {
/// Store definitely has at least 1 of the item
pub fn has_stock(&self) -> bool {
match self {
Self::Available => true,
Self::Count(n) => *n > 0,
_ => false,
}
}
/// Store is definitely out of stock of the item
pub fn is_oos(&self) -> bool {
matches!(self, Self::SoldOut)
}
/// Store does not know the stock of the item
pub fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
}
impl std::fmt::Display for StoreStock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SoldOut => write!(f, "OOS"),
Self::Available => write!(f, "InStock"),
Self::Count(n) => write!(f, "InStock:{}", n),
Self::Unknown => write!(f, "???"),
}
}
}
/// Store price information
pub struct StorePrice {
/// Price of store result, in 100ths of a dollar

View file

@ -195,6 +195,8 @@ impl std::convert::Into<StoreEntry> for ProductInfo {
cents: (self.salePrice * 100.0) as _,
currency: StoreCurrency::Cad,
},
stock: crate::StoreStock::Unknown, // TODO do query to API endpoint that provides this info
// e.g. https://www.bestbuy.ca/ecomm-api/availability/products?accept=application/vnd.bestbuy.simpleproduct.v1+json&accept-language=en-CA&locations=940|928|972|639|627|224|975&postalCode=K1R&skus=M2234719
}
}
}

View file

@ -4,7 +4,7 @@ use serde::Deserialize;
use super::GeneralSearchStore;
use crate::audio::{AudioExtra, music::{MusicExtra, MusicMediumType}};
use crate::video::{VideoExtra, VideoFormat};
use crate::{MuniteError, StoreEntry, StorePrice, StoreCurrency, StoreType, StoreId, StoreExtra};
use crate::{MuniteError, StoreEntry, StorePrice, StoreCurrency, StoreType, StoreId, StoreExtra, StoreStock};
/// BestBuy Canada store client
pub struct SunriseRecords {
@ -24,11 +24,12 @@ impl SunriseRecords {
.query(&[
("page", &page.to_string() as &str),
("limit", &page_size.to_string() as &str),
(&format!("controls[{}]", page), query),
("controls[1]", query),
("sortBy", sort_by),
])
//.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; rv:108.0) Gecko/20100101 Firefox/108.0")
.header("Accept", "application/json, text/javascript, */*; q=0.01")
.header("DNT", "1")
}
fn search_store(&self, query: &str, page: u64, page_size: u64, sort_by: &str) -> RequestBuilder {
@ -54,9 +55,9 @@ const MAX_PAGE_SIZE: u64 = 48; // Anything larger is clamped back down to this v
impl GeneralSearchStore for SunriseRecords {
async fn search(&self, s: String, category: StoreType) -> crate::MuniteResult<Vec<StoreEntry>> {
let result = match category {
StoreType::General => self.search_store(&s, 1, MAX_PAGE_SIZE, "stock_desc").send().await,
StoreType::Video(_) => self.search_store(&s, 1, MAX_PAGE_SIZE, "stock_desc").send().await,
StoreType::Audio(_) => self.search_store(&s, 1, MAX_PAGE_SIZE, "stock_desc").send().await,
StoreType::General => self.search_store(&s, 1, MAX_PAGE_SIZE, "relevance_desc").send().await,
StoreType::Video(_) => self.search_store(&s, 1, MAX_PAGE_SIZE, "relevance_desc").send().await,
StoreType::Audio(_) => self.search_store(&s, 1, MAX_PAGE_SIZE, "relevance_desc").send().await,
}.map_err(|e| MuniteError::Http(e))?;
let json_data: SearchResultsResponse = result.json().await.map_err(|e| MuniteError::Http(e))?;
let mut output = Vec::with_capacity(json_data.items.len());
@ -130,7 +131,7 @@ struct ProductInfo {
#[derive(Deserialize)]
struct StockInfo {
isBackordered: bool,
available: u64,
available: i64,
}
#[allow(non_snake_case, dead_code)]
@ -186,6 +187,7 @@ impl std::convert::Into<StoreEntry> for ProductInfo {
cents: (dollar_price * 100.0) as _,
currency: StoreCurrency::Cad,
},
stock: if self.stock.available <= 0 || self.stock.isBackordered { StoreStock::SoldOut } else { StoreStock::Count(self.stock.available as _) }
}
}
}

View file

@ -10,7 +10,7 @@ mod entry;
mod errors;
mod search;
pub use entry::{StoreEntry, StoreExtra, StoreType, StorePrice, StoreCurrency, StoreId};
pub use entry::{StoreEntry, StoreExtra, StoreType, StorePrice, StoreCurrency, StoreId, StoreStock};
pub use errors::{MuniteError, MuniteResult};
pub use search::StoreSearch;

View file

@ -49,6 +49,7 @@ impl CinemaOne {
if let Some(format) = formats.tag("li").class("active").find() {
let format_info = match format.text().trim() as &str {
"4K" => VideoFormat::BlurayUhd,
"UHD" => VideoFormat::BlurayUhd, // idk why there's a distinction
"3D BLU-RAY" => VideoFormat::Bluray3d,
"BLU-RAY" => VideoFormat::Bluray,
"DVD" => VideoFormat::Dvd,
@ -74,6 +75,7 @@ impl CinemaOne {
info: None, // TODO
}.into(),
price: price_info,
stock: crate::StoreStock::Available,
});
}
}