Add stock info, fix sunrise sorting
This commit is contained in:
parent
3d0cf7dafb
commit
6ddf5d7201
7 changed files with 66 additions and 10 deletions
|
@ -70,6 +70,7 @@ impl MusicSearchStore for ProStudioMasters {
|
|||
},
|
||||
}).into(),
|
||||
price: StorePrice { cents: 0, currency: StoreCurrency::Unknown },
|
||||
stock: crate::StoreStock::Available,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 _) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue