diff --git a/README.md b/README.md index bfb6543..2f005a9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # tModDownloader - A mod browser/downloader for tModLoader. +A mod browser/downloader for tModLoader and a dump of inefficient, unoptimized, slow and spagetti code. + +tModDownloader is a standalone Steam Workshop mod browser/downloader written in C#. It works by parsing Steam Workshop HTML data and use `steamcmd` to download mods behind the scene. + +## Compiling +To compile tModDownloader, you need .NET 6.0 SDK installed. After that just open `tModDownloader.sln` in Visual Studio and build the project. You need to put `steamcmd.exe` into a folder named `steamcmd` in the same directory as `tModDownloader.exe` to be able to download mods. + +*Note: tModDownloader is Windows-only at the moment. \ No newline at end of file diff --git a/tModDownloader.sln b/tModDownloader.sln new file mode 100644 index 0000000..4f6dbf0 --- /dev/null +++ b/tModDownloader.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.34031.178 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tModDownloader", "tModDownloader\tModDownloader.csproj", "{AB78FE3B-2A6D-4FB3-9414-B97270D5EBE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AB78FE3B-2A6D-4FB3-9414-B97270D5EBE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB78FE3B-2A6D-4FB3-9414-B97270D5EBE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB78FE3B-2A6D-4FB3-9414-B97270D5EBE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB78FE3B-2A6D-4FB3-9414-B97270D5EBE0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6CABEAF6-DE2D-4571-B71F-9CD12088CC5F} + EndGlobalSection +EndGlobal diff --git a/tModDownloader/Config.cs b/tModDownloader/Config.cs new file mode 100644 index 0000000..54aaf2e --- /dev/null +++ b/tModDownloader/Config.cs @@ -0,0 +1,7 @@ +namespace tModDownloader +{ + public static class Config + { + public static List selectedMods = new List(); + } +} diff --git a/tModDownloader/DownloadForm.Designer.cs b/tModDownloader/DownloadForm.Designer.cs new file mode 100644 index 0000000..aa97050 --- /dev/null +++ b/tModDownloader/DownloadForm.Designer.cs @@ -0,0 +1,113 @@ +namespace tModDownloader +{ + partial class DownloadForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + statusLabel = new Label(); + progressBar1 = new ProgressBar(); + progressLabel = new Label(); + label1 = new Label(); + logRTB = new RichTextBox(); + SuspendLayout(); + // + // statusLabel + // + statusLabel.AutoSize = true; + statusLabel.Location = new Point(14, 10); + statusLabel.Margin = new Padding(4, 0, 4, 0); + statusLabel.Name = "statusLabel"; + statusLabel.Size = new Size(151, 15); + statusLabel.TabIndex = 0; + statusLabel.Text = "Downloading, please wait..."; + // + // progressBar1 + // + progressBar1.Location = new Point(14, 29); + progressBar1.Margin = new Padding(4, 3, 4, 3); + progressBar1.Name = "progressBar1"; + progressBar1.Size = new Size(505, 27); + progressBar1.TabIndex = 1; + // + // progressLabel + // + progressLabel.AutoSize = true; + progressLabel.Location = new Point(14, 59); + progressLabel.Margin = new Padding(4, 0, 4, 0); + progressLabel.Name = "progressLabel"; + progressLabel.Size = new Size(75, 15); + progressLabel.TabIndex = 2; + progressLabel.Text = "Progress: 0/0"; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(14, 87); + label1.Margin = new Padding(4, 0, 4, 0); + label1.Name = "label1"; + label1.Size = new Size(32, 15); + label1.TabIndex = 4; + label1.Text = "Logs"; + // + // logRTB + // + logRTB.Location = new Point(14, 105); + logRTB.Margin = new Padding(4, 3, 4, 3); + logRTB.Name = "logRTB"; + logRTB.ReadOnly = true; + logRTB.Size = new Size(504, 115); + logRTB.TabIndex = 5; + logRTB.Text = ""; + // + // DownloadForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(533, 236); + Controls.Add(logRTB); + Controls.Add(label1); + Controls.Add(progressLabel); + Controls.Add(progressBar1); + Controls.Add(statusLabel); + Margin = new Padding(4, 3, 4, 3); + MaximizeBox = false; + MinimizeBox = false; + Name = "DownloadForm"; + Text = "Downloading..."; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label statusLabel; + private ProgressBar progressBar1; + private Label progressLabel; + private Label label1; + private RichTextBox logRTB; + } +} \ No newline at end of file diff --git a/tModDownloader/DownloadForm.cs b/tModDownloader/DownloadForm.cs new file mode 100644 index 0000000..82f092c --- /dev/null +++ b/tModDownloader/DownloadForm.cs @@ -0,0 +1,76 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Net; + +namespace tModDownloader +{ + public partial class DownloadForm : Form + { + string currentDir = Environment.CurrentDirectory; + + public DownloadForm(string saveDirectory) + { + InitializeComponent(); + progressBar1.Maximum = 100; + progressBar1.Style = ProgressBarStyle.Blocks; + InitiateDownload(saveDirectory); + } + + private async void InitiateDownload(string saveDirectory) + { + var totalMods = Config.selectedMods.Count; + var downloaded = 0; + var percentPerMods = 100 / totalMods; + var currentDir = Environment.CurrentDirectory; + logRTB.Text += "Save Directory: " + saveDirectory + "\n"; + foreach (ModItem item in Config.selectedMods) + { + progressLabel.Text = downloaded + "/" + totalMods + " downloaded."; + logRTB.Text += "Downloading mod " + item.Title + "...\n"; + string cliargs = "+login anonymous +workshop_download_item 1281930 " + item.ID + " +exit"; + Process scmd = new Process(); + scmd.StartInfo.FileName = Path.Combine(currentDir, "steamcmd", "steamcmd.exe"); + scmd.StartInfo.Arguments = cliargs; + scmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + scmd.StartInfo.CreateNoWindow = true; + scmd.Start(); + await scmd.WaitForExitAsync(); + if (scmd.ExitCode == 0) + { + downloaded += 1; + progressBar1.Value += percentPerMods; + } + else + { + MessageBox.Show("An error occured while trying to download " + item.Title + ". Aborting...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + break; + } + } + if (downloaded == totalMods) + { + logRTB.Text += "Copying mod files to save directory...\n"; + progressBar1.Style = ProgressBarStyle.Marquee; + progressBar1.MarqueeAnimationSpeed = 50; + var workshopDir = Path.Combine(currentDir, "steamcmd", "steamapps", "workshop", "content", "1281930"); + foreach(string dir in Directory.GetDirectories(workshopDir)) + { + var modDir = Path.Combine(workshopDir, dir); + List verList = new List(); + foreach(string i in Directory.GetDirectories(modDir)) + { + verList.Add(float.Parse(new DirectoryInfo(i).Name)); + } + Console.WriteLine(verList.Max().ToString()); + var realModDir = Path.Combine(workshopDir, dir, verList.Max().ToString()); + foreach(string file in Directory.GetFiles(realModDir, "*.tmod")) + { + logRTB.Text += "Copying " + Path.GetFileName(file) + " (" + verList.Max().ToString() + ")...\n"; + File.Copy(file, Path.Combine(saveDirectory, Path.GetFileName(file))); + } + } + logRTB.Text += "Done.\nYou may now close this window."; + statusLabel.Text = "You may now close this window."; + } + } + } +} diff --git a/tModDownloader/DownloadForm.resx b/tModDownloader/DownloadForm.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/tModDownloader/DownloadForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/tModDownloader/ModBrowser.Designer.cs b/tModDownloader/ModBrowser.Designer.cs new file mode 100644 index 0000000..7f4f6a5 --- /dev/null +++ b/tModDownloader/ModBrowser.Designer.cs @@ -0,0 +1,254 @@ +namespace tModDownloader +{ + partial class ModBrowser + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + nextBtn = new Button(); + previousBtn = new Button(); + pageLabel = new Label(); + label1 = new Label(); + label2 = new Label(); + tmlVersionComboBox = new ComboBox(); + progressBar = new ProgressBar(); + statusLabel = new Label(); + modsList = new FlowLayoutPanel(); + selectedModsLabel = new Label(); + downloadButton = new Button(); + label3 = new Label(); + searchTextBox = new TextBox(); + searchButton = new Button(); + refreshBtn = new Button(); + SuspendLayout(); + // + // nextBtn + // + nextBtn.Anchor = AnchorStyles.Top | AnchorStyles.Right; + nextBtn.Location = new Point(873, 3); + nextBtn.Margin = new Padding(4, 3, 4, 3); + nextBtn.Name = "nextBtn"; + nextBtn.Size = new Size(50, 27); + nextBtn.TabIndex = 8; + nextBtn.Text = ">"; + nextBtn.UseVisualStyleBackColor = true; + nextBtn.Click += nextBtn_Click; + // + // previousBtn + // + previousBtn.Anchor = AnchorStyles.Top | AnchorStyles.Right; + previousBtn.Location = new Point(818, 3); + previousBtn.Margin = new Padding(4, 3, 4, 3); + previousBtn.Name = "previousBtn"; + previousBtn.Size = new Size(47, 27); + previousBtn.TabIndex = 7; + previousBtn.Text = "<"; + previousBtn.UseVisualStyleBackColor = true; + previousBtn.Click += previousBtn_Click; + // + // pageLabel + // + pageLabel.Anchor = AnchorStyles.Top; + pageLabel.AutoSize = true; + pageLabel.Location = new Point(756, 9); + pageLabel.Margin = new Padding(4, 0, 4, 0); + pageLabel.Name = "pageLabel"; + pageLabel.Size = new Size(45, 15); + pageLabel.TabIndex = 6; + pageLabel.Text = "Page: 1"; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(10, 9); + label1.Margin = new Padding(4, 0, 4, 0); + label1.Name = "label1"; + label1.Size = new Size(204, 15); + label1.TabIndex = 5; + label1.Text = "tModDownloader - Version 0.0.1-beta\r\n"; + // + // label2 + // + label2.Anchor = AnchorStyles.Top; + label2.AutoSize = true; + label2.Location = new Point(320, 9); + label2.Margin = new Padding(4, 0, 4, 0); + label2.Name = "label2"; + label2.Size = new Size(113, 15); + label2.TabIndex = 10; + label2.Text = "tModLoader Version"; + // + // tmlVersionComboBox + // + tmlVersionComboBox.DropDownStyle = ComboBoxStyle.DropDownList; + tmlVersionComboBox.FormattingEnabled = true; + tmlVersionComboBox.Items.AddRange(new object[] { "1.4.4", "1.4.3" }); + tmlVersionComboBox.Location = new Point(450, 6); + tmlVersionComboBox.Margin = new Padding(4, 3, 4, 3); + tmlVersionComboBox.MaxDropDownItems = 2; + tmlVersionComboBox.Name = "tmlVersionComboBox"; + tmlVersionComboBox.Size = new Size(140, 23); + tmlVersionComboBox.TabIndex = 11; + tmlVersionComboBox.SelectionChangeCommitted += tmlVersionComboBox_SelectionChangeCommitted; + // + // progressBar + // + progressBar.Anchor = AnchorStyles.Top | AnchorStyles.Right; + progressBar.Location = new Point(783, 492); + progressBar.Margin = new Padding(4, 3, 4, 3); + progressBar.MarqueeAnimationSpeed = 0; + progressBar.Maximum = 30; + progressBar.Name = "progressBar"; + progressBar.Size = new Size(140, 19); + progressBar.TabIndex = 12; + // + // statusLabel + // + statusLabel.Anchor = AnchorStyles.Top; + statusLabel.AutoSize = true; + statusLabel.Location = new Point(14, 495); + statusLabel.Margin = new Padding(4, 0, 4, 0); + statusLabel.Name = "statusLabel"; + statusLabel.Size = new Size(39, 15); + statusLabel.TabIndex = 13; + statusLabel.Text = "Ready"; + // + // modsList + // + modsList.Anchor = AnchorStyles.Left | AnchorStyles.Right; + modsList.AutoScroll = true; + modsList.Location = new Point(14, 36); + modsList.Margin = new Padding(4, 3, 4, 3); + modsList.Name = "modsList"; + modsList.Size = new Size(909, 399); + modsList.TabIndex = 14; + // + // selectedModsLabel + // + selectedModsLabel.AutoSize = true; + selectedModsLabel.Location = new Point(14, 449); + selectedModsLabel.Margin = new Padding(4, 0, 4, 0); + selectedModsLabel.Name = "selectedModsLabel"; + selectedModsLabel.Size = new Size(96, 15); + selectedModsLabel.TabIndex = 15; + selectedModsLabel.Text = "Selected Mods: 0"; + // + // downloadButton + // + downloadButton.Location = new Point(790, 443); + downloadButton.Margin = new Padding(4, 3, 4, 3); + downloadButton.Name = "downloadButton"; + downloadButton.Size = new Size(133, 27); + downloadButton.TabIndex = 16; + downloadButton.Text = "Download Selected"; + downloadButton.UseVisualStyleBackColor = true; + downloadButton.Click += downloadButton_Click; + // + // label3 + // + label3.AutoSize = true; + label3.Location = new Point(331, 449); + label3.Margin = new Padding(4, 0, 4, 0); + label3.Name = "label3"; + label3.Size = new Size(42, 15); + label3.TabIndex = 17; + label3.Text = "Search"; + // + // searchTextBox + // + searchTextBox.Location = new Point(386, 445); + searchTextBox.Margin = new Padding(4, 3, 4, 3); + searchTextBox.Name = "searchTextBox"; + searchTextBox.Size = new Size(160, 23); + searchTextBox.TabIndex = 18; + // + // searchButton + // + searchButton.Location = new Point(554, 445); + searchButton.Margin = new Padding(4, 3, 4, 3); + searchButton.Name = "searchButton"; + searchButton.Size = new Size(88, 27); + searchButton.TabIndex = 19; + searchButton.Text = "Search"; + searchButton.UseVisualStyleBackColor = true; + searchButton.Click += searchButton_Click; + // + // refreshBtn + // + refreshBtn.Location = new Point(642, 6); + refreshBtn.Name = "refreshBtn"; + refreshBtn.Size = new Size(75, 23); + refreshBtn.TabIndex = 20; + refreshBtn.Text = "Refresh"; + refreshBtn.UseVisualStyleBackColor = true; + refreshBtn.Click += refreshBtn_Click; + // + // ModBrowser + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(933, 519); + Controls.Add(refreshBtn); + Controls.Add(searchButton); + Controls.Add(searchTextBox); + Controls.Add(label3); + Controls.Add(downloadButton); + Controls.Add(selectedModsLabel); + Controls.Add(modsList); + Controls.Add(statusLabel); + Controls.Add(progressBar); + Controls.Add(tmlVersionComboBox); + Controls.Add(label2); + Controls.Add(nextBtn); + Controls.Add(previousBtn); + Controls.Add(pageLabel); + Controls.Add(label1); + Margin = new Padding(4, 3, 4, 3); + MaximizeBox = false; + Name = "ModBrowser"; + Text = "tModDownloader"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + private Button nextBtn; + private Button previousBtn; + private Label pageLabel; + private Label label1; + private Label label2; + private ComboBox tmlVersionComboBox; + private ProgressBar progressBar; + private Label statusLabel; + private FlowLayoutPanel modsList; + private Label selectedModsLabel; + private Button downloadButton; + private Label label3; + private TextBox searchTextBox; + private Button searchButton; + private Button refreshBtn; + } +} \ No newline at end of file diff --git a/tModDownloader/ModBrowser.cs b/tModDownloader/ModBrowser.cs new file mode 100644 index 0000000..759897c --- /dev/null +++ b/tModDownloader/ModBrowser.cs @@ -0,0 +1,251 @@ +using HtmlAgilityPack; +using Microsoft.WindowsAPICodePack.Dialogs; +using System.ComponentModel; +using System.Net; +using System.Text.RegularExpressions; + +namespace tModDownloader +{ + public partial class ModBrowser : Form + { + int currentPage = 1; + + string previousSearchKeyword = ""; + + Dictionary> pagedMods = new Dictionary>(); + + Dictionary> searchPagedMods = new Dictionary>(); + + public ModBrowser() + { + InitializeComponent(); + tmlVersionComboBox.SelectedIndex = 0; + Label updatingText = new Label(); + progressBar.Style = ProgressBarStyle.Blocks; + progressBar.Value = 0; + progressBar.Maximum = 100; + UpdateModList(); + } + + private void UpdateModList(string searchKeyword = "") + { + if (pagedMods.ContainsKey("page_" + currentPage) && searchKeyword.Equals("")) + { + DisplayEntries(); + return; + } + if (searchPagedMods.ContainsKey("page_" + currentPage) && !(searchKeyword.Equals("")) && searchKeyword.Equals(previousSearchKeyword)) + { + DisplayEntries(); + return; + } + + BackgroundWorker worker = new BackgroundWorker(); + worker.WorkerReportsProgress = true; + worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate (object sender, RunWorkerCompletedEventArgs e) + { + previousSearchKeyword = searchKeyword; + DisplayEntries(); + statusLabel.Text = "Ready"; + progressBar.Value = 0; + }); + worker.DoWork += new DoWorkEventHandler(delegate (Object sender, DoWorkEventArgs args) + { + List mods = new List(); + string queryURL = @"https://steamcommunity.com/workshop/browse/?appid=1281930&searchtext=" + searchKeyword + "&childpublishedfileid=0&browsesort=trend§ion=readytouseitems&requiredtags%5B0%5D=" + tmlVersionComboBox.GetItemText(tmlVersionComboBox.SelectedItem) + "&created_date_range_filter_start=0&created_date_range_filter_end=0&updated_date_range_filter_start=0&updated_date_range_filter_end=0&actualsort=trend&p=" + currentPage; + var data = new HtmlWeb().Load(queryURL); + string initialPageData = ""; + foreach (var node in data.DocumentNode.SelectNodes("//div[@class='workshopBrowseItems']")) + { + initialPageData += node.OuterHtml; + } + initialPageData.Replace("
", ""); + var parsedDoc = new HtmlAgilityPack.HtmlDocument(); + parsedDoc.LoadHtml(initialPageData); + Regex regex = new Regex(@"\?id=(\d+)&"); + var totalModsToParse = parsedDoc.DocumentNode.SelectNodes("//div[@data-panel='{"type":"PanelGroup"}']").Count; + var percentPerMod = 100 / totalModsToParse; + var currentIndex = 0; + foreach (var node in parsedDoc.DocumentNode.SelectNodes("//div[@data-panel='{"type":"PanelGroup"}']")) + { + statusLabel.Text = "Updating..."; + currentIndex += 1; + progressBar.Value += percentPerMod; + ModItem modItem = new ModItem(null, null, null, null); + foreach (var childNode in node.ChildNodes) + { + if (childNode.Name == "a") + { + var href = childNode.GetAttributeValue("href", null); + if (href != null) + { + HtmlWeb tempWeb = new HtmlWeb(); + modItem.SteamURL = href; + var itemPage = tempWeb.Load(href); + modItem.Title = itemPage.DocumentNode.SelectSingleNode("//head/title").InnerHtml.Trim().Replace("Steam Workshop::", ""); + Match match = regex.Match(href); + if (match.Success) + { + string id = match.Groups[1].Value; + modItem.ID = id; + } + var authorNode = itemPage.DocumentNode.SelectSingleNode("//div[@class='rightDetailsBlock']//a[@class='friendBlockLinkOverlay']"); + var authorUrl = authorNode.Attributes["href"].Value; + modItem.AuthorURL = authorUrl; + modItem.AuthorName = tempWeb.Load(authorUrl).DocumentNode.SelectSingleNode("//head/title").InnerHtml.Trim().Replace("Steam Community :: ", ""); + } + } + } + var img = node.SelectSingleNode("./a/div/img"); + var src = img.GetAttributeValue("src", null); + if (src != null) + { + Image origIcon = Image.FromStream(new MemoryStream(new WebClient().DownloadData(src))); + modItem.Icon = (Image)(new Bitmap(origIcon, new Size(64, 61))); + } + mods.Add(modItem); + } + + if (searchKeyword.Equals("")) + { + pagedMods.Add("page_" + currentPage, mods); + } + else + { + searchPagedMods.Add("page_" + currentPage, mods); + } + }); + worker.RunWorkerAsync(); + } + + private void DisplayEntries() + { + selectedModsLabel.Text = "Selected Mods: " + Config.selectedMods.Count; + modsList.Controls.Clear(); + List modList; + if (!(searchTextBox.Text.Equals(""))) + { + modList = searchPagedMods.GetValueOrDefault("page_" + currentPage); + } + else + { + modList = pagedMods.GetValueOrDefault("page_" + currentPage); + } + foreach (ModItem item in modList) + { + Panel modPanel = new Panel(); + modPanel.Size = new Size(773, 67); + PictureBox modIcon = new PictureBox(); + modIcon.Size = new Size(64, 61); + modIcon.Image = item.Icon; + Label modTitle = new Label(); + modTitle.Text = item.Title; + modTitle.Font = new Font("Segoe UI", 14.25F, FontStyle.Regular, GraphicsUnit.Point); + modTitle.Location = new Point(73, 3); + modTitle.AutoSize = true; + Label modAuthor = new Label(); + modAuthor.Location = new Point(73, 37); + modAuthor.AutoSize = true; + modAuthor.Text = "By " + item.AuthorName; + CheckBox download = new CheckBox(); + download.AutoSize = true; + download.Location = new Point(675, 11); + download.Text = "Download"; + download.CheckedChanged += new EventHandler(delegate (Object sender, EventArgs e) + { + if (download.Checked == true) + { + Config.selectedMods.Add(item); + } + else + { + Config.selectedMods.Remove(item); + } + selectedModsLabel.Text = "Selected Mods: " + Config.selectedMods.Count; + }); + if (Config.selectedMods.Contains(item)) + { + download.Checked = true; + } + else + { + download.Checked = false; + } + Button moreInfoButton = new Button(); + moreInfoButton.Location = new Point(674, 32); + moreInfoButton.Text = "More Info"; + modPanel.Controls.Add(modIcon); + modPanel.Controls.Add(modTitle); + modPanel.Controls.Add(modAuthor); + modPanel.Controls.Add(download); + modPanel.Controls.Add(moreInfoButton); + modsList.Controls.Add(modPanel); + } + } + + private void nextBtn_Click(object sender, EventArgs e) + { + currentPage += 1; + pageLabel.Text = "Page: " + currentPage; + UpdateModList(searchTextBox.Text); + } + + private void previousBtn_Click(object sender, EventArgs e) + { + if (!(currentPage - 1 < 1)) + { + currentPage -= 1; + pageLabel.Text = "Page: " + currentPage; + UpdateModList(searchTextBox.Text); + } + } + + private void tmlVersionComboBox_SelectionChangeCommitted(object sender, EventArgs e) + { + UpdateModList(searchTextBox.Text); + } + + private void downloadButton_Click(object sender, EventArgs e) + { + if (Config.selectedMods.Count < 1) + { + MessageBox.Show("No mods selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + var currentDir = Environment.CurrentDirectory; + if (!(Directory.Exists(Path.Combine(currentDir, "steamcmd"))) || !(File.Exists(Path.Combine(currentDir, "steamcmd", "steamcmd.exe")))) + { + MessageBox.Show("SteamCMD executable not found, cannot download selected mods.\n\nPlease manually download SteamCMD from Valve Developer Community and put it into \'steamcmd\' folder.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + else + { + CommonOpenFileDialog saveDir = new CommonOpenFileDialog(); + saveDir.InitialDirectory = "C:/"; + saveDir.IsFolderPicker = true; + saveDir.Multiselect = false; + saveDir.Title = "Select directory to save mods."; + if (saveDir.ShowDialog() == CommonFileDialogResult.Ok) + { + new DownloadForm(saveDir.FileName).Show(); + } + else + { + MessageBox.Show("No directory selected, cancelled.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + } + } + + private void searchButton_Click(object sender, EventArgs e) + { + UpdateModList(searchTextBox.Text); + } + + private void refreshBtn_Click(object sender, EventArgs e) + { + pagedMods.Remove("page_" + currentPage); + UpdateModList(); + } + } +} \ No newline at end of file diff --git a/tModDownloader/ModBrowser.resx b/tModDownloader/ModBrowser.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/tModDownloader/ModBrowser.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/tModDownloader/ModItem.cs b/tModDownloader/ModItem.cs new file mode 100644 index 0000000..a298266 --- /dev/null +++ b/tModDownloader/ModItem.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace tModDownloader +{ + public class ModItem + { + public string ID { get; set; } + public string SteamURL { get; set; } + public Image Icon { get; set; } + public string Title { get; set; } + public string AuthorName { get; set; } + public string AuthorURL { get; set; } + + public ModItem(string id, Image icon, string title, string description) + { + ID = id; + Icon = icon; + Title = title; + } + } +} diff --git a/tModDownloader/Program.cs b/tModDownloader/Program.cs new file mode 100644 index 0000000..36ebfec --- /dev/null +++ b/tModDownloader/Program.cs @@ -0,0 +1,17 @@ +namespace tModDownloader +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new ModBrowser()); + } + } +} \ No newline at end of file diff --git a/tModDownloader/obj/project.assets.json b/tModDownloader/obj/project.assets.json new file mode 100644 index 0000000..ddc07b4 --- /dev/null +++ b/tModDownloader/obj/project.assets.json @@ -0,0 +1,236 @@ +{ + "version": 3, + "targets": { + "net6.0-windows7.0": { + "HtmlAgilityPack/1.11.53": { + "type": "package", + "compile": { + "lib/netstandard2.0/HtmlAgilityPack.dll": { + "related": ".deps.json;.pdb;.xml" + } + }, + "runtime": { + "lib/netstandard2.0/HtmlAgilityPack.dll": { + "related": ".deps.json;.pdb;.xml" + } + } + }, + "Microsoft-WindowsAPICodePack-Core/1.1.5": { + "type": "package", + "compile": { + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.dll": { + "related": ".xml" + } + }, + "frameworkReferences": [ + "Microsoft.WindowsDesktop.App.WindowsForms" + ] + }, + "Microsoft-WindowsAPICodePack-Shell/1.1.5": { + "type": "package", + "dependencies": { + "Microsoft-WindowsAPICodePack-Core": "1.1.5" + }, + "compile": { + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.Shell.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.Shell.dll": { + "related": ".xml" + } + }, + "frameworkReferences": [ + "Microsoft.WindowsDesktop.App" + ] + } + } + }, + "libraries": { + "HtmlAgilityPack/1.11.53": { + "sha512": "FeBqVmrMVoKFcsg6BhMJ5FYSx476AKDic9oHk5DsYSj606agR1XuxaaicxJ28X/LZkPTX51e3NaB8QJ5G+1B/w==", + "type": "package", + "path": "htmlagilitypack/1.11.53", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "htmlagilitypack.1.11.53.nupkg.sha512", + "htmlagilitypack.nuspec", + "lib/Net35/HtmlAgilityPack.dll", + "lib/Net35/HtmlAgilityPack.pdb", + "lib/Net35/HtmlAgilityPack.xml", + "lib/Net40-client/HtmlAgilityPack.dll", + "lib/Net40-client/HtmlAgilityPack.pdb", + "lib/Net40-client/HtmlAgilityPack.xml", + "lib/Net40/HtmlAgilityPack.XML", + "lib/Net40/HtmlAgilityPack.dll", + "lib/Net40/HtmlAgilityPack.pdb", + "lib/Net45/HtmlAgilityPack.XML", + "lib/Net45/HtmlAgilityPack.dll", + "lib/Net45/HtmlAgilityPack.pdb", + "lib/NetCore45/HtmlAgilityPack.XML", + "lib/NetCore45/HtmlAgilityPack.dll", + "lib/NetCore45/HtmlAgilityPack.pdb", + "lib/netstandard1.3/HtmlAgilityPack.deps.json", + "lib/netstandard1.3/HtmlAgilityPack.dll", + "lib/netstandard1.3/HtmlAgilityPack.pdb", + "lib/netstandard1.3/HtmlAgilityPack.xml", + "lib/netstandard1.6/HtmlAgilityPack.deps.json", + "lib/netstandard1.6/HtmlAgilityPack.dll", + "lib/netstandard1.6/HtmlAgilityPack.pdb", + "lib/netstandard1.6/HtmlAgilityPack.xml", + "lib/netstandard2.0/HtmlAgilityPack.deps.json", + "lib/netstandard2.0/HtmlAgilityPack.dll", + "lib/netstandard2.0/HtmlAgilityPack.pdb", + "lib/netstandard2.0/HtmlAgilityPack.xml", + "lib/portable-net45+netcore45+wp8+MonoAndroid+MonoTouch/HtmlAgilityPack.XML", + "lib/portable-net45+netcore45+wp8+MonoAndroid+MonoTouch/HtmlAgilityPack.dll", + "lib/portable-net45+netcore45+wp8+MonoAndroid+MonoTouch/HtmlAgilityPack.pdb", + "lib/portable-net45+netcore45+wpa81+wp8+MonoAndroid+MonoTouch/HtmlAgilityPack.XML", + "lib/portable-net45+netcore45+wpa81+wp8+MonoAndroid+MonoTouch/HtmlAgilityPack.dll", + "lib/portable-net45+netcore45+wpa81+wp8+MonoAndroid+MonoTouch/HtmlAgilityPack.pdb", + "lib/uap10.0/HtmlAgilityPack.XML", + "lib/uap10.0/HtmlAgilityPack.dll", + "lib/uap10.0/HtmlAgilityPack.pdb", + "lib/uap10.0/HtmlAgilityPack.pri" + ] + }, + "Microsoft-WindowsAPICodePack-Core/1.1.5": { + "sha512": "3feeT5wxrH/T4YmoZwCglVrUw6aS4+WJLA3FRADLVT2J85/zjptrCikvGNcLI1+gDeoI1AZ4w45gF2FvBv6eQw==", + "type": "package", + "path": "microsoft-windowsapicodepack-core/1.1.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net452/Microsoft.WindowsAPICodePack.dll", + "lib/net452/Microsoft.WindowsAPICodePack.xml", + "lib/net462/Microsoft.WindowsAPICodePack.dll", + "lib/net462/Microsoft.WindowsAPICodePack.xml", + "lib/net472/Microsoft.WindowsAPICodePack.dll", + "lib/net472/Microsoft.WindowsAPICodePack.xml", + "lib/net48/Microsoft.WindowsAPICodePack.dll", + "lib/net48/Microsoft.WindowsAPICodePack.xml", + "lib/net481/Microsoft.WindowsAPICodePack.dll", + "lib/net481/Microsoft.WindowsAPICodePack.xml", + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.dll", + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.xml", + "lib/net7.0-windows7.0/Microsoft.WindowsAPICodePack.dll", + "lib/net7.0-windows7.0/Microsoft.WindowsAPICodePack.xml", + "lib/netcoreapp3.1/Microsoft.WindowsAPICodePack.dll", + "lib/netcoreapp3.1/Microsoft.WindowsAPICodePack.xml", + "microsoft-windowsapicodepack-core.1.1.5.nupkg.sha512", + "microsoft-windowsapicodepack-core.nuspec" + ] + }, + "Microsoft-WindowsAPICodePack-Shell/1.1.5": { + "sha512": "lZ+oIxvTp1Ph0YrzFl3AKcrry7OCfi0awf43nrGwodWqDlFASktZ+pN532rbU/5o09irYjxVu1m3UxO5L1H8fw==", + "type": "package", + "path": "microsoft-windowsapicodepack-shell/1.1.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net452/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net452/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/net462/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net462/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/net472/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net472/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/net48/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net48/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/net481/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net481/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net6.0-windows7.0/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/net7.0-windows7.0/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/net7.0-windows7.0/Microsoft.WindowsAPICodePack.Shell.xml", + "lib/netcoreapp3.1/Microsoft.WindowsAPICodePack.Shell.dll", + "lib/netcoreapp3.1/Microsoft.WindowsAPICodePack.Shell.xml", + "microsoft-windowsapicodepack-shell.1.1.5.nupkg.sha512", + "microsoft-windowsapicodepack-shell.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0-windows7.0": [ + "HtmlAgilityPack >= 1.11.53", + "Microsoft-WindowsAPICodePack-Shell >= 1.1.5" + ] + }, + "packageFolders": { + "C:\\Users\\Administrator\\.nuget\\packages\\": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj", + "projectName": "tModDownloader", + "projectPath": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj", + "packagesPath": "C:\\Users\\Administrator\\.nuget\\packages\\", + "outputPath": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\Administrator\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0-windows" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0-windows7.0": { + "targetAlias": "net6.0-windows", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0-windows7.0": { + "targetAlias": "net6.0-windows", + "dependencies": { + "HtmlAgilityPack": { + "target": "Package", + "version": "[1.11.53, )" + }, + "Microsoft-WindowsAPICodePack-Shell": { + "target": "Package", + "version": "[1.1.5, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + }, + "Microsoft.WindowsDesktop.App.WindowsForms": { + "privateAssets": "none" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\7.0.403\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/tModDownloader/obj/project.nuget.cache b/tModDownloader/obj/project.nuget.cache new file mode 100644 index 0000000..0535f14 --- /dev/null +++ b/tModDownloader/obj/project.nuget.cache @@ -0,0 +1,12 @@ +{ + "version": 2, + "dgSpecHash": "tifwuPhcY57OI9rw0UfcXnQH2jQNtx3DXH1QxkSrqkaabgJKjkR9emkXTowweoEPtwk1mFEL41VcFYkvT1gzWQ==", + "success": true, + "projectFilePath": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj", + "expectedPackageFiles": [ + "C:\\Users\\Administrator\\.nuget\\packages\\htmlagilitypack\\1.11.53\\htmlagilitypack.1.11.53.nupkg.sha512", + "C:\\Users\\Administrator\\.nuget\\packages\\microsoft-windowsapicodepack-core\\1.1.5\\microsoft-windowsapicodepack-core.1.1.5.nupkg.sha512", + "C:\\Users\\Administrator\\.nuget\\packages\\microsoft-windowsapicodepack-shell\\1.1.5\\microsoft-windowsapicodepack-shell.1.1.5.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/tModDownloader/obj/tModDownloader.csproj.nuget.dgspec.json b/tModDownloader/obj/tModDownloader.csproj.nuget.dgspec.json new file mode 100644 index 0000000..5f7bc7c --- /dev/null +++ b/tModDownloader/obj/tModDownloader.csproj.nuget.dgspec.json @@ -0,0 +1,76 @@ +{ + "format": 1, + "restore": { + "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj": {} + }, + "projects": { + "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj", + "projectName": "tModDownloader", + "projectPath": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\tModDownloader.csproj", + "packagesPath": "C:\\Users\\Administrator\\.nuget\\packages\\", + "outputPath": "E:\\WIN7BACKUP\\tModDownloader\\tModDownloader\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\Administrator\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0-windows" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0-windows7.0": { + "targetAlias": "net6.0-windows", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0-windows7.0": { + "targetAlias": "net6.0-windows", + "dependencies": { + "HtmlAgilityPack": { + "target": "Package", + "version": "[1.11.53, )" + }, + "Microsoft-WindowsAPICodePack-Shell": { + "target": "Package", + "version": "[1.1.5, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + }, + "Microsoft.WindowsDesktop.App.WindowsForms": { + "privateAssets": "none" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\7.0.403\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/tModDownloader/obj/tModDownloader.csproj.nuget.g.props b/tModDownloader/obj/tModDownloader.csproj.nuget.g.props new file mode 100644 index 0000000..53b218f --- /dev/null +++ b/tModDownloader/obj/tModDownloader.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\Administrator\.nuget\packages\ + PackageReference + 6.7.0 + + + + + \ No newline at end of file diff --git a/tModDownloader/obj/tModDownloader.csproj.nuget.g.targets b/tModDownloader/obj/tModDownloader.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/tModDownloader/obj/tModDownloader.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/tModDownloader/tModDownloader.csproj b/tModDownloader/tModDownloader.csproj new file mode 100644 index 0000000..909ac89 --- /dev/null +++ b/tModDownloader/tModDownloader.csproj @@ -0,0 +1,16 @@ + + + + WinExe + net6.0-windows + enable + true + enable + + + + + + + + \ No newline at end of file diff --git a/tModDownloader/tModDownloader.csproj.user b/tModDownloader/tModDownloader.csproj.user new file mode 100644 index 0000000..8742af4 --- /dev/null +++ b/tModDownloader/tModDownloader.csproj.user @@ -0,0 +1,11 @@ + + + + + Form + + + Form + + + \ No newline at end of file