mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-04-10 13:22:24 +00:00
Add command line interface and change solution structure (#26)
This commit is contained in:
24
DiscordChatExporter.Cli/CliOptions.cs
Normal file
24
DiscordChatExporter.Cli/CliOptions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using DiscordChatExporter.Core.Models;
|
||||
|
||||
namespace DiscordChatExporter.Cli
|
||||
{
|
||||
public class CliOptions
|
||||
{
|
||||
public string Token { get; set; }
|
||||
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
public ExportFormat ExportFormat { get; set; }
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
public DateTime? From { get; set; }
|
||||
|
||||
public DateTime? To { get; set; }
|
||||
|
||||
public string DateFormat { get; set; }
|
||||
|
||||
public int MessageGroupLimit { get; set; }
|
||||
}
|
||||
}
|
||||
37
DiscordChatExporter.Cli/Container.cs
Normal file
37
DiscordChatExporter.Cli/Container.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using DiscordChatExporter.Cli.ViewModels;
|
||||
using DiscordChatExporter.Core.Services;
|
||||
using GalaSoft.MvvmLight.Ioc;
|
||||
using Microsoft.Practices.ServiceLocation;
|
||||
|
||||
namespace DiscordChatExporter.Cli
|
||||
{
|
||||
public class Container
|
||||
{
|
||||
public IMainViewModel MainViewModel => Resolve<IMainViewModel>();
|
||||
public ISettingsService SettingsService => Resolve<ISettingsService>();
|
||||
|
||||
private T Resolve<T>(string key = null)
|
||||
{
|
||||
return ServiceLocator.Current.GetInstance<T>(key);
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
|
||||
SimpleIoc.Default.Reset();
|
||||
|
||||
// Services
|
||||
SimpleIoc.Default.Register<IDataService, DataService>();
|
||||
SimpleIoc.Default.Register<IExportService, ExportService>();
|
||||
SimpleIoc.Default.Register<IMessageGroupService, MessageGroupService>();
|
||||
SimpleIoc.Default.Register<ISettingsService, SettingsService>();
|
||||
|
||||
// View models
|
||||
SimpleIoc.Default.Register<IMainViewModel, MainViewModel>(true);
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
24
DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj
Normal file
24
DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net45</TargetFramework>
|
||||
<Version>2.3</Version>
|
||||
<Company>Tyrrrz</Company>
|
||||
<Copyright>Copyright (c) 2017-2018 Alexey Golub</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommonServiceLocator" Version="1.3" />
|
||||
<PackageReference Include="Costura.Fody" Version="1.6.2" />
|
||||
<PackageReference Include="FluentCommandLineParser" Version="1.4.3" />
|
||||
<PackageReference Include="Fody" Version="2.3.18" />
|
||||
<PackageReference Include="MvvmLightLibs" Version="5.3.0.0" />
|
||||
<PackageReference Include="Tyrrrz.Extensions" Version="1.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DiscordChatExporter.Core\DiscordChatExporter.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
4
DiscordChatExporter.Cli/FodyWeavers.xml
Normal file
4
DiscordChatExporter.Cli/FodyWeavers.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers>
|
||||
<Costura />
|
||||
</Weavers>
|
||||
83
DiscordChatExporter.Cli/Program.cs
Normal file
83
DiscordChatExporter.Cli/Program.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using DiscordChatExporter.Core.Models;
|
||||
using Fclp;
|
||||
|
||||
namespace DiscordChatExporter.Cli
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
private static readonly Container Container = new Container();
|
||||
|
||||
private static CliOptions ParseOptions(string[] args)
|
||||
{
|
||||
var argsParser = new FluentCommandLineParser<CliOptions>();
|
||||
|
||||
var settings = Container.SettingsService;
|
||||
|
||||
argsParser.Setup(o => o.Token).As('t', "token").Required();
|
||||
argsParser.Setup(o => o.ChannelId).As('c', "channel").Required();
|
||||
argsParser.Setup(o => o.ExportFormat).As('f', "format").SetDefault(ExportFormat.HtmlDark);
|
||||
argsParser.Setup(o => o.FilePath).As('o', "output").SetDefault(null);
|
||||
argsParser.Setup(o => o.From).As("datefrom").SetDefault(null);
|
||||
argsParser.Setup(o => o.To).As("dateto").SetDefault(null);
|
||||
argsParser.Setup(o => o.DateFormat).As("dateformat").SetDefault(settings.DateFormat);
|
||||
argsParser.Setup(o => o.MessageGroupLimit).As("grouplimit").SetDefault(settings.MessageGroupLimit);
|
||||
|
||||
var parsed = argsParser.Parse(args);
|
||||
|
||||
// Show help if no arguments
|
||||
if (parsed.EmptyArgs)
|
||||
{
|
||||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
Console.WriteLine($"=== Discord Chat Exporter (Command Line Interface) v{version} ===");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("[-t] [--token] Discord authorization token.");
|
||||
Console.WriteLine("[-c] [--channel] Discord channel ID.");
|
||||
Console.WriteLine("[-f] [--format] Export format (PlainText/HtmlDark/HtmlLight). Optional.");
|
||||
Console.WriteLine("[-o] [--output] Output file path. Optional.");
|
||||
Console.WriteLine(" [--datefrom] Limit to messages after this date. Optional.");
|
||||
Console.WriteLine(" [--dateto] Limit to messages before this date. Optional.");
|
||||
Console.WriteLine(" [--dateformat] Date format. Optional.");
|
||||
Console.WriteLine(" [--grouplimit] Message group limit. Optional.");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
// Show error if there are any
|
||||
else if (parsed.HasErrors)
|
||||
{
|
||||
Console.Error.Write(parsed.ErrorText);
|
||||
Environment.Exit(-1);
|
||||
}
|
||||
|
||||
return argsParser.Object;
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Init container
|
||||
Container.Init();
|
||||
|
||||
// Parse options
|
||||
var options = ParseOptions(args);
|
||||
|
||||
// Inject some settings
|
||||
var settings = Container.SettingsService;
|
||||
settings.DateFormat = options.DateFormat;
|
||||
settings.MessageGroupLimit = options.MessageGroupLimit;
|
||||
|
||||
// Export
|
||||
var vm = Container.MainViewModel;
|
||||
vm.ExportAsync(
|
||||
options.Token,
|
||||
options.ChannelId,
|
||||
options.FilePath,
|
||||
options.ExportFormat,
|
||||
options.From,
|
||||
options.To).GetAwaiter().GetResult();
|
||||
|
||||
// Cleanup container
|
||||
Container.Cleanup();
|
||||
Console.WriteLine("Export complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
12
DiscordChatExporter.Cli/ViewModels/IMainViewModel.cs
Normal file
12
DiscordChatExporter.Cli/ViewModels/IMainViewModel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using DiscordChatExporter.Core.Models;
|
||||
|
||||
namespace DiscordChatExporter.Cli.ViewModels
|
||||
{
|
||||
public interface IMainViewModel
|
||||
{
|
||||
Task ExportAsync(string token, string channelId, string filePath, ExportFormat format, DateTime? from,
|
||||
DateTime? to);
|
||||
}
|
||||
}
|
||||
53
DiscordChatExporter.Cli/ViewModels/MainViewModel.cs
Normal file
53
DiscordChatExporter.Cli/ViewModels/MainViewModel.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using DiscordChatExporter.Core.Models;
|
||||
using DiscordChatExporter.Core.Services;
|
||||
using Tyrrrz.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Cli.ViewModels
|
||||
{
|
||||
public class MainViewModel : IMainViewModel
|
||||
{
|
||||
private readonly IDataService _dataService;
|
||||
private readonly IMessageGroupService _messageGroupService;
|
||||
private readonly IExportService _exportService;
|
||||
|
||||
public MainViewModel(IDataService dataService, IMessageGroupService messageGroupService,
|
||||
IExportService exportService)
|
||||
{
|
||||
_dataService = dataService;
|
||||
_messageGroupService = messageGroupService;
|
||||
_exportService = exportService;
|
||||
}
|
||||
|
||||
public async Task ExportAsync(string token, string channelId, string filePath, ExportFormat format, DateTime? from,
|
||||
DateTime? to)
|
||||
{
|
||||
// Get channel and guild
|
||||
var channel = await _dataService.GetChannelAsync(token, channelId);
|
||||
var guild = channel.GuildId == Guild.DirectMessages.Id
|
||||
? Guild.DirectMessages
|
||||
: await _dataService.GetGuildAsync(token, channel.GuildId);
|
||||
|
||||
// Generate file path if not set
|
||||
if (filePath.IsBlank())
|
||||
{
|
||||
filePath = $"{guild} - {channel}.{format.GetFileExtension()}"
|
||||
.Replace(Path.GetInvalidFileNameChars(), '_');
|
||||
}
|
||||
|
||||
// Get messages
|
||||
var messages = await _dataService.GetChannelMessagesAsync(token, channelId, from, to);
|
||||
|
||||
// Group them
|
||||
var messageGroups = _messageGroupService.GroupMessages(messages);
|
||||
|
||||
// Create log
|
||||
var log = new ChannelChatLog(guild, channel, messageGroups, messages.Count);
|
||||
|
||||
// Export
|
||||
await _exportService.ExportAsync(format, filePath, log);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user