diff --git a/Jukebox_Mascot/App.config b/Jukebox_Mascot/App.config index 193aecc..ea2564f 100644 --- a/Jukebox_Mascot/App.config +++ b/Jukebox_Mascot/App.config @@ -1,6 +1,18 @@ - + + + + + + + + + + + + + \ No newline at end of file diff --git a/Jukebox_Mascot/App.xaml.cs b/Jukebox_Mascot/App.xaml.cs index f8d0786..6964baa 100644 --- a/Jukebox_Mascot/App.xaml.cs +++ b/Jukebox_Mascot/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace Jukebox_Mascot { diff --git a/Jukebox_Mascot/Config.txt b/Jukebox_Mascot/Config.txt index 105253f..15d289c 100644 --- a/Jukebox_Mascot/Config.txt +++ b/Jukebox_Mascot/Config.txt @@ -1,4 +1,4 @@ -//RiceShower//Tachyon//Tokai//Oguri//Pasa +//RiceShower//Tachyon//Teio//Oguri//Pasa START_CHAR=Tachyon ALLOW_RANDOM_MASCOT=false ALLOW_MUSIC_NOTES=true diff --git a/Jukebox_Mascot/Jukebox_Mascot.csproj b/Jukebox_Mascot/Jukebox_Mascot.csproj index 1bcd43a..c446a50 100644 --- a/Jukebox_Mascot/Jukebox_Mascot.csproj +++ b/Jukebox_Mascot/Jukebox_Mascot.csproj @@ -1,105 +1,35 @@ - - - + - Debug - AnyCPU - {6D5FB859-0563-40B6-B20C-B91EE10D592C} + net48 WinExe - Jukebox_Mascot - Jukebox_Mascot - v4.8 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + true + true + true icon2.ico - - - - - + + + + + + + + + + + + + + + + + - - - - - 4.0 - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - PreserveNewest @@ -107,6 +37,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -175,5 +108,8 @@ PreserveNewest - + + + + \ No newline at end of file diff --git a/Jukebox_Mascot/MainWindow.xaml.cs b/Jukebox_Mascot/MainWindow.xaml.cs index 058962b..3d8d706 100644 --- a/Jukebox_Mascot/MainWindow.xaml.cs +++ b/Jukebox_Mascot/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Linq; using System.Windows; using System.Windows.Forms; @@ -9,8 +10,8 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; -using System.IO; -using System.Data.SqlTypes; +using Windows.Media.Control; +using WindowsMediaController; namespace Jukebox_Mascot { @@ -62,6 +63,8 @@ public partial class MainWindow : Window private bool ALLOW_RANDOM_MASCOT = true; private bool ALLOW_MUSIC_NOTES = true; private bool IS_RANDOM = false; + private bool OTHER_MEDIA_TRACKED = false; + private string OTHER_MEDIA_CURRENT_TRACK = ""; private double SCROLL_POS; @@ -69,7 +72,8 @@ public partial class MainWindow : Window private List MUSIC_FILES = new List(); private MediaPlayer PLAYER; - + private MediaManager MEDIA_MANAGER; + private MediaManager.MediaSession CURRENT_SESSION; private BitmapImage LoadSprite(string filefolder, string fileName, string rootFolder = "Characters") { string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SpriteSheet", rootFolder, filefolder, fileName); @@ -124,7 +128,7 @@ private void FatalError(string message, string title = "Error") TRAY_ICON?.Dispose(); System.Windows.Application.Current.Shutdown(); } - private int PlayAnimation(BitmapImage sheet,int currentFrame,int frameCount,int frameWidth,int frameHeight,System.Windows.Controls.Image targetImage,bool reverse = false) + private int PlayAnimation(BitmapImage sheet, int currentFrame, int frameCount, int frameWidth, int frameHeight, System.Windows.Controls.Image targetImage, bool reverse = false) { if (sheet == null) return currentFrame; @@ -138,7 +142,7 @@ private int PlayAnimation(BitmapImage sheet,int currentFrame,int frameCount,int targetImage.Source = new CroppedBitmap(sheet, new Int32Rect(x, y, frameWidth, frameHeight)); if (!reverse) - { + { return (currentFrame + 1) % frameCount; } else @@ -157,14 +161,82 @@ private int PlayAnimation(BitmapImage sheet,int currentFrame,int frameCount,int } } + private void UpdateMediaProperties(MediaManager.MediaSession sender, GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties) + { + if (mediaProperties == null) + { + OTHER_MEDIA_CURRENT_TRACK = ""; + } + GC.Collect(0); + + if (CURRENT_SESSION == sender) + { + // Get the name and the artist of the current track + string title = string.IsNullOrEmpty(mediaProperties.Title) ? "Unkown Title" : mediaProperties.Title; + string artist = string.IsNullOrEmpty(mediaProperties.Artist) ? "Unknown Artist" : mediaProperties.Artist; + OTHER_MEDIA_CURRENT_TRACK = $"🎵 Now Playing: {title} by {artist} 🎵"; + + this.Dispatcher.Invoke(() => + { + ScrollingText.Text = OTHER_MEDIA_CURRENT_TRACK; + ReopenScrollingBorder(); + if (ALLOW_RANDOM_MASCOT) + { + SwitchToRandomCharacter(); + } + if (PLAY_INTRO_ON_NEW_SONG) + { + JukeBoxSprite.Source = null; + IS_INTRO = true; + CURRENT_INTRO_FRAME = 0; + CURRENT_JUKEBOX_FRAME = 0; + } + }); + } + } + + private void SenderPlaybackStateChanged(MediaManager.MediaSession sender, GlobalSystemMediaTransportControlsSessionPlaybackInfo args) + { + switch (args.PlaybackStatus) + { + /* + * This allows for different outcomes based on: + * if the media is closed, opened, changing, stopped, playing, or paused. + * So it can be used for different animations or actions, which would be cool. + */ + case GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing: + case GlobalSystemMediaTransportControlsSessionPlaybackStatus.Changing: + CURRENT_SESSION = sender; + /* + * Calling this here when it is already being listened to seems redundant but it is needed for when the user pauses/unpauses or starts a new song + * The listener exists for automatic changes, such as spotify going to the next playlist. + */ + UpdateMediaProperties(sender, sender.ControlSession.TryGetMediaPropertiesAsync().AsTask().Result); + break; + default: + break; + } + } + + private void InitializeMediaManager() + { + MEDIA_MANAGER = new MediaManager(); + + MEDIA_MANAGER.OnAnyPlaybackStateChanged += SenderPlaybackStateChanged; + MEDIA_MANAGER.OnAnyMediaPropertyChanged += UpdateMediaProperties; + + // Start listening + MEDIA_MANAGER.Start(); + } + private void InitializeAnimations() { - MASTER_TIMER = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(FRAME_RATE)}; + MASTER_TIMER = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(FRAME_RATE) }; MASTER_TIMER.Tick += (s, e) => { if (IS_INTRO) { - CURRENT_INTRO_FRAME = PlayAnimation(INTRO_SHEET, CURRENT_INTRO_FRAME, INTRO_FRAME_COUNT,FRAME_WIDTH, FRAME_HEIGHT, SpriteImage); + CURRENT_INTRO_FRAME = PlayAnimation(INTRO_SHEET, CURRENT_INTRO_FRAME, INTRO_FRAME_COUNT, FRAME_WIDTH, FRAME_HEIGHT, SpriteImage); if (CURRENT_INTRO_FRAME == 0) { @@ -223,10 +295,10 @@ private void InitializeMusic() private void LoadTrack(int index) { if (index < 0 || index >= MUSIC_FILES.Count) - { + { return; } - + string filePath = MUSIC_FILES[index]; PLAYER.Open(new Uri(filePath)); @@ -247,13 +319,12 @@ private void LoadTrack(int index) } } - private void PlayMusic() => PLAYER.Play(); private void PauseMusic() => PLAYER.Pause(); private void NextTrack() { - if(MUSIC_FILES.Count <= 0) + if (MUSIC_FILES.Count <= 0) { return; } @@ -294,10 +365,7 @@ private void ReopenScrollingBorder() else { openTimer.Stop(); - string filePath = MUSIC_FILES[CURRENT_TRACK_INDEX]; - string songName = System.IO.Path.GetFileNameWithoutExtension(filePath); - ScrollingText.Text = $"🎵 Now Playing: {songName} 🎵"; - ScrollingText.Visibility = Visibility.Visible; + ScrollingText.Visibility = Visibility.Visible; StartScrolling(); } }; @@ -348,6 +416,7 @@ private void ResetApp() { TRAY_ICON.Visible = false; string exePath = Process.GetCurrentProcess().MainModule.FileName; + SaveMasterConfig(); Process.Start(exePath); System.Windows.Application.Current.Shutdown(); } @@ -356,7 +425,9 @@ private void CloseApp() { TRAY_ICON.Visible = false; TRAY_ICON?.Dispose(); + MEDIA_MANAGER?.Dispose(); MASTER_TIMER.Stop(); + SaveMasterConfig(); System.Windows.Application.Current.Shutdown(); } private void SetupTrayIcon() @@ -367,24 +438,62 @@ private void SetupTrayIcon() TRAY_ICON.Text = "Jukebox"; var menu = new ContextMenuStrip(); - menu.Items.Add("Play", null, (s, e) => PlayMusic()); - menu.Items.Add("Pause", null, (s, e) => PauseMusic()); - menu.Items.Add("Next Track", null, (s, e) => NextTrack()); - var randomChar = new ToolStripMenuItem("Random Characters") { CheckOnClick = true }; + // Save the buttons in variables so that they can be disabled/enabled later if needed + var playButton = new ToolStripMenuItem("Play") { Enabled = !OTHER_MEDIA_TRACKED }; + playButton.Click += (sender, e) => PlayMusic(); + + var pauseButton = new ToolStripMenuItem("Pause") { Enabled = !OTHER_MEDIA_TRACKED }; + pauseButton.Click += (sender, e) => PauseMusic(); + + var nextButton = new ToolStripMenuItem("Next Track") { Enabled = !OTHER_MEDIA_TRACKED }; + nextButton.Click += (sender, e) => NextTrack(); + + var randomChar = new ToolStripMenuItem("Random Characters") { CheckOnClick = true, Checked = ALLOW_RANDOM_MASCOT }; randomChar.CheckedChanged += (s, e) => { ALLOW_RANDOM_MASCOT = randomChar.Checked; }; - var randomItem = new ToolStripMenuItem("Random Music") { CheckOnClick = true }; + var randomItem = new ToolStripMenuItem("Random Music") { CheckOnClick = true, Enabled = !OTHER_MEDIA_TRACKED }; randomItem.CheckedChanged += (s, e) => - { + { IS_RANDOM = randomItem.Checked; }; + var otherMediaToggle = new ToolStripMenuItem("Track Other Media") { CheckOnClick = true, Checked = OTHER_MEDIA_TRACKED }; + otherMediaToggle.CheckedChanged += (s, e) => + { + OTHER_MEDIA_TRACKED = otherMediaToggle.Checked; + + // If the spotify tracker is enabled, stop the user from using the built in music player + playButton.Enabled = !OTHER_MEDIA_TRACKED; + pauseButton.Enabled = !OTHER_MEDIA_TRACKED; + nextButton.Enabled = !OTHER_MEDIA_TRACKED; + randomItem.Enabled = !OTHER_MEDIA_TRACKED; + + // Pause the music if tracking spotify + if (OTHER_MEDIA_TRACKED) + { + PauseMusic(); + + if (MEDIA_MANAGER == null) + { + InitializeMediaManager(); + } + } + else + { + MEDIA_MANAGER?.Dispose(); + } + }; + + menu.Items.Add(playButton); + menu.Items.Add(pauseButton); + menu.Items.Add(nextButton); menu.Items.Add(randomItem); - menu.Items.Add(randomChar); + menu.Items.Add(randomChar); + menu.Items.Add(otherMediaToggle); menu.Items.Add(new ToolStripSeparator()); menu.Items.Add("Reappear", null, (s, e) => ResetApp()); menu.Items.Add("Close", null, (s, e) => CloseApp()); @@ -403,9 +512,10 @@ public MainWindow() LoadConfigChar(); SetupTrayIcon(); LoadSpritesSheet(); - LoadMascotList(); + LoadMascotList(); InitializeAnimations(); InitializeMusic(); + if (OTHER_MEDIA_TRACKED) InitializeMediaManager(); } private void JukeBoxSprite_Click(object sender, MouseButtonEventArgs e) { @@ -413,8 +523,8 @@ private void JukeBoxSprite_Click(object sender, MouseButtonEventArgs e) CURRENT_MASCOT_INDEX = (CURRENT_MASCOT_INDEX + 1) % MASCOTS.Count; START_CHAR = MASCOTS[CURRENT_MASCOT_INDEX]; - - + + INTRO_SHEET = null; DANCE_SHEET = null; SpriteImage.Source = null; @@ -429,7 +539,7 @@ private void JukeBoxSprite_Click(object sender, MouseButtonEventArgs e) SpriteLabel.Content = $"Mascot: {START_CHAR}"; - } + } private void SwitchToRandomCharacter() { if (MASCOTS == null || MASCOTS.Count == 0) @@ -459,6 +569,22 @@ private void SwitchToRandomCharacter() JukeBoxSprite.Source = null; } + private void SaveMasterConfig() + { + string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.txt"); + + var lines = new List + { + $"START_CHAR={START_CHAR}", + $"ALLOW_RANDOM_MASCOT={ALLOW_RANDOM_MASCOT}", + $"ALLOW_MUSIC_NOTES={ALLOW_MUSIC_NOTES}", + $"SPRITE_SPEED={FRAME_RATE}", + $"TRACK_OTHER_MEDIA={OTHER_MEDIA_TRACKED}" + }; + + File.WriteAllLines(path, lines); + } + private void LoadMasterConfig() { string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.txt"); @@ -486,34 +612,42 @@ private void LoadMasterConfig() switch (key.ToUpper()) { case "START_CHAR": - { - START_CHAR = value; - break; - } + { + START_CHAR = value; + break; + } case "ALLOW_RANDOM_MASCOT": - { - if (bool.TryParse(value, out bool boolValue)) { - ALLOW_RANDOM_MASCOT = boolValue; + if (bool.TryParse(value, out bool boolValue)) + { + ALLOW_RANDOM_MASCOT = boolValue; + } + break; } - break; - } case "ALLOW_MUSIC_NOTES": - { - if (bool.TryParse(value, out bool boolValue2)) { - ALLOW_MUSIC_NOTES = boolValue2; + if (bool.TryParse(value, out bool boolValue2)) + { + ALLOW_MUSIC_NOTES = boolValue2; + } + break; } - break; - } case "SPRITE_SPEED": - { - if (int.TryParse(value, out int intValue)) { - FRAME_RATE = intValue; + if (int.TryParse(value, out int intValue)) + { + FRAME_RATE = intValue; + } + break; + } + case "TRACK_OTHER_MEDIA": + { + if (bool.TryParse(value, out bool boolValue3)) + { + OTHER_MEDIA_TRACKED = boolValue3; + } + break; } - break; - } } } } diff --git a/Jukebox_Mascot/Properties/AssemblyInfo.cs b/Jukebox_Mascot/Properties/AssemblyInfo.cs deleted file mode 100644 index a6eb798..0000000 --- a/Jukebox_Mascot/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Jukebox_Mascot")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Jukebox_Mascot")] -[assembly: AssemblyCopyright("Copyright © 2025")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Jukebox_Mascot/icon.ico b/Jukebox_Mascot/icon.ico new file mode 100644 index 0000000..c51d61e Binary files /dev/null and b/Jukebox_Mascot/icon.ico differ diff --git a/README.md b/README.md index be6922c..76c5cf6 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ -# Jukebox_Mascot +# Jukebox_Mascot ![GitHub all releases](https://img.shields.io/github/downloads/MojLovesApples/Jukebox/total) + A desktop jukebox mascot app built with C# (WPF), Mostly related to Umamusume, but can be edited through the spritesheet. Perfect for having a little dancing gremlin to waste your time while procrastinating. # Installation | Windows Only -Download latest here: [Download](https://github.com/KurtVelasco/JukeBox/releases/download/v1.0/JukeBox_V1.0.zip) +Download latest here: [Download](https://github.com/MojLovesApples/JukeBox/releases/download/V1.1/Jukebox_Mascot_V1.1.zip) You can Insta-Change the character by clicking the Jukebox image @@ -17,7 +18,7 @@ ALLOW_RANDOM_MASCOT = //Change sprite for every music change ALLOW_MUSIC_NOTES = //Show the floating music note SPRITE_SPEED = <30...> //change the rate (milisecond) when animating the sprites ``` -image +configFile ![dasdsa](https://github.com/user-attachments/assets/769d2fc3-6b90-4dfe-a767-3fd6c33513d9)