diff --git a/.idea/.idea.buypeeb.dir/.idea/dictionaries/lynne.xml b/.idea/.idea.buypeeb.dir/.idea/dictionaries/lynne.xml new file mode 100644 index 0000000..78a5302 --- /dev/null +++ b/.idea/.idea.buypeeb.dir/.idea/dictionaries/lynne.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/AddItemDialogue.cs b/AddItemDialogue.cs index 07334d4..594d71f 100644 --- a/AddItemDialogue.cs +++ b/AddItemDialogue.cs @@ -1,32 +1,30 @@ using Gtk; namespace Buypeeb { - - class AddItemDialogue : Dialog { - private Entry EntryURL; - private Entry EntryName; + internal class AddItemDialogue : Dialog { + private readonly Entry entryURL; + private readonly Entry entryName; public AddItemDialogue() : this(new Builder("add.glade")) { } private AddItemDialogue(Builder builder) : base(builder.GetObject("DialogueAdd").Handle) { - this.Title = "Add item"; + Title = "Add item"; builder.Autoconnect(this); - this.EntryURL = (Entry)builder.GetObject("EntryAddURL"); - this.EntryName = (Entry)builder.GetObject("EntryAddName"); + entryURL = (Entry)builder.GetObject("EntryAddURL"); + entryName = (Entry)builder.GetObject("EntryAddName"); DeleteEvent += Window_Shutdown; } - private void Window_Shutdown(object sender, DeleteEventArgs args) { + private static void Window_Shutdown(object sender, DeleteEventArgs args) { Application.Quit(); } public string GetURL() { - return this.EntryURL.Text; + return entryURL.Text; } public string GetName() { - return this.EntryName.Text; + return entryName.Text; } - } } diff --git a/BuypeebApp.cs b/BuypeebApp.cs index cfa38f6..022f3d9 100644 --- a/BuypeebApp.cs +++ b/BuypeebApp.cs @@ -1,15 +1,16 @@ using System; -using Gtk; using System.Text.RegularExpressions; +using GLib; +using Application = Gtk.Application; namespace Buypeeb { - class BuypeebApp { + internal class BuypeebApp { [STAThread] public static void Main(string[] args) { Application.Init(); - var app = new Application("space.lynnesbian.Buypeeb", GLib.ApplicationFlags.None); - app.Register(GLib.Cancellable.Current); + var app = new Application("space.lynnesbian.Buypeeb", ApplicationFlags.None); + app.Register(Cancellable.Current); var win = new MainWindow(); app.AddWindow(win); @@ -18,13 +19,16 @@ namespace Buypeeb { Application.Run(); } + // ReSharper disable once InconsistentNaming + // i prefer "IDFromURL" to "IdFromUrl". also i will never forgive microsoft for the name of XmlHTTPRequest and you + // may consider this an act of spite/revenge public static string IDFromURL(string url) { // TODO: handle invalid URLs better, or at all really - Regex rx = new Regex(@"^([^?#]+)"); + var rx = new Regex(@"^([^?#]+)"); url = rx.Match(url).Groups[1].Value; // remove query params (if any) rx = new Regex(@".+\/(.+?)/?$"); - string id = rx.Match(url).Groups[1].Value; // extracts "k12345" from "https://buypeeb.biz/whatever/k12345/" + var id = rx.Match(url).Groups[1].Value; // extracts "k12345" from "https://buypeeb.biz/whatever/k12345/" return id; } diff --git a/Folder.DotSettings b/Folder.DotSettings new file mode 100644 index 0000000..f43935c --- /dev/null +++ b/Folder.DotSettings @@ -0,0 +1,6 @@ + + URL + True + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + True \ No newline at end of file diff --git a/MainWindow.cs b/MainWindow.cs index 79f60c4..1e1dafc 100755 --- a/MainWindow.cs +++ b/MainWindow.cs @@ -18,19 +18,27 @@ along with this program. If not, see . using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO; -using System.Text.RegularExpressions; +using System.Linq; +using System.Net; +using System.Text.Encodings.Web; using System.Text.Json; +using System.Text.RegularExpressions; +using System.Text.Unicode; using System.Threading; using System.Threading.Tasks; -using System.Net; -using System.Linq; -using System.Diagnostics; using CsvHelper; using Gtk; +using Timeout = GLib.Timeout; + +// ReSharper disable UnusedParameter.Local namespace Buypeeb { - class MainWindow : Window { + [SuppressMessage("ReSharper", "UnusedMember.Local")] + internal class MainWindow : Window { private string location; private JsonSerializerOptions jsonOptions; @@ -52,24 +60,24 @@ namespace Buypeeb { // ...to here. - static SemaphoreSlim taskLimit = new SemaphoreSlim(6); + private static SemaphoreSlim taskLimit = new SemaphoreSlim(6); private Queue updateQueue = new Queue(); private IEnumerable filterQuery { get { // father forgive me for i have lynned return - from item in this.settings.watchlist.Values.ToList() - where (item.favourite != this.filterChecks["Favourites"].Active || - item.favourite == this.filterChecks["NonFavourites"].Active) && - (item.available != this.filterChecks["Active"].Active || - item.available == this.filterChecks["Ended"].Active) && - (item.endingToday != this.filterChecks["EndingToday"].Active || - item.endingToday == this.filterChecks["EndingAfterToday"].Active) && - (item.hasWinPrice != this.filterChecks["WithWinPrice"].Active || - item.hasWinPrice == this.filterChecks["WithNoWinPrice"].Active) && - (String.IsNullOrWhiteSpace(this.searchEntry.Text) || - item.name.ToLower().Contains(this.searchEntry.Text.ToLower()) || - item.originalName.ToLower().Contains(this.searchEntry.Text.ToLower())) + from item in settings.watchlist.Values.ToList() + where (item.favourite != filterChecks["Favourites"].Active || + item.favourite == filterChecks["NonFavourites"].Active) && + (item.Available != filterChecks["Active"].Active || + item.Available == filterChecks["Ended"].Active) && + (item.endingToday != filterChecks["EndingToday"].Active || + item.endingToday == filterChecks["EndingAfterToday"].Active) && + (item.hasWinPrice != filterChecks["WithWinPrice"].Active || + item.hasWinPrice == filterChecks["WithNoWinPrice"].Active) && + (String.IsNullOrWhiteSpace(searchEntry.Text) || + item.name.ToLower().Contains(searchEntry.Text.ToLower()) || + item.originalName.ToLower().Contains(searchEntry.Text.ToLower())) select item; } } @@ -79,45 +87,45 @@ namespace Buypeeb { // - marked as "ready", as in, they aren't in the process of updating // - not updated since the interval return - from item in this.settings.watchlist.Values.ToList() - where item.ready && this.settings.ItemNotUpdatedSinceInterval(item) + from item in settings.watchlist.Values.ToList() + where item.Ready && settings.ItemNotUpdatedSinceInterval(item) select item; } } private YahooAuctionsItem selectedItem { get { - if (this.itemTreeView.Selection.CountSelectedRows() == 0) { + if (itemTreeView.Selection.CountSelectedRows() == 0) { // avoids incurring the wrath of Gtk-CRITICAL ** return null; } - this.itemTreeView.Selection.GetSelected(out TreeIter iter); - return (YahooAuctionsItem)this.itemTreeView.Model.GetValue(iter, 0); + itemTreeView.Selection.GetSelected(out var iter); + return (YahooAuctionsItem)itemTreeView.Model.GetValue(iter, 0); } } public MainWindow() : this(new Builder("main.glade")) { } private MainWindow(Builder builder) : base(builder.GetObject("wndMain").Handle) { - this.jsonOptions = new JsonSerializerOptions { - Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) + jsonOptions = new JsonSerializerOptions { + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), }; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { // C:\Users\Beebus\AppData\Roaming\Lynnear Software\buypeeb - this.location = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%APPDATA%"), "Lynnear Software", "buypeeb"); + location = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%APPDATA%"), "Lynnear Software", "buypeeb"); } else { // ~/.config/Lynnear Software/buypeeb - this.location = System.IO.Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".config", "Lynnear Software", "buypeeb"); + location = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Lynnear Software", "buypeeb"); } - string userdata = System.IO.Path.Combine(location, "userdata.json"); + var userdata = System.IO.Path.Combine(location, "userdata.json"); if (File.Exists(userdata)) { try { - string j = File.ReadAllText(userdata); - this.settings = JsonSerializer.Deserialize(j); + var j = File.ReadAllText(userdata); + settings = JsonSerializer.Deserialize(j); } catch { // ??? @@ -127,10 +135,10 @@ namespace Buypeeb { } else { - this.settings = new Settings(); + settings = new Settings(); } - this.SaveSettings(); - this.Title = "Buypeeb"; + SaveSettings(); + Title = "Buypeeb"; this.builder = builder; builder.Autoconnect(this); @@ -140,38 +148,37 @@ namespace Buypeeb { menuButtonFilter.Child = (Image)builder.GetObject("ImageFilter"); menuButtonSort.Child = (Image)builder.GetObject("ImageSort"); - this.selectionViewBox = (Box)builder.GetObject("SelectionViewBox"); - this.endingLabel = (Label)builder.GetObject("LabelSelectedEnding"); - this.searchEntry = (SearchEntry)builder.GetObject("FilterSearchEntry"); + selectionViewBox = (Box)builder.GetObject("SelectionViewBox"); + endingLabel = (Label)builder.GetObject("LabelSelectedEnding"); + searchEntry = (SearchEntry)builder.GetObject("FilterSearchEntry"); foreach (var name in new List { "Favourites", "NonFavourites", "Active", "Ended", "EndingToday", "EndingAfterToday", "WithWinPrice", "WithNoWinPrice" }) { - this.filterChecks.Add(name, (CheckButton)builder.GetObject($"CheckButtonFilter{name}")); - this.filterChecks[name].Active = false; + filterChecks.Add(name, (CheckButton)builder.GetObject($"CheckButtonFilter{name}")); + filterChecks[name].Active = false; } // bind treeview columns to watchlist instead of needing to manually sync its liststore - this.itemTreeView = (TreeView)builder.GetObject("TreeViewItems"); - this.items = new ListStore(typeof(YahooAuctionsItem)); - var filteredItems = new TreeModelFilter(this.items, null); - filteredItems.VisibleFunc = this.ItemFilter; + itemTreeView = (TreeView)builder.GetObject("TreeViewItems"); + items = new ListStore(typeof(YahooAuctionsItem)); + var filteredItems = new TreeModelFilter(items, null) {VisibleFunc = ItemFilter}; - this.itemTreeView.Model = filteredItems; + itemTreeView.Model = filteredItems; TreeCellDataFunc[] funcs = { - new TreeCellDataFunc(this.RenderColumnFavourite), - new TreeCellDataFunc(this.RenderColumnName), - new TreeCellDataFunc(this.RenderColumnPriceYen), - new TreeCellDataFunc(this.RenderColumnPriceAUD), - new TreeCellDataFunc(this.RenderColumnEnding) + RenderColumnFavourite, + RenderColumnName, + RenderColumnPriceYen, + RenderColumnPriceAUD, + RenderColumnEnding, }; - for (int i = 0; i < this.itemTreeView.Columns.Length; i++) { - var c = this.itemTreeView.Columns[i]; + for (var i = 0; i < itemTreeView.Columns.Length; i++) { + var c = itemTreeView.Columns[i]; c.SetCellDataFunc(c.Cells[0], funcs[i]); } - this.RenderList(); - this.UpdateItems(); - GLib.Timeout.Add(1000, new GLib.TimeoutHandler(UpdateSelectionEndTime)); - GLib.Timeout.Add(10000, new GLib.TimeoutHandler(AutoUpdateItems)); + RenderList(); + UpdateItems(); + Timeout.Add(1000, UpdateSelectionEndTime); + Timeout.Add(10000, AutoUpdateItems); DeleteEvent += WindowShutdown; } @@ -191,17 +198,16 @@ namespace Buypeeb { private (TreePath path, TreeIter iter) GetRow(string id) { // TODO: surely there's a better way to do this TreeIter iter; - this.itemTreeView.Model.GetIterFirst(out iter); - var m = (TreeModelFilter)this.itemTreeView.Model; + itemTreeView.Model.GetIterFirst(out iter); + var m = (TreeModelFilter)itemTreeView.Model; - for (int i = 0; i < this.itemTreeView.Model.IterNChildren(); i++) { - var x = (YahooAuctionsItem)this.itemTreeView.Model.GetValue(iter, 0); + for (var i = 0; i < itemTreeView.Model.IterNChildren(); i++) { + var x = (YahooAuctionsItem)itemTreeView.Model.GetValue(iter, 0); if (x.id == id) { return (m.ConvertPathToChildPath(m.GetPath(iter)), m.ConvertIterToChildIter(iter)); } - else { - this.itemTreeView.Model.IterNext(ref iter); - } + + itemTreeView.Model.IterNext(ref iter); } Console.WriteLine($"Couldn't find {id}!"); @@ -212,14 +218,14 @@ namespace Buypeeb { /// saves the settings to userdata.json. /// private void SaveSettings() { - string j = JsonSerializer.Serialize(this.settings, this.jsonOptions); - string p = System.IO.Path.Combine(this.location, "userdata.json"); + var j = JsonSerializer.Serialize(settings, jsonOptions); + var p = System.IO.Path.Combine(location, "userdata.json"); Console.WriteLine(j); - if (!Directory.Exists(this.location)) { - Directory.CreateDirectory(this.location); + if (!Directory.Exists(location)) { + Directory.CreateDirectory(location); } - using (StreamWriter fs = File.CreateText(p)) { + using (var fs = File.CreateText(p)) { fs.Write(j); } @@ -230,40 +236,40 @@ namespace Buypeeb { /// /// the id of the item to update private void UpdateThread(string id) { - var item = this.settings.watchlist[id]; + var item = settings.watchlist[id]; // Console.WriteLine($"Updating {id}..."); // set item.ready to false to show that it's still being updated // this changes a few behaviours, such as displaying the price as "..." instead of whatever's currently stored - item.ready = false; + item.Ready = false; - Gtk.Application.Invoke(delegate { + Application.Invoke(delegate { // TODO: find a way to not have to do this. i think we need to avoid actually modifying the items outside of the main thread :/ - var pathAndIter = this.GetRow(id); + var pathAndIter = GetRow(id); if (pathAndIter.path != null) { - this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); + items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); } }); - using (WebClient client = new WebClient()) { + using (var client = new WebClient()) { // TODO: download should have timeout item.Update(client.DownloadString(item.url)); // Thread.Sleep(5000); // item.Update(File.ReadAllText("yahoo.html")); } - Gtk.Application.Invoke(delegate { - var pathAndIter = this.GetRow(id); + Application.Invoke(delegate { + var pathAndIter = GetRow(id); if (pathAndIter.path != null) { - this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); + items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); } - if (item == this.selectedItem) { + if (item == selectedItem) { // if the user has this item selected and it just became ready, enable the selection box and redraw the info - this.selectionViewBox.Sensitive = true; - this.UpdateSelectionView(); + selectionViewBox.Sensitive = true; + UpdateSelectionView(); } }); - item.ready = true; + item.Ready = true; // Console.WriteLine($"{id} updated."); } @@ -271,13 +277,13 @@ namespace Buypeeb { /// recursively processes the update queue. this is a blocking function. /// private void ProcessUpdateQueue() { - this.queueActive = true; - this.UpdateItem(this.updateQueue.Dequeue()); - if (this.updateQueue.TryPeek(out string _)) { - this.ProcessUpdateQueue(); + queueActive = true; + UpdateItem(updateQueue.Dequeue()); + if (updateQueue.TryPeek(out var _)) { + ProcessUpdateQueue(); } else { - this.queueActive = false; + queueActive = false; } } @@ -287,7 +293,7 @@ namespace Buypeeb { /// the id of the task to update /// whether or not to call this.RenderList() after updating the item private void UpdateItem(string id, bool renderListWhenDone = false) { - var item = this.settings.watchlist[id]; + var item = settings.watchlist[id]; if (item.updatedRecently) { // the item has been updated recently, and force is not true return; @@ -296,13 +302,13 @@ namespace Buypeeb { // don't start a new task if there are more than `tasklimit` tasks currently running // this makes sure we don't make 1000 simultaneous requests to yahoo auctions if there are 1000 items on the watchlist taskLimit.Wait(); - var t = Task.Factory.StartNew(() => { - this.UpdateThread(id); + Task.Factory.StartNew(() => { + UpdateThread(id); }).ContinueWith(task => { taskLimit.Release(); if (renderListWhenDone) { - Gtk.Application.Invoke(delegate { - this.RenderList(); + Application.Invoke(delegate { + RenderList(); }); } }); @@ -312,28 +318,28 @@ namespace Buypeeb { /// add every item in the watchlist to the update queue. if the update queue is already being processed (this.queueActive), this will do nothing. /// private void UpdateItems() { - if (this.queueActive) { + if (queueActive) { return; } - this.selectionViewBox.Sensitive = false; - foreach (var item in this.settings.watchlist) { - if (!this.updateQueue.Contains(item.Key)) { + selectionViewBox.Sensitive = false; + foreach (var item in settings.watchlist) { + if (!updateQueue.Contains(item.Key)) { // set everything to not ready first // ensures other actions don't attempt to display the items even if UpdateItem hasn't started yet - item.Value.ready = false; - this.updateQueue.Enqueue(item.Key); + item.Value.Ready = false; + updateQueue.Enqueue(item.Key); } } - if (!this.updateQueue.TryPeek(out string _)) { + if (!updateQueue.TryPeek(out var _)) { // queue is empty return; } - this.itemTreeView.QueueDraw(); - var t = Task.Factory.StartNew(() => { - this.ProcessUpdateQueue(); + itemTreeView.QueueDraw(); + Task.Factory.StartNew(() => { + ProcessUpdateQueue(); }); } @@ -343,43 +349,43 @@ namespace Buypeeb { /// private void UpdateSelectionView() { // get the currently selected item - var item = this.selectedItem; - var infobox = (Box)this.builder.GetObject("SelectionInfoBox"); + var item = selectedItem; + var infobox = (Box)builder.GetObject("SelectionInfoBox"); if (item == null) { - this.selectionViewBox.Sensitive = false; + selectionViewBox.Sensitive = false; infobox.Visible = false; - (this.builder.GetObject("LabelSelectedName") as Label).Text = "buypeeb"; + ((Label) builder.GetObject("LabelSelectedName")).Text = "buypeeb"; return; } - this.selectionViewBox.Sensitive = item.ready; + selectionViewBox.Sensitive = item.Ready; infobox.Visible = true; var info = new Dictionary { { "Name", item.name }, { "YahooName", item.originalName }, - { "Price", item.priceJPY }, - { "PriceAUD", item.priceAUD }, + { "Price", item.priceJpy }, + { "PriceAUD", item.priceAud }, { "Ending", "Please wait..." }, - { "Bids", $"{item.bids}" }, - { "BuyItNow", item.winPrice == 0 ? "No" : $"{item.winPriceJPY} ({item.winPriceAUD})" }, - { "AutoExtension", item.autoExtension ? "Yes" : "No" }, - { "LastUpdated", $"Last updated: {(item.ready ? item.lastUpdated.ToString("MMM dd, HH:mm:ss") : "Right now!")}" } + { "Bids", $"{item.Bids}" }, + { "BuyItNow", item.WinPrice == 0 ? "No" : $"{item.winPriceJpy} ({item.winPriceAud})" }, + { "AutoExtension", item.AutoExtension ? "Yes" : "No" }, + { "LastUpdated", $"Last updated: {(item.Ready ? item.LastUpdated.ToString("MMM dd, HH:mm:ss") : "Right now!")}" }, }; foreach (var row in info) { - (this.builder.GetObject($"LabelSelected{row.Key}") as Label).Text = row.Value; + ((Label) builder.GetObject($"LabelSelected{row.Key}")).Text = row.Value; } - this.UpdateSelectionEndTime(); + UpdateSelectionEndTime(); - var noteBuffer = (TextBuffer)this.builder.GetObject("TextBufferSelectedNotes"); + var noteBuffer = (TextBuffer)builder.GetObject("TextBufferSelectedNotes"); noteBuffer.Clear(); if (!String.IsNullOrWhiteSpace(item.notes)) { noteBuffer.Text = item.notes; } - (this.builder.GetObject("ButtonSelectedFavourite") as ToggleButton).Active = item.favourite; + ((ToggleButton) builder.GetObject("ButtonSelectedFavourite")).Active = item.favourite; } @@ -390,9 +396,9 @@ namespace Buypeeb { private void OpenUrl(string url) { // https://github.com/dotnet/runtime/issues/17938 if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - ProcessStartInfo psi = new ProcessStartInfo { + var psi = new ProcessStartInfo { FileName = url, - UseShellExecute = true + UseShellExecute = true, }; Process.Start(psi); } @@ -432,7 +438,7 @@ namespace Buypeeb { /// a string to prefill the input box with /// private (Boolean accepted, string response) EntryDialogue(string title = "Buypeeb", string message = "Hi there!", string prefill = null) { - Dialog ed = new Dialog( + var ed = new Dialog( title: title, parent: this, flags: DialogFlags.DestroyWithParent | DialogFlags.Modal, @@ -442,8 +448,8 @@ namespace Buypeeb { ed.DefaultResponse = ResponseType.Ok; ed.KeepAbove = true; - Label edLabel = new Label(message); - Entry edEntry = new Entry(); + var edLabel = new Label(message); + var edEntry = new Entry(); if (!String.IsNullOrWhiteSpace(prefill)) { edEntry.Text = prefill; } @@ -460,8 +466,8 @@ namespace Buypeeb { ed.ContentArea.MarginEnd = 5; ed.MarginBottom = 5; - ResponseType accepted = (ResponseType)ed.Run(); - string response = edEntry.Text; + var accepted = (ResponseType)ed.Run(); + var response = edEntry.Text; ed.Dispose(); return (accepted == ResponseType.Ok, response); } @@ -472,7 +478,7 @@ namespace Buypeeb { /// the id of the radiobutton without the "Sort" prefix private string GetSortType() { foreach (var name in new List { "NameDescending", "NameAscending", "PriceDescending", "PriceAscending", "EndingDescending", "EndingAscending" }) { - var radio = (RadioMenuItem)this.builder.GetObject($"Sort{name}"); + var radio = (RadioMenuItem)builder.GetObject($"Sort{name}"); if (radio.Active) { return name; } @@ -486,14 +492,14 @@ namespace Buypeeb { /// private void RenderList() { string id = null; - if (this.selectedItem != null) { - id = this.selectedItem.id; + if (selectedItem != null) { + id = selectedItem.id; } - this.items.Clear(); - var values = this.settings.watchlist.Values; + items.Clear(); + var values = settings.watchlist.Values; IOrderedEnumerable sorted; - var type = this.GetSortType(); + var type = GetSortType(); if (type == "NameDescending") { sorted = values.OrderByDescending(item => item.name); } @@ -501,10 +507,10 @@ namespace Buypeeb { sorted = values.OrderBy(item => item.name); } else if (type == "PriceDescending") { - sorted = values.OrderByDescending(item => item.price); + sorted = values.OrderByDescending(item => item.Price); } else if (type == "PriceAscending") { - sorted = values.OrderBy(item => item.price); + sorted = values.OrderBy(item => item.Price); } else if (type == "EndingDescending") { sorted = values.OrderByDescending(item => item.endDate); @@ -528,14 +534,15 @@ namespace Buypeeb { } } - (this.itemTreeView.Model as TreeModelFilter).Refilter(); + ((TreeModelFilter) itemTreeView.Model).Refilter(); - if (id != null) { - // attempt to reselect the item we were just looking at - var pathAndIter = this.GetRow(id); - if (pathAndIter.path != null) { - this.itemTreeView.Selection.SelectPath(pathAndIter.path); - } + if (id == null) { return; } + + // attempt to reselect the item we were just looking at + // ReSharper disable once UseDeconstruction + var pathAndIter = GetRow(id); + if (pathAndIter.path != null) { + itemTreeView.Selection.SelectPath(pathAndIter.path); } } @@ -543,33 +550,32 @@ namespace Buypeeb { private void ButtonAddClicked(object sender, EventArgs a) { // Console.WriteLine("ButtonAddClicked"); - AddItemDialogue aid = new AddItemDialogue(); - aid.Title = "Buypeeb"; - ResponseType accepted = (ResponseType)aid.Run(); - string url = aid.GetURL(); - string name = aid.GetName(); + var aid = new AddItemDialogue {Title = "Buypeeb"}; + aid.Run(); + var url = aid.GetURL(); + var name = aid.GetName(); aid.Dispose(); // vry simpl url validation for simpol creachers // TODO: better. do better. - Regex rx = new Regex(@"^http.+yahoo.+"); + var rx = new Regex(@"^http.+yahoo.+"); if (rx.IsMatch(url)) { - this.UpdateItem(this.settings.Watch(url, name).id, true); - this.RenderList(); + UpdateItem(settings.Watch(url, name).id, true); + RenderList(); } else { - var md = this.MsgBox($"\"{url}\" is not a valid Buyee or Yahoo! Auctions Japan URL.", ButtonsType.Ok); + var md = MsgBox($"\"{url}\" is not a valid Buyee or Yahoo! Auctions Japan URL.", ButtonsType.Ok); md.Run(); md.Dispose(); } } private void ButtonUpdateAllClicked(object sender, EventArgs a) { - this.UpdateItems(); + UpdateItems(); } private void ButtonClearEndedClicked(object sender, EventArgs a) { - var md = this.MsgBox("Are you sure you want to remove all ended auctions from the list?"); + var md = MsgBox("Are you sure you want to remove all ended auctions from the list?"); var r = (ResponseType)md.Run(); md.Dispose(); if (r != ResponseType.Ok) { @@ -577,24 +583,24 @@ namespace Buypeeb { } var removeMe = new List(); - foreach (var item in this.settings.watchlist) { - if (!item.Value.available) { - removeMe.Add(item.Key); + foreach (var (key, value) in settings.watchlist) { + if (!value.Available) { + removeMe.Add(key); } } foreach (var id in removeMe) { - this.settings.watchlist.Remove(id); + settings.watchlist.Remove(id); } - this.RenderList(); + RenderList(); } private void ButtonClearAllClicked(object sender, EventArgs a) { - var md = this.MsgBox("Are you sure you want to clear ALL items?"); + var md = MsgBox("Are you sure you want to clear ALL items?"); if (md.Run() == (int)ResponseType.Ok) { - this.settings.watchlist.Clear(); - this.RenderList(); + settings.watchlist.Clear(); + RenderList(); } md.Dispose(); } @@ -615,10 +621,10 @@ namespace Buypeeb { if (od.Run() == (int)ResponseType.Accept) { try { - string j = File.ReadAllText(od.Filename); - this.settings = JsonSerializer.Deserialize(j); - this.RenderList(); - this.UpdateItems(); + var j = File.ReadAllText(od.Filename); + settings = JsonSerializer.Deserialize(j); + RenderList(); + UpdateItems(); } catch (Exception e) { Console.WriteLine(e); @@ -631,7 +637,7 @@ namespace Buypeeb { } private void ButtonSaveClicked(object sender, EventArgs a) { - this.SaveSettings(); + SaveSettings(); } private void ButtonSaveAsClicked(object sender, EventArgs a) { @@ -652,8 +658,8 @@ namespace Buypeeb { if (sd.Run() == (int)ResponseType.Accept) { try { if (!File.Exists(sd.Filename)) { - using (StreamWriter fs = File.CreateText(sd.Filename)) { - fs.Write(JsonSerializer.Serialize(this.settings, jsonOptions)); + using (var fs = File.CreateText(sd.Filename)) { + fs.Write(JsonSerializer.Serialize(settings, jsonOptions)); } } } @@ -669,7 +675,7 @@ namespace Buypeeb { } private void ButtonExportClicked(object sender, EventArgs a) { - var readyQuery = from item in this.settings.watchlist.Values.ToList() where !item.ready select item; + var readyQuery = from item in settings.watchlist.Values.ToList() where !item.Ready select item; if (readyQuery.Count() != 0) { var md = MsgBox("Please wait for all items to update before exporting a CSV.", ButtonsType.Ok); @@ -695,9 +701,9 @@ namespace Buypeeb { if (sd.Run() == (int)ResponseType.Accept) { try { using (var writer = new StreamWriter(sd.Filename)) - using (var csv = new CsvWriter(writer, System.Globalization.CultureInfo.InvariantCulture)) { + using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { - csv.WriteRecords(this.settings.watchlist); + csv.WriteRecords(settings.watchlist); } } catch (Exception e) { @@ -713,104 +719,103 @@ namespace Buypeeb { private void ButtonHelpClicked(object sender, EventArgs args) { Console.WriteLine("Watchlist:"); - foreach (var item in this.settings.watchlist) { + foreach (var item in settings.watchlist) { Console.WriteLine(item); } Console.WriteLine("---\nFilter results:"); - foreach (var item in this.filterQuery) { + foreach (var item in filterQuery) { Console.WriteLine(item); } Console.WriteLine("---\nListstore contents:"); - foreach (object[] item in this.items) { + foreach (object[] item in items) { Console.WriteLine(item[0]); } } private void ButtonQuitClicked(object sender, EventArgs a) { - var md = this.MsgBox("Are you sure you want to quit?"); + var md = MsgBox("Are you sure you want to quit?"); - ResponseType response = (ResponseType)md.Run(); + var response = (ResponseType)md.Run(); md.Dispose(); if (response == ResponseType.Ok) { - this.SaveSettings(); + SaveSettings(); Application.Quit(); } } private void ButtonSettingsClicked(object sender, EventArgs args) { - var win = new SettingsWindow(this.settings); + var win = new SettingsWindow(settings); Application.AddWindow(win); - win.DeleteEvent += this.WindowSettingsClosed; + win.DeleteEvent += WindowSettingsClosed; win.Show(); } private void TreeViewItemsSelectionChanged(object sender, EventArgs a) { - this.UpdateSelectionView(); + UpdateSelectionView(); } private void ButtonViewBuyeeClicked(object sender, EventArgs a) { - this.OpenUrl(this.selectedItem.buyeeUrl); + OpenUrl(selectedItem.buyeeUrl); } private void ButtonViewYahooClicked(object sender, EventArgs a) { - this.OpenUrl(this.selectedItem.url); + OpenUrl(selectedItem.url); } private void ButtonSelectedRemoveClicked(object sender, EventArgs a) { - var item = this.selectedItem; + var item = selectedItem; - var md = this.MsgBox($"Are you sure you want to remove the item \"{item.name}\"?"); // TODO: this looks bad being all on one line + var md = MsgBox($"Are you sure you want to remove the item \"{item.name}\"?"); // TODO: this looks bad being all on one line - ResponseType response = (ResponseType)md.Run(); + var response = (ResponseType)md.Run(); md.Dispose(); if (response == ResponseType.Ok) { - this.settings.watchlist.Remove(item.id); - this.RenderList(); + settings.watchlist.Remove(item.id); + RenderList(); } } private void ButtonSelectedRenameClicked(object sender, EventArgs a) { - var item = this.selectedItem; - (bool accepted, string response) = this.EntryDialogue("Rename item", $"Enter a new name for the item \"{item.name}\".", item.name); + var item = selectedItem; + (var accepted, var response) = EntryDialogue("Rename item", $"Enter a new name for the item \"{item.name}\".", item.name); if (accepted) { item.name = response; - this.UpdateSelectionView(); + UpdateSelectionView(); } } private void ButtonSelectedUpdateClicked(object sender, EventArgs args) { - this.selectionViewBox.Sensitive = false; - if (this.updateQueue.Contains(this.selectedItem.id)) { + selectionViewBox.Sensitive = false; + if (updateQueue.Contains(selectedItem.id)) { // the item is already waiting to be updated return; } - this.UpdateItem(this.selectedItem.id); + UpdateItem(selectedItem.id); } private void ButtonSelectedFavouriteToggled(object sender, EventArgs args) { - ToggleButton s = (ToggleButton)sender; - this.selectedItem.favourite = s.Active; + var s = (ToggleButton)sender; + selectedItem.favourite = s.Active; - if (this.settings.showFavouritesAtTopOfList) { - var id = this.selectedItem.id; - this.RenderList(); + if (settings.showFavouritesAtTopOfList) { + RenderList(); } else { // i don't know why this is necessary - var pathAndIter = this.GetRow(this.selectedItem.id); + var pathAndIter = GetRow(selectedItem.id); if (pathAndIter.path != null) { - this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); + items.EmitRowChanged(pathAndIter.path, pathAndIter.iter); } } } private void ButtonSelectedNotesClearClicked(object sender, EventArgs args) { - var item = this.selectedItem; - var md = this.MsgBox($"Are you sure you want to clear the notes for \"{item.name}\"?"); + var item = selectedItem; + var md = MsgBox($"Are you sure you want to clear the notes for \"{item.name}\"?"); if (md.Run() == (int)ResponseType.Ok) { - var noteBuffer = (TextBuffer)this.builder.GetObject("TextBufferSelectedNotes"); + var noteBuffer = (TextBuffer)builder.GetObject("TextBufferSelectedNotes"); noteBuffer.Clear(); - this.selectedItem.notes = null; + selectedItem.notes = null; } md.Dispose(); } @@ -818,18 +823,18 @@ namespace Buypeeb { private void TextViewSelectedNotesFocusOut(object sender, FocusOutEventArgs args) { // the "save" button does nothing, however, when you click the save button, you transfer focus to it, firing this event! // how very sneaky - var noteBuffer = (TextBuffer)this.builder.GetObject("TextBufferSelectedNotes"); - if (this.selectedItem != null) { - this.selectedItem.notes = String.IsNullOrWhiteSpace(noteBuffer.Text) ? null : noteBuffer.Text; + var noteBuffer = (TextBuffer)builder.GetObject("TextBufferSelectedNotes"); + if (selectedItem != null) { + selectedItem.notes = String.IsNullOrWhiteSpace(noteBuffer.Text) ? null : noteBuffer.Text; } } private void SortMenuClosed(object sender, EventArgs args) { - this.RenderList(); + RenderList(); } private void WindowSettingsClosed(object sender, EventArgs args) { - this.RenderList(); + RenderList(); } // timers @@ -839,17 +844,17 @@ namespace Buypeeb { /// /// true private bool UpdateSelectionEndTime() { - if (!this.selectionViewBox.IsSensitive) { + if (!selectionViewBox.IsSensitive) { return true; } - var item = this.selectedItem; - if (!item.ready) { + var item = selectedItem; + if (!item.Ready) { return true; } - string ending = ""; - if (item.available) { + var ending = ""; + if (item.Available) { var now = DateTime.Now; var end = item.endDate.ToLocalTime(); var span = end.Subtract(now); @@ -866,7 +871,7 @@ namespace Buypeeb { ending = "Auction has ended"; } - this.endingLabel.Text = ending; + endingLabel.Text = ending; return true; } @@ -875,18 +880,18 @@ namespace Buypeeb { /// /// true private bool AutoUpdateItems() { - if (this.queueActive) { + if (queueActive) { // don't autoupdate if the queue is active return true; } - foreach (var item in this.outdatedItemQuery) { + foreach (var item in outdatedItemQuery) { updateQueue.Enqueue(item.id); } - if (updateQueue.TryPeek(out string _)) { + if (updateQueue.TryPeek(out var _)) { // there's at least one item in the queue - this.ProcessUpdateQueue(); + ProcessUpdateQueue(); } return true; @@ -894,31 +899,31 @@ namespace Buypeeb { // column renderers - private void RenderColumnFavourite(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) { - YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0); - (cell as Gtk.CellRendererText).Text = item.favourite ? "♥" : ""; + private void RenderColumnFavourite(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { + var item = (YahooAuctionsItem)model.GetValue(iter, 0); + ((CellRendererText) cell).Text = item.favourite ? "♥" : ""; } - private void RenderColumnName(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) { - YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0); - (cell as Gtk.CellRendererText).Text = item.name ?? "Loading..."; + private void RenderColumnName(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { + var item = (YahooAuctionsItem)model.GetValue(iter, 0); + ((CellRendererText) cell).Text = item.name ?? "Loading..."; } - private void RenderColumnPriceYen(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) { - YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0); - (cell as Gtk.CellRendererText).Text = item.ready ? item.priceJPY : "..."; + private void RenderColumnPriceYen(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { + var item = (YahooAuctionsItem)model.GetValue(iter, 0); + ((CellRendererText) cell).Text = item.Ready ? item.priceJpy : "..."; } - private void RenderColumnPriceAUD(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) { - YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0); - (cell as Gtk.CellRendererText).Text = item.ready ? item.priceAUD : "..."; + private void RenderColumnPriceAUD(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { + var item = (YahooAuctionsItem)model.GetValue(iter, 0); + ((CellRendererText) cell).Text = item.Ready ? item.priceAud : "..."; } - private void RenderColumnEnding(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) { - YahooAuctionsItem item = (YahooAuctionsItem)model.GetValue(iter, 0); - string ending = ""; - if (item.ready) { - if (!item.available) { + private void RenderColumnEnding(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { + var item = (YahooAuctionsItem)model.GetValue(iter, 0); + var ending = ""; + if (item.Ready) { + if (!item.Available) { ending = "Ended"; } else { @@ -930,13 +935,13 @@ namespace Buypeeb { ending += end.ToString("MMM d "); } ending += end.ToString("HH:mm"); - if (this.settings.showSecondsInListView) { + if (settings.showSecondsInListView) { // add the seconds on to the end ending += end.ToString(":ss"); } } } - (cell as Gtk.CellRendererText).Text = item.ready ? ending : "..."; + ((CellRendererText) cell).Text = item.Ready ? ending : "..."; } // tree filter @@ -946,13 +951,13 @@ namespace Buypeeb { if (item == null) { return true; } - if (item.price == 0) { + if (item.Price == 0) { // the item has only just been added, so we can't compare it against the filters, since it's missing most of its data return true; } bool Filtered(string name) { - return this.filterChecks[name].Active; + return filterChecks[name].Active; } // first, check to see if any filters are set that would exclude everything, such as hiding both active and ended auctions @@ -966,11 +971,11 @@ namespace Buypeeb { return false; } - return this.filterQuery.Contains(item); + return filterQuery.Contains(item); } private void RunFilter(object sender, EventArgs a) { - (this.itemTreeView.Model as TreeModelFilter).Refilter(); + ((TreeModelFilter) itemTreeView.Model).Refilter(); } } } diff --git a/Settings.cs b/Settings.cs index b2c14c4..4a3d013 100644 --- a/Settings.cs +++ b/Settings.cs @@ -2,8 +2,7 @@ using System; using System.Collections.Generic; namespace Buypeeb { - - class Settings { + internal class Settings { public int updateInterval { get; set; } = 10 * 60; public int favouriteUpdateInterval { get; set; } = 5 * 60; public int updateIntervalCritical { get; set; } = 60; @@ -17,40 +16,29 @@ namespace Buypeeb { } public Settings() { - if (this.watchlist == null) { - // either this is the first time the program has been run, or there's something wrong with userdata.json - this.watchlist = new Dictionary(); - } + // create a new watchlist from an empty dictionary if it's null, which should only happen if either this is the + // first time the program has been run, or there's something wrong with userdata.json + watchlist ??= new Dictionary(); } public YahooAuctionsItem Watch(string url, string name) { - string id = BuypeebApp.IDFromURL(url); + var id = BuypeebApp.IDFromURL(url); Console.WriteLine(id); - this.watchlist[id] = new YahooAuctionsItem(id, name); - return this.watchlist[id]; + watchlist[id] = new YahooAuctionsItem(id, name); + return watchlist[id]; } // TRUE if the item hasn't been updated for at least interval seconds // for example, if the interval is 10, and the item hasn't been updated since 20 seconds ago, this will be TRUE public bool ItemNotUpdatedSinceInterval(YahooAuctionsItem item) { - int seconds = 1000; + int seconds; if (item.favourite) { - if (item.endingSoon) { - seconds = this.favouriteUpdateIntervalCritical; - } - else { - seconds = this.favouriteUpdateInterval; - } + seconds = item.endingSoon ? favouriteUpdateIntervalCritical : favouriteUpdateInterval; } else { - if (item.endingSoon) { - seconds = this.updateIntervalCritical; - } - else { - seconds = this.updateInterval; - } + seconds = item.endingSoon ? updateIntervalCritical : updateInterval; } - var later = item.lastUpdated.AddSeconds(seconds); + var later = item.LastUpdated.AddSeconds(seconds); return DateTime.Compare(later, DateTime.UtcNow) < 0; } } diff --git a/SettingsWindow.cs b/SettingsWindow.cs index 8ca7bb8..4bef5f8 100644 --- a/SettingsWindow.cs +++ b/SettingsWindow.cs @@ -1,44 +1,46 @@ using System; using System.Collections.Generic; using Gtk; +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedParameter.Local namespace Buypeeb { - class SettingsWindow : Window { - private List generalSwitches = new List(); - private List updateIntervalEntries = new List(); - private Settings settings; - private Builder builder; + internal class SettingsWindow : Window { + private readonly List generalSwitches = new List(); + private readonly List updateIntervalEntries = new List(); + private readonly Settings settings; + private readonly Builder builder; - private List generalSwitchNames = new List { "ShowSecondsInListView", "Autosave", "ShowFavouritesAtTopOfList" }; - private List updateIntervalEntryNames = new List { "UpdateInterval", "UpdateIntervalCritical", "FavouriteUpdateInterval", "FavouriteUpdateIntervalCritical" }; + private readonly List generalSwitchNames = new List { "ShowSecondsInListView", "Autosave", "ShowFavouritesAtTopOfList" }; + private readonly List updateIntervalEntryNames = new List { "UpdateInterval", "UpdateIntervalCritical", "FavouriteUpdateInterval", "FavouriteUpdateIntervalCritical" }; public SettingsWindow(Settings settings) : this(new Builder("settings.glade"), settings) { } private SettingsWindow(Builder builder, Settings settings) : base(builder.GetObject("WindowSettings").Handle) { - this.Title = "Buypeeb - Settings"; + Title = "Buypeeb - Settings"; this.settings = settings; this.builder = builder; builder.Autoconnect(this); - foreach (var name in this.generalSwitchNames) { + foreach (var name in generalSwitchNames) { var s = (Switch)builder.GetObject($"Switch{name}"); - this.generalSwitches.Add(s); - s.Active = GetSetting(this.PropertyName(name)); + generalSwitches.Add(s); + s.Active = GetSetting(PropertyName(name)); } - foreach (var name in this.updateIntervalEntryNames) { + foreach (var name in updateIntervalEntryNames) { var e = (Entry)builder.GetObject($"Entry{name}"); - this.updateIntervalEntries.Add(e); - e.Text = GetSetting(this.PropertyName(name)).ToString(); + updateIntervalEntries.Add(e); + e.Text = GetSetting(PropertyName(name)).ToString(); } } private T GetSetting(string property) { - return (T)this.settings.GetType().GetProperty(property).GetValue(this.settings, null); + return (T)settings.GetType().GetProperty(property).GetValue(settings, null); } private void SetSetting(string property, T value) { - this.settings.GetType().GetProperty(property).SetValue(this.settings, value); + settings.GetType().GetProperty(property).SetValue(settings, value); } private string PropertyName(string property) { @@ -48,10 +50,10 @@ namespace Buypeeb { private void ButtonSaveClicked(object sender, EventArgs args) { // first, validate all the intervals - bool failed = false; - foreach (var name in this.updateIntervalEntryNames) { + var failed = false; + foreach (var name in updateIntervalEntryNames) { var e = (Entry)builder.GetObject($"Entry{name}"); - if (!int.TryParse(e.Text, out int result)) { + if (!int.TryParse(e.Text, out var result)) { failed = true; } else { @@ -60,28 +62,30 @@ namespace Buypeeb { } } - if (failed) { - var md = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, "Update intervals must be a whole number between 30 and 6000."); - md.Run(); - md.Dispose(); - return; + if (!failed) { + continue; } + + var md = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, "Update intervals must be a whole number between 30 and 6000."); + md.Run(); + md.Dispose(); + return; } // validation success! - foreach (var name in this.updateIntervalEntryNames) { - this.SetSetting(PropertyName(name), int.Parse((builder.GetObject($"Entry{name}") as Entry).Text)); + foreach (var name in updateIntervalEntryNames) { + SetSetting(PropertyName(name), int.Parse(((Entry) builder.GetObject($"Entry{name}")).Text)); } - foreach (var name in this.generalSwitchNames) { - this.SetSetting(PropertyName(name), (builder.GetObject($"Switch{name}") as Switch).Active); + foreach (var name in generalSwitchNames) { + SetSetting(PropertyName(name), ((Switch) builder.GetObject($"Switch{name}")).Active); } - this.Dispose(); + Dispose(); } private void ButtonCancelClicked(object sender, EventArgs args) { - this.Dispose(); + Dispose(); } } } \ No newline at end of file diff --git a/YahooAuctionsItem.cs b/YahooAuctionsItem.cs index effeb20..ee94c31 100644 --- a/YahooAuctionsItem.cs +++ b/YahooAuctionsItem.cs @@ -1,26 +1,18 @@ using System; -using System.Globalization; -using System.Text.RegularExpressions; using System.Collections.Generic; +using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; +using System.Text.RegularExpressions; using CsvHelper.Configuration.Attributes; namespace Buypeeb { - class YahooAuctionsItem { + internal class YahooAuctionsItem { [JsonIgnore] - public string url { - get { - return $"https://page.auctions.yahoo.co.jp/jp/auction/{this.id}"; - } - } + public string url => $"https://page.auctions.yahoo.co.jp/jp/auction/{id}"; [JsonIgnore] - public string buyeeUrl { - get { - return $"https://buyee.jp/item/yahoo/auction/{this.id}"; - } - } + public string buyeeUrl => $"https://buyee.jp/item/yahoo/auction/{id}"; // 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 @@ -29,43 +21,50 @@ namespace Buypeeb { // there's not really a need for it i guess but it's my program and i can do what i want // anything with the attribute [Ignore] won't be put in the CSV, and things with [JsonIgnore] won't be put in userdata.json [Ignore] - public string id { get; set; } + public string id { get; } public string name { get; set; } - public int price = 0; - public int winPrice; + public int Price; + public int WinPrice; public string originalName { get; set; } public string notes { get; set; } - public bool favourite { get; set; } = false; - public DateTime startDate; + public bool favourite { get; set; } + public DateTime StartDate; public DateTime endDate { get; set; } - public DateTime lastUpdated; - public int bids; - public bool autoExtension; - public bool ready; - public bool available; + public DateTime LastUpdated; + public int Bids; + public bool AutoExtension; + public bool Ready; + public bool Available; [Ignore, JsonIgnore] public bool updatedRecently { get { - var later = this.lastUpdated.AddSeconds(15); - return DateTime.Compare(later, this.lastUpdated) < 0; + var later = LastUpdated.AddSeconds(15); + return DateTime.Compare(later, LastUpdated) < 0; } } [JsonIgnore] - public string priceJPY { get { return $"¥{this.price}"; } } + public string priceJpy => $"¥{Price}"; + [JsonIgnore] - public string winPriceJPY { get { return $"¥{this.winPrice}"; } } + public string winPriceJpy => $"¥{WinPrice}"; + [Ignore, JsonIgnore] - public string priceAUD { get { return $"${(this.price / 75.0):f2}"; } } + public string priceAud => $"${(Price / 75.0):f2}"; + [Ignore, JsonIgnore] - public string winPriceAUD { get { return $"${(this.winPrice / 75.0):f2}"; } } + public string winPriceAud => $"${(WinPrice / 75.0):f2}"; + [Ignore, JsonIgnore] - public bool endingToday { get { return this.endDate.DayOfYear == DateTime.UtcNow.DayOfYear; } } + public bool endingToday => endDate.DayOfYear == DateTime.UtcNow.DayOfYear; + [Ignore, JsonIgnore] - public bool hasWinPrice { get { return this.winPrice != 0; } } + public bool hasWinPrice => WinPrice != 0; + [Ignore, JsonIgnore] - public bool endingSoon { get { return DateTime.Compare(DateTime.UtcNow.AddMinutes(10), this.endDate) > 0; } } + public bool endingSoon => DateTime.Compare(DateTime.UtcNow.AddMinutes(10), endDate) > 0; + private bool success { get; set; } // TODO: custom setter that throws an exception if set to false or something idk public YahooAuctionsItem(string id, string name) { @@ -81,52 +80,48 @@ namespace Buypeeb { // TODO: handle all the parsing errors and weird interpretation that could possibly happen here var rx = new Regex(@"var pageData ?= ?(\{.+?\});", RegexOptions.Singleline); // TODO: maybe compile and match the regex in another thread var m = rx.Match(html); - if (m == null) { - Console.WriteLine("no sir i don't like it"); - return; - } - Dictionary> j_full; + Dictionary> jFull; try { // master forgive me, but i must go all out, just this once... - j_full = JsonSerializer.Deserialize>>(m.Groups[1].Value); + jFull = JsonSerializer.Deserialize>>(m.Groups[1].Value); } - catch (Exception e) { + catch { Console.WriteLine("oh jeez oh man oh jeez oh man oh jeez oh man"); Console.WriteLine(m.Groups[1].Value); - throw e; + throw; } var jst = TimeZoneInfo.CreateCustomTimeZone("JST", new TimeSpan(9, 0, 0), "Japan Standard Time", "Japen Standard Time"); - var j = j_full["items"]; - this.originalName = j["productName"]; - this.startDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(j["starttime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst); - this.endDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.ParseExact(j["endtime"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), jst); - this.lastUpdated = DateTime.UtcNow; - this.available = j["isClosed"] == "0"; + var j = jFull["items"]; + originalName = j["productName"]; + 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); + LastUpdated = DateTime.UtcNow; + Available = j["isClosed"] == "0"; - this.success = int.TryParse(j["price"], out this.price); - this.success = int.TryParse(j["winPrice"], out this.winPrice); - this.success = int.TryParse(j["bids"], out this.bids); + success = int.TryParse(j["price"], out Price); + success = int.TryParse(j["winPrice"], out WinPrice); + success = int.TryParse(j["bids"], out Bids); - if (String.IsNullOrWhiteSpace(this.name)) { - this.name = this.originalName; + if (String.IsNullOrWhiteSpace(name)) { + name = originalName; } // 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"). - var autoExtensionCheck = new Regex(@"自動延長.+\n.+>(.+)<"); + rx = new Regex(@"自動延長.+\n.+>(.+)<"); m = rx.Match(html); if (m.Groups[1].Value != null) { - this.autoExtension = (m.Groups[1].Value == "あり"); + AutoExtension = (m.Groups[1].Value == "あり"); } } public override string ToString() { - return $"{this.id}: {this.name}"; + return $"{id}: {name}"; } } }