Skip to content

Commit

Permalink
MediaIntegration: Initial support for UWP
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongnemo committed Mar 30, 2024
1 parent f7bf022 commit 988b8f2
Show file tree
Hide file tree
Showing 9 changed files with 244 additions and 0 deletions.
1 change: 1 addition & 0 deletions SonicLair.Cli/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
bin
obj
album.png
Binary file added SonicLair.Cli/Icon.ico
Binary file not shown.
Binary file added SonicLair.Cli/Icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions SonicLair.Cli/SonicLair.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableCoreMrtTooling Condition=" '$(BuildingInsideVisualStudio)' != 'true' ">false</EnableCoreMrtTooling>

<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>

<ItemGroup>
Expand Down
191 changes: 191 additions & 0 deletions SonicLair.Lib/Services/MediaIntergration/Windows/Control.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
using System;

using Windows.Media;
using Windows.Media.Playback;
using Windows.Media.Core;
using Windows.Storage;
using Microsoft.Toolkit.Uwp.Notifications;
using Windows.Storage.Streams;

using Windows.Data.Xml.Dom;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;

namespace SonicLair.Lib.Services.MediaIntergration.Windows
{
internal class Control
{
private MediaPlayer _mediaPlayer;
private IMusicPlayerService _musicPlayerService;
private SystemMediaTransportControls _systemMediaTransportControls;
private void sendNotification(string line1, string line2)
{
string filePath = Path.Combine(Environment.CurrentDirectory, "Icon.png");
sendNotification(line1, line2, filePath);
}

private void sendNotification(string line1, string line2, string imageUri)
{

// Construct the content and show the toast!
new ToastContentBuilder()


// Inline image
.AddInlineImage(new Uri(imageUri))

// Profile (app logo override) image
// .AddAppLogoOverride(new Uri(@"D:\UserData\Documents\GitHub\SonicLair.Cli\Icon.png"), ToastGenericAppLogoCrop.Circle)
.AddText(line1, AdaptiveTextStyle.Title)
.AddText(line2, AdaptiveTextStyle.Default)

.Show();
// var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText02);
// var stringElements = toastXml.GetElementsByTagName("text");
// stringElements[0].AppendChild(toastXml.CreateTextNode(line1));
// stringElements[1].AppendChild(toastXml.CreateTextNode(line2));

// // add icon in visual area
// // https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/element-image
// string filePath = imageUri;
// var imageElements = toastXml.GetElementsByTagName("image");
// imageElements[0].Attributes.GetNamedItem("src").NodeValue = filePath;

// var placement = toastXml.CreateAttribute("placement");
// placement.Value = "appLogoOverride";
// imageElements[0].Attributes.SetNamedItem(placement);

// // debug write
// // Set a variable to the Documents path.
// string docPath =
// Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
// // Write the string array to a new file named "WriteLines.txt".
// using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "Toast.xml")))
// {
// outputFile.WriteLine(toastXml.GetXml());
// }

// // show
// var toast = new ToastNotification(toastXml);
// ToastNotificationManager.CreateToastNotifier("SonicLair").Show(toast);
}

public Control(IMusicPlayerService musicPlayerService)
{
_musicPlayerService = musicPlayerService;
_mediaPlayer = new MediaPlayer();
_systemMediaTransportControls = _mediaPlayer.SystemMediaTransportControls;
_systemMediaTransportControls.IsEnabled = false;
_mediaPlayer.CommandManager.IsEnabled = false;

_systemMediaTransportControls.IsPlayEnabled = true;
_systemMediaTransportControls.IsPauseEnabled = true;
_systemMediaTransportControls.IsStopEnabled = true;
_systemMediaTransportControls.IsNextEnabled = true;
_systemMediaTransportControls.IsPreviousEnabled = true;

_systemMediaTransportControls.ButtonPressed += systemMediaControls_ButtonPressed;
_systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Closed;

sendNotification("SonicLair is running", "on Windows");
}

public void Update(string title, string artist, string album, string imageUri)
{
_systemMediaTransportControls.IsEnabled = true;
// https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/system-media-transport-controls
// Get the updater.
SystemMediaTransportControlsDisplayUpdater updater = _systemMediaTransportControls.DisplayUpdater;
updater.ClearAll();

// Music metadata.
updater.Type = MediaPlaybackType.Music;
updater.MusicProperties.Artist = artist;
updater.MusicProperties.AlbumTitle = album;
updater.MusicProperties.Title = title;


// download thumbnail
if (imageUri.StartsWith("http"))
{
string remoteUri = imageUri;
string fileName = "album.png", myStringWebResource = null;

// Create a new WebClient instance.
using (WebClient myWebClient = new())

Check warning on line 119 in SonicLair.Lib/Services/MediaIntergration/Windows/Control.cs

View workflow job for this annotation

GitHub Actions / Build CLI

'WebClient.WebClient()' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
{
myStringWebResource = remoteUri;
// Download the Web resource and save it into the current filesystem folder.
myWebClient.DownloadFile(myStringWebResource, fileName);
}

imageUri = Path.Combine(Environment.CurrentDirectory, fileName);
}
// RandomAccessStreamReference is defined in Windows.Storage.Streams
StorageFile sampleFile = Task.Run(() => StorageFile.GetFileFromPathAsync(imageUri)).Result.GetResults();
updater.Thumbnail =
RandomAccessStreamReference.CreateFromFile(sampleFile);

// Update the system media transport controls.
updater.Update();

sendNotification(title, artist + " :: " + album, imageUri);
}

public void Play()
{
_systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Playing;
}
public void Pause()
{
_systemMediaTransportControls.PlaybackStatus = MediaPlaybackStatus.Paused;
}

private void systemMediaControls_ButtonPressed(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
{
// The system media transport control's ButtonPressed event may not fire on the app's UI thread. XAML controls
// (including the MediaPlayerElement control in our page as well as the scenario page itself) typically can only be
// safely accessed and manipulated on the UI thread, so here for simplicity, we dispatch our entire event handling
// code to execute on the UI thread, as our code here primarily deals with updating the UI and the MediaPlayerElement.
//
// Depending on how exactly you are handling the different button presses (which for your app may include buttons
// not used in this sample scenario), you may instead choose to only dispatch certain parts of your app's
// event handling code (such as those that interact with XAML) to run on UI thread.
// Because the handling code is dispatched asynchronously, it is possible the user may have
// navigated away from this scenario page to another scenario page by the time we are executing here.
// Check to ensure the page is still active before proceeding.
switch (args.Button)
{
case SystemMediaTransportControlsButton.Play:
_musicPlayerService.Play();
break;

case SystemMediaTransportControlsButton.Pause:
_musicPlayerService.Pause();
break;

case SystemMediaTransportControlsButton.Stop:
_musicPlayerService.Pause();
break;

case SystemMediaTransportControlsButton.Next:
// range-checking will be performed in SetNewMediaItem()
_musicPlayerService.ToggleNext();
break;

case SystemMediaTransportControlsButton.Previous:
// range-checking will be performed in SetNewMediaItem()
_musicPlayerService.Prev();
break;

// Insert additional case statements for other buttons you want to handle in your app.
// Remember that you also need to first enable those buttons via the corresponding
// Is****Enabled property on the SystemMediaTransportControls object.
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using SonicLair.Lib.Types;

namespace SonicLair.Lib.Services.MediaIntergration.Windows
{
public class MediaIntergration : IMediaIntergration
{
private Control _control;

public MediaIntergration(IMusicPlayerService musicPlayerService)
{
_control = new Control(musicPlayerService);
}

public void Update(string title, string artist, string album, string imageUri)
{
_control.Update(title, artist, album, imageUri);
}

public void Play()
{
_control.Play();
}

public void Pause()
{
_control.Pause();
}
}
}
9 changes: 9 additions & 0 deletions SonicLair.Lib/Services/MusicPlayerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@
using SonicLair.Lib.Types;
using SonicLair.Lib.Types.SonicLair;

using SonicLair.Lib.Services;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace SonicLair.Lib.Services
{
public class MusicPlayerService : IMusicPlayerService
{
private IMediaIntergration _mediaIntergration = null;
private readonly LibVLC _libVlc;
private readonly MediaPlayer _mediaPlayer;
private readonly ISubsonicService _client;
Expand Down Expand Up @@ -49,6 +53,8 @@ public MusicPlayerService(ISubsonicService subsonicService)
Public = false,
SongCount = 0
};
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
_mediaIntergration = new MediaIntergration.Windows.MediaIntergration(this);
_originalPlaylist = new List<Song>();
_currentStateListeners = new List<EventHandler<CurrentStateChangedEventArgs>>();
_playerTimeListeners = new List<EventHandler<MediaPlayerTimeChangedEventArgs>>();
Expand Down Expand Up @@ -264,6 +270,7 @@ public void Play()
_currentTrack = _playlist.Entry[0];
LoadMedia();
}
_mediaIntergration?.Play();
_mediaPlayer.Play();
}

Expand All @@ -280,6 +287,7 @@ public void SkipTo(int index)
public void Pause()
{
_mediaPlayer.Pause();
_mediaIntergration?.Pause();
}

public void Seek(float time, bool relative = false)
Expand Down Expand Up @@ -307,6 +315,7 @@ private void LoadMedia()
Notifier.NotifyObservers("MScurrentTrack", $"{{\"currentTrack\": {JsonConvert.SerializeObject(_currentTrack, StaticHelpers.GetJsonSerializerSettings())}}}");
}
_client.Scrobble(_currentTrack.Id);
_mediaIntergration?.Update(_currentTrack.Title, _currentTrack.Artist, _currentTrack.Album, _currentTrack.Image);
}

// intendeded by user
Expand Down
1 change: 1 addition & 0 deletions SonicLair.Lib/SonicLair.Lib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<ItemGroup>
<PackageReference Include="LibVLCSharp" Version="3.8.2" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Text.Json" Version="8.0.2" />
</ItemGroup>
Expand Down
11 changes: 11 additions & 0 deletions SonicLair.Lib/Types/IMediaIntergration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace SonicLair.Lib.Types
{
public interface IMediaIntergration
{
void Update(string title, string artist, string album, string imageUri);
void Play();
void Pause();
}
}

0 comments on commit 988b8f2

Please sign in to comment.