#region License Information (GPL v3) /* ShareX - A program that allows you to take screenshots and share any file type Copyright (c) 2007-2025 ShareX Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Optionally you can also view the license at . */ #endregion License Information (GPL v3) using Microsoft.Data.Sqlite; using Newtonsoft.Json; using ShareX.HelpersLib; using System; using System.Collections.Generic; namespace ShareX.HistoryLib { public class HistoryManagerSQLite : HistoryManager, IDisposable { private SqliteConnection connection; public HistoryManagerSQLite(string filePath) : base(filePath) { Connect(filePath); EnsureDatabase(); } private void Connect(string filePath) { FileHelpers.CreateDirectoryFromFilePath(filePath); string connectionString = $"Data Source={filePath}"; connection = new SqliteConnection(connectionString); connection.Open(); SetBusyTimeout(5000); } private void SetBusyTimeout(int milliseconds) { using (SqliteCommand cmd = connection.CreateCommand()) { cmd.CommandText = $"PRAGMA busy_timeout = {milliseconds};"; cmd.ExecuteNonQuery(); } } private void EnsureDatabase() { using (SqliteCommand cmd = connection.CreateCommand()) { cmd.CommandText = @" CREATE TABLE IF NOT EXISTS History ( Id INTEGER PRIMARY KEY AUTOINCREMENT, FileName TEXT, FilePath TEXT, DateTime TEXT, Type TEXT, Host TEXT, URL TEXT, ThumbnailURL TEXT, DeletionURL TEXT, ShortenedURL TEXT, Tags TEXT ); "; cmd.ExecuteNonQuery(); } } internal override List Load(string dbPath) { List items = new List(); using (SqliteCommand cmd = new SqliteCommand("SELECT * FROM History;", connection)) using (SqliteDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { HistoryItem item = new HistoryItem() { Id = (long)reader["Id"], FileName = reader["FileName"].ToString(), FilePath = reader["FilePath"].ToString(), DateTime = DateTime.Parse(reader["DateTime"].ToString()), Type = reader["Type"].ToString(), Host = reader["Host"].ToString(), URL = reader["URL"].ToString(), ThumbnailURL = reader["ThumbnailURL"].ToString(), DeletionURL = reader["DeletionURL"].ToString(), ShortenedURL = reader["ShortenedURL"].ToString(), Tags = JsonConvert.DeserializeObject>(reader["Tags"]?.ToString() ?? "{}") }; items.Add(item); } } return items; } protected override bool Append(string dbPath, IEnumerable historyItems) { using (SqliteTransaction transaction = connection.BeginTransaction()) { foreach (HistoryItem item in historyItems) { using (SqliteCommand cmd = connection.CreateCommand()) { cmd.CommandText = @" INSERT INTO History (FileName, FilePath, DateTime, Type, Host, URL, ThumbnailURL, DeletionURL, ShortenedURL, Tags) VALUES (@FileName, @FilePath, @DateTime, @Type, @Host, @URL, @ThumbnailURL, @DeletionURL, @ShortenedURL, @Tags); SELECT last_insert_rowid();"; cmd.Parameters.AddWithValue("@FileName", item.FileName ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@FilePath", item.FilePath ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@DateTime", item.DateTime.ToString("o") ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@Type", item.Type ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@Host", item.Host ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@URL", item.URL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@ThumbnailURL", item.ThumbnailURL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@DeletionURL", item.DeletionURL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@ShortenedURL", item.ShortenedURL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@Tags", item.Tags != null ? JsonConvert.SerializeObject(item.Tags) : (object)DBNull.Value); item.Id = (long)cmd.ExecuteScalar(); } } transaction.Commit(); } return true; } public void Edit(HistoryItem item) { using (SqliteTransaction transaction = connection.BeginTransaction()) using (SqliteCommand cmd = connection.CreateCommand()) { cmd.CommandText = @" UPDATE History SET FileName = @FileName, FilePath = @FilePath, DateTime = @DateTime, Type = @Type, Host = @Host, URL = @URL, ThumbnailURL = @ThumbnailURL, DeletionURL = @DeletionURL, ShortenedURL = @ShortenedURL, Tags = @Tags WHERE Id = @Id;"; cmd.Parameters.AddWithValue("@FileName", item.FileName ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@FilePath", item.FilePath ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@DateTime", item.DateTime.ToString("o") ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@Type", item.Type ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@Host", item.Host ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@URL", item.URL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@ThumbnailURL", item.ThumbnailURL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@DeletionURL", item.DeletionURL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@ShortenedURL", item.ShortenedURL ?? (object)DBNull.Value); cmd.Parameters.AddWithValue("@Tags", item.Tags != null ? JsonConvert.SerializeObject(item.Tags) : (object)DBNull.Value); cmd.Parameters.AddWithValue("@Id", item.Id); cmd.ExecuteNonQuery(); transaction.Commit(); } } public void Delete(params HistoryItem[] items) { if (items != null && items.Length > 0) { using (SqliteTransaction transaction = connection.BeginTransaction()) using (SqliteCommand cmd = connection.CreateCommand()) { cmd.CommandText = "DELETE FROM History WHERE Id = @Id;"; SqliteParameter idParam = cmd.CreateParameter(); idParam.ParameterName = "@Id"; cmd.Parameters.Add(idParam); foreach (HistoryItem item in items) { idParam.Value = item.Id; cmd.ExecuteNonQuery(); } transaction.Commit(); } } } public void MigrateFromJSON(string jsonFilePath) { HistoryManagerJSON jsonManager = new HistoryManagerJSON(jsonFilePath); List items = jsonManager.Load(jsonFilePath); if (items.Count > 0) { Append(items); } } public void Dispose() { connection?.Dispose(); } } }