Created
January 18, 2021 19:05
-
-
Save flashwave/9c39d6e9542f366818ac936fbe1a8d6a to your computer and use it in GitHub Desktop.
music man
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Threading; | |
namespace MusicManager { | |
public class Playlist : IDisposable, IEnumerable<string> { | |
private Stream Stream { get; } | |
private Mutex Lock { get; } = new Mutex(); | |
private List<string> Paths { get; } = new List<string>(); | |
public Playlist(string filename) : this(new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) { } | |
public Playlist(Stream stream) { | |
Stream = stream ?? throw new ArgumentNullException(nameof(stream)); | |
} | |
public void Add(string path) { | |
Lock.WaitOne(); | |
if(!Paths.Contains(path)) | |
Paths.Add(path); | |
Lock.ReleaseMutex(); | |
} | |
public bool Contains(string path) { | |
Lock.WaitOne(); | |
bool contains = Paths.Contains(path); | |
Lock.ReleaseMutex(); | |
return contains; | |
} | |
public void Load(bool allowGone = false) { | |
Lock.WaitOne(); | |
Stream.Seek(0, SeekOrigin.Begin); | |
using StreamReader sr = new StreamReader(Stream, new UTF8Encoding(false), leaveOpen: true); | |
string line = sr.ReadLine(); | |
if(line != null && line.StartsWith(@"#")) { // YEAH FILE FORMATS | |
while((line = sr.ReadLine()) != null) | |
if(allowGone || File.Exists(line)) | |
Paths.Add(line); | |
} | |
Lock.ReleaseMutex(); | |
} | |
public void Save() { | |
Lock.WaitOne(); | |
Stream.SetLength(0); | |
using StreamWriter sw = new StreamWriter(Stream, new UTF8Encoding(false), leaveOpen: true); | |
sw.WriteLine(@"#"); | |
foreach(string path in Paths) | |
sw.WriteLine(path); | |
Lock.ReleaseMutex(); | |
} | |
private bool IsDisposed; | |
~Playlist() | |
=> Dispose(false); | |
public void Dispose() | |
=> Dispose(true); | |
private void Dispose(bool disposing) { | |
if(IsDisposed) | |
return; | |
IsDisposed = true; | |
Stream.Dispose(); | |
Lock.Dispose(); | |
if(disposing) | |
GC.SuppressFinalize(this); | |
} | |
public string this[int index] { | |
get { | |
string str; | |
Lock.WaitOne(); | |
try { | |
str = Paths[index]; | |
} finally { | |
Lock.ReleaseMutex(); | |
} | |
return str; | |
} | |
} | |
public int Count | |
=> Paths.Count; | |
public IEnumerator<string> GetEnumerator() | |
=> new PlaylistEnumerator(this); | |
IEnumerator IEnumerable.GetEnumerator() | |
=> GetEnumerator(); | |
} | |
public class PlaylistEnumerator : IEnumerator<string> { | |
public string Current => Playlist[CurrentIndex]; | |
object IEnumerator.Current => Current; | |
private int CurrentIndex { get; set; } = -1; | |
private Playlist Playlist { get; } | |
public PlaylistEnumerator(Playlist playlist) { | |
Playlist = playlist ?? throw new ArgumentNullException(nameof(playlist)); | |
} | |
public bool MoveNext() { | |
return ++CurrentIndex < Playlist.Count; | |
} | |
public void Reset() { | |
CurrentIndex = -1; | |
} | |
public void Dispose() { | |
GC.SuppressFinalize(this); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using static System.Console; | |
namespace MusicManager { | |
public static class Program { | |
private const string PREV_FILE = @"prev.m3u8"; | |
private const string PREV_FILE_OLD = @"prev-{0}.m3u8"; | |
private const string LIST_FILE = @"list.m3u8"; | |
private const string SCAN_FILE = @"scan.txt"; | |
private const string FINAL_FILE = @"final.m3u8"; | |
public static void Main(string[] args) { | |
WriteLine(@"MusicManager"); | |
WriteLine(@"Doing housekeeping..."); | |
if(File.Exists(FINAL_FILE)) | |
File.Delete(FINAL_FILE); | |
if(File.Exists(PREV_FILE)) | |
File.Move(PREV_FILE, string.Format(PREV_FILE_OLD, DateTimeOffset.Now.ToUnixTimeSeconds())); | |
if(File.Exists(LIST_FILE)) | |
File.Move(LIST_FILE, PREV_FILE); | |
WriteLine(@"Constructing new playlist according to the scanfile..."); | |
using ScanFile scan = new ScanFile(SCAN_FILE); | |
using Playlist pl = new Playlist(LIST_FILE); | |
foreach(ScanFileDirective sfd in scan) { | |
foreach(string file in sfd.GetFiles()) { | |
pl.Add(file); | |
} | |
} | |
pl.Save(); | |
if(File.Exists(PREV_FILE)) { | |
using Playlist prev = new Playlist(PREV_FILE); | |
using Playlist final = new Playlist(FINAL_FILE); | |
WriteLine(@"Loading previous playlist..."); | |
prev.Load(); | |
WriteLine(@"Filtering existing songs..."); | |
foreach(string path in pl) | |
if(!prev.Contains(path)) | |
final.Add(path); | |
WriteLine(@"Saving finalised playlist..."); | |
final.Save(); | |
} else { | |
WriteLine(@"No previous playlist is present, copying list to final."); | |
File.Copy(LIST_FILE, FINAL_FILE); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading; | |
namespace MusicManager { | |
public class ScanFile : IDisposable, IEnumerable<ScanFileDirective> { | |
private Stream Stream { get; } | |
private Mutex Lock { get; } = new Mutex(); | |
private List<ScanFileDirective> Directives { get; } = new List<ScanFileDirective>(); | |
public ScanFile(string filename) : this(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { Load(); } | |
public ScanFile(Stream stream) { | |
Stream = stream ?? throw new ArgumentNullException(nameof(stream)); | |
} | |
public void Load() { | |
Lock.WaitOne(); | |
using StreamReader sr = new StreamReader(Stream, new UTF8Encoding(false), leaveOpen: true); | |
string str; | |
Directives.Clear(); | |
while((str = sr.ReadLine()) != null) | |
Directives.Add(new ScanFileDirective(str)); | |
Lock.ReleaseMutex(); | |
} | |
private bool IsDisposed; | |
~ScanFile() | |
=> Dispose(false); | |
public void Dispose() | |
=> Dispose(true); | |
private void Dispose(bool disposing) { | |
if(IsDisposed) | |
return; | |
IsDisposed = true; | |
Stream.Dispose(); | |
Lock.Dispose(); | |
if(disposing) | |
GC.SuppressFinalize(this); | |
} | |
public ScanFileDirective this[int index] { | |
get { | |
ScanFileDirective sfd; | |
Lock.WaitOne(); | |
try { | |
sfd = Directives[index]; | |
} finally { | |
Lock.ReleaseMutex(); | |
} | |
return sfd; | |
} | |
} | |
public int Count | |
=> Directives.Count; | |
public IEnumerator<ScanFileDirective> GetEnumerator() | |
=> new ScanFileEnumerator(this); | |
IEnumerator IEnumerable.GetEnumerator() | |
=> GetEnumerator(); | |
} | |
public class ScanFileDirective { | |
public string Directive { get; } | |
public ScanFileDirective(string directive) { | |
Directive = directive ?? throw new ArgumentNullException(nameof(directive)); | |
} | |
private static readonly string[] Extensions = new[] { | |
@".flac", @".mp3", @".ogg", @".m4a", | |
}; | |
private static IEnumerable<string> RecursiveFiles(string directory) { | |
List<string> files = new List<string>(); | |
foreach(string dir in Directory.GetDirectories(directory)) | |
files.AddRange(RecursiveFiles(dir)); | |
string[] cueFiles = Directory.GetFiles(directory, @"*.cue"); | |
//if(cueFiles.Length == 1) | |
// files.Add(cueFiles.First()); | |
//else | |
foreach(string file in Directory.GetFiles(directory)) { | |
if(Extensions.Contains(Path.GetExtension(file))) | |
files.Add(file); | |
} | |
return files; | |
} | |
public IEnumerable<string> GetFiles() { | |
if(Directory.Exists(Directive)) | |
return RecursiveFiles(Directive); | |
if(File.Exists(Directive)) | |
return new[] { Directive }; | |
return Enumerable.Empty<string>(); | |
} | |
} | |
public class ScanFileEnumerator : IEnumerator<ScanFileDirective> { | |
public ScanFileDirective Current => ScanFile[CurrentIndex]; | |
object IEnumerator.Current => Current; | |
private int CurrentIndex { get; set; } = -1; | |
private ScanFile ScanFile { get; } | |
public ScanFileEnumerator(ScanFile scanFile) { | |
ScanFile = scanFile ?? throw new ArgumentNullException(nameof(scanFile)); | |
} | |
public bool MoveNext() { | |
return ++CurrentIndex < ScanFile.Count; | |
} | |
public void Reset() { | |
CurrentIndex = -1; | |
} | |
public void Dispose() { | |
GC.SuppressFinalize(this); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment