() { creds.accessKey, creds.secretKey, creds.serviceURL, creds.bucketName, creds.bucketURL };
foreach (var (item, index) in Instances.Select((v, i) => (v, i)))
{
- PlaceholderAdorner adorner = Helpers.TextBoxHelper.GetPlaceholderAdorner(item);
+ PlaceholderAdorner adorner = GetPlaceholderAdorner(item);
item.Text = (mode == ShowMode.Show) ? Keys[index] : new string('*', Keys[index].Length);
item.IsEnabled = (mode == ShowMode.Show) ? true : false;
if (Keys[index].Length > 0)
diff --git a/AMDiscordRPC/UIComponents/OptionsWindow.xaml b/AMDiscordRPC/UIComponents/OptionsWindow.xaml
new file mode 100644
index 0000000..37fdd44
--- /dev/null
+++ b/AMDiscordRPC/UIComponents/OptionsWindow.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs b/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs
new file mode 100644
index 0000000..4e4e68c
--- /dev/null
+++ b/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs
@@ -0,0 +1,23 @@
+
+using System.Management.Instrumentation;
+using System.Windows;
+
+namespace AMDiscordRPC.UIComponents
+{
+ ///
+ /// Interaction logic for OptionsWindow.xaml
+ ///
+ public partial class OptionsWindow : Window
+ {
+ private static OptionsWindow Instance;
+ public OptionsWindow()
+ {
+ InitializeComponent();
+ Instance = this;
+ Instance.Loaded += (s, e) =>
+ {
+
+ };
+ }
+ }
+}
diff --git a/AMDiscordRPC/log4netconf.xml b/AMDiscordRPC/log4netconf.xml
index 30837d1..8f1ebc9 100644
--- a/AMDiscordRPC/log4netconf.xml
+++ b/AMDiscordRPC/log4netconf.xml
@@ -4,23 +4,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 8e17c67..3b9cb6a 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@
AMDiscordRPC
An another Apple Music Discord RPC
+[Support Server](https://discord.gg/5trvjuqgm8)
## Usage
[Download](https://github.com/CrawLeyYou/AMDiscordRPC/releases/latest) latest release and make sure you have [.NET Framework 4.7.2](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472).
From 7b0eb9b5cbbeb0b956b3c674ee9ad2169e4137d9 Mon Sep 17 00:00:00 2001
From: CrawLeyYou <60201017+CrawLeyYou@users.noreply.github.com>
Date: Tue, 9 Sep 2025 20:13:59 +0300
Subject: [PATCH 2/5] Push not finished features and bug fixes
---
AMDiscordRPC/AMDiscordRPC.cs | 8 +++-----
AMDiscordRPC/Covers.cs | 20 ++++++++++++++-----
AMDiscordRPC/Database.cs | 17 +++++++++++-----
AMDiscordRPC/Discord.cs | 3 +++
AMDiscordRPC/Globals.cs | 13 ++++++++----
AMDiscordRPC/UIComponents/InputWindow.xaml.cs | 5 ++++-
AMDiscordRPC/UIComponents/OptionsWindow.xaml | 2 +-
.../UIComponents/OptionsWindow.xaml.cs | 15 +++++++++++++-
8 files changed, 61 insertions(+), 22 deletions(-)
diff --git a/AMDiscordRPC/AMDiscordRPC.cs b/AMDiscordRPC/AMDiscordRPC.cs
index 07dabcb..0657ea7 100644
--- a/AMDiscordRPC/AMDiscordRPC.cs
+++ b/AMDiscordRPC/AMDiscordRPC.cs
@@ -45,7 +45,7 @@ static void Main(string[] args)
}
};
CheckDatabaseIntegrity();
- InitDBCreds();
+ ConfigureFromDB();
CheckFFmpeg();
InitS3();
AMEvent();
@@ -144,7 +144,7 @@ static void AMEvent()
if (oldValue == 0) oldValue = slider.AsSlider().Value;
DateTime currentTime = DateTime.UtcNow;
DateTime startTime = currentTime.Subtract(subractThis);
- DateTime endTime = currentTime.AddSeconds(slider.AsSlider().Maximum).Subtract(subractThis);
+ DateTime endTime = startTime.AddSeconds(slider.AsSlider().Maximum);
DateTime oldEndTime = DateTime.MinValue;
DateTime oldStartTime = DateTime.MinValue;
bool isSingle = dashSplit[dashSplit.Length - 1].Contains("Single");
@@ -214,8 +214,6 @@ static void AMEvent()
}
else format = AudioFormat.AAC;
oldValue = 0;
- startTime = currentTime.Subtract(subractThis);
- endTime = currentTime.AddSeconds(slider.AsSlider().Maximum).Subtract(subractThis);
oldStartTime = startTime;
oldEndTime = endTime;
AMSongDataEvent.ChangeSong(new SongData(currentSong, (isSingle) ? string.Join("-", dashSplit.Take(dashSplit.Length - 1).ToArray()) : string.Join("—", currentArtistAlbum.Split('—').Take(2).ToArray()), currentArtistAlbum.Split('—').Length <= 1, startTime, endTime, format));
@@ -256,7 +254,7 @@ static void AMEvent()
}
Thread.Sleep(20);
}
- if (!AMAttached & AppleMusicProc.HasExited != true)
+ if (!AMAttached && AppleMusicProc.HasExited != true)
{
log.Info("Something happened which needs to reattach");
client.ClearPresence();
diff --git a/AMDiscordRPC/Covers.cs b/AMDiscordRPC/Covers.cs
index 02f867e..4a9e667 100644
--- a/AMDiscordRPC/Covers.cs
+++ b/AMDiscordRPC/Covers.cs
@@ -4,6 +4,7 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using AngleSharp.Dom;
using static AMDiscordRPC.Database;
using static AMDiscordRPC.Globals;
using static AMDiscordRPC.Playlist;
@@ -30,9 +31,10 @@ private static async Task AsyncFetchiTunes(string album, string
(
imageRes["results"][0]["artworkUrl100"].ToString(),
imageRes["results"][0]["trackViewUrl"].ToString(),
- imageRes["results"][0]["collectionName"].ToString()
+ imageRes["results"][0]["collectionName"].ToString(),
+ imageRes["results"][0]["artistViewUrl"].ToString()
);
- Database.UpdateAlbum(new Database.SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL));
+ UpdateAlbum(new SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL, null, null, null, webRes.artistURL));
CoverThread = null;
return webRes;
}
@@ -58,6 +60,11 @@ private static async Task AsyncFetchiTunes(string album, string
}
}
+ public static async Task AsyncArtistProfileFetch(string url)
+ {
+ return null;
+ }
+
public static async Task AsyncAMFetch(string album, string searchStr)
{
log.Debug($"https://music.apple.com/{AMRegion.ToLower()}/search?term={searchStr}");
@@ -68,12 +75,15 @@ public static async Task AsyncAMFetch(string album, string sear
{
string DOMasAString = await AMRequest.Content.ReadAsStringAsync();
IHtmlDocument document = parser.ParseDocument(DOMasAString);
+
WebSongResponse webRes = new WebSongResponse(
- document.DocumentElement.QuerySelectorAll("div.top-search-lockup__artwork > div > picture > source")[1].GetAttribute("srcset").Split(' ')[0],
- document.DocumentElement.QuerySelector("div.top-search-lockup__action > a").GetAttribute("href")
+ document.DocumentElement.QuerySelectorAll("div.track-lockup__artwork-wrapper > div > picture > source")[1].GetAttribute("srcset").Split(',')[1].Split(' ')[0],
+ document.DocumentElement.QuerySelectorAll("div.track-lockup__clamp-wrapper > a")[0].GetAttribute("href"),
+ null,
+ document.DocumentElement.QuerySelectorAll("div.track-lockup__clamp-wrapper > span > a")[0].GetAttribute("href")
);
CoverThread = null;
- Database.UpdateAlbum(new Database.SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL));
+ UpdateAlbum(new Database.SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL, null, null, null, webRes.artistURL));
return webRes;
}
else
diff --git a/AMDiscordRPC/Database.cs b/AMDiscordRPC/Database.cs
index 2594fb2..684c33e 100644
--- a/AMDiscordRPC/Database.cs
+++ b/AMDiscordRPC/Database.cs
@@ -11,9 +11,10 @@ internal class Database
private static SQLiteConnection sqlite;
public static readonly Dictionary sqlMap = new Dictionary()
{
- {"coverTable", "album TEXT PRIMARY KEY NOT NULL, source TEXT, redirURL TEXT DEFAULT 'https://music.apple.com/home', animated BOOLEAN CHECK (animated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT" },
+ {"coverTable", "album TEXT PRIMARY KEY NOT NULL, source TEXT, redirURL TEXT DEFAULT 'https://music.apple.com/home', artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistSource TEXT, animated BOOLEAN CHECK (animated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT" },
{"creds", "S3_accessKey TEXT, S3_secretKey TEXT, S3_serviceURL TEXT, S3_bucketName TEXT, S3_bucketURL TEXT, S3_isSpecificKey BOOLEAN CHECK (S3_isSpecificKey IN (0,1)), FFmpegPath TEXT" },
- {"logs", "timestamp INTEGER, type TEXT, occuredAt TEXT, message TEXT" }
+ {"logs", "timestamp INTEGER, type TEXT, occuredAt TEXT, message TEXT" },
+ {"clientSettings", "smallImage INTEGER"}
};
private static void InitDatabase()
@@ -57,6 +58,7 @@ private static void CreateDatabase()
}
}
+ // Note: source, streamurl, animated, animatedUrl can be stored in external table so we decrease the file size of database
private static void CheckForeignKeys()
{
ExecuteNonQueryCommand("PRAGMA foreign_keys = on");
@@ -119,7 +121,9 @@ public static SQLCoverResponse GetAlbumDataFromSQL(string album)
reader.GetString(2),
((!reader.IsDBNull(3)) ? reader.GetBoolean(3) : null),
((!reader.IsDBNull(4)) ? reader.GetString(4) : null),
- ((!reader.IsDBNull(5)) ? reader.GetString(5) : null));
+ ((!reader.IsDBNull(5)) ? reader.GetString(5) : null),
+ reader.GetString(6)
+ );
}
}
return null;
@@ -155,7 +159,7 @@ private static void CheckColumns()
// Recovery functionality will be added next release.
}
}
- else if (column == null)
+ else if (column == null && !item.Value.primaryKey)
{
ExecuteNonQueryCommand($"ALTER TABLE {table} ADD COLUMN {SQLInfo}");
}
@@ -255,8 +259,10 @@ public class SQLCoverResponse
public bool? animated { get; set; }
public string streamURL { get; set; }
public string animatedURL { get; set; }
+ public string artistRedirURL { get; set; }
- public SQLCoverResponse(string album = null, string source = null, string redirURL = null, bool? animated = null, string streamURL = null, string animatedURL = null)
+
+ public SQLCoverResponse(string album = null, string source = null, string redirURL = null, bool? animated = null, string streamURL = null, string animatedURL = null, string artistRedirURL = null)
{
this.album = album;
this.source = source;
@@ -264,6 +270,7 @@ public SQLCoverResponse(string album = null, string source = null, string redirU
this.animated = animated;
this.streamURL = streamURL;
this.animatedURL = animatedURL;
+ this.artistRedirURL = artistRedirURL;
}
public List GetNotNullKeys()
diff --git a/AMDiscordRPC/Discord.cs b/AMDiscordRPC/Discord.cs
index 8912d27..715c973 100644
--- a/AMDiscordRPC/Discord.cs
+++ b/AMDiscordRPC/Discord.cs
@@ -80,6 +80,7 @@ public static void SetPresence(SongData x, WebSongResponse resp)
{
Type = ActivityType.Listening,
Details = ConvertToValidString(x.SongName),
+ StateUrl = resp.artistURL,
StatusDisplay = StatusDisplayType.State,
State = (x.IsMV) ? x.ArtistandAlbumName : ConvertToValidString(x.ArtistandAlbumName.Split('—')[0]),
Assets = new Assets()
@@ -99,6 +100,8 @@ public static void SetPresence(SongData x, WebSongResponse resp)
End = x.EndTime,
}
};
+ if (oldData.Assets.LargeImageText.Length == 1)
+ oldData.Assets.LargeImageText = $"{oldData.Assets.LargeImageText}"; // THIS HAS U+200D AT THE END OF STRING TO FIX '"large_text" length must be at least 2 characters long' ERROR
client.SetPresence(oldData);
if (resp.artworkURL != null && !resp.artworkURL.Contains((S3_Credentials != null) ? (S3_Credentials.GetNullKeys().Count == 0) ? S3_Credentials.bucketURL : "" : ""))
{
diff --git a/AMDiscordRPC/Globals.cs b/AMDiscordRPC/Globals.cs
index 231b826..c4fbd51 100644
--- a/AMDiscordRPC/Globals.cs
+++ b/AMDiscordRPC/Globals.cs
@@ -121,9 +121,9 @@ public static string ConvertToValidString(string data)
return data;
}
- public static void InitDBCreds()
+ public static void ConfigureFromDB()
{
- using (SQLiteDataReader dbResp = Database.ExecuteReaderCommand($"SELECT {string.Join(", ", Regex.Matches(Database.sqlMap["creds"], @"S3_\w+").FilterRepeatMatches())} FROM creds LIMIT 1"))
+ using (SQLiteDataReader dbResp = ExecuteReaderCommand($"SELECT {string.Join(", ", Regex.Matches(sqlMap["creds"], @"S3_\w+").FilterRepeatMatches())} FROM creds LIMIT 1"))
{
while (dbResp.Read())
{
@@ -136,6 +136,8 @@ public static void InitDBCreds()
((!dbResp.IsDBNull(5)) ? dbResp.GetBoolean(5) : null));
}
}
+
+ SelectedSmallImage = (SmallImage)Convert.ToInt32(ExecuteScalarCommand("SELECT smallImage FROM clientSettings"));
}
private static void StartFFmpegProcess(string filename)
@@ -279,12 +281,14 @@ public class WebSongResponse
public string artworkURL { get; set; }
public string trackURL { get; set; }
public string trackName { get; set; }
+ public string artistURL { get; set; }
- public WebSongResponse(string artworkURL = null, string trackURL = null, string trackName = null)
+ public WebSongResponse(string artworkURL = null, string trackURL = null, string trackName = null, string artistURL = null)
{
this.artworkURL = artworkURL;
this.trackURL = trackURL;
this.trackName = trackName;
+ this.artistURL = artistURL;
}
public override bool Equals(object obj)
@@ -292,7 +296,8 @@ public override bool Equals(object obj)
return obj is WebSongResponse other &&
artworkURL == other.artworkURL &&
trackURL == other.trackURL &&
- trackName == other.trackName;
+ trackName == other.trackName &&
+ artistURL == other.artistURL;
}
}
}
diff --git a/AMDiscordRPC/UIComponents/InputWindow.xaml.cs b/AMDiscordRPC/UIComponents/InputWindow.xaml.cs
index 723d161..9d57c8a 100644
--- a/AMDiscordRPC/UIComponents/InputWindow.xaml.cs
+++ b/AMDiscordRPC/UIComponents/InputWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+
+using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
@@ -79,6 +80,8 @@ private void PutValues(S3_Creds creds, ShowMode mode = ShowMode.Hide)
foreach (var (item, index) in Instances.Select((v, i) => (v, i)))
{
PlaceholderAdorner adorner = GetPlaceholderAdorner(item);
+ if (Keys[index] == null)
+ return;
item.Text = (mode == ShowMode.Show) ? Keys[index] : new string('*', Keys[index].Length);
item.IsEnabled = (mode == ShowMode.Show) ? true : false;
if (Keys[index].Length > 0)
diff --git a/AMDiscordRPC/UIComponents/OptionsWindow.xaml b/AMDiscordRPC/UIComponents/OptionsWindow.xaml
index 37fdd44..8c4a0af 100644
--- a/AMDiscordRPC/UIComponents/OptionsWindow.xaml
+++ b/AMDiscordRPC/UIComponents/OptionsWindow.xaml
@@ -8,7 +8,7 @@
Icon="../Resources/Logo Black 32.ico"
d:DesignHeight="450" d:DesignWidth="800" d:MaxHeight="450" d:MaxWidth="800" d:ResizeMode="NoResize" ResizeMode="NoResize" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" Title="Options">
-
+
diff --git a/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs b/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs
index 4e4e68c..eb3c5de 100644
--- a/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs
+++ b/AMDiscordRPC/UIComponents/OptionsWindow.xaml.cs
@@ -1,6 +1,10 @@
+using System;
using System.Management.Instrumentation;
+using System.Text.RegularExpressions;
using System.Windows;
+using System.Windows.Controls;
+using static AMDiscordRPC.Globals;
namespace AMDiscordRPC.UIComponents
{
@@ -16,8 +20,17 @@ public OptionsWindow()
Instance = this;
Instance.Loaded += (s, e) =>
{
-
+ smallImage.SelectedIndex = (int)SelectedSmallImage;
};
}
+
+ private void SmallImage_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ SelectedSmallImage = (SmallImage)smallImage.SelectedIndex;
+ if (Database.ExecuteScalarCommand("SELECT smallImage FROM clientSettings") == null)
+ Database.ExecuteNonQueryCommand($"INSERT INTO clientSettings (smallImage) VALUES ({smallImage.SelectedIndex})");
+ else
+ Database.ExecuteNonQueryCommand($"UPDATE clientSettings SET (smallImage) = ({smallImage.SelectedIndex})");
+ }
}
}
From f74a9d19378c76fb8665bae1b6be1f9f0c3d13bd Mon Sep 17 00:00:00 2001
From: CrawLeyYou <60201017+CrawLeyYou@users.noreply.github.com>
Date: Sat, 4 Oct 2025 09:57:06 +0300
Subject: [PATCH 3/5] Add new database base and rewrite checks
---
AMDiscordRPC/Covers.cs | 6 ++---
AMDiscordRPC/Database.cs | 55 +++++++++++++++++++++++++++++++++-------
AMDiscordRPC/Globals.cs | 12 ++++++---
3 files changed, 57 insertions(+), 16 deletions(-)
diff --git a/AMDiscordRPC/Covers.cs b/AMDiscordRPC/Covers.cs
index 4a9e667..0d207e1 100644
--- a/AMDiscordRPC/Covers.cs
+++ b/AMDiscordRPC/Covers.cs
@@ -1,10 +1,10 @@
-using AngleSharp.Html.Dom;
+using AngleSharp.Dom;
+using AngleSharp.Html.Dom;
using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using AngleSharp.Dom;
using static AMDiscordRPC.Database;
using static AMDiscordRPC.Globals;
using static AMDiscordRPC.Playlist;
@@ -129,7 +129,7 @@ public static async Task GetCover(string album, string searchSt
{
try
{
- log.Debug($"https://music.apple.com/us/search?term={searchStr}");
+ log.Debug($"https://music.apple.com/{AMRegion.ToLower()}/search?term={searchStr}");
SQLCoverResponse cover = GetAlbumDataFromSQL(album);
if (cover != null)
{
diff --git a/AMDiscordRPC/Database.cs b/AMDiscordRPC/Database.cs
index 684c33e..46a17ac 100644
--- a/AMDiscordRPC/Database.cs
+++ b/AMDiscordRPC/Database.cs
@@ -1,4 +1,5 @@
-using System;
+using Amazon.Runtime.Internal.Transform;
+using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Linq;
@@ -11,7 +12,11 @@ internal class Database
private static SQLiteConnection sqlite;
public static readonly Dictionary sqlMap = new Dictionary()
{
- {"coverTable", "album TEXT PRIMARY KEY NOT NULL, source TEXT, redirURL TEXT DEFAULT 'https://music.apple.com/home', artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistSource TEXT, animated BOOLEAN CHECK (animated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT" },
+ //{"coverTable", "album TEXT PRIMARY KEY NOT NULL, source TEXT, redirURL TEXT DEFAULT 'https://music.apple.com/home', artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistSource TEXT, animated BOOLEAN CHECK (animated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT" },
+ {"coverTableNew", "coverID INTEGER PRIMARY KEY AUTOINCREMENT, staticCoverURL TEXT NOT NULL, isAnimated BOOLEAN CHECK (isAnimated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT"},
+ {"artistTable", "artistID INTEGER PRIMARY KEY AUTOINCREMENT, artistName TEXT NOT NULL, artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistProfileSource TEXT"},
+ {"albumTable", "albumID INTEGER PRIMARY KEY AUTOINCREMENT, albumName TEXT NOT NULL, albumURL TEXT UNIQUE, isSingle BOOLEAN CHECK (isSingle IN (0,1)), coverID INTEGER, artistID INTEGER, FOREIGN KEY (coverID) REFERENCES coverTableNew(coverID), FOREIGN KEY (artistID) REFERENCES artistTable(artistID)"},
+ {"songTable", "songTitle TEXT, songURL TEXT, albumID INTEGER, artistID INTEGER, FOREIGN KEY (albumID) REFERENCES albumTable(albumID), FOREIGN KEY (artistID) REFERENCES artistTable(artistID)"},
{"creds", "S3_accessKey TEXT, S3_secretKey TEXT, S3_serviceURL TEXT, S3_bucketName TEXT, S3_bucketURL TEXT, S3_isSpecificKey BOOLEAN CHECK (S3_isSpecificKey IN (0,1)), FFmpegPath TEXT" },
{"logs", "timestamp INTEGER, type TEXT, occuredAt TEXT, message TEXT" },
{"clientSettings", "smallImage INTEGER"}
@@ -39,7 +44,7 @@ public static void CheckDatabaseIntegrity()
{
try
{
- //CheckForeignKeys(); we don't have use case for relationships rn so no need to waste resources on this check
+ CheckForeignKeys();
CheckTables();
CheckColumns();
}
@@ -133,12 +138,21 @@ private static void CheckColumns()
{
foreach (var table in sqlMap.Keys)
{
- SQLiteDataReader data = ExecuteReaderCommand($"PRAGMA table_info({table})");
+ SQLiteDataReader data = ExecuteReaderCommand($"SELECT * FROM sqlite_master");
Dictionary tableData = new Dictionary();
while (data.Read())
{
- tableData.Add(data.GetString(1), new ColumnInfo(data.GetString(2), data.GetBoolean(3), (!data.IsDBNull(4)) ? data.GetString(4) : null, data.GetBoolean(5)));
+ if (data.GetString(0) == "table" && data.GetString(2) == table)
+ {
+ string sqlStr = string.Join("(", data.GetString(4).Split(new[] { "CREATE TABLE " }, StringSplitOptions.None)[1].Split('(').Skip(1)).TrimEnd(1);
+ var temp = ConvertSQLStringToColumnInfo(sqlStr);
+ foreach (var keyValuePair in temp)
+ {
+ //log.Debug($"{keyValuePair.Key}, autoIncrement: {keyValuePair.Value.isAutoIncrementing}, defaultValue: {keyValuePair.Value.defaultValue}, foreignKey: [Key: {keyValuePair.Value.foreignKey?.key}, refColumn: {keyValuePair.Value.foreignKey?.refColumn}, refTable: {keyValuePair.Value.foreignKey?.refTable}], nullCheck: {keyValuePair.Value.nullCheck}, primaryKey: {keyValuePair.Value.primaryKey}, type: {keyValuePair.Value.type}");
+ tableData.Add(keyValuePair.Key, keyValuePair.Value);
+ }
+ }
}
foreach (var item in ConvertSQLStringToColumnInfo(sqlMap[table]))
@@ -148,7 +162,7 @@ private static void CheckColumns()
if (!item.Value.Equals(column) && column != null)
{
log.Debug($"Corrupted/Outdated column:{SQLInfo.Split(' ')[0]} found.");
- if (!item.Value.primaryKey && ((item.Value.nullCheck && item.Value.defaultValue != null) || !item.Value.nullCheck))
+ if (!item.Value.primaryKey && ((item.Value.nullCheck && item.Value.defaultValue != null) || !item.Value.nullCheck) && item.Value.foreignKey == null)
{
ExecuteNonQueryCommand($"ALTER TABLE {table} DROP COLUMN {SQLInfo.Split(' ')[0]}");
ExecuteNonQueryCommand($"ALTER TABLE {table} ADD COLUMN {SQLInfo}");
@@ -174,11 +188,14 @@ private static Dictionary ConvertSQLStringToColumnInfo(strin
foreach (var column in columns)
{
string[] splitStr = column.Split(' ');
+ if (splitStr[0] == "FOREIGN") continue;
columnsMap.Add(splitStr[0], new ColumnInfo(
splitStr[1],
column.Contains("NOT NULL"),
(column.Contains("DEFAULT")) ? column.Split(new[] { "DEFAULT " }, StringSplitOptions.None)[1] : null, //This is not a proper way to do this but it works for now (DEFAULT value must be on the last section of the SQL Command)
- column.Contains("PRIMARY KEY")
+ column.Contains("PRIMARY KEY"),
+ column.Contains("AUTOINCREMENT"),
+ (sqlStr.Contains($"FOREIGN KEY ({splitStr[0]})")) ? new ForeignKey(splitStr[0], columns.Where(a => a.Contains($"FOREIGN KEY ({splitStr[0]})")).First().Split(new[] { "REFERENCES " }, StringSplitOptions.None)[1].Split('(')[0], columns.Where(a => a.Contains($"FOREIGN KEY ({splitStr[0]})")).First().Split(new[] { "REFERENCES " }, StringSplitOptions.None)[1].Split('(')[1].Split(')')[0]) : null
));
}
return columnsMap;
@@ -232,13 +249,17 @@ private class ColumnInfo
public bool nullCheck { get; set; }
public string defaultValue { get; set; }
public bool primaryKey { get; set; }
+ public bool isAutoIncrementing { get; set; }
+ public ForeignKey foreignKey { get; set; }
- public ColumnInfo(string type, bool nullCheck, string defaultValue, bool primaryKey)
+ public ColumnInfo(string type, bool nullCheck, string defaultValue, bool primaryKey, bool isAutoIncrementing, ForeignKey foreignKey = null)
{
this.type = type;
this.nullCheck = nullCheck;
this.defaultValue = defaultValue;
this.primaryKey = primaryKey;
+ this.isAutoIncrementing = isAutoIncrementing;
+ this.foreignKey = foreignKey;
}
public override bool Equals(object obj)
@@ -247,7 +268,23 @@ public override bool Equals(object obj)
type == other.type &&
nullCheck == other.nullCheck &&
defaultValue == other.defaultValue &&
- primaryKey == other.primaryKey;
+ primaryKey == other.primaryKey &&
+ isAutoIncrementing == other.isAutoIncrementing &&
+ foreignKey == other.foreignKey;
+ }
+ }
+
+ public class ForeignKey
+ {
+ public string key { get; set; }
+ public string refTable { get; set; }
+ public string refColumn { get; set; }
+
+ public ForeignKey(string key, string refTable, string refColumn)
+ {
+ this.key = key;
+ this.refTable = refTable;
+ this.refColumn = refColumn;
}
}
diff --git a/AMDiscordRPC/Globals.cs b/AMDiscordRPC/Globals.cs
index c4fbd51..e0a1bff 100644
--- a/AMDiscordRPC/Globals.cs
+++ b/AMDiscordRPC/Globals.cs
@@ -55,9 +55,9 @@ public static void ConfigureLogger()
LevelMax = Level.Fatal,
LevelMin = Level.Info
};
- #if DEBUG
- lrf.LevelMin = Level.Debug;
- #endif
+#if DEBUG
+ lrf.LevelMin = Level.Debug;
+#endif
lrf.ActivateOptions();
PatternLayout pl = new PatternLayout
@@ -296,9 +296,13 @@ public override bool Equals(object obj)
return obj is WebSongResponse other &&
artworkURL == other.artworkURL &&
trackURL == other.trackURL &&
- trackName == other.trackName &&
+ trackName == other.trackName &&
artistURL == other.artistURL;
}
}
+ public static String TrimEnd(this String str, int count)
+ {
+ return str.Substring(0, str.Length - count);
+ }
}
}
\ No newline at end of file
From 7e85228dc8aee0ed7c7a4a501d34fb7165f0d75f Mon Sep 17 00:00:00 2001
From: CrawLeyYou <60201017+CrawLeyYou@users.noreply.github.com>
Date: Sun, 5 Oct 2025 15:30:06 +0300
Subject: [PATCH 4/5] Add FullScreen Tweak
This fixes the issue with Apple Music is not going fullscreen on non primary monitors.
---
AMDiscordRPC/AMDiscordRPC.cs | 2 +-
AMDiscordRPC/Globals.cs | 99 ++++++++++++++++++++++++++++++++++++
AMDiscordRPC/UI.cs | 44 +++++++++++++++-
3 files changed, 143 insertions(+), 2 deletions(-)
diff --git a/AMDiscordRPC/AMDiscordRPC.cs b/AMDiscordRPC/AMDiscordRPC.cs
index 0657ea7..8305796 100644
--- a/AMDiscordRPC/AMDiscordRPC.cs
+++ b/AMDiscordRPC/AMDiscordRPC.cs
@@ -88,7 +88,7 @@ static void AMEvent()
{
for (var i = 0; i < windows.Length; i++)
{
- if (windows[i].Name == "Apple Music") window = windows[i];
+ if (windows[i].Name == "Apple Music" && windows[i].FindFirstChild().Name == "Non Client Input Sink Window") window = windows[i];
}
}
else if (windows.Length == 1)
diff --git a/AMDiscordRPC/Globals.cs b/AMDiscordRPC/Globals.cs
index e0a1bff..ee644c5 100644
--- a/AMDiscordRPC/Globals.cs
+++ b/AMDiscordRPC/Globals.cs
@@ -216,6 +216,105 @@ public enum SmallImage
None
}
+ public enum GWLP {
+ EXSTYLE = -20,
+ HINSTANCE = -6,
+ HWNDPARENT = -8,
+ ID = -12,
+ STYLE = -16,
+ USERDATA = -21,
+ WNDPROC = -4
+ }
+
+ public enum WS : long
+ {
+ BORDER = 0x00800000L,
+ CAPTION = 0x00C00000L,
+ CHILD = 0x40000000L,
+ CHILDWINDOW = 0x40000000L,
+ CLIPCHILDREN = 0x02000000L,
+ CLIPSIBLINGS = 0x04000000L,
+ DISABLED = 0x08000000L,
+ DLGFRAME = 0x00400000L,
+ GROUP = 0x00020000L,
+ HSCROLL = 0x00100000L,
+ ICONIC = 0x20000000L,
+ MAXIMIZE = 0x01000000L,
+ MAXIMIZEBOX = 0x00010000L,
+ MINIMIZE = 0x20000000L,
+ MINIMIZEBOX = 0x00020000L,
+ OVERLAPPED = 0x00000000L,
+ OVERLAPPEDWINDOW = (OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX),
+ POPUP = 0x80000000L,
+ POPUPWINDOW = (POPUP | BORDER | SYSMENU),
+ SIZEBOX = 0x00040000L,
+ SYSMENU = 0x00080000L,
+ TABSTOP = 0x00010000L,
+ THICKFRAME = 0x00040000L,
+ TILED = 0x00000000L,
+ TILEDWINDOW = (OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX),
+ VISIBLE = 0x10000000L,
+ VSCROLL = 0x00200000L
+ }
+
+ public enum WS_EX : long
+ {
+ ACCEPTFILES = 0x00000010L,
+ APPWINDOW = 0x00040000L,
+ CLIENTEDGE = 0x00000200L,
+ COMPOSITED = 0x02000000L,
+ CONTEXTHELP = 0x00000400L,
+ CONTROLPARENT = 0x00010000L,
+ DLGMODALFRAME = 0x00000001L,
+ LAYERED = 0x00080000L,
+ LAYOUTRTL = 0x00400000L,
+ LEFT = 0x00000000L,
+ LEFTSCROLLBAR = 0x00004000L,
+ LTRREADING = 0x00000000L,
+ MDICHILD = 0x00000040L,
+ NOACTIVATE = 0x08000000L,
+ NOINHERITLAYOUT = 0x00100000L,
+ NOPARENTNOTIFY = 0x00000004L,
+ NOREDIRECTIONBITMAP = 0x00200000L,
+ OVERLAPPEDWINDOW = (WINDOWEDGE | CLIENTEDGE),
+ PALETTEWINDOW = (WINDOWEDGE | TOOLWINDOW | TOPMOST),
+ RIGHT = 0x00001000L,
+ RIGHTSCROLLBAR = 0x00000000L,
+ RTLREADING = 0x00002000L,
+ STATICEDGE = 0x00020000L,
+ TOOLWINDOW = 0x00000080L,
+ TOPMOST = 0x00000008L,
+ TRANSPARENT = 0x00000020L,
+ WINDOWEDGE = 0x00000100L
+ }
+
+ public enum HWND
+ {
+ BOTTOM = 1,
+ NOTOPMOST = -2,
+ TOP = 0,
+ TOPMOST = -1
+ }
+
+ public enum SWP
+ {
+ ASYNCWINDOWPOS = 0x4000,
+ DEFERERASE = 0x2000,
+ DRAWFRAME = 0x0020,
+ FRAMECHANGED = 0x0020,
+ HIDEWINDOW = 0x0080,
+ NOACTIVATE = 0x0010,
+ NOCOPYBITS = 0x0100,
+ NOMOVE = 0x0002,
+ NOOWNERZORDER = 0x0200,
+ NOREDRAW = 0x0008,
+ NOREPOSITION = 0x0200,
+ NOSENDCHANGING = 0x0400,
+ NOSIZE = 0x0001,
+ NOZORDER = 0x0004,
+ SHOWWINDOW = 0x0040
+ }
+
public class SongData : EventArgs
{
public string SongName { get; set; }
diff --git a/AMDiscordRPC/UI.cs b/AMDiscordRPC/UI.cs
index 1043fff..2b4a651 100644
--- a/AMDiscordRPC/UI.cs
+++ b/AMDiscordRPC/UI.cs
@@ -1,8 +1,9 @@
using AMDiscordRPC.UIComponents;
+using FlaUI.UIA3;
using System;
using System.Diagnostics;
-using System.Drawing;
using System.IO;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
@@ -10,6 +11,7 @@
using static AMDiscordRPC.Globals;
using Application = System.Windows.Application;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
+using Window = FlaUI.Core.AutomationElements.Window;
namespace AMDiscordRPC
{
@@ -20,6 +22,15 @@ internal class UI
private static Application app;
private static Thread mainThread = Thread.CurrentThread;
+ [DllImport("user32.dll")]
+ private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ [DllImport("user32.dll")]
+ private static extern long GetWindowLongPtrA(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32.dll")]
+ private static extern long SetWindowLongPtrA(IntPtr hWnd, int nIndex, long dwNewLong);
+
public static void CreateUI()
{
Thread thread = new Thread(() =>
@@ -69,6 +80,36 @@ public static void FFmpegDialog()
thread.Start();
}
+ public static void FullScreenTweak()
+ {
+ using (var automation = new UIA3Automation())
+ {
+ Window lyricScreenWindow = null;
+ foreach (var window in AppleMusicProc.GetAllTopLevelWindows(automation))
+ {
+ if (window.FindFirstChild().Name != "Non Client Input Sink Window" && window.Name == "Apple Music") lyricScreenWindow = window;
+ }
+
+ if (lyricScreenWindow != null)
+ {
+ IntPtr lyricsScreenHandler = (IntPtr)lyricScreenWindow.Properties.NativeWindowHandle;
+ Screen lyricsScreenHandlerCurrentMonitor = Screen.FromHandle(lyricsScreenHandler);
+ long style = GetWindowLongPtrA(lyricsScreenHandler, (int) GWLP.STYLE);
+ style &= ~((long) WS.CAPTION | (long) WS.THICKFRAME);
+ SetWindowLongPtrA(lyricsScreenHandler, (int) GWLP.STYLE, style);
+
+ long exStyle = GetWindowLongPtrA(lyricsScreenHandler, (int) GWLP.EXSTYLE);
+ exStyle &= ~((long) WS_EX.DLGMODALFRAME | (long) WS_EX.CLIENTEDGE | (long) WS_EX.STATICEDGE);
+ SetWindowLongPtrA(lyricsScreenHandler, (int) GWLP.EXSTYLE, exStyle);
+
+ SetWindowPos(lyricsScreenHandler, (int) HWND.TOPMOST, lyricsScreenHandlerCurrentMonitor.Bounds.Left,
+ lyricsScreenHandlerCurrentMonitor.Bounds.Top, lyricsScreenHandlerCurrentMonitor.Bounds.Width,
+ lyricsScreenHandlerCurrentMonitor.Bounds.Height,
+ (uint) SWP.NOOWNERZORDER | (uint) SWP.FRAMECHANGED | (uint) SWP.SHOWWINDOW);
+ }
+ }
+ }
+
public class AMDiscordRPCTray
{
private static NotifyIcon notifyIcon = new NotifyIcon();
@@ -111,6 +152,7 @@ public AMDiscordRPCTray()
notifySongState,
s3Menu,
optionsMenu,
+ new MenuItem("Fix Fullscreen", (s,e) => FullScreenTweak()),
new MenuItem("Show Latest Log", (s,e) => { Process.Start("notepad", $"{Path.Combine(Directory.GetCurrentDirectory(), @"logs\latest.log")}"); }),
new MenuItem("Exit", (s, e) => { Environment.Exit(0); })
}
From 9e6e9375d56f3e2f003b7153f7da7e794aac5a5b Mon Sep 17 00:00:00 2001
From: CrawLeyYou <60201017+CrawLeyYou@users.noreply.github.com>
Date: Fri, 28 Nov 2025 13:55:35 +0300
Subject: [PATCH 5/5] Fix the not registering to database issue on albums with
apostrophe
also
+ Add WebView2 (in the near future we will switch to React based UI prob.)
+ Change how albums gets registered in first place
+ New data types for new database structure
---
AMDiscordRPC/AMDiscordRPC.cs | 5 +-
AMDiscordRPC/AMDiscordRPC.csproj | 14 +++
AMDiscordRPC/App.config | 4 +
AMDiscordRPC/Covers.cs | 4 +-
AMDiscordRPC/Database.cs | 146 +++++++++++++++++++++++++++----
AMDiscordRPC/packages.config | 1 +
6 files changed, 153 insertions(+), 21 deletions(-)
diff --git a/AMDiscordRPC/AMDiscordRPC.cs b/AMDiscordRPC/AMDiscordRPC.cs
index 8305796..9aa03e6 100644
--- a/AMDiscordRPC/AMDiscordRPC.cs
+++ b/AMDiscordRPC/AMDiscordRPC.cs
@@ -26,7 +26,7 @@ static void Main(string[] args)
InitDiscordRPC();
AttachToAM();
AMSongDataEvent.SongChanged += async (sender, x) =>
- {
+ {
log.Info($"Song: {x.SongName} \\ Artist and Album: {x.ArtistandAlbumName}");
AMDiscordRPCTray.ChangeSongState($"{x.ArtistandAlbumName.Split('—')[0]} - {x.SongName}");
if (x.ArtistandAlbumName == oldAlbumnArtist && oldData.Assets.LargeImageKey != null)
@@ -43,7 +43,7 @@ static void Main(string[] args)
SetPresence(x, httpRes);
oldAlbumnArtist = x.ArtistandAlbumName;
}
- };
+ };
CheckDatabaseIntegrity();
ConfigureFromDB();
CheckFFmpeg();
@@ -181,7 +181,6 @@ static void AMEvent()
}
else log.Debug("Continue");
string idontknowwhatshouldinamethisbutitsaboutalbum = (isSingle) ? string.Join("-", dashSplit.Take(dashSplit.Length - 1).ToArray()) : string.Join("—", currentArtistAlbum.Split('—').Take(2).ToArray());
- CheckAndInsertAlbum(idontknowwhatshouldinamethisbutitsaboutalbum.Split('—')[1]);
Task t = new Task(async () =>
{
httpRes = await GetCover(idontknowwhatshouldinamethisbutitsaboutalbum.Split('—')[1], Uri.EscapeDataString((isSingle) ? string.Join("-", dashSplit.Take(dashSplit.Length - 1).ToArray()) : string.Join("—", currentArtistAlbum.Split('—').Take(2).ToArray()) + $" {currentSong}"));
diff --git a/AMDiscordRPC/AMDiscordRPC.csproj b/AMDiscordRPC/AMDiscordRPC.csproj
index 53f51a0..1178e86 100644
--- a/AMDiscordRPC/AMDiscordRPC.csproj
+++ b/AMDiscordRPC/AMDiscordRPC.csproj
@@ -100,6 +100,9 @@
Resources\Logo Black.ico
+
+ false
+
..\packages\AngleSharp.1.3.0\lib\net472\AngleSharp.dll
@@ -138,6 +141,15 @@
..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.7\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll
+
+ ..\packages\Microsoft.Web.WebView2.1.0.3595.46\lib\net462\Microsoft.Web.WebView2.Core.dll
+
+
+ ..\packages\Microsoft.Web.WebView2.1.0.3595.46\lib\net462\Microsoft.Web.WebView2.WinForms.dll
+
+
+ ..\packages\Microsoft.Web.WebView2.1.0.3595.46\lib\net462\Microsoft.Web.WebView2.Wpf.dll
+
..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll
@@ -317,8 +329,10 @@
+
+
\ No newline at end of file
diff --git a/AMDiscordRPC/App.config b/AMDiscordRPC/App.config
index 2012abb..64a9a5f 100644
--- a/AMDiscordRPC/App.config
+++ b/AMDiscordRPC/App.config
@@ -49,6 +49,10 @@
+
+
+
+
diff --git a/AMDiscordRPC/Covers.cs b/AMDiscordRPC/Covers.cs
index 0d207e1..294c511 100644
--- a/AMDiscordRPC/Covers.cs
+++ b/AMDiscordRPC/Covers.cs
@@ -34,7 +34,7 @@ private static async Task AsyncFetchiTunes(string album, string
imageRes["results"][0]["collectionName"].ToString(),
imageRes["results"][0]["artistViewUrl"].ToString()
);
- UpdateAlbum(new SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL, null, null, null, webRes.artistURL));
+ InsertAlbum(new SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL, null, null, null, webRes.artistURL));
CoverThread = null;
return webRes;
}
@@ -83,7 +83,7 @@ public static async Task AsyncAMFetch(string album, string sear
document.DocumentElement.QuerySelectorAll("div.track-lockup__clamp-wrapper > span > a")[0].GetAttribute("href")
);
CoverThread = null;
- UpdateAlbum(new Database.SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL, null, null, null, webRes.artistURL));
+ InsertAlbum(new Database.SQLCoverResponse(album, webRes.artworkURL, webRes.trackURL, null, null, null, webRes.artistURL));
return webRes;
}
else
diff --git a/AMDiscordRPC/Database.cs b/AMDiscordRPC/Database.cs
index 46a17ac..03ec51a 100644
--- a/AMDiscordRPC/Database.cs
+++ b/AMDiscordRPC/Database.cs
@@ -1,5 +1,4 @@
-using Amazon.Runtime.Internal.Transform;
-using System;
+using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Linq;
@@ -12,12 +11,12 @@ internal class Database
private static SQLiteConnection sqlite;
public static readonly Dictionary sqlMap = new Dictionary()
{
- //{"coverTable", "album TEXT PRIMARY KEY NOT NULL, source TEXT, redirURL TEXT DEFAULT 'https://music.apple.com/home', artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistSource TEXT, animated BOOLEAN CHECK (animated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT" },
+ {"coverTable", "album TEXT PRIMARY KEY NOT NULL, source TEXT, redirURL TEXT DEFAULT 'https://music.apple.com/home', artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistSource TEXT, animated BOOLEAN CHECK (animated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT" }, // will be replaced
{"coverTableNew", "coverID INTEGER PRIMARY KEY AUTOINCREMENT, staticCoverURL TEXT NOT NULL, isAnimated BOOLEAN CHECK (isAnimated IN (0,1)) DEFAULT NULL, streamURL TEXT, animatedURL TEXT"},
{"artistTable", "artistID INTEGER PRIMARY KEY AUTOINCREMENT, artistName TEXT NOT NULL, artistRedirURL TEXT DEFAULT 'https://music.apple.com/home', artistProfileSource TEXT"},
{"albumTable", "albumID INTEGER PRIMARY KEY AUTOINCREMENT, albumName TEXT NOT NULL, albumURL TEXT UNIQUE, isSingle BOOLEAN CHECK (isSingle IN (0,1)), coverID INTEGER, artistID INTEGER, FOREIGN KEY (coverID) REFERENCES coverTableNew(coverID), FOREIGN KEY (artistID) REFERENCES artistTable(artistID)"},
{"songTable", "songTitle TEXT, songURL TEXT, albumID INTEGER, artistID INTEGER, FOREIGN KEY (albumID) REFERENCES albumTable(albumID), FOREIGN KEY (artistID) REFERENCES artistTable(artistID)"},
- {"creds", "S3_accessKey TEXT, S3_secretKey TEXT, S3_serviceURL TEXT, S3_bucketName TEXT, S3_bucketURL TEXT, S3_isSpecificKey BOOLEAN CHECK (S3_isSpecificKey IN (0,1)), FFmpegPath TEXT" },
+ {"creds", "S3_accessKey TEXT, S3_secretKey TEXT, S3_serviceURL TEXT, S3_bucketName TEXT, S3_bucketURL TEXT, S3_isSpecificKey BOOLEAN CHECK (S3_isSpecificKey IN (0,1)), FFmpegPath TEXT, LastFMToken TEXT" },
{"logs", "timestamp INTEGER, type TEXT, occuredAt TEXT, message TEXT" },
{"clientSettings", "smallImage INTEGER"}
};
@@ -105,18 +104,18 @@ private static void CheckTables()
public static void UpdateAlbum(SQLCoverResponse data)
{
- ExecuteNonQueryCommand($"UPDATE coverTable SET ({string.Join(", ", data.GetNotNullKeys())}) = ({string.Join(", ", data.GetNotNullValues())}) WHERE album = '{data.album}'");
+ ExecuteNonQueryCommand($"UPDATE coverTable SET ({string.Join(", ", data.GetNotNullKeys())}) = ({string.Join(", ", data.GetNotNullValues())}) WHERE album = @album", new[] { new SQLiteParameter("@album", data.album)});
}
- public static void CheckAndInsertAlbum(string album)
+ public static void InsertAlbum(SQLCoverResponse data)
{
- if (ExecuteScalarCommand($"SELECT album from coverTable WHERE album = '{album}'") == null)
- ExecuteNonQueryCommand($"INSERT INTO coverTable(album) VALUES ('{album}')");
+ if (ExecuteScalarCommand($"SELECT album from coverTable WHERE album = @album", new[] { new SQLiteParameter("@album", data.album) }) == null)
+ ExecuteNonQueryCommand($@"INSERT INTO coverTable(album, {string.Join(", ", data.GetNotNullKeys())}) VALUES (@album, {string.Join(", ", data.GetNotNullValues())})", new[] {new SQLiteParameter("@album", data.album)});
}
public static SQLCoverResponse GetAlbumDataFromSQL(string album)
{
- using (SQLiteDataReader reader = ExecuteReaderCommand($"SELECT * FROM coverTable WHERE album = '{album}' LIMIT 1"))
+ using (SQLiteDataReader reader = ExecuteReaderCommand($"SELECT * FROM coverTable WHERE album = @album LIMIT 1", new[] { new SQLiteParameter("@album", album) }))
{
while (reader.Read())
{
@@ -134,6 +133,32 @@ public static SQLCoverResponse GetAlbumDataFromSQL(string album)
return null;
}
+ public static SQLSongResponse GetSongFromDB(string song, string album, string artist)
+ {
+ string cmd = @"
+ SELECT
+ IIF(coverTableNew.isAnimated = 1, coverTableNew.animatedURL, coverTableNew.staticCoverURL) as coverURL,
+ artistTable.artistRedirURL as artistRedirURL,
+ artistTable.artistProfileSource as artistProfileSource,
+ albumTable.albumURL,
+ songTable.songURL
+ FROM songTable
+ INNER JOIN albumTable on albumTable.albumID = songTable.albumID
+ INNER JOIN artistTable on artistTable.artistID = albumTable.artistID
+ INNER JOIN coverTableNew on coverTableNew.coverID = albumTable.coverID
+ WHERE
+ artistTable.artistName = @artist
+ AND songTable.songTitle = @song
+ AND albumTable.albumName = @album;
+ ";
+ using (SQLiteDataReader reader = ExecuteReaderCommand(cmd, new[] { new SQLiteParameter("@album", album), new SQLiteParameter("@song", song), new SQLiteParameter("@artist", artist) }))
+ {
+
+ }
+
+ return null;
+ }
+
private static void CheckColumns()
{
foreach (var table in sqlMap.Keys)
@@ -201,11 +226,12 @@ private static Dictionary ConvertSQLStringToColumnInfo(strin
return columnsMap;
}
- public static object ExecuteScalarCommand(string command)
+ public static object ExecuteScalarCommand(string command, SQLiteParameter[] parameters = null)
{
try
{
- SQLiteCommand cmd = new SQLiteCommand($@"{command}", sqlite);
+ SQLiteCommand cmd = new SQLiteCommand(command, sqlite);
+ if (parameters != null) cmd.Parameters.AddRange(parameters);
return cmd.ExecuteScalar();
}
catch (Exception ex)
@@ -215,11 +241,12 @@ public static object ExecuteScalarCommand(string command)
}
}
- public static SQLiteDataReader ExecuteReaderCommand(string command)
+ public static SQLiteDataReader ExecuteReaderCommand(string command, SQLiteParameter[] parameters = null)
{
try
{
- SQLiteCommand cmd = new SQLiteCommand($@"{command}", sqlite);
+ SQLiteCommand cmd = new SQLiteCommand(command, sqlite);
+ if (parameters != null) cmd.Parameters.AddRange(parameters);
return cmd.ExecuteReader();
}
catch (Exception ex)
@@ -229,11 +256,12 @@ public static SQLiteDataReader ExecuteReaderCommand(string command)
}
}
- public static int ExecuteNonQueryCommand(string command)
+ public static int ExecuteNonQueryCommand(string command, SQLiteParameter[] parameters = null)
{
try
{
- SQLiteCommand cmd = new SQLiteCommand($@"{command}", sqlite);
+ SQLiteCommand cmd = new SQLiteCommand(command, sqlite);
+ if (parameters != null) cmd.Parameters.AddRange(parameters);
return cmd.ExecuteNonQuery();
}
catch (Exception ex)
@@ -274,7 +302,7 @@ public override bool Equals(object obj)
}
}
- public class ForeignKey
+ private class ForeignKey
{
public string key { get; set; }
public string refTable { get; set; }
@@ -321,5 +349,91 @@ public List