First commit for basic naive implementation

This commit is contained in:
Théo Marchal 2021-08-08 17:12:36 +02:00
parent 0cda436dfe
commit d85449e3aa
24 changed files with 6060 additions and 1 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ bin/
publish
.vs
*.csproj.user
*.user

9
App.xaml Normal file
View File

@ -0,0 +1,9 @@
<Application x:Class="unison.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:unison"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

17
App.xaml.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace unison
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

10
AssemblyInfo.cs Normal file
View File

@ -0,0 +1,10 @@
using System.Windows;
[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)
)]

1415
MPDCtrl/BinaryDownloader.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MPDCtrl.Models
{
/// <summary>
/// AlbumCover class.
/// </summary>
public class AlbumImage
{
public bool IsDownloading { get; set; }
public bool IsSuccess { get; set; }
public string SongFilePath { get; set; }
public byte[] BinaryData { get; set; } = Array.Empty<byte>();
public int BinarySize { get; set; }
public ImageSource AlbumImageSource { get; set; }
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MPDCtrl.Models
{
public class Playlist
{
public string Name { get; set; } = "";
private string _lastModified;
public string LastModified
{
get
{
return _lastModified;
}
set
{
if (_lastModified == value)
return;
_lastModified = value;
}
}
public string LastModifiedFormated
{
get
{
DateTime _lastModifiedDateTime = default; //new DateTime(1998,04,30)
if (!string.IsNullOrEmpty(_lastModified))
{
try
{
_lastModifiedDateTime = DateTime.Parse(_lastModified, null, System.Globalization.DateTimeStyles.RoundtripKind);
}
catch
{
System.Diagnostics.Debug.WriteLine("Wrong LastModified timestamp format. " + _lastModified);
}
}
var culture = System.Globalization.CultureInfo.CurrentCulture;
return _lastModifiedDateTime.ToString(culture);
}
}
}
}

52
MPDCtrl/Classes/Result.cs Normal file
View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MPDCtrl.Models
{
public class Result
{
public bool IsSuccess;
public string ErrorMessage;
}
public class ConnectionResult: Result
{
}
// generic
public class CommandResult : Result
{
public string ResultText;
}
public class CommandBinaryResult : Result
{
public int WholeSize;
public int ChunkSize;
public string Type;
public byte[] BinaryData;
}
// for commands that return playlist songs.
public class CommandPlaylistResult : CommandResult
{
public ObservableCollection<SongInfo> PlaylistSongs;
}
// for commands that return search result.
public class CommandSearchResult : CommandResult
{
public ObservableCollection<SongInfo> SearchResult;
}
// TODO: Not used?
public class IdleResult : CommandResult
{
}
}

231
MPDCtrl/Classes/Song.cs Normal file
View File

@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using MPDCtrl.Common;
namespace MPDCtrl.Models
{
// SongFile > SongInfo > SongInfoEx
/// <summary>
/// Generic song file class. (for listall)
/// </summary>
public class SongFile// : ViewModelBase
{
public string File { get; set; } = "";
}
/// <summary>
/// SongInfo class. (for playlist or search result)
/// </summary>
public class SongInfo : SongFile
{
public string Title { get; set; } = "";
public string Track { get; set; } = "";
public string Disc { get; set; } = "";
public string Time { get; set; } = "";
public string TimeFormated
{
get
{
string _timeFormatted = "";
try
{
if (!string.IsNullOrEmpty(Time))
{
int sec, min, hour, s;
double dtime = double.Parse(Time);
sec = Convert.ToInt32(dtime);
//sec = Int32.Parse(_time);
min = sec / 60;
s = sec % 60;
hour = min / 60;
min %= 60;
if ((hour == 0) && min == 0)
{
_timeFormatted = String.Format("{0}", s);
}
else if ((hour == 0) && (min != 0))
{
_timeFormatted = String.Format("{0}:{1:00}", min, s);
}
else if ((hour != 0) && (min != 0))
{
_timeFormatted = String.Format("{0}:{1:00}:{2:00}", hour, min, s);
}
else if (hour != 0)
{
_timeFormatted = String.Format("{0}:{1:00}:{2:00}", hour, min, s);
}
else
{
System.Diagnostics.Debug.WriteLine("Oops@TimeFormated: " + Time + " : " + hour.ToString() + " " + min.ToString() + " " + s.ToString());
}
}
}
catch (FormatException e)
{
// Ignore.
// System.Diagnostics.Debug.WriteLine(e.Message);
System.Diagnostics.Debug.WriteLine("Wrong Time format. " + Time + " " + e.Message);
}
return _timeFormatted;
}
}
public double TimeSort
{
get
{
double dtime = double.NaN;
try
{
dtime = double.Parse(Time);
}
catch { }
return dtime;
}
}
public string Duration { get; set; } = "";
public string Artist { get; set; } = "";
public string Album { get; set; } = "";
public string AlbumArtist { get; set; } = "";
public string Composer { get; set; } = "";
public string Date { get; set; } = "";
public string Genre { get; set; } = "";
private string _lastModified;
public string LastModified
{
get
{
return _lastModified;
}
set
{
if (_lastModified == value)
return;
_lastModified = value;
}
}
public string LastModifiedFormated
{
get
{
DateTime _lastModifiedDateTime = default; //new DateTime(1998,04,30)
if (!string.IsNullOrEmpty(_lastModified))
{
try
{
_lastModifiedDateTime = DateTime.Parse(_lastModified, null, System.Globalization.DateTimeStyles.RoundtripKind);
}
catch
{
System.Diagnostics.Debug.WriteLine("Wrong LastModified timestamp format. " + _lastModified);
}
}
var culture = System.Globalization.CultureInfo.CurrentCulture;
return _lastModifiedDateTime.ToString(culture);
}
}
// for sorting and (playlist pos)
private int _index;
public int Index
{
get
{
return _index;
}
set
{
if (_index == value)
return;
_index = value;
//this.NotifyPropertyChanged(nameof(Index));
}
}
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
if (_isSelected == value)
return;
_isSelected = value;
//NotifyPropertyChanged("IsSelected");
}
}
public int IndexPlusOne
{
get
{
return _index+1;
}
}
}
/// <summary>
/// song class with some extra info. (for queue)
/// </summary>
public class SongInfoEx : SongInfo
{
// Queue specific
public string Id { get; set; }
private string _pos;
public string Pos
{
get
{
return _pos;
}
set
{
if (_pos == value)
return;
_pos = value;
//this.NotifyPropertyChanged(nameof(Pos));
}
}
private bool _isPlaying;
public bool IsPlaying
{
get
{
return _isPlaying;
}
set
{
if (_isPlaying == value)
return;
_isPlaying = value;
//this.NotifyPropertyChanged(nameof(IsPlaying));
}
}
}
}

149
MPDCtrl/Classes/Status.cs Normal file
View File

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MPDCtrl.Models
{
/// <summary>
/// MPD "status" class. (for "status" command result)
/// </summary>
public class Status
{
public enum MpdPlayState
{
Play, Pause, Stop
};
private MpdPlayState _ps;
private string _bitrate;
private int _volume = 50;
private bool _volumeIsSet;
private bool _repeat;
private bool _random;
private bool _consume;
private bool _single;
private string _songID = "";
private double _songTime = 0;
private double _songElapsed = 0;
private string _error = "";
public MpdPlayState MpdState
{
get { return _ps; }
set { _ps = value; }
}
public string MpdBitrate
{
get { return _bitrate; }
set
{
_bitrate = value;
}
}
public int MpdVolume
{
get { return _volume; }
set
{
_volume = value;
}
}
public bool MpdVolumeIsSet
{
get { return _volumeIsSet; }
set
{
_volumeIsSet = value;
}
}
public bool MpdRepeat
{
get { return _repeat; }
set
{
_repeat = value;
}
}
public bool MpdRandom
{
get { return _random; }
set
{
_random = value;
}
}
public bool MpdConsume
{
get { return _consume; }
set
{
_consume = value;
}
}
public bool MpdSingle
{
get { return _single; }
set
{
_single = value;
}
}
public string MpdSongID
{
get { return _songID; }
set
{
_songID = value;
}
}
public double MpdSongTime
{
get { return _songTime; }
set
{
_songTime = value;
}
}
public double MpdSongElapsed
{
get { return _songElapsed; }
set
{
_songElapsed = value;
}
}
public string MpdError
{
get { return _error; }
set
{
_error = value;
}
}
public void Reset()
{
_volume = 50;
_volumeIsSet = false;
_repeat = false;
_random = false;
_consume = false;
_songID = "";
_songTime = 0;
_songElapsed = 0;
_error = "";
}
}
}

3722
MPDCtrl/MPC.cs Normal file

File diff suppressed because it is too large Load Diff

69
MainWindow.xaml Normal file
View File

@ -0,0 +1,69 @@
<Window x:Class="unison.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:unison"
mc:Ignorable="d"
Title="unison"
Closing="Window_Closing" Icon="/images/nocover.png" ResizeMode="CanMinimize" WindowStyle="SingleBorderWindow" SizeToContent="WidthAndHeight">
<Grid Background="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" MinHeight="280">
<Grid x:Name="TopLayout" Margin="10,10,10,0" VerticalAlignment="Top" Width="Auto" MinHeight="220">
<Grid x:Name="Display" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="220,0,0,0" MinHeight="220" MinWidth="400">
<Grid x:Name="CurrentSong" Margin="10,0,10,0" VerticalAlignment="Top" MinHeight="140">
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<TextBlock x:Name="SongTitle" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="20"/>
<TextBlock x:Name="SongArtist" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold" FontSize="18"/>
<TextBlock x:Name="SongAlbum" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="16"/>
<TextBlock x:Name="Bitrate" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal"/>
</StackPanel>
</Grid>
<Grid x:Name="Controls" VerticalAlignment="Bottom">
<StackPanel HorizontalAlignment="Stretch" Orientation="Vertical" VerticalAlignment="Center">
<Grid HorizontalAlignment="Center" Margin="0,0,0,5">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="CurrentTime" Text="0:00" TextWrapping="Wrap" HorizontalAlignment="Left"/>
<Slider x:Name="TimeSlider" Height="18" MinWidth="320" Margin="5,0,5,0" HorizontalAlignment="Center" Maximum="100"/>
<TextBlock x:Name="EndTime" Text="0:00" TextWrapping="Wrap" Height="18" HorizontalAlignment="Right"/>
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top">
<Button x:Name="PreviousTrack" Content="⏪︎" Click="Previous_Clicked" FontSize="18" Background="{x:Null}" BorderBrush="{x:Null}" FontWeight="Bold" HorizontalAlignment="Left"/>
<Button x:Name="PauseButton" Content="⏯️" Click="Pause_Clicked" FontSize="18" FontWeight="Bold" Background="{x:Null}" BorderBrush="{x:Null}" Margin="10,0,10,0"/>
<Button x:Name="NextTrack" Content="⏩︎" Click="Next_Clicked" FontSize="18" Background="{x:Null}" BorderBrush="{x:Null}" FontWeight="Bold" HorizontalAlignment="Right"/>
</StackPanel>
<Grid VerticalAlignment="Stretch">
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" HorizontalAlignment="Center" Margin="0,6,0,0">
<TextBlock Text="🔈" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Slider x:Name="VolumeSlider" Maximum="100" Value="50" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" MinWidth="180" FlowDirection="LeftToRight" Margin="5,0,5,0"/>
<TextBlock Text="🔊" TextWrapping="Wrap" HorizontalAlignment="Right" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="Random" Content="🔀" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Background="{x:Null}" BorderBrush="{x:Null}" FontSize="15" Click="Random_Clicked" Foreground="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}"/>
<Button x:Name="Repeat" Content="🔁" Background="{x:Null}" FontSize="15" BorderBrush="{x:Null}" Click="Repeat_Clicked"/>
</StackPanel>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="Single" Content="🔂" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="15" Background="{x:Null}" BorderBrush="{x:Null}" Click="Single_Clicked"/>
<Button x:Name="Consume" Content="❎" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="15" BorderBrush="{x:Null}" Background="{x:Null}" Click="Consume_Clicked"/>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
</Grid>
<Border x:Name="Cover_Border" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Left" VerticalAlignment="Center" MaxWidth="215" MaxHeight="215" >
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="images/nocover.png" MinWidth="215" MinHeight="215" MaxWidth="215" MaxHeight="215"/>
</Border>
</Grid>
<Grid x:Name="BottomLayout" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="{DynamicResource {x:Static SystemColors.AppWorkspaceBrushKey}}" Width="Auto" Margin="0,-2,0,0" MinHeight="40">
<Button x:Name="Snapcast" Content="Start Snapcast" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Snapcast_Clicked" Margin="10,0,0,0" Padding="5, 2"/>
<TextBlock x:Name="DebugText" HorizontalAlignment="Center" Text="debug" TextWrapping="Wrap" VerticalAlignment="Center" TextAlignment="Center" MinWidth="350"/>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,10,0">
<!--<Button x:Name="Settings" Content="Shuffle" Padding="5, 2" HorizontalAlignment="Right" Margin="0,0,10,0"/>
<Button x:Name="Shuffle" Content="Settings" Padding="5, 2"/>-->
</StackPanel>
</Grid>
</Grid>
</Window>

216
MainWindow.xaml.cs Normal file
View File

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using MPDCtrl.Models;
namespace unison
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly MPC _mpd = new();
private bool _connected = false;
private int _currentVolume;
private bool _currentRandom;
private bool _currentRepeat;
private bool _currentSingle;
private bool _currentConsume;
private double _currentElapsed;
private readonly Process _snapcast = new Process();
private bool _snapcastStarted = false;
private string _snapcastVersion = "snapclient_0.25.0-1_win64";
private string _mpdHost = "192.168.1.13";
private int _mpdPort = 6600;
private string _mpdPassword = null;
public MainWindow()
{
InitializeComponent();
ConnectToMPD();
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(0.2);
timer.Tick += timer_Tick;
timer.Start();
}
public async void ConnectToMPD()
{
Trace.WriteLine("Trying to connect...");
_connected = await _mpd.MpdCommandConnectionStart(_mpdHost, _mpdPort, _mpdPassword);
if (_connected)
{
await _mpd.MpdQueryStatus();
await Task.Delay(5);
_currentVolume = _mpd.MpdStatus.MpdVolume;
_currentRandom = _mpd.MpdStatus.MpdRandom;
_currentRepeat = _mpd.MpdStatus.MpdRepeat;
_currentSingle = _mpd.MpdStatus.MpdSingle;
_currentConsume = _mpd.MpdStatus.MpdConsume;
_currentElapsed = _mpd.MpdStatus.MpdSongElapsed;
}
}
void timer_Tick(object sender, EventArgs e)
{
LoopMPD();
UpdateInterface();
}
public void CheckStatus<T>(ref T a, T b)
{
if (Comparer<T>.Default.Compare(a, b) != 0)
a = b;
}
public async void LoopMPD()
{
if (!_connected)
return;
var status = await _mpd.MpdQueryStatus();
//Trace.WriteLine(status.ResultText);
await Task.Delay(5);
if (status != null)
{
CheckStatus(ref _currentVolume, _mpd.MpdStatus.MpdVolume);
CheckStatus(ref _currentRandom, _mpd.MpdStatus.MpdRandom);
CheckStatus(ref _currentRepeat, _mpd.MpdStatus.MpdRepeat);
CheckStatus(ref _currentSingle, _mpd.MpdStatus.MpdSingle);
CheckStatus(ref _currentConsume, _mpd.MpdStatus.MpdConsume);
CheckStatus(ref _currentElapsed, _mpd.MpdStatus.MpdSongElapsed);
}
await _mpd.MpdQueryCurrentSong();
await Task.Delay(5);
}
public void UpdateButton(ref Button button, bool b)
{
if (b)
button.Foreground = System.Windows.SystemColors.GradientActiveCaptionBrush;
else
button.Foreground = System.Windows.SystemColors.DesktopBrush;
}
public string FormatSeconds(double time)
{
var timespan = TimeSpan.FromSeconds(time);
return timespan.ToString(@"mm\:ss");
}
public void UpdateInterface()
{
if (_mpd.MpdCurrentSong != null)
{
SongTitle.Text = _mpd.MpdCurrentSong.Title;
SongTitle.ToolTip = _mpd.MpdCurrentSong.File;
SongArtist.Text = _mpd.MpdCurrentSong.Artist;
SongAlbum.Text = _mpd.MpdCurrentSong.Album + " (" + _mpd.MpdCurrentSong.Date + ")";
Bitrate.Text = _mpd.MpdCurrentSong.File.Substring(_mpd.MpdCurrentSong.File.LastIndexOf(".") + 1);
Bitrate.Text += " ";
Bitrate.Text += _mpd.MpdStatus.MpdBitrate + "kbps";
CurrentTime.Text = FormatSeconds(_currentElapsed);
EndTime.Text = FormatSeconds(_mpd.MpdStatus.MpdSongTime);
TimeSlider.Value = _currentElapsed / _mpd.MpdCurrentSong.TimeSort * 100;
}
if (VolumeSlider.Value != _currentVolume)
{
VolumeSlider.Value = _currentVolume;
VolumeSlider.ToolTip = _currentVolume;
}
if (_mpd.MpdStatus.MpdState == Status.MpdPlayState.Play)
PauseButton.Content = "⏸";
else if (_mpd.MpdStatus.MpdState == Status.MpdPlayState.Pause)
PauseButton.Content = "▶️";
if (_snapcastStarted)
Snapcast.Content = "Stop Snapcast";
else
Snapcast.Content = "Start Snapcast";
DebugText.Text = _mpd.MpdHost + ":" + _mpd.MpdPort;
UpdateButton(ref Random, _currentRandom);
UpdateButton(ref Repeat, _currentRepeat);
UpdateButton(ref Single, _currentSingle);
UpdateButton(ref Consume, _currentConsume);
}
private async void Pause_Clicked(object sender, RoutedEventArgs e)
{
if (_mpd.MpdStatus.MpdState == Status.MpdPlayState.Play)
await _mpd.MpdPlaybackPause();
else if (_mpd.MpdStatus.MpdState == Status.MpdPlayState.Pause)
await _mpd.MpdPlaybackPlay(_currentVolume);
}
private async void Previous_Clicked(object sender, RoutedEventArgs e)
{
await _mpd.MpdPlaybackPrev(_currentVolume);
}
private async void Next_Clicked(object sender, RoutedEventArgs e)
{
await _mpd.MpdPlaybackNext(_currentVolume);
}
private async void Random_Clicked(object sender, RoutedEventArgs e)
{
await _mpd.MpdSetRandom(!_currentRandom);
}
private async void Repeat_Clicked(object sender, RoutedEventArgs e)
{
await _mpd.MpdSetRepeat(!_currentRepeat);
}
private async void Single_Clicked(object sender, RoutedEventArgs e)
{
await _mpd.MpdSetSingle(!_currentSingle);
}
private async void Consume_Clicked(object sender, RoutedEventArgs e)
{
await _mpd.MpdSetConsume(!_currentConsume);
}
private void Snapcast_Clicked(object sender, RoutedEventArgs e)
{
if (!_snapcastStarted)
{
_snapcast.StartInfo.FileName = _snapcastVersion + @"\snapclient.exe";
_snapcast.StartInfo.Arguments = "--host " + _mpd.MpdHost;
_snapcast.StartInfo.CreateNoWindow = true;
_snapcast.Start();
_snapcastStarted = true;
}
else
{
_snapcast.Kill();
_snapcastStarted = false;
}
}
private void Window_Closing(object sender, CancelEventArgs e)
{
if (_snapcastStarted)
_snapcast.Kill();
}
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net5.0-windows</TargetFramework>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

BIN
images/nocover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

47
unison.csproj Normal file
View File

@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ApplicationIcon>unison.ico</ApplicationIcon>
<Win32Resource></Win32Resource>
<StartupObject>unison.App</StartupObject>
<Version>0.0.1</Version>
</PropertyGroup>
<ItemGroup>
<None Remove="images\nocover.png" />
<None Remove="snapclient_0.25.0-1_win64\FLAC.dll" />
<None Remove="snapclient_0.25.0-1_win64\ogg.dll" />
<None Remove="snapclient_0.25.0-1_win64\opus.dll" />
<None Remove="snapclient_0.25.0-1_win64\snapclient.exe" />
<None Remove="snapclient_0.25.0-1_win64\soxr.dll" />
<None Remove="snapclient_0.25.0-1_win64\vorbis.dll" />
</ItemGroup>
<ItemGroup>
<Resource Include="images\nocover.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<Content Include="snapclient_0.25.0-1_win64\FLAC.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="snapclient_0.25.0-1_win64\ogg.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="snapclient_0.25.0-1_win64\opus.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="snapclient_0.25.0-1_win64\snapclient.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="snapclient_0.25.0-1_win64\soxr.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="snapclient_0.25.0-1_win64\vorbis.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

BIN
unison.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

25
unison.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31515.178
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "unison", "unison.csproj", "{489048C4-3FCA-4573-B34C-943D03F94D04}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{489048C4-3FCA-4573-B34C-943D03F94D04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{489048C4-3FCA-4573-B34C-943D03F94D04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{489048C4-3FCA-4573-B34C-943D03F94D04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{489048C4-3FCA-4573-B34C-943D03F94D04}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {12DA9EE9-38C6-4BBE-8133-6F7F30AF3A67}
EndGlobalSection
EndGlobal