443 lines
16 KiB
C#
443 lines
16 KiB
C#
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;
|
|
using System.IO.Compression;
|
|
using System.Configuration;
|
|
using Newtonsoft.Json;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace SongCrawler
|
|
{
|
|
|
|
class Program
|
|
{
|
|
private static Guid GuidFromString(string input)
|
|
{
|
|
using (MD5 md5 = MD5.Create())
|
|
{
|
|
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(input));
|
|
return new Guid(hash);
|
|
}
|
|
}
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
if (args.Count() == 3)
|
|
{
|
|
DeleteSongs(args);
|
|
}
|
|
else {
|
|
CrawlSongs(args);
|
|
}
|
|
|
|
}
|
|
|
|
private static void CrawlSongs(string[] args)
|
|
{
|
|
//string [] test = { "mbrucedogs", "z://" };
|
|
//args = test;
|
|
var debug = false;
|
|
if (args.Length != 2)
|
|
{
|
|
Console.WriteLine("usage: songcrawler partyid songspath");
|
|
return;
|
|
}
|
|
string controller = args[0];
|
|
string songpath = args[1];
|
|
IFirebaseConfig config = new FirebaseConfig
|
|
{
|
|
AuthSecret = ConfigurationManager.AppSettings["Firebase.Secret"],
|
|
BasePath = ConfigurationManager.AppSettings["Firebase.Path"]
|
|
};
|
|
FireSharp.FirebaseClient client = new FireSharp.FirebaseClient(config);
|
|
string songsPath = string.Format("controllers/{0}/songs", controller);
|
|
string favoritesPath = string.Format("controllers/{0}/favorites", controller);
|
|
string disabledPath = string.Format("controllers/{0}/disabled", controller);
|
|
Console.WriteLine("Loading current library");
|
|
|
|
List<Song> songs = null; //client.Get(songsPath).ResultAs<List<Song>>();
|
|
List<Song> disabled = null;
|
|
List<Song> favorited = null;
|
|
try
|
|
{
|
|
disabled = client.Get(disabledPath).ResultAs<List<Song>>();
|
|
}
|
|
catch
|
|
{
|
|
disabled = convertToList(client.Get(disabledPath).Body);
|
|
}
|
|
|
|
try
|
|
{
|
|
favorited = client.Get(favoritesPath).ResultAs<List<Song>>();
|
|
}
|
|
catch
|
|
{
|
|
favorited = convertToList(client.Get(favoritesPath).Body);
|
|
}
|
|
|
|
songs = new List<Song>();
|
|
|
|
client.Set(songsPath, songs);
|
|
|
|
List<string> files = new List<string>();
|
|
files.AddRange(FindFiles("mp4", songpath));
|
|
files.AddRange(FindFiles("mp3", songpath));
|
|
files.AddRange(FindFiles("zip", songpath));
|
|
|
|
Song song = null;
|
|
int i = 0;
|
|
foreach (string filepath in files)
|
|
{
|
|
i++;
|
|
try
|
|
{
|
|
song = MakeSong(filepath);
|
|
Console.WriteLine(string.Format("{0:000000}/{1} - {2} - {3}", i, files.Count, song.Artist, song.Title));
|
|
songs.Add(song);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.Message);
|
|
}
|
|
if (debug && i > 1000)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//sync all favorite, history, disabled
|
|
if (favorited != null && favorited.Count > 0)
|
|
{
|
|
favorited.ForEach(s =>
|
|
{
|
|
if (s != null)
|
|
{
|
|
var found = songs.Find(ls => s.Path.ToLower() == ls.Path.ToLower());
|
|
if (found != null)
|
|
{
|
|
found.Favorite = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (disabled != null && disabled.Count > 0)
|
|
{
|
|
disabled.ForEach(s =>
|
|
{
|
|
if (s != null)
|
|
{
|
|
var found = songs.Find(ls => s.Path.ToLower() == ls.Path.ToLower());
|
|
if (found != null)
|
|
{
|
|
found.Disabled = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
client.Set(songsPath, songs);
|
|
|
|
//string test = string.Format("controllers/{0}/testsongs", controller);
|
|
//Dictionary<string, Song> testSongs = new Dictionary<string, Song>();
|
|
//foreach (Song s in songs)
|
|
//{
|
|
// testSongs[s.Guid] = s;
|
|
//}
|
|
//client.Set(test, testSongs);
|
|
|
|
var created = songs.Select(s => new CreatedSong(File.GetCreationTime(s.Path), s)).ToList();
|
|
var first200 = created.Where(s => s.created != null).OrderByDescending(s => s.created).Take(200);
|
|
var added = first200.Select(s => new PathOnly(path: s.song.Path)).ToList();
|
|
string newSongs = string.Format("controllers/{0}/newSongs", controller);
|
|
client.Set(newSongs, added);
|
|
|
|
}
|
|
private class PathOnly
|
|
{
|
|
[JsonProperty("path")]
|
|
public String Path { get; set; }
|
|
public PathOnly(string path)
|
|
{
|
|
this.Path = path;
|
|
}
|
|
}
|
|
|
|
private static List<Song> convertToList(dynamic json)
|
|
{
|
|
dynamic data = JsonConvert.DeserializeObject<dynamic>(json);
|
|
var list = new List<Song>();
|
|
foreach (var itemDynamic in data)
|
|
{
|
|
var fjson = itemDynamic.Value.ToString();
|
|
var f = JsonConvert.DeserializeObject<Song>(fjson);
|
|
list.Add(f);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private static void DeleteSongs(string[] args)
|
|
{
|
|
if (args.Length != 3)
|
|
{
|
|
Console.WriteLine("usage: songcrawler partyid songspath delete");
|
|
return;
|
|
}
|
|
string controller = args[0];
|
|
string songpath = args[1];
|
|
IFirebaseConfig config = new FirebaseConfig
|
|
{
|
|
AuthSecret = ConfigurationManager.AppSettings["Firebase.Secret"],
|
|
BasePath = ConfigurationManager.AppSettings["Firebase.Path"]
|
|
};
|
|
FireSharp.FirebaseClient client = new FireSharp.FirebaseClient(config);
|
|
string firepath = string.Format("controllers/{0}/songs", controller);
|
|
Console.WriteLine("Deleting Songs ...");
|
|
List<Song> songs = new List<Song>();
|
|
client.Set(firepath, songs);
|
|
|
|
}
|
|
public class CreatedSong
|
|
{
|
|
public DateTime created { get; set; }
|
|
public Song song { get; set; }
|
|
public CreatedSong(DateTime created, Song song)
|
|
{
|
|
this.song = song;
|
|
this.created = created;
|
|
}
|
|
}
|
|
|
|
|
|
private static void CrawlNoDupeSongs(string[] args)
|
|
{
|
|
if (args.Length != 2)
|
|
{
|
|
Console.WriteLine("usage: songcrawler partyid songspath");
|
|
return;
|
|
}
|
|
string controller = args[0];
|
|
string songpath = args[1];
|
|
IFirebaseConfig config = new FirebaseConfig
|
|
{
|
|
AuthSecret = ConfigurationManager.AppSettings["Firebase.Secret"],
|
|
BasePath = ConfigurationManager.AppSettings["Firebase.Path"]
|
|
};
|
|
FireSharp.FirebaseClient client = new FireSharp.FirebaseClient(config);
|
|
string firepath = string.Format("controllers/{0}/songs", controller);
|
|
Console.WriteLine("Loading current library");
|
|
List<Song> songs = new List<Song>();
|
|
|
|
List<string> files = new List<string>();
|
|
files.AddRange(FindFiles("mp4", songpath));
|
|
files.AddRange(FindFiles("mp3", songpath));
|
|
files.AddRange(FindFiles("zip", songpath));
|
|
|
|
Song song = null;
|
|
int i = 0;
|
|
foreach (string filepath in files)
|
|
{
|
|
i++;
|
|
try
|
|
{
|
|
song = MakeSong(filepath);
|
|
Console.WriteLine(string.Format("{0:000000}/{1} - {2}", i, files.Count(), song.Title));
|
|
if (!songs.Any(s => s.Title.ToLower() == song.Title.ToLower() && s.Artist.ToLower() == song.Artist.ToLower())) songs.Add(song);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.Message);
|
|
}
|
|
}
|
|
Console.WriteLine(string.Format("{0:000000}/{1} unique songs", songs.Count(), files.Count()));
|
|
client.Set(firepath, songs);
|
|
}
|
|
|
|
private static void FindDuplicates(string[] args)
|
|
{
|
|
string songpath = @"D:\KaraokeData\Karaoke"; // args[0];
|
|
List<Song> songs = songs = new List<Song>();
|
|
|
|
List<string> files = new List<string>();
|
|
files.AddRange(FindFiles("mp3", songpath));
|
|
files.AddRange(FindFiles("zip", songpath));
|
|
files.AddRange(FindFiles("mp4", songpath));
|
|
|
|
Song song = null;
|
|
int i = 0;
|
|
foreach (string filepath in files)
|
|
{
|
|
i++;
|
|
try
|
|
{
|
|
song = MakeSong(filepath);
|
|
Console.WriteLine(string.Format("{0:000000}/{1} - {2}", i, files.Count, song.Title));
|
|
songs.Add(song);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.Message);
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
Dictionary<string, List<Song>> dupes = new Dictionary<string, List<Song>>();
|
|
foreach (var localsong in songs)
|
|
{
|
|
i++;
|
|
Console.WriteLine(string.Format("Checking for {0:000000}/{1}) {2} - {3}", i, files.Count, localsong.Artist, localsong.Title));
|
|
if (!string.IsNullOrEmpty(localsong.Artist) && !string.IsNullOrEmpty(localsong.Title))
|
|
{
|
|
string key = localsong.Artist + " - " + localsong.Title;
|
|
if (dupes.ContainsKey(key) == false)
|
|
{
|
|
var dsongs = songs.Where(s => s.Title.ToLower() == localsong.Title.ToLower() && s.Artist.ToLower() == localsong.Artist.ToLower());
|
|
if (dsongs.Count() > 1)
|
|
{
|
|
List<Song> d = new List<Song>();
|
|
d.AddRange(dsongs.ToList());
|
|
dupes.Add(key, d);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
File.WriteAllText(@"D:\dupliates.json", JsonConvert.SerializeObject(dupes.OrderBy(o => o.Key)));
|
|
}
|
|
private static void DisableDuplicates(string[] args)
|
|
{
|
|
if (args.Length != 1)
|
|
{
|
|
Console.WriteLine("usage: songcrawler partyid songspath");
|
|
return;
|
|
}
|
|
string controller = args[0];
|
|
IFirebaseConfig config = new FirebaseConfig
|
|
{
|
|
AuthSecret = ConfigurationManager.AppSettings["Firebase.Secret"],
|
|
BasePath = ConfigurationManager.AppSettings["Firebase.Path"]
|
|
};
|
|
FireSharp.FirebaseClient client = new FireSharp.FirebaseClient(config);
|
|
string firepath = string.Format("controllers/{0}/songs", controller);
|
|
Console.WriteLine("Loading current library");
|
|
List<Song> songs = client.Get(firepath).ResultAs<List<Song>>();
|
|
|
|
Dictionary<string, List<Song>> dupes = new Dictionary<string, List<Song>>();
|
|
|
|
int i = 0;
|
|
foreach (var localsong in songs)
|
|
{
|
|
i++;
|
|
Console.WriteLine(string.Format("Checking for {0:000000}/{1}) {2} - {3}", i, songs.Count, localsong.Artist, localsong.Title));
|
|
if (!string.IsNullOrEmpty(localsong.Artist) && !string.IsNullOrEmpty(localsong.Title) && localsong.Disabled == false && localsong.Path.Contains(".mp4"))
|
|
{
|
|
string key = localsong.Artist + " - " + localsong.Title;
|
|
if (dupes.ContainsKey(key) == false)
|
|
{
|
|
var dsongs = songs.Where(s =>
|
|
s.Path != localsong.Path &&
|
|
s.Title.ToLower() == localsong.Title.ToLower() &&
|
|
s.Artist.ToLower() == localsong.Artist.ToLower() &&
|
|
localsong.Disabled == false);
|
|
|
|
if (dsongs.Count() > 1)
|
|
{
|
|
List<Song> d = new List<Song>();
|
|
d.AddRange(dsongs.ToList());
|
|
dupes.Add(key, d);
|
|
}
|
|
foreach (var item in dsongs)
|
|
{
|
|
item.Disabled = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
client.Set(firepath, songs);
|
|
}
|
|
|
|
private static Song MakeSong(string filepath)
|
|
{
|
|
|
|
Song song = null;
|
|
var ext = Path.GetExtension(filepath).ToLower();
|
|
switch (ext)
|
|
{
|
|
case ".mp3":
|
|
case ".mp4":
|
|
song = ReadId3(filepath);
|
|
break;
|
|
case ".zip":
|
|
song = ReadId3FromZip(filepath);
|
|
break;
|
|
}
|
|
CheckTitle(song);
|
|
song.Path = filepath;
|
|
song.Guid = GuidFromString(filepath).ToString();
|
|
return song;
|
|
}
|
|
|
|
private static string[] FindFiles(string ext, string path)
|
|
{
|
|
Console.Write(string.Format("\rscanning {0} for {1} - ", path, ext));
|
|
string[] files = Directory.GetFiles(path, "*." + ext, SearchOption.AllDirectories);
|
|
Console.WriteLine(string.Format("{0} found", files.Length));
|
|
return files;
|
|
}
|
|
|
|
private static void CheckTitle(Song song)
|
|
{
|
|
if(string.IsNullOrEmpty(song.Title))
|
|
{
|
|
string file = Path.GetFileNameWithoutExtension(song.Path);
|
|
string[] parts = file.Split('-');
|
|
if (parts.Length == 1)
|
|
{
|
|
song.Title = parts[0].Trim();
|
|
}
|
|
else if (parts.Length > 1)
|
|
{
|
|
song.Artist = parts[parts.Length - 2].Trim();
|
|
song.Title = parts[parts.Length - 1].Trim();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Song ReadId3FromZip(string zippath)
|
|
{
|
|
ZipFile.ExtractToDirectory(zippath, "c:\\temp");
|
|
string filepath = Directory.GetFiles("c:\\temp", "*.mp3")[0];
|
|
Song song = ReadId3(filepath);
|
|
foreach (string file in Directory.GetFiles("c:\\temp")) File.Delete(file);
|
|
return song;
|
|
}
|
|
|
|
static Song ReadId3(string path)
|
|
{
|
|
Song song = new Song();
|
|
TagLib.File tagFile;
|
|
try
|
|
{
|
|
tagFile = TagLib.File.Create(path);
|
|
song.Title = tagFile.Tag.Title.Trim();
|
|
song.Artist = tagFile.Tag.FirstPerformer.Trim();
|
|
if (tagFile.Tag.FirstGenre != null) {
|
|
song.Genre = tagFile.Tag.FirstGenre.Trim();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// do nothing;
|
|
}
|
|
song.Path = path;
|
|
return song;
|
|
}
|
|
}
|
|
}
|