diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7665042 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "herse.models"] + path = herse.models + url = git@bitbucket.org:teamherse/herse.models.git diff --git a/FirebaseKaraoke/FirebaseController.cs b/FirebaseKaraoke/FirebaseController.cs index 0ac9225..28a25f5 100644 --- a/FirebaseKaraoke/FirebaseController.cs +++ b/FirebaseKaraoke/FirebaseController.cs @@ -1,32 +1,77 @@ using System; using System.Collections.Generic; using System.Linq; -using KaraokePlayer.Interfaces; using KaraokePlayer.Enums; using FireSharp.Interfaces; using FireSharp.Config; using FireSharp; +using Newtonsoft.Json; +using System.Configuration; namespace KaraokePlayer.Classes { - public class FirebaseSong : ISong + + public class Singer { - public Guid Id { get; set; } - public int Order { get; set; } - public string Title { get; set; } - public string Artist { get; set; } - public FileType FileType { get; set; } - public string Path { get; set; } - public string Description { get { return Artist + " - " + Title; } } + [JsonProperty("name")] + public string Name { get; set; } } - public class FirebaseController : IController + public class Song + { + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("artist")] + public string Artist { get; set; } + + [JsonProperty("genre")] + public string Genre { get; set; } + + [JsonProperty("year")] + public int Year { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + + [JsonIgnore] + public FileType FileType + { + get + { + switch (Path.Substring(Path.Length - 3, 3).ToLower()) + { + case "cdg": + case "mp3": + return FileType.CDG; + case "mp4": + return FileType.MP4; + case "zip": + return FileType.ZIP; + default: + throw new Exception("file type not handled"); + + } + } + } + } + + + public class QueueItem + { + [JsonProperty("singer")] + public Singer Singer { get; set; } + + [JsonProperty("song")] + public Song Song { get; set; } + } + + public class FirebaseController { - public static Guid TestGuid = Guid.Parse("f1ec2c8a-6f11-4ac0-8b0e-e576d15f2759"); private IFirebaseConfig config = new FirebaseConfig { - AuthSecret = "wj0ERDFZqNSysTtIXcCgCr8Itahr6pJOBeqCjvDF", - BasePath = "https://karaokecontroller.firebaseio.com/" + AuthSecret = ConfigurationManager.AppSettings["Firebase.Secret"], + BasePath = ConfigurationManager.AppSettings["Firebase.Path"] }; private string _state = "stop"; private IFirebaseClient _client; @@ -36,36 +81,36 @@ namespace KaraokePlayer.Classes private string StatePath { - get { return string.Format("Controllers/{0}/State", this.Id); } + get { return string.Format("controllers/{0}/state/", this.Id); } } private string PlayQueuePath { - get { return string.Format("Controllers/{0}/PlayQueue", this.Id); } + get { return string.Format("controllers/{0}/queue/", this.Id); } } private string CurrentSongPath { - get { return string.Format("Controllers/{0}/CurrentSong", this.Id); } + get { return string.Format("controllers/{0}/queue/0/", this.Id); } } - public Guid Id { get; set; } - public ISong CurrentSong { get; set; } - public List PlayQueue { get; set; } + public string Id { get; set; } + public Song CurrentSong { get; set; } + public List PlayQueue { get; set; } public string State { get { return State; } set { _state = value; - Update(string.Format("Controllers/{0}", this.Id), new { State = _state }); + Update(string.Format("controllers/{0}", this.Id), new { state = _state }); } } - public FirebaseController(Guid clientId, ControllerStateChangedEventHandler stateChanged, ControllerSongChangedEventHandler songChanged, ControllerPlayQueueChangedEventHandler playQueueChanged) + public FirebaseController(string clientId, ControllerStateChangedEventHandler stateChanged, ControllerSongChangedEventHandler songChanged, ControllerPlayQueueChangedEventHandler playQueueChanged) { Id = clientId; _stateChanged = stateChanged; _songChanged = songChanged; _playQueueChanged = playQueueChanged; - PlayQueue = new List(); + PlayQueue = new List(); _client = new FirebaseClient(config); Reset(); SetupListener(); @@ -73,46 +118,12 @@ namespace KaraokePlayer.Classes public void NextSong() { - ISong song = PlayQueue.FirstOrDefault(); + Song song = PlayQueue.FirstOrDefault(); Stop(); if(song != null) { PlaySong(song); } } - public void PlaySong(ISong song) { Update(string.Format("Controllers/{0}", this.Id), new { CurrentSong = song }); } - - public void AddSong(ISong song) { Update(string.Format("Controllers/{0}/PlayQueue/{1}", this.Id, song.Id), song); } - - public void RemoveSong(ISong song) - { - ISong found = PlayQueue.FirstOrDefault(s => s.Id == song.Id); - if (found != null) - { - PlayQueue.Remove(found); - Delete(PlayQueuePath + "/" + song.Id); - } - } - - public void SkipSong() - { - ISong song = null; - int count = PlayQueue.Count(); - int index = PlayQueue.FindIndex(s => s.Id == CurrentSong.Id); - if (index + 1 == count && count > 1) - { - song = PlayQueue.First(); - } - else { - if (PlayQueue.Count() > index) - { - song = PlayQueue[index + 1]; - } - } - Stop(); - if(song != null) - { - PlaySong(song); - } - } + public void PlaySong(Song song) { Update(string.Format("Controllers/{0}", this.Id), new { CurrentSong = song }); } public void Next() { this.State = "Next"; } @@ -130,7 +141,7 @@ namespace KaraokePlayer.Classes { Stop(); Delete(PlayQueuePath); - Delete(CurrentSongPath); + Delete(CurrentSongPath); } private async void SetupListener() @@ -138,24 +149,26 @@ namespace KaraokePlayer.Classes await _client.OnAsync(CurrentSongPath, added: (s, args, obj) => { - if (args.Path.Contains("Id")) + if (args.Path == "/singer/name") { + Console.WriteLine("added " + args.Path + " " + args.Data); CurrentSongDidChange(); } - }, - changed: (s, args, obj) => + }, + removed: (s, args, obj) => { - if (args.Path.Contains("Id")) + //TODO: the current song was removed from the queue + if (args.Path == "/singer") { - CurrentSongDidChange(); + Console.WriteLine("removed " + args.Path); } - }, - removed: null + } ); - + /* await _client.OnAsync(PlayQueuePath, added: (s, args, obj) => { + Console.WriteLine(args.Path); if (args.Path.Contains("Id")) { PlayQueueDidChange(); @@ -185,18 +198,19 @@ namespace KaraokePlayer.Classes }, removed: null ); + */ } private void PlayQueueDidChange() { bool autoPlay = PlayQueue.Count() == 0; var response = _client.Get(PlayQueuePath); - var dict = response.ResultAs>(); + var dict = response.ResultAs>(); PlayQueue.Clear(); if (dict != null && dict.Count() > 0) { - var array = dict.Values.OrderBy(s => s.Order).ToArray(); + var array = dict.Values.ToArray(); PlayQueue.AddRange(array); if (autoPlay) { @@ -209,11 +223,11 @@ namespace KaraokePlayer.Classes private void CurrentSongDidChange() { var response = _client.Get(CurrentSongPath); - var song = response.ResultAs(); - if (song != null) + var item = response.ResultAs(); + if (item != null) { - CurrentSong = song; - _songChanged(new ControllerSongChangedEventArgs(false, song)); + CurrentSong = item.Song; + _songChanged(new ControllerSongChangedEventArgs(item.Song)); } } @@ -233,7 +247,7 @@ namespace KaraokePlayer.Classes { s = PlayerState.Next; } - _stateChanged(new ControllerStateChangedEventArgs(s)); + //_stateChanged(new ControllerStateChangedEventArgs(s)); } } diff --git a/FirebaseKaraoke/FirebaseKaraoke.csproj b/FirebaseKaraoke/FirebaseKaraoke.csproj index f50d235..c32abee 100644 --- a/FirebaseKaraoke/FirebaseKaraoke.csproj +++ b/FirebaseKaraoke/FirebaseKaraoke.csproj @@ -51,6 +51,7 @@ True + @@ -73,7 +74,6 @@ - diff --git a/FirebaseKaraoke/Interfaces.cs b/FirebaseKaraoke/Interfaces.cs deleted file mode 100644 index 0d47a12..0000000 --- a/FirebaseKaraoke/Interfaces.cs +++ /dev/null @@ -1,36 +0,0 @@ -using KaraokePlayer.Enums; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace KaraokePlayer.Interfaces -{ - public interface ISong - { - Guid Id { get; set; } - int Order { get; set; } - string Title { get; set; } - string Artist { get; set; } - FileType FileType { get; set; } - string Path { get; set; } - string Description { get; } - } - - public interface IController - { - Guid Id { get; set; } - ISong CurrentSong { get; set; } - string State { get; set; } - List PlayQueue { get; set; } - void NextSong(); - void RemoveSong(ISong song); - void AddSong(ISong song); - void SkipSong(); - void Play(); - void Pause(); - void Stop(); - void Next(); - } -} diff --git a/FirebaseKaraoke/PlayerDelegates.cs b/FirebaseKaraoke/PlayerDelegates.cs index 007f3e7..af67f7d 100644 --- a/FirebaseKaraoke/PlayerDelegates.cs +++ b/FirebaseKaraoke/PlayerDelegates.cs @@ -1,5 +1,4 @@ using KaraokePlayer.Enums; -using KaraokePlayer.Interfaces; using System; using System.Collections.Generic; using System.Linq; @@ -18,17 +17,17 @@ namespace KaraokePlayer.Classes } public class ControllerSongChangedEventArgs { - public ControllerSongChangedEventArgs(ISong song) + public ControllerSongChangedEventArgs(Song song) { ShouldPlay = true; Song = song; } - public ControllerSongChangedEventArgs(bool shouldPlay, ISong song) + public ControllerSongChangedEventArgs(bool shouldPlay, Song song) { ShouldPlay = shouldPlay; Song = song; } - public ISong Song { get; } + public Song Song { get; } public bool ShouldPlay { get; } } diff --git a/KaraokePlayer.sln b/KaraokePlayer.sln index 36498c6..520ff4e 100644 --- a/KaraokePlayer.sln +++ b/KaraokePlayer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CdgLib", "CdgLib\CdgLib.csproj", "{3203DFD2-DA5B-47B3-B009-18DD9C401FC3}" EndProject @@ -13,10 +13,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KaraokePlayer", "KaraokePla EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CdgPlayer", "CdgPlayer\CdgPlayer.csproj", "{A5324295-6BD2-4415-92CD-6EA77D708E00}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestSelector", "TestSelector\TestSelector.csproj", "{B81665BC-A207-47F5-BBF4-2DE59965325F}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FirebaseKaraoke", "FirebaseKaraoke\FirebaseKaraoke.csproj", "{4FE25E6D-1BEB-4902-9815-C2B421233BD7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SongCrawler", "SongCrawler\SongCrawler.csproj", "{82F60DD0-80EC-49C8-9E7C-95A250783E68}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Herse.Models", "herse.models\Herse.Models.csproj", "{BDE9BC7B-DB3D-4A28-9902-B5D8D1965E5C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -35,14 +37,18 @@ Global {A5324295-6BD2-4415-92CD-6EA77D708E00}.Debug|Any CPU.Build.0 = Debug|Any CPU {A5324295-6BD2-4415-92CD-6EA77D708E00}.Release|Any CPU.ActiveCfg = Release|Any CPU {A5324295-6BD2-4415-92CD-6EA77D708E00}.Release|Any CPU.Build.0 = Release|Any CPU - {B81665BC-A207-47F5-BBF4-2DE59965325F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B81665BC-A207-47F5-BBF4-2DE59965325F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B81665BC-A207-47F5-BBF4-2DE59965325F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B81665BC-A207-47F5-BBF4-2DE59965325F}.Release|Any CPU.Build.0 = Release|Any CPU {4FE25E6D-1BEB-4902-9815-C2B421233BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FE25E6D-1BEB-4902-9815-C2B421233BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FE25E6D-1BEB-4902-9815-C2B421233BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU {4FE25E6D-1BEB-4902-9815-C2B421233BD7}.Release|Any CPU.Build.0 = Release|Any CPU + {82F60DD0-80EC-49C8-9E7C-95A250783E68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {82F60DD0-80EC-49C8-9E7C-95A250783E68}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82F60DD0-80EC-49C8-9E7C-95A250783E68}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82F60DD0-80EC-49C8-9E7C-95A250783E68}.Release|Any CPU.Build.0 = Release|Any CPU + {BDE9BC7B-DB3D-4A28-9902-B5D8D1965E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDE9BC7B-DB3D-4A28-9902-B5D8D1965E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDE9BC7B-DB3D-4A28-9902-B5D8D1965E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDE9BC7B-DB3D-4A28-9902-B5D8D1965E5C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/KaraokePlayer/App.config b/KaraokePlayer/App.config index dd5da42..e89053c 100644 --- a/KaraokePlayer/App.config +++ b/KaraokePlayer/App.config @@ -3,10 +3,13 @@
- - - - + + + + + + + diff --git a/KaraokePlayer/KaraokePlayer.csproj b/KaraokePlayer/KaraokePlayer.csproj index 66d8d73..80b48a0 100644 --- a/KaraokePlayer/KaraokePlayer.csproj +++ b/KaraokePlayer/KaraokePlayer.csproj @@ -79,6 +79,7 @@ + diff --git a/KaraokePlayer/MainForm.cs b/KaraokePlayer/MainForm.cs index 32c7bc6..270cfbf 100644 --- a/KaraokePlayer/MainForm.cs +++ b/KaraokePlayer/MainForm.cs @@ -7,9 +7,9 @@ using System.Linq; using System.Text.RegularExpressions; using System.IO.Compression; using System.Windows.Forms; -using KaraokePlayer.Interfaces; using KaraokePlayer.Classes; using System.Threading.Tasks; +using System.Configuration; namespace KaraokePlayer { @@ -18,8 +18,8 @@ namespace KaraokePlayer private SongInfoForm songInfoForm = new SongInfoForm(); private delegate void Action(); private KaraokeVideoPlayer currentPlayer = null; - private IController controller; - private ISong currentSong; + private FirebaseController controller; + private Song currentSong; public MainForm() { InitializeComponent(); @@ -35,7 +35,7 @@ namespace KaraokePlayer karaokeMP4Player.Dock = DockStyle.Fill; controller = new FirebaseController( - clientId: FirebaseController.TestGuid, + clientId: ConfigurationManager.AppSettings["KaraokePlayer.ControllerId"], stateChanged: (args) => { if (args.State == Enums.PlayerState.Play) @@ -70,7 +70,8 @@ namespace KaraokePlayer songInfoForm.Update(currentSong); songInfoForm.Show(); await Task.Delay(TimeSpan.FromSeconds(5)); - controller.Play(); + //controller.Play(); + play(); songInfoForm.Hide(); } @@ -81,7 +82,6 @@ namespace KaraokePlayer private void next() { - controller.RemoveSong(currentSong); controller.NextSong(); } diff --git a/KaraokePlayer/SongInfoForm.Designer.cs b/KaraokePlayer/SongInfoForm.Designer.cs index b1d5998..a10a1ea 100644 --- a/KaraokePlayer/SongInfoForm.Designer.cs +++ b/KaraokePlayer/SongInfoForm.Designer.cs @@ -1,6 +1,4 @@ -using KaraokePlayer.Interfaces; - -namespace KaraokePlayer +namespace KaraokePlayer { partial class SongInfoForm { diff --git a/KaraokePlayer/SongInfoForm.cs b/KaraokePlayer/SongInfoForm.cs index 7528062..3cbd206 100644 --- a/KaraokePlayer/SongInfoForm.cs +++ b/KaraokePlayer/SongInfoForm.cs @@ -1,4 +1,4 @@ -using KaraokePlayer.Interfaces; +using KaraokePlayer.Classes; using System; using System.Collections.Generic; using System.ComponentModel; @@ -21,7 +21,7 @@ namespace KaraokePlayer this.ShowInTaskbar = false; } - public void Update(ISong song) + public void Update(Song song) { previewLabel.Text = "Up Next:" + "\r\n\r\n" + song.Artist + "\r\n\r\n\r\n" + song.Title; } diff --git a/SongCrawler/App.config b/SongCrawler/App.config new file mode 100644 index 0000000..71a06ba --- /dev/null +++ b/SongCrawler/App.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SongCrawler/Program.cs b/SongCrawler/Program.cs new file mode 100644 index 0000000..db1c182 --- /dev/null +++ b/SongCrawler/Program.cs @@ -0,0 +1,40 @@ +using FireSharp.Config; +using FireSharp.Interfaces; +using FireSharp.Response; +using Herse.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SongCrawler +{ + class Program + { + static void Main(string[] args) + { + string controller = args[0]; + string songpath = args[1]; + IFirebaseConfig config = new FirebaseConfig + { + AuthSecret = "9BQHUEJhScgK2FP10hvlToxTlGQpXT94Cvx01piO", + BasePath = "https://herse.firebaseio.com/" + }; + FireSharp.FirebaseClient client = new FireSharp.FirebaseClient(config); + string firepath = string.Format("controllers/{0}/songs", controller); + + + string[] files = Directory.GetFiles(songpath, "*.mp3"); + List songs = new List(); + foreach (string file in files) + { + TagLib.File tagFile = TagLib.File.Create(file); + songs.Add(new Song() { Title = tagFile.Tag.Title, Artist = tagFile.Tag.FirstPerformer, Path = file, Genre = tagFile.Tag.FirstGenre, Year = (int)tagFile.Tag.Year }); + } + + SetResponse response = client.Set(firepath, songs); + } + } +} diff --git a/SongCrawler/Properties/AssemblyInfo.cs b/SongCrawler/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a23dc8a --- /dev/null +++ b/SongCrawler/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 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("SongCrawler")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SongCrawler")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[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)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("82f60dd0-80ec-49c8-9e7c-95a250783e68")] + +// 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/SongCrawler/SongCrawler.csproj b/SongCrawler/SongCrawler.csproj new file mode 100644 index 0000000..6aab986 --- /dev/null +++ b/SongCrawler/SongCrawler.csproj @@ -0,0 +1,109 @@ + + + + + Debug + AnyCPU + {82F60DD0-80EC-49C8-9E7C-95A250783E68} + Exe + Properties + SongCrawler + SongCrawler + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\FireSharp.2.0.4\lib\portable-net45+sl5+wp8+win8\FireSharp.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True + + + + + + ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll + True + + + + + + + + + + False + libs\taglib-sharp.dll + + + + + + + + + + + + + {BDE9BC7B-DB3D-4A28-9902-B5D8D1965E5C} + Herse.Models + + + + + + + + + + + + + \ No newline at end of file diff --git a/SongCrawler/libs/taglib-sharp.dll b/SongCrawler/libs/taglib-sharp.dll new file mode 100644 index 0000000..4d61148 Binary files /dev/null and b/SongCrawler/libs/taglib-sharp.dll differ diff --git a/SongCrawler/packages.config b/SongCrawler/packages.config new file mode 100644 index 0000000..d628a03 --- /dev/null +++ b/SongCrawler/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/TestSelector/Form1.cs b/TestSelector/Form1.cs index 3338b0a..6aedbe6 100644 --- a/TestSelector/Form1.cs +++ b/TestSelector/Form1.cs @@ -83,7 +83,6 @@ namespace TestSelector _fileList = filtered.Select(file => new FileInfo(file)).ToList(); listBox1.DataSource = _fileList; listBox1.DisplayMember = "Name"; - } } private static string[] GetFiles(string path, string searchPattern, SearchOption searchOption) diff --git a/TestSongs/SF365/Thumbs.db b/TestSongs/SF365/Thumbs.db new file mode 100644 index 0000000..94c5864 Binary files /dev/null and b/TestSongs/SF365/Thumbs.db differ diff --git a/herse.models b/herse.models new file mode 160000 index 0000000..bb11626 --- /dev/null +++ b/herse.models @@ -0,0 +1 @@ +Subproject commit bb1162615a259730c3c5786142525060bc1a3128