mirror of
https://github.com/rmcrackan/Libation.git
synced 2025-12-23 22:17:52 -05:00
187 lines
4.8 KiB
C#
187 lines
4.8 KiB
C#
using AudibleApi.Common;
|
|
using ClosedXML.Excel;
|
|
using CsvHelper;
|
|
using DataLayer;
|
|
using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
namespace ApplicationServices
|
|
{
|
|
public static class RecordExporter
|
|
{
|
|
public static void ToXlsx(string saveFilePath, IEnumerable<IRecord> records)
|
|
{
|
|
if (!records.Any())
|
|
return;
|
|
|
|
using var workbook = new XLWorkbook();
|
|
var worksheet = workbook.AddWorksheet("Records");
|
|
|
|
// headers
|
|
var columns = new List<string>
|
|
{
|
|
nameof(Type.Name),
|
|
nameof(IRecord.Created),
|
|
nameof(IRecord.Start) + "_ms",
|
|
};
|
|
|
|
if (records.OfType<IAnnotation>().Any())
|
|
{
|
|
columns.Add(nameof(IAnnotation.AnnotationId));
|
|
columns.Add(nameof(IAnnotation.LastModified));
|
|
}
|
|
if (records.OfType<IRangeAnnotation>().Any())
|
|
{
|
|
columns.Add(nameof(IRangeAnnotation.End) + "_ms");
|
|
columns.Add(nameof(IRangeAnnotation.Text));
|
|
}
|
|
if (records.OfType<Clip>().Any())
|
|
columns.Add(nameof(Clip.Title));
|
|
|
|
int rowIndex = 1, col = 1;
|
|
var headerRow = worksheet.Row(rowIndex++);
|
|
foreach (var c in columns)
|
|
{
|
|
var headerCell = headerRow.Cell(col++);
|
|
headerCell.Value = c;
|
|
headerCell.Style.Font.Bold = true;
|
|
}
|
|
|
|
var dateFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern + " HH:mm:ss";
|
|
|
|
// Add data rows
|
|
foreach (var record in records)
|
|
{
|
|
col = 1;
|
|
var row = worksheet.Row(rowIndex++);
|
|
|
|
row.Cell(col++).Value = record.GetType().Name;
|
|
row.Cell(col++).SetDate(record.Created.DateTime, dateFormat);
|
|
row.Cell(col++).Value = record.Start.TotalMilliseconds;
|
|
|
|
if (record is IAnnotation annotation)
|
|
{
|
|
|
|
row.Cell(col++).Value = annotation.AnnotationId;
|
|
row.Cell(col++).SetDate(annotation.LastModified.DateTime, dateFormat);
|
|
|
|
if (annotation is IRangeAnnotation rangeAnnotation)
|
|
{
|
|
row.Cell(col++).Value = rangeAnnotation.End.TotalMilliseconds;
|
|
row.Cell(col++).Value = rangeAnnotation.Text;
|
|
|
|
if (rangeAnnotation is Clip clip)
|
|
row.Cell(col++).Value = clip.Title;
|
|
}
|
|
}
|
|
}
|
|
|
|
workbook.SaveAs(saveFilePath);
|
|
}
|
|
|
|
private static void SetDate(this IXLCell cell, DateTime? value, string dateFormat)
|
|
{
|
|
cell.Value = value;
|
|
cell.Style.DateFormat.Format = dateFormat;
|
|
}
|
|
public static void ToJson(string saveFilePath, LibraryBook libraryBook, IEnumerable<IRecord> records)
|
|
{
|
|
if (!records.Any())
|
|
return;
|
|
|
|
var recordsEx = extendRecords(records);
|
|
|
|
var recordsObj = new JObject
|
|
{
|
|
{ "title", libraryBook.Book.TitleWithSubtitle},
|
|
{ "asin", libraryBook.Book.AudibleProductId},
|
|
{ "exportTime", DateTime.Now},
|
|
{ "records", JArray.FromObject(recordsEx) }
|
|
};
|
|
|
|
System.IO.File.WriteAllText(saveFilePath, recordsObj.ToString(Newtonsoft.Json.Formatting.Indented));
|
|
}
|
|
|
|
public static void ToCsv(string saveFilePath, IEnumerable<IRecord> records)
|
|
{
|
|
if (!records.Any())
|
|
return;
|
|
|
|
using var writer = new System.IO.StreamWriter(saveFilePath);
|
|
using var csv = new CsvWriter(writer, System.Globalization.CultureInfo.CurrentCulture);
|
|
|
|
//Write headers for the present record type that has the most properties
|
|
if (records.OfType<Clip>().Any())
|
|
csv.WriteHeader(typeof(ClipEx));
|
|
else if (records.OfType<Note>().Any())
|
|
csv.WriteHeader(typeof(NoteEx));
|
|
else if (records.OfType<Bookmark>().Any())
|
|
csv.WriteHeader(typeof(BookmarkEx));
|
|
else
|
|
csv.WriteHeader(typeof(LastHeardEx));
|
|
|
|
var recordsEx = extendRecords(records);
|
|
|
|
csv.NextRecord();
|
|
csv.WriteRecords(recordsEx.OfType<ClipEx>());
|
|
csv.WriteRecords(recordsEx.OfType<NoteEx>());
|
|
csv.WriteRecords(recordsEx.OfType<BookmarkEx>());
|
|
csv.WriteRecords(recordsEx.OfType<LastHeardEx>());
|
|
}
|
|
|
|
private static IEnumerable<IRecordEx> extendRecords(IEnumerable<IRecord> records)
|
|
=> records
|
|
.Select<IRecord, IRecordEx>(
|
|
r => r switch
|
|
{
|
|
Clip c => new ClipEx(nameof(Clip), c),
|
|
Note n => new NoteEx(nameof(Note), n),
|
|
Bookmark b => new BookmarkEx(nameof(Bookmark), b),
|
|
LastHeard l => new LastHeardEx(nameof(LastHeard), l),
|
|
_ => throw new InvalidOperationException(),
|
|
});
|
|
|
|
|
|
private interface IRecordEx { string Type { get; } }
|
|
|
|
private record LastHeardEx : LastHeard, IRecordEx
|
|
{
|
|
public string Type { get; }
|
|
public LastHeardEx(string type, LastHeard original) : base(original)
|
|
{
|
|
Type = type;
|
|
}
|
|
}
|
|
|
|
private record BookmarkEx : Bookmark, IRecordEx
|
|
{
|
|
public string Type { get; }
|
|
public BookmarkEx(string type, Bookmark original) : base(original)
|
|
{
|
|
Type = type;
|
|
}
|
|
}
|
|
|
|
private record NoteEx : Note, IRecordEx
|
|
{
|
|
public string Type { get; }
|
|
public NoteEx(string type, Note original) : base(original)
|
|
{
|
|
Type = type;
|
|
}
|
|
}
|
|
|
|
private record ClipEx : Clip, IRecordEx
|
|
{
|
|
public string Type { get; }
|
|
public ClipEx(string type, Clip original) : base(original)
|
|
{
|
|
Type = type;
|
|
}
|
|
}
|
|
}
|
|
}
|