Skip to content

Instantly share code, notes, and snippets.

@holly-hacker
Last active November 25, 2018 18:14
Show Gist options
  • Save holly-hacker/3bce6cfa0f5349e1fcc87a4473cf7c2c to your computer and use it in GitHub Desktop.
Save holly-hacker/3bce6cfa0f5349e1fcc87a4473cf7c2c to your computer and use it in GitHub Desktop.
Converts Teach2000 files to CSV and Anki's APKG format.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using AnkiSharp; // Import form NuGet package
namespace TeachConvert
{
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
internal static class Program
{
public static void Main(string[] args)
{
if (args.Length != 1) {
Console.WriteLine("Pass me a folder containing .t2k files.");
Console.WriteLine("If you don't know how, just drag the folder on this exe.");
Console.ReadLine();
return;
}
string path = args[0];
if (!Directory.Exists(path)) {
Console.WriteLine("Passed argument is not a directory.");
Console.ReadLine();
return;
}
foreach (string filePath in Directory.EnumerateFiles(path, "*.t2k", SearchOption.AllDirectories)) {
try {
string folder = Path.GetDirectoryName(filePath);
string file = Path.GetFileName(filePath);
string fileClean = Path.GetFileNameWithoutExtension(filePath);
var dic = LoadFile(filePath);
Console.WriteLine($"Loaded {dic.Count} lines from {file}.");
WriteCsv(Path.Combine(folder, fileClean + ".csv"), dic);
WriteAnki(Path.Combine(folder, fileClean + ".apkg"), dic, fileClean);
} catch (Exception e) {
Console.WriteLine($"! Failed to process {filePath}, {e.Message}");
}
}
}
private static void WriteAnki(string outFile, Dictionary<string, string> dic, string packageName)
{
var anki = new Anki(packageName);
foreach (var pair in dic)
anki.AddItem(pair.Key, pair.Value);
anki.CreateApkgFile(Path.GetDirectoryName(outFile)); // quality API design, AnkiSharp :(
}
private static void WriteCsv(string outFile, Dictionary<string, string> dic)
{
const char separator = ',';
string Escaped(string s) => $"\"{s}\""; // csv is weird, man
using (var sw = new StreamWriter(outFile, false, Encoding.Unicode)) { // using UTF16 is the only way to make Excel happy :(
sw.WriteLine($"Question{separator}Answer");
foreach (var pair in dic) {
sw.WriteLine(Escaped(pair.Key) + separator + Escaped(pair.Value));
}
}
}
private static Dictionary<string, string> LoadFile(string path)
{
var dic = new Dictionary<string, string>();
var doc = new XmlDocument();
doc.Load(path);
var items = doc.DocumentElement.SelectNodes("/teach2000/message_data/items/item");
foreach (XmlElement elem in items) {
var ql = elem.SelectNodes("questions/question");
var al = elem.SelectNodes("answers/answer");
var q = string.Join("/", ql.OfType<XmlElement>().Select(x => x.InnerText));
var a = string.Join("/", al.OfType<XmlElement>().Select(x => x.InnerText));
// Console.WriteLine($"{q};{a}");
dic[q] = a;
}
return dic;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment