2020-09-01 10:41:29 +00:00
using System ;
2020-09-03 16:09:19 +00:00
using System.Collections.Generic ;
2021-06-15 00:20:46 +00:00
using System.Globalization ;
2020-09-03 16:09:19 +00:00
using System.Text.Json ;
2020-09-06 03:10:00 +00:00
using System.Text.Json.Serialization ;
2021-06-15 00:20:46 +00:00
using System.Text.RegularExpressions ;
2020-09-06 03:10:00 +00:00
using CsvHelper.Configuration.Attributes ;
2020-09-01 10:41:29 +00:00
namespace Buypeeb {
2021-06-15 00:20:46 +00:00
internal class YahooAuctionsItem {
2021-06-15 00:34:11 +00:00
[JsonIgnore] public string url = > $"https://page.auctions.yahoo.co.jp/jp/auction/{id}" ;
2020-09-04 07:23:32 +00:00
2021-06-15 00:34:11 +00:00
[JsonIgnore] public string buyeeUrl = > $"https://buyee.jp/item/yahoo/auction/{id}" ;
2020-09-04 07:23:32 +00:00
2020-09-04 10:16:42 +00:00
// any items with a getter will be saved to userdata.json
// anything that's configurable by the user, such as the custom name, should be saved
// the id *must* be saved!
// i'm also saving the original name to make it easier to tell what the items are in the userdata.json
// there's not really a need for it i guess but it's my program and i can do what i want
2020-09-06 03:12:46 +00:00
// anything with the attribute [Ignore] won't be put in the CSV, and things with [JsonIgnore] won't be put in userdata.json
2021-06-15 00:34:11 +00:00
[Ignore] public string id { get ; }
2020-09-02 04:12:56 +00:00
public string name { get ; set ; }
2021-06-15 00:20:46 +00:00
public int Price ;
public int WinPrice ;
2020-09-04 10:16:42 +00:00
public string originalName { get ; set ; }
2020-09-04 11:59:54 +00:00
public string notes { get ; set ; }
2021-06-15 00:20:46 +00:00
public bool favourite { get ; set ; }
public DateTime StartDate ;
2020-09-06 02:56:10 +00:00
public DateTime endDate { get ; set ; }
2021-06-15 00:20:46 +00:00
public DateTime LastUpdated ;
public int Bids ;
public bool AutoExtension ;
public bool Ready ;
public bool Available ;
2020-09-04 10:16:42 +00:00
2020-09-06 03:10:00 +00:00
[Ignore, JsonIgnore]
2020-09-04 10:16:42 +00:00
public bool updatedRecently {
get {
2021-06-15 00:20:46 +00:00
var later = LastUpdated . AddSeconds ( 15 ) ;
return DateTime . Compare ( later , LastUpdated ) < 0 ;
2020-09-04 10:16:42 +00:00
}
}
2020-09-01 10:41:29 +00:00
2021-06-15 00:34:11 +00:00
[JsonIgnore] public string priceJpy = > $"¥{Price}" ;
2021-06-15 00:20:46 +00:00
2021-06-15 00:34:11 +00:00
[JsonIgnore] public string winPriceJpy = > $"¥{WinPrice}" ;
2021-06-15 00:20:46 +00:00
2021-06-15 00:34:11 +00:00
[Ignore, JsonIgnore] public string priceAud = > $"${(Price / 75.0):f2}" ;
2021-06-15 00:20:46 +00:00
2021-06-15 00:34:11 +00:00
[Ignore, JsonIgnore] public string winPriceAud = > $"${(WinPrice / 75.0):f2}" ;
2021-06-15 00:20:46 +00:00
2021-06-15 00:34:11 +00:00
[Ignore, JsonIgnore] public bool endingToday = > endDate . DayOfYear = = DateTime . UtcNow . DayOfYear ;
2021-06-15 00:20:46 +00:00
2021-06-15 00:34:11 +00:00
[Ignore, JsonIgnore] public bool hasWinPrice = > WinPrice ! = 0 ;
2021-06-15 00:20:46 +00:00
2021-06-15 00:34:11 +00:00
[Ignore, JsonIgnore] public bool endingSoon = > DateTime . Compare ( DateTime . UtcNow . AddMinutes ( 10 ) , endDate ) > 0 ;
2021-06-15 00:20:46 +00:00
2020-09-06 03:10:00 +00:00
private bool success { get ; set ; } // TODO: custom setter that throws an exception if set to false or something idk
2020-09-03 16:09:19 +00:00
2020-09-04 09:13:16 +00:00
public YahooAuctionsItem ( string id , string name ) {
2020-09-01 10:41:29 +00:00
this . id = id ;
this . name = name ;
}
2020-09-04 09:13:16 +00:00
public YahooAuctionsItem ( ) {
2020-09-03 16:09:19 +00:00
// parameterless constructor for deserialisation
2020-09-03 13:47:36 +00:00
}
2020-09-03 16:09:19 +00:00
public void Update ( string html ) {
2020-09-04 10:16:42 +00:00
// TODO: handle all the parsing errors and weird interpretation that could possibly happen here
2021-06-15 00:34:11 +00:00
var rx = new Regex ( @"var pageData ?= ?(\{.+?\});" ,
RegexOptions . Singleline ) ; // TODO: maybe compile and match the regex in another thread
2020-09-03 16:09:19 +00:00
var m = rx . Match ( html ) ;
2021-06-15 00:20:46 +00:00
Dictionary < string , Dictionary < string , string > > jFull ;
2020-09-03 16:09:19 +00:00
try {
// master forgive me, but i must go all out, just this once...
2021-06-15 00:20:46 +00:00
jFull = JsonSerializer . Deserialize < Dictionary < string , Dictionary < string , string > > > ( m . Groups [ 1 ] . Value ) ;
2021-06-15 00:34:11 +00:00
} catch {
2020-09-04 10:16:42 +00:00
Console . WriteLine ( "oh jeez oh man oh jeez oh man oh jeez oh man" ) ;
Console . WriteLine ( m . Groups [ 1 ] . Value ) ;
2021-06-15 00:20:46 +00:00
throw ;
2020-09-03 16:09:19 +00:00
}
2021-06-15 00:34:11 +00:00
var jst = TimeZoneInfo . CreateCustomTimeZone ( "JST" , new TimeSpan ( 9 , 0 , 0 ) , "Japan Standard Time" ,
"Japen Standard Time" ) ;
2020-09-04 10:16:42 +00:00
2021-06-15 00:20:46 +00:00
var j = jFull [ "items" ] ;
originalName = j [ "productName" ] ;
2021-06-15 00:34:11 +00:00
StartDate = TimeZoneInfo . ConvertTimeToUtc (
DateTime . ParseExact ( j [ "starttime" ] , "yyyy-MM-dd HH:mm:ss" , CultureInfo . InvariantCulture ) , jst ) ;
endDate = TimeZoneInfo . ConvertTimeToUtc (
DateTime . ParseExact ( j [ "endtime" ] , "yyyy-MM-dd HH:mm:ss" , CultureInfo . InvariantCulture ) , jst ) ;
2021-06-15 00:20:46 +00:00
LastUpdated = DateTime . UtcNow ;
Available = j [ "isClosed" ] = = "0" ;
2020-09-04 10:16:42 +00:00
2021-06-15 00:20:46 +00:00
success = int . TryParse ( j [ "price" ] , out Price ) ;
success = int . TryParse ( j [ "winPrice" ] , out WinPrice ) ;
success = int . TryParse ( j [ "bids" ] , out Bids ) ;
2020-09-03 16:09:19 +00:00
2021-06-15 00:34:11 +00:00
if ( string . IsNullOrWhiteSpace ( name ) ) {
2021-06-15 00:20:46 +00:00
name = originalName ;
2020-09-03 16:09:19 +00:00
}
// as far as i can tell, neither the `pageData` nor the `conf` variables in the html seem to store whether or not the auction uses automatic extension
// the `conf` variable *does* store whether or not the auction has the "early end" feature enabled, in the key `earlyed`.
// unfortunately, it seems like the only way to get the auto extension info is to scrape the page for the info column that displays the auto ext status
// and check whether or not it's equal to "ari" (japanese for "yes").
2021-06-15 00:20:46 +00:00
rx = new Regex ( @"自動延長.+\n.+>(.+)<" ) ;
2020-09-03 16:09:19 +00:00
m = rx . Match ( html ) ;
if ( m . Groups [ 1 ] . Value ! = null ) {
2021-06-15 00:20:46 +00:00
AutoExtension = ( m . Groups [ 1 ] . Value = = "あり" ) ;
2020-09-03 16:09:19 +00:00
}
2020-09-01 10:41:29 +00:00
}
2020-09-05 06:51:28 +00:00
public override string ToString ( ) {
2021-06-15 00:20:46 +00:00
return $"{id}: {name}" ;
2020-09-05 06:51:28 +00:00
}
2020-09-01 10:41:29 +00:00
}
}