mirror of
https://github.com/bellingcat/reddit-post-scraping-tool.git
synced 2026-06-12 13:38:28 +03:00
Add files via upload
This commit is contained in:
84
RPST GUI/RPST/Assets/ApiHandler.vb
Normal file
84
RPST GUI/RPST/Assets/ApiHandler.vb
Normal file
@@ -0,0 +1,84 @@
|
||||
Imports System.IO
|
||||
Imports System.Net.Http
|
||||
Imports Newtonsoft.Json
|
||||
Imports Newtonsoft.Json.Linq
|
||||
|
||||
''' <summary>
|
||||
''' Handles requests to Reddit and Github APIs.
|
||||
''' </summary>
|
||||
Public Class ApiHandler
|
||||
Public Property LogFile As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RedditPostScrapingTool", "logs", $"debug.log")
|
||||
Public Property Headers As String = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15"
|
||||
Public Property UpdatesEndpoint As String = "https://api.github.com/repos/bellingcat/reddit-post-scraping-tool/releases/latest"
|
||||
|
||||
''' <summary>
|
||||
''' Asyncrosnously scrape Reddit data.
|
||||
''' </summary>
|
||||
''' <returns>Json object containing scraped data.</returns>
|
||||
Public Async Function AsyncGetPosts(subreddit As String, listing As String, limit As Integer, timeframe As String) As Task(Of JArray)
|
||||
Dim PostsEndpoint As String = $"https://www.reddit.com/r/{subreddit}/{listing}.json?limit={limit}&t={timeframe}"
|
||||
Return Await PaginatedPosts(endpoint:=PostsEndpoint, limit:=limit)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Retrieves posts in a paginated manner until the specified limit is reached.
|
||||
''' </summary>
|
||||
''' <param name="endpoint">The API endpoint for retrieving posts.</param>
|
||||
''' <param name="limit">The limit on the number of posts to retrieve.</param>
|
||||
''' <returns>A Task(Of JArray) representing the asynchronous operation, which upon completion returns a JArray of posts.</returns>
|
||||
Private Async Function PaginatedPosts(endpoint As String, limit As Integer) As Task(Of JArray)
|
||||
Dim allPosts As New JArray()
|
||||
Dim lastPostId As String = ""
|
||||
Dim useAfter As Boolean = limit > 100
|
||||
|
||||
While allPosts.Count < limit
|
||||
Dim endpointWithAfter As String = If(useAfter And Not String.IsNullOrEmpty(lastPostId), $"{endpoint}&after={lastPostId}", endpoint)
|
||||
Dim postsData As JObject = Await AsyncGetData(endpoint:=endpointWithAfter)
|
||||
Dim postsChildren As JArray = postsData("data")("children")
|
||||
|
||||
If postsChildren.Count = 0 Then
|
||||
Exit While
|
||||
End If
|
||||
|
||||
allPosts.Merge(postsChildren)
|
||||
|
||||
lastPostId = postsChildren.Last("data")("id").ToString()
|
||||
End While
|
||||
|
||||
Return allPosts
|
||||
End Function
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Asyncrosnously gets remote version information from the repository release page.
|
||||
''' </summary>
|
||||
''' <returns>Json object containing update data.</returns>
|
||||
Public Async Function CheckUpdatesAsync() As Task(Of JObject)
|
||||
Return Await AsyncGetData(endpoint:=UpdatesEndpoint)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Asyncronously retrieves a JObject from the specified endpoint.
|
||||
''' </summary>
|
||||
''' <param name="endpoint">The URL endpoint to retrieve data from.</param>
|
||||
''' <returns>A JObject containing the retrieved data.</returns>
|
||||
Private Async Function AsyncGetData(endpoint As String) As Task(Of JObject)
|
||||
Try
|
||||
Using httpClient As New HttpClient()
|
||||
httpClient.DefaultRequestHeaders.Add("User-Agent", Headers)
|
||||
Dim response As HttpResponseMessage = Await httpClient.GetAsync(endpoint)
|
||||
If response.IsSuccessStatusCode Then
|
||||
Dim json As String = response.Content.ReadAsStringAsync().Result
|
||||
Dim data As JObject = JsonConvert.DeserializeObject(Of JObject)(json)
|
||||
Return data
|
||||
Else
|
||||
MessageBox.Show(response.ReasonPhrase, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
|
||||
End If
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
My.Computer.FileSystem.WriteAllText(LogFile, $"{DateTime.Now}: {ex}{Environment.NewLine}", True)
|
||||
MessageBox.Show($"{ex.Message}. Please see the debug log '{LogFile}' for more information.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
|
||||
End Try
|
||||
Return New JObject()
|
||||
End Function
|
||||
End Class
|
||||
115
RPST GUI/RPST/Assets/PostsProcessor.vb
Normal file
115
RPST GUI/RPST/Assets/PostsProcessor.vb
Normal file
@@ -0,0 +1,115 @@
|
||||
Imports Newtonsoft.Json.Linq
|
||||
|
||||
Public Class PostsProcessor
|
||||
Private Shared ReadOnly ApiHandler As New ApiHandler()
|
||||
|
||||
''' <summary>
|
||||
''' Checks if the given Reddit post contains the given keyword in its text.
|
||||
''' </summary>
|
||||
''' <param name="post">The Reddit post to check.</param>
|
||||
''' <param name="keyword">The keyword to check for.</param>
|
||||
''' <returns>True if the post contains the keyword, False otherwise.</returns>
|
||||
Public Shared Function PostContainsKeyword(post As JObject, keyword As String) As Boolean
|
||||
Return post("data")("selftext").ToString.ToLower(Globalization.CultureInfo.InvariantCulture).Contains(keyword.ToLower(System.Globalization.CultureInfo.InvariantCulture))
|
||||
End Function
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Collects user inputs, fetches Reddit posts based on the inputs, checks if posts contain the keyword, and saves posts to a JSON file if necessary.
|
||||
''' </summary>
|
||||
''' <param name="JSONToolStripMenuItem">Indicates whether to save the posts to a JSON file.</param>
|
||||
''' <remarks>
|
||||
''' This function initializes the DataGridView, iterates over each post, adds the posts containing the keyword to the DataGridView and updates the UI.
|
||||
''' It also shows a message if the keyword was not found in any of the posts or if the inputs are empty.
|
||||
''' </remarks>
|
||||
Public Shared Async Sub ProcessRedditPosts(settings)
|
||||
' Collect inputs from the user.
|
||||
Dim inputs = Utilities.CollectInputs()
|
||||
|
||||
If inputs.HasValue Then
|
||||
' Fetch Reddit posts based on the inputs.
|
||||
Dim processor As New PostsProcessor()
|
||||
Dim posts As JArray = Await ApiHandler.AsyncGetPosts(subreddit:=inputs.Value.Subreddit, listing:=inputs.Value.Listing, limit:=inputs.Value.Limit, timeframe:=inputs.Value.Timeframe)
|
||||
Dim totalPosts As Integer = 0
|
||||
Dim keywordFound As Boolean = False
|
||||
Dim foundPosts As Integer = 0
|
||||
Dim foundPostsList As New JArray
|
||||
|
||||
PostsWindow.DataGridViewPosts.Rows.Clear()
|
||||
PostsWindow.DataGridViewPosts.Columns.Clear()
|
||||
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostCount", "Index")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostAuthor", "Author")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostID", "ID")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostTitle", "Title")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostText", "Text")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostSubreddit", "Subreddit")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("SubredditVisibility", "Subreddit Type")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostThumbnail", "Thumbnail")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostIsNSFW", "NSFW")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostIsGilded", "Is Gilded")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostUpvotes", "Upvotes")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostUpvoteRatio", "Upvote Ratio")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostDownvotes", "Downvotes")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostIsCrosspostable", "↪️ Is Shareable")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostScore", "Score")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostCategory", "Category")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostDomain", "Domain")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostPermalink", "Permalink")
|
||||
PostsWindow.DataGridViewPosts.Columns.Add("PostCreatedAt", "Created At")
|
||||
|
||||
' Iterate over each post.
|
||||
For Each post In posts
|
||||
totalPosts += 1
|
||||
' Check if the post contains the keyword
|
||||
If PostsProcessor.PostContainsKeyword(post, inputs.Value.Keyword.ToLower(Globalization.CultureInfo.InvariantCulture)) Then
|
||||
foundPosts += 1
|
||||
foundPostsList.Add(post)
|
||||
|
||||
PostsWindow.DataGridViewPosts.Rows.Add(totalPosts,
|
||||
post("data")("author"),
|
||||
post("data")("id"),
|
||||
post("data")("title"),
|
||||
post("data")("selftext"),
|
||||
post("data")("subreddit_name_prefixed"),
|
||||
post("data")("subreddit_type"),
|
||||
post("data")("thumbnail"),
|
||||
post("data")("over_18"),
|
||||
post("data")("gilded"),
|
||||
post("data")("ups"),
|
||||
post("data")("upvote_ratio"),
|
||||
post("data")("downs"),
|
||||
post("data")("is_crosspostable"),
|
||||
post("data")("score"),
|
||||
post("data")("category"),
|
||||
post("data")("domain"),
|
||||
post("data")("permalink"),
|
||||
post("data")("created"))
|
||||
|
||||
PostsWindow.Text = $"Showing {foundPosts}/{inputs.Value.Limit} {inputs.Value.Listing} posts containing the word {inputs.Value.Keyword}, from r/{inputs.Value.Subreddit}"
|
||||
PostsWindow.Show()
|
||||
keywordFound = True
|
||||
End If
|
||||
Next
|
||||
|
||||
' Check if the keyword was found in any posts
|
||||
If Not keywordFound Then
|
||||
MessageBox.Show($"Keyword `{inputs.Value.Keyword}` was not found in any of the " + posts("data")("children").Count.ToString(Globalization.CultureInfo.InvariantCulture) _
|
||||
+ $" {inputs.Value.Listing} posts from r/{inputs.Value.Subreddit}", "Not Found", MessageBoxButtons.OK, MessageBoxIcon.Warning)
|
||||
End If
|
||||
|
||||
|
||||
If settings.SaveToJson Then
|
||||
' Save posts to a JSON file if SaveToJson is True.
|
||||
Utilities.SavePostsToJson(posts:=foundPostsList)
|
||||
End If
|
||||
|
||||
If settings.SaveToCsv Then
|
||||
' Save posts to a CSV file if SaveToCsv is True.
|
||||
Utilities.SavePostsToCSV(posts:=foundPostsList)
|
||||
End If
|
||||
Else
|
||||
End If
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
230
RPST GUI/RPST/Assets/Settings.vb
Normal file
230
RPST GUI/RPST/Assets/Settings.vb
Normal file
@@ -0,0 +1,230 @@
|
||||
Imports System.IO
|
||||
Imports System.Text.Json
|
||||
Imports Newtonsoft.Json.Linq
|
||||
|
||||
|
||||
Public Class SettingsManager
|
||||
|
||||
''' <summary>
|
||||
''' Represents the Dark Mode property.
|
||||
''' Indicates whether the dark mode is enabled or disabled.
|
||||
''' </summary>
|
||||
Public Property DarkMode As Boolean
|
||||
Public Property SaveToJson As Boolean
|
||||
Public Property SaveToCsv As Boolean
|
||||
|
||||
Private ReadOnly settingsFilePath As String = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"RPST",
|
||||
"settings.json"
|
||||
)
|
||||
|
||||
''' <summary>
|
||||
''' Loads application settings from the 'settings.json' file.
|
||||
''' If the settings file doesn't exist, it creates a new file with default settings.
|
||||
''' </summary>
|
||||
Public Sub LoadSettings()
|
||||
' Check if the settings.json file exists
|
||||
' and load the configurations from it
|
||||
If File.Exists(settingsFilePath) Then
|
||||
Dim json As String = File.ReadAllText(settingsFilePath)
|
||||
Dim options As New JsonSerializerOptions With {.PropertyNameCaseInsensitive = True}
|
||||
Dim settings = JsonSerializer.Deserialize(Of SettingsManager)(json, options)
|
||||
|
||||
DarkMode = settings.DarkMode
|
||||
SaveToJson = settings.SaveToJson
|
||||
SaveToCsv = settings.SaveToCsv
|
||||
|
||||
MainWindow.DarkModeToolStripMenuItem.Checked = settings.DarkMode
|
||||
MainWindow.ToJSONToolStripMenuItem.Checked = settings.SaveToJson
|
||||
MainWindow.ToCSVToolStripMenuItem.Checked = settings.SaveToCsv
|
||||
Else
|
||||
' Settings file does not exist
|
||||
' Create a new file with default settings 'False'
|
||||
Dim defaultSettings = New SettingsManager With {.DarkMode = False, .SaveToCsv = False, .SaveToJson = False}
|
||||
Dim jsonOutput = JsonSerializer.Serialize(defaultSettings)
|
||||
File.WriteAllText(settingsFilePath, jsonOutput)
|
||||
|
||||
|
||||
SaveToJson = False
|
||||
SaveToCsv = False
|
||||
MainWindow.ToJSONToolStripMenuItem.Checked = False
|
||||
MainWindow.ToCSVToolStripMenuItem.Checked = False
|
||||
|
||||
If Utilities.IsSystemDarkTheme() Then
|
||||
DarkMode = True
|
||||
MainWindow.DarkModeToolStripMenuItem.Checked = True
|
||||
Else
|
||||
DarkMode = False
|
||||
MainWindow.DarkModeToolStripMenuItem.Checked = False
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Retrieves application settings from a JSON file.
|
||||
''' </summary>
|
||||
''' <returns>A Dictionary containing the names and values of all settings.
|
||||
''' If the settings file doesn't exist, returns a Dictionary with default values.</returns>
|
||||
Private Function GetSettings() As Dictionary(Of String, Object)
|
||||
Dim settings As New Dictionary(Of String, Object)
|
||||
If File.Exists(settingsFilePath) Then
|
||||
' Read and parse the JSON settings file.
|
||||
Dim json As String = File.ReadAllText(settingsFilePath)
|
||||
Dim jObject As JObject = JObject.Parse(json)
|
||||
|
||||
' Loop through each property in the JObject and add it to the settings Dictionary.
|
||||
For Each item As JProperty In jObject.Properties()
|
||||
settings.Add(item.Name, item.Value.ToObject(Of Object)())
|
||||
Next
|
||||
Else
|
||||
End If
|
||||
Return settings
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Saves the provided settings to the 'settings.json' file.
|
||||
''' </summary>
|
||||
''' <param name="settings">An instance of the SettingsManager containing the configurations to be saved.</param>
|
||||
Private Sub SaveSettings(settings)
|
||||
Dim jsonOutput = JsonSerializer.Serialize(settings)
|
||||
File.WriteAllText(settingsFilePath, jsonOutput)
|
||||
End Sub
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Applies the current settings to the application's interface. This includes
|
||||
''' toggling SaveToJson, SaveToCsv, and applying the visual theme based on the Dark Mode setting.
|
||||
''' </summary>
|
||||
Public Sub ApplySettings()
|
||||
' Retrieve the current settings
|
||||
Dim settings As Dictionary(Of String, Object) = GetSettings()
|
||||
|
||||
' Apply the SaveToJson setting to the menu item checkbox
|
||||
MainWindow.ToJSONToolStripMenuItem.Checked = CBool(settings("SaveToJson"))
|
||||
|
||||
' Apply the SaveToCsv setting to the menu item checkbox
|
||||
MainWindow.ToCSVToolStripMenuItem.Checked = CBool(settings("SaveToCsv"))
|
||||
|
||||
' Apply the color scheme based on the Dark Mode setting
|
||||
ApplyColorScheme(isDarkMode:=CBool(settings("DarkMode")))
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Applies the color scheme based on the given Dark Mode setting.
|
||||
''' Colors are defined in a mapping for easier maintenance and flexibility.
|
||||
''' </summary>
|
||||
''' <param name="isDarkMode">Indicates whether Dark Mode is enabled.</param>
|
||||
Public Shared Sub ApplyColorScheme(ByVal isDarkMode As Boolean)
|
||||
' Initialize color mapping
|
||||
Dim colorMap As New Dictionary(Of String, Color)
|
||||
|
||||
If isDarkMode Then
|
||||
' Dark Mode colors
|
||||
colorMap("MainBackground") = ColorTranslator.FromHtml("#FF121212")
|
||||
colorMap("TextBoxBackground") = ColorTranslator.FromHtml("#FF2E2E2E")
|
||||
colorMap("Foreground") = SystemColors.Control
|
||||
colorMap("MenuBackground") = ColorTranslator.FromHtml("#FF121212")
|
||||
colorMap("AboutBackground") = ColorTranslator.FromHtml("#FF121212")
|
||||
colorMap("AboutForeground") = SystemColors.Control
|
||||
colorMap("TabPageBackground") = ColorTranslator.FromHtml("#FF2E2E2E")
|
||||
colorMap("TabPageForeground") = SystemColors.Control
|
||||
colorMap("ButtonForeground") = Color.Black
|
||||
Else
|
||||
' Light Mode colors
|
||||
colorMap("MainBackground") = Color.Gainsboro
|
||||
colorMap("TextBoxBackground") = SystemColors.Control
|
||||
colorMap("Foreground") = ColorTranslator.FromHtml("#FF121212")
|
||||
colorMap("MenuBackground") = Color.Gainsboro
|
||||
colorMap("AboutBackground") = Color.Gainsboro
|
||||
colorMap("AboutForeground") = SystemColors.WindowText
|
||||
colorMap("TabPageBackground") = SystemColors.Control
|
||||
colorMap("TabPageForeground") = SystemColors.WindowText
|
||||
colorMap("ButtonForeground") = Color.Black
|
||||
End If
|
||||
|
||||
' Applying Main Form colors
|
||||
MainWindow.BackColor = colorMap("MainBackground")
|
||||
MainWindow.TextBoxKeyword.BackColor = colorMap("TextBoxBackground")
|
||||
MainWindow.TextBoxSubreddit.BackColor = colorMap("TextBoxBackground")
|
||||
MainWindow.NumericUpDownLimit.BackColor = colorMap("TextBoxBackground")
|
||||
MainWindow.ComboBoxListing.BackColor = colorMap("TextBoxBackground")
|
||||
MainWindow.ComboBoxTimeframe.BackColor = colorMap("TextBoxBackground")
|
||||
MainWindow.TextBoxKeyword.ForeColor = colorMap("Foreground")
|
||||
MainWindow.TextBoxSubreddit.ForeColor = colorMap("Foreground")
|
||||
MainWindow.NumericUpDownLimit.ForeColor = colorMap("Foreground")
|
||||
MainWindow.ComboBoxListing.ForeColor = colorMap("Foreground")
|
||||
MainWindow.ComboBoxTimeframe.ForeColor = colorMap("Foreground")
|
||||
MainWindow.LabelKeyword.ForeColor = colorMap("Foreground")
|
||||
MainWindow.LabelSubreddit.ForeColor = colorMap("Foreground")
|
||||
MainWindow.LabelLimit.ForeColor = colorMap("Foreground")
|
||||
MainWindow.LabelListing.ForeColor = colorMap("Foreground")
|
||||
MainWindow.LabelTimeframe.ForeColor = colorMap("Foreground")
|
||||
|
||||
' Applying Right-Click Menu colors
|
||||
MainWindow.SettingsToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.DarkModeToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.SavePostsToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.ToJSONToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.ToCSVToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.AboutToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.CheckForUpdatesToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.QuitToolStripMenuItem.BackColor = colorMap("MenuBackground")
|
||||
MainWindow.SettingsToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.DarkModeToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.SavePostsToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.ToJSONToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.ToCSVToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.AboutToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.CheckForUpdatesToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
MainWindow.QuitToolStripMenuItem.ForeColor = colorMap("Foreground")
|
||||
|
||||
' Applying About Box colors
|
||||
AboutBox.BackColor = colorMap("AboutBackground")
|
||||
AboutBox.TabPageAbout.BackColor = colorMap("TabPageBackground")
|
||||
AboutBox.TabPageAuthor.BackColor = colorMap("TabPageBackground")
|
||||
AboutBox.ForeColor = colorMap("AboutForeground")
|
||||
AboutBox.LabelProgramName.ForeColor = colorMap("AboutForeground")
|
||||
AboutBox.LabelDescription.ForeColor = colorMap("AboutForeground")
|
||||
AboutBox.LabelCopyright.ForeColor = colorMap("AboutForeground")
|
||||
AboutBox.LabelVersion.ForeColor = colorMap("AboutForeground")
|
||||
AboutBox.LabelAuthor.ForeColor = colorMap("AboutForeground")
|
||||
AboutBox.ButtonClose.ForeColor = colorMap("ButtonForeground")
|
||||
|
||||
' Updating Dark Mode Text
|
||||
If isDarkMode Then
|
||||
MainWindow.DarkModeToolStripMenuItem.Text = "Dark Mode: Disable"
|
||||
Else
|
||||
MainWindow.DarkModeToolStripMenuItem.Text = "Dark Mode: Enable"
|
||||
End If
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Toggles specific settings on or off based on the provided parameters.
|
||||
''' </summary>
|
||||
''' <param name="enabled">A Boolean indicating if the setting option should be enabled or not.</param>
|
||||
''' <param name="saveTo">A String specifying the type of setting to toggle ('json', 'csv', or 'darkmode').</param>
|
||||
Public Sub ToggleSettings(enabled As Boolean, saveTo As String)
|
||||
' Read the existing settings from the settings file
|
||||
Dim json As String = File.ReadAllText(settingsFilePath)
|
||||
Dim options As New JsonSerializerOptions With {.PropertyNameCaseInsensitive = True}
|
||||
Dim settings As SettingsManager = JsonSerializer.Deserialize(Of SettingsManager)(json, options)
|
||||
|
||||
' Update the settings based on the specified saveTo parameter
|
||||
If saveTo.ToLower(Globalization.CultureInfo.InvariantCulture) = "json" Then
|
||||
settings.SaveToJson = enabled
|
||||
ElseIf saveTo.ToLower(Globalization.CultureInfo.InvariantCulture) = "csv" Then
|
||||
settings.SaveToCsv = enabled
|
||||
ElseIf saveTo.ToLower(Globalization.CultureInfo.InvariantCulture) = "darkmode" Then
|
||||
settings.DarkMode = enabled
|
||||
Else
|
||||
' Handle unexpected value of saveTo (if needed)
|
||||
End If
|
||||
|
||||
' Save the updated settings back to the settings file
|
||||
SaveSettings(settings)
|
||||
' Apply the updated settings to the application
|
||||
ApplySettings()
|
||||
End Sub
|
||||
End Class
|
||||
173
RPST GUI/RPST/Assets/Utilities.vb
Normal file
173
RPST GUI/RPST/Assets/Utilities.vb
Normal file
@@ -0,0 +1,173 @@
|
||||
Imports System.IO
|
||||
Imports Microsoft.Win32
|
||||
Imports Newtonsoft.Json
|
||||
Imports Newtonsoft.Json.Linq
|
||||
|
||||
Public Class Utilities
|
||||
|
||||
''' <summary>
|
||||
''' Determines if the Windows system theme is in dark mode.
|
||||
''' </summary>
|
||||
''' <returns>
|
||||
''' True if the dark mode is enabled, otherwise false.
|
||||
''' </returns>
|
||||
Public Shared Function IsSystemDarkTheme() As Boolean
|
||||
Dim registryKey As RegistryKey = Registry.CurrentUser.OpenSubKey(
|
||||
"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
|
||||
)
|
||||
If registryKey IsNot Nothing Then
|
||||
Dim appsUseLightTheme As Object = registryKey.GetValue("AppsUseLightTheme")
|
||||
Return appsUseLightTheme IsNot Nothing AndAlso CType(appsUseLightTheme, Integer) = 0
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Shows the license notice in a messagebox.
|
||||
''' </summary>
|
||||
''' <returns>
|
||||
''' Result of the Dialog (Yes/No).
|
||||
''' </returns>
|
||||
Public Shared Function LicenseAgreement()
|
||||
Dim result As DialogResult = MessageBox.Show($"{My.Application.Info.Copyright}
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the ""Software""), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", "MIT License", MessageBoxButtons.OK, MessageBoxIcon.Information)
|
||||
|
||||
Return result
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Checks for the existence of the 'logs' directory under the 'RPST' directory within the user's AppData\Roaming folder.
|
||||
''' If the directory does not exist, it creates one.
|
||||
''' </summary>
|
||||
''' <remarks>
|
||||
''' The directory path is 'C:\Users\<username>\AppData\Roaming\RPST\logs'.
|
||||
''' If the 'RPST' or 'logs' directories do not exist, the function will create them.
|
||||
''' If the directories already exist, the function will not perform any actions.
|
||||
''' </remarks>
|
||||
Public Shared Sub PathFinder()
|
||||
Dim directoryPath As String = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"RPST", "logs"
|
||||
)
|
||||
|
||||
If Not Directory.Exists(directoryPath) Then
|
||||
Directory.CreateDirectory(directoryPath)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Collects and validates user inputs from StartForm and returns them as a Tuple.
|
||||
''' </summary>
|
||||
''' <returns>
|
||||
''' Tuple containing:
|
||||
''' Keyword (String) - Keyword entered by user in theMainWindow.
|
||||
''' Subreddit (String) - Subreddit entered by user in theMainWindow.
|
||||
''' Listing (String) - Listing chosen by user in the StartForm, defaults to 'top' if none is selected.
|
||||
''' Limit (Integer) - Limit entered by user in the StartForm, defaults to 10 if the entered value is over 100.
|
||||
''' Timeframe (String) - Timeframe chosen by user in the StartForm, defaults to 'all' if none is selected.
|
||||
''' </returns>
|
||||
''' <remarks>
|
||||
''' If keyword or subreddit are empty, Displays a warning and returns nothing.
|
||||
''' </remarks>
|
||||
Public Shared Function CollectInputs() As (Keyword As String, Subreddit As String, Listing As String, Limit As Integer, Timeframe As String)?
|
||||
Dim keyword As String = MainWindow.TextBoxKeyword.Text.Trim()
|
||||
Dim subreddit As String = MainWindow.TextBoxSubreddit.Text.Trim()
|
||||
' Convert the Listing and Subreddit to lowercase using InvariantCulture.
|
||||
Dim listing As String = If(String.IsNullOrEmpty(MainWindow.ComboBoxListing.Text), "top", MainWindow.ComboBoxListing.Text.ToLower(Globalization.CultureInfo.InvariantCulture).Trim())
|
||||
Dim timeframe As String = If(String.IsNullOrEmpty(MainWindow.ComboBoxTimeframe.Text), "all", MainWindow.ComboBoxTimeframe.Text.ToLower(Globalization.CultureInfo.InvariantCulture).Trim())
|
||||
Dim limit As Integer = MainWindow.NumericUpDownLimit.Value
|
||||
|
||||
' Validate inputs.
|
||||
If String.IsNullOrEmpty(keyword) AndAlso String.IsNullOrEmpty(subreddit) Then
|
||||
MessageBox.Show("Keyword and Subreddit should not be empty.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
|
||||
Return Nothing
|
||||
ElseIf String.IsNullOrEmpty(keyword) Then
|
||||
MessageBox.Show("Keyword field should not be empty.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
|
||||
Return Nothing
|
||||
ElseIf String.IsNullOrEmpty(subreddit) Then
|
||||
MessageBox.Show("Subreddit field should not be empty.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
|
||||
Return Nothing
|
||||
End If
|
||||
Return (keyword, subreddit, listing, limit, timeframe)
|
||||
End Function
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Saves the gives posts' data to a JSON file.
|
||||
''' </summary>
|
||||
''' <param name="Posts">The object containing posts to be saved.</param>
|
||||
''' <remarks>
|
||||
''' This function allows the user to select a location to save the posts.
|
||||
''' If the user confirms the save location, the posts will be serialized
|
||||
''' to JSON with an indented format and written to the chosen file.
|
||||
''' A success message will be displayed to the user upon successful save.
|
||||
''' </remarks>
|
||||
Public Shared Sub SavePostsToJson(posts As Object)
|
||||
Dim saveFileDialog As New SaveFileDialog With {
|
||||
.Filter = "JSON files (*.json)|*.json",
|
||||
.Title = "Save posts to JSON"
|
||||
}
|
||||
|
||||
If saveFileDialog.ShowDialog() = DialogResult.OK Then
|
||||
Dim fileName As String = saveFileDialog.FileName
|
||||
Dim serializerSettings As New JsonSerializerSettings With {
|
||||
.Formatting = Formatting.Indented
|
||||
}
|
||||
Dim json As String = JsonConvert.SerializeObject(posts, serializerSettings)
|
||||
|
||||
File.WriteAllText(fileName, json)
|
||||
|
||||
MessageBox.Show($"Posts saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
|
||||
''' <summary>
|
||||
''' Saves Reddit posts contained in a JArray to a CSV file.
|
||||
''' </summary>
|
||||
''' <param name="posts">A JArray containing the Reddit posts to be saved.</param>
|
||||
''' <remarks>
|
||||
''' This function displays a SaveFileDialog to allow the user to specify the file name and location.
|
||||
''' It then iterates through the JArray to write each post's details (totalPosts, title, subreddit, author, score) into the selected CSV file.
|
||||
''' </remarks>
|
||||
Public Shared Sub SavePostsToCSV(posts As JArray)
|
||||
Dim saveFileDialog As New SaveFileDialog With {
|
||||
.Filter = "CSV files (*.csv)|*.csv",
|
||||
.Title = "Save posts to CSV"
|
||||
}
|
||||
|
||||
If saveFileDialog.ShowDialog() = DialogResult.OK Then
|
||||
Dim fileName As String = saveFileDialog.FileName
|
||||
Using csvWriter As New StreamWriter(fileName)
|
||||
' Write the header.
|
||||
csvWriter.WriteLine("Index,Author,ID,Subreddit,Visibility,Thumbnail,NSFW,Gilded,Upvotes,Upvote Ratio,Downvotes,Award,Top Award,Is cross-postable?,Score,Category,Text,Domain,Permalink,Created At,Approved At,Approved By")
|
||||
|
||||
Dim postCount As Integer = 0
|
||||
For Each post In posts
|
||||
postCount += 1
|
||||
csvWriter.WriteLine($"{postCount},{post("data")("author")},{post("data")("id")},{post("data")("subreddit_name_prefixed")},{post("data")("subreddit_type")},{post("data")("thumbnail")},{post("data")("over_18")},{post("data")("gilded")},{post("data")("ups")},{post("data")("upvote_ratio")},{post("data")("downs")},{post("data")("total_awards_received")},{post("data")("top_awarded_type")},{post("data")("is_crosspostable")},{post("data")("score")},{post("data")("category")},{post("data")("selftext")},{post("data")("domain")},{post("data")("permalink")},{post("data")("created")},{post("data")("approved_at_utc")},{post("data")("approved_by")}")
|
||||
Next
|
||||
End Using
|
||||
|
||||
MessageBox.Show($"Posts saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information)
|
||||
End If
|
||||
End Sub
|
||||
End Class
|
||||
Reference in New Issue
Block a user