├── AnkiPoetry.BlazorWasm ├── wwwroot │ ├── .nojekyll │ ├── favicon.png │ ├── css │ │ ├── card.css │ │ └── app.css │ └── index.html ├── App.razor.js ├── _Imports.razor ├── Program.cs ├── Properties │ └── launchSettings.json ├── App.razor.css ├── AnkiPoetry.BlazorWasm.csproj ├── Samples.cs ├── App.razor └── App.razor.cs ├── docs ├── line.gif ├── page.gif ├── word.gif ├── Screenshot_01.png ├── Screenshot_02.png ├── Screenshot_03.png └── William_Shakespeare_-_Hamlet_soliloquy.apkg ├── AnkiPoetry.Engine ├── Utils │ ├── EnumerableExtension.cs │ ├── Regexes.cs │ ├── TextWrapper.cs │ ├── CsvSaver.cs │ ├── LoaderText.cs │ └── Chunker.cs ├── AnkiPoetry.Engine.csproj └── Creators │ ├── SimpleCreator.cs │ ├── SampleCreator.cs │ ├── DataTypes.cs │ ├── LineCreator.cs │ ├── LineBackCreator.cs │ ├── TitleCreator.cs │ ├── PageCreator.cs │ ├── BaseCreator.cs │ └── WordCreator.cs ├── AnkiPoetry.ConsoleApp ├── AnkiPoetry.ConsoleApp.csproj └── Program.cs ├── LICENSE ├── .github └── workflows │ └── main.yml ├── AnkiPoetry.sln ├── .gitattributes ├── README.md └── .gitignore /AnkiPoetry.BlazorWasm/wwwroot/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/line.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/line.gif -------------------------------------------------------------------------------- /docs/page.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/page.gif -------------------------------------------------------------------------------- /docs/word.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/word.gif -------------------------------------------------------------------------------- /docs/Screenshot_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/Screenshot_01.png -------------------------------------------------------------------------------- /docs/Screenshot_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/Screenshot_02.png -------------------------------------------------------------------------------- /docs/Screenshot_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/Screenshot_03.png -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/AnkiPoetry.BlazorWasm/wwwroot/favicon.png -------------------------------------------------------------------------------- /docs/William_Shakespeare_-_Hamlet_soliloquy.apkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiety/AnkiPoetry/HEAD/docs/William_Shakespeare_-_Hamlet_soliloquy.apkg -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Utils/EnumerableExtension.cs: -------------------------------------------------------------------------------- 1 | namespace System.Linq; 2 | 3 | public static class EnumerableExtensions 4 | { 5 | public static IEnumerable<(TItem item, int index)> Indexed(this IEnumerable items) 6 | => items.Select((item, index) => (item, index)); 7 | } 8 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Utils/Regexes.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace AnkiPoetry.Engine; 4 | 5 | public static partial class Regexes 6 | { 7 | //this regex matches words that may contain apostrophes within them 8 | [GeneratedRegex(@"\b(?:['`’]\b|\B['`’]\B)?\w+(?:(['`’])\w+)*\b")] 9 | public static partial Regex RegexWord(); 10 | } 11 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/AnkiPoetry.Engine.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net10.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/App.razor.js: -------------------------------------------------------------------------------- 1 | export function downloadContent(element_id, file_name) { 2 | var input_element = document.getElementById(element_id); 3 | var text = input_element.value; 4 | 5 | var el = document.createElement("a"); 6 | el.href = "data:text/plain;charset=UTF-8," + encodeURIComponent(text); 7 | el.setAttribute("download", file_name); 8 | el.click(); 9 | } 10 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using AnkiPoetry.BlazorWasm 10 | -------------------------------------------------------------------------------- /AnkiPoetry.ConsoleApp/AnkiPoetry.ConsoleApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net10.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/Program.cs: -------------------------------------------------------------------------------- 1 | using AnkiPoetry.BlazorWasm; 2 | 3 | using Blazored.LocalStorage; 4 | 5 | using Microsoft.AspNetCore.Components.Web; 6 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 7 | 8 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 9 | builder.RootComponents.Add("#app"); 10 | builder.RootComponents.Add("head::after"); 11 | 12 | builder.Services.AddBlazoredLocalStorage(); 13 | 14 | await builder.Build().RunAsync(); 15 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/wwwroot/css/card.css: -------------------------------------------------------------------------------- 1 | .card hr { 2 | height: 0px; 3 | border: none; 4 | border-top: 1px solid white; 5 | } 6 | 7 | .card .hiddenInfo { 8 | display: none; 9 | } 10 | 11 | .card .line0 { 12 | color: #FF6666; 13 | } 14 | 15 | .card .line1 { 16 | color: #FF9166; 17 | } 18 | 19 | .card .line2 { 20 | color: #FFFF66; 21 | } 22 | 23 | .card .line3 { 24 | color: #66FF66; 25 | } 26 | 27 | .card .line4 { 28 | color: #66FFFF; 29 | } 30 | 31 | .card .line5 { 32 | color: #7777FF; 33 | } 34 | 35 | .card .line6 { 36 | color: #FF66FF; 37 | } 38 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "https": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": true, 8 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 9 | "applicationUrl": "https://localhost:7169/;http://localhost:5227/", 10 | "launchUrl": "AnkiPoetry", 11 | "commandLineArgs": "--pathbase=/AnkiPoetry", 12 | "environmentVariables": { 13 | "ASPNETCORE_ENVIRONMENT": "Development" 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Creators/SimpleCreator.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace AnkiPoetry.Engine; 4 | 5 | public partial class SimpleCreator : BaseCreator 6 | { 7 | protected override IEnumerable CardFromChunk(Chunk chunk, Parameters parameters) 8 | { 9 | var from = chunk.Lines.First(); 10 | var number = CreateNumber(chunk, from.LineNumber); 11 | 12 | var sb = new StringBuilder(); 13 | 14 | foreach (var line in chunk.Lines) 15 | { 16 | var text = GetLineText(line, line.Text, parameters); 17 | sb.Append(text); 18 | } 19 | 20 | yield return new(number, sb.ToString()); 21 | } 22 | 23 | protected override string GetLineText(MyLine line, string text, Parameters parameters) 24 | { 25 | var number = GetLineNumber(line, parameters); 26 | return number + text + Environment.NewLine; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Creators/SampleCreator.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace AnkiPoetry.Engine; 4 | 5 | public partial class SampleCreator : BaseCreator 6 | { 7 | protected override IEnumerable CardFromChunk(Chunk chunk, Parameters parameters) 8 | { 9 | var from = chunk.Lines.First(); 10 | var number = CreateNumber(chunk, from.LineNumber); 11 | 12 | var sb = new StringBuilder(); 13 | 14 | var header = CreateHeader(chunk, parameters); 15 | sb.Append(header); 16 | 17 | foreach (var line in chunk.Lines) 18 | { 19 | if (line.IsFirst) 20 | sb.Append("
"); 21 | 22 | var text = GetLineText(line, line.Text, parameters); 23 | 24 | sb.Append(text); 25 | 26 | if (line.IsLast) 27 | sb.Append("
"); 28 | } 29 | 30 | yield return new(number, sb.ToString()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 xiety 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/App.razor.css: -------------------------------------------------------------------------------- 1 | .title { 2 | font-size: 110%; 3 | font-weight: bold; 4 | } 5 | 6 | .links { 7 | display: flex; 8 | justify-content: space-between; 9 | margin: 5px; 10 | } 11 | 12 | .parameters { 13 | display: flex; 14 | flex-wrap: wrap; 15 | gap: 10px; 16 | margin-top: 5px; 17 | margin-bottom: 5px; 18 | } 19 | 20 | .json input { 21 | width: 100%; 22 | } 23 | 24 | .parameter-name { 25 | width: 100px; 26 | } 27 | 28 | .parameters input[type="number"] { 29 | width: 100px; 30 | } 31 | 32 | .main-button { 33 | font-size: 150%; 34 | width: 200px; 35 | height: 50px; 36 | } 37 | 38 | .item { 39 | margin-top: 15px; 40 | } 41 | 42 | .item textarea { 43 | width: 100%; 44 | height: 10em; 45 | } 46 | 47 | .item .item-name { 48 | font-weight: bold; 49 | } 50 | 51 | .item .item-buttons { 52 | margin: 5px; 53 | } 54 | 55 | .sample-container { 56 | display: flex; 57 | flex-wrap: wrap; 58 | gap: 5px 5px; 59 | } 60 | 61 | .card { 62 | border: 1px solid gray; 63 | padding: 2px; 64 | background-color: black; 65 | color: white; 66 | font-size: 14px; 67 | } 68 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Creators/DataTypes.cs: -------------------------------------------------------------------------------- 1 | namespace AnkiPoetry.Engine; 2 | 3 | public record MyDocument(MySection[] Sections); 4 | public record MySection(int SectionNumber, string SectionName, MySong[] Songs); 5 | public record MySong(int SongNumber, string SongName, MyLine[] Lines); 6 | public record MyLine(int LineNumber, int ContinuousNumber, int NumberForColor, string Text, LineType LineType, bool IsFirst, bool IsLast, bool NotMy); 7 | public record Card(string Number, string Text); 8 | 9 | public enum LineType { Norm, PrevPage, NextPage, PrevSong, NextSong }; 10 | 11 | public record Parameters 12 | { 13 | public string DeckName { get; set; } = ""; 14 | public int ChunkSize { get; set; } = 20; 15 | public int WordWrap { get; set; } = -1; 16 | public int Colors { get; set; } = 7; 17 | public bool OverlapChapters { get; set; } = true; 18 | public bool LineNumbers { get; set; } = true; 19 | public bool Continuous { get; set; } = true; 20 | public StarMode StarMode { get; set; } = StarMode.PerChunk; 21 | public int StarNumber { get; set; } = 5; 22 | } 23 | 24 | public enum StarMode 25 | { 26 | None, 27 | PerChunk, 28 | PerSection, 29 | PerSong, 30 | } 31 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AnkiPoetry 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 | An unhandled error has occurred. 28 | Reload 29 | 🗙 30 |
31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Utils/TextWrapper.cs: -------------------------------------------------------------------------------- 1 | namespace AnkiPoetry.Engine; 2 | 3 | public static class TextWrapper 4 | { 5 | public static IEnumerable Wrap(string text, Parameters parameters) 6 | { 7 | if (parameters.WordWrap == -1) 8 | { 9 | yield return text; 10 | yield break; 11 | } 12 | 13 | var matches = Regexes.RegexWord().Matches(text); 14 | if (matches.Count == 0) 15 | { 16 | yield return text; 17 | yield break; 18 | } 19 | 20 | var start = matches[0].Index; 21 | var longWordCount = 0; 22 | 23 | for (var i = 0; i < matches.Count; ++i) 24 | { 25 | if (matches[i].Value.Length >= 4) 26 | longWordCount++; 27 | 28 | var isLast = i == matches.Count - 1; 29 | var shouldWrap = longWordCount == parameters.WordWrap || isLast; 30 | 31 | if (shouldWrap) 32 | { 33 | var end = isLast ? text.Length : matches[i + 1].Index; 34 | yield return text[start..end].TrimEnd(); 35 | start = end; 36 | longWordCount = 0; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Pages 2 | 3 | on: 4 | push: 5 | branches: ['main'] 6 | paths-ignore: 7 | - '**/README.md' 8 | - 'docs/**' 9 | 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | concurrency: 19 | group: 'pages' 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | deploy: 24 | environment: 25 | name: github-pages 26 | url: ${{ steps.deployment.outputs.page_url }} 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v6 31 | - name: Install dotnet 32 | uses: actions/setup-dotnet@v5 33 | with: 34 | dotnet-version: '10.0.x' 35 | - name: Publish 36 | run: dotnet publish AnkiPoetry.BlazorWasm --configuration Release --output Publish --nologo 37 | - name: Setup Pages 38 | uses: actions/configure-pages@v5 39 | - name: Upload artifact 40 | uses: actions/upload-pages-artifact@v4 41 | with: 42 | path: './Publish/wwwroot/AnkiPoetry' 43 | - name: Deploy to GitHub Pages 44 | id: deployment 45 | uses: actions/deploy-pages@v4 46 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Creators/LineCreator.cs: -------------------------------------------------------------------------------- 1 | namespace AnkiPoetry.Engine; 2 | 3 | public class LineCreator : BaseCreator 4 | { 5 | protected override IEnumerable CardFromChunk(Chunk chunk, Parameters parameters) 6 | { 7 | for (var i = 0; i < chunk.Lines.Length - 1; ++i) 8 | { 9 | var to = chunk.Lines[i + 1]; 10 | 11 | if (!to.NotMy && to.LineType != LineType.NextPage) 12 | { 13 | var number = CreateNumber(chunk, to.LineNumber); 14 | 15 | var beginning = CreateHeader(chunk, parameters) + JoinLines(chunk.Lines[..(i + 1)], parameters); 16 | 17 | if (to.IsFirst) 18 | beginning += "
"; 19 | 20 | var ending = to.IsLast ? "
" : ""; 21 | 22 | var card = CreateCard(number, beginning, ending, to, parameters); 23 | 24 | yield return card; 25 | } 26 | } 27 | } 28 | 29 | protected Card CreateCard(string number, string beginning, string ending, MyLine to, Parameters parameters) 30 | { 31 | var text = MakeCloze(to.Text); 32 | var cloze = GetLineText(to, text, parameters); 33 | return new(number, beginning + cloze + ending); 34 | } 35 | 36 | private static string MakeCloze(string text) 37 | => $"{{{{c1::{text}}}}}"; 38 | } 39 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Creators/LineBackCreator.cs: -------------------------------------------------------------------------------- 1 | namespace AnkiPoetry.Engine; 2 | 3 | public class LineBackCreator : LineCreator 4 | { 5 | protected override IEnumerable CardFromChunk(Chunk chunk, Parameters parameters) 6 | { 7 | var header = CreateHeader(chunk, parameters); 8 | 9 | for (var i = chunk.Lines.Length; i >= 1; --i) 10 | { 11 | var lineToRecall = chunk.Lines[i - 1]; 12 | 13 | if (!lineToRecall.NotMy && 14 | lineToRecall.LineType != LineType.PrevPage && 15 | lineToRecall.LineType != LineType.NextPage && 16 | lineToRecall.LineType != LineType.NextSong) 17 | { 18 | var number = CreateNumber(chunk, lineToRecall.LineNumber); 19 | 20 | var beginning = header; 21 | 22 | var emptyLinesCount = i - 1; 23 | if (emptyLinesCount > 0) 24 | beginning += string.Join("", Enumerable.Repeat("
", emptyLinesCount)); 25 | 26 | if (lineToRecall.IsFirst) 27 | beginning += "
"; 28 | 29 | var ending = lineToRecall.IsLast ? "
" : ""; 30 | 31 | ending += JoinLines(chunk.Lines[i..], parameters); 32 | 33 | var card = CreateCard(number, beginning, ending, lineToRecall, parameters); 34 | 35 | yield return card; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AnkiPoetry.ConsoleApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | using AnkiPoetry.Engine; 4 | 5 | switch (args) 6 | { 7 | case [string parameters_file, string text_file, string output_folder]: 8 | Create(parameters_file, text_file, output_folder); 9 | break; 10 | default: 11 | Console.WriteLine("Args: parameters_file text_file output_folder"); 12 | break; 13 | } 14 | 15 | static void Create(string parameters_file, string text_file, string output_folder) 16 | { 17 | var parameters = JsonSerializer.Deserialize(File.ReadAllText(parameters_file))!; 18 | var text = File.ReadAllText(text_file); 19 | 20 | CreatorInfo[] infos = 21 | [ 22 | new(new WordCreator(), "word", "1. word"), 23 | new(new LineCreator(), "line", "2. line"), 24 | new(new PageCreator(), "page", "3. page"), 25 | ]; 26 | 27 | var doc = LoaderText.LoadText(text, parameters); 28 | 29 | var chunks = Chunker.Run(doc, parameters); 30 | 31 | if (!Directory.Exists(output_folder)) 32 | Directory.CreateDirectory(output_folder); 33 | 34 | foreach (var info in infos) 35 | { 36 | var cards = info.Creator.Run(chunks, parameters); 37 | 38 | var csv = CsvSaver.CreateCsv(cards, [ 39 | "#separator:semicolon", 40 | $"#notetype:poetry::{info.Id}", 41 | $"#deck:{parameters.DeckName}::{info.DeckName}"]); 42 | 43 | var full_file = Path.Combine(output_folder, info.DeckName + ".csv"); 44 | 45 | File.WriteAllText(full_file, csv); 46 | } 47 | } 48 | 49 | record CreatorInfo(BaseCreator Creator, string Id, string DeckName); 50 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/AnkiPoetry.BlazorWasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net10.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | AnkiPoetry 12 | full 13 | false 14 | false 15 | false 16 | false 17 | false 18 | false 19 | true 20 | false 21 | false 22 | true 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Utils/CsvSaver.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Globalization; 3 | 4 | using CsvHelper; 5 | using CsvHelper.Configuration; 6 | 7 | namespace AnkiPoetry.Engine; 8 | 9 | public static class CsvSaver 10 | { 11 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Card))] 12 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DefaultClassMap))] 13 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MemberMap))] 14 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CsvHelper.Expressions.RecordManager))] 15 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CsvHelper.Expressions.RecordWriterFactory))] 16 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CsvHelper.Expressions.RecordCreatorFactory))] 17 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CsvHelper.Expressions.RecordHydrator))] 18 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CsvHelper.Expressions.ExpressionManager))] 19 | [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CsvHelper.TypeConversion.StringConverter))] 20 | public static string CreateCsv(IEnumerable cards, string[] infos) 21 | { 22 | var configuration = new CsvConfiguration(CultureInfo.InvariantCulture) 23 | { 24 | Delimiter = ";", 25 | HasHeaderRecord = false, 26 | ShouldQuote = args => true, 27 | }; 28 | 29 | using var writer = new StringWriter(); 30 | 31 | foreach (var info in infos) 32 | writer.WriteLine(info); 33 | 34 | using var csv = new CsvWriter(writer, configuration); 35 | csv.WriteRecords(cards); 36 | 37 | return writer.ToString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AnkiPoetry.Engine/Creators/TitleCreator.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace AnkiPoetry.Engine; 4 | 5 | public partial class TitleCreator : PageCreator 6 | { 7 | public override Card[] Run(Chunk[] chunks, Parameters parameters) 8 | { 9 | var titleParameters = parameters with 10 | { 11 | ChunkSize = parameters.StarNumber + 1, 12 | StarMode = StarMode.None, 13 | }; 14 | 15 | var titleDoc = CreateTitlesDoc(chunks, titleParameters); 16 | var titleChunks = Chunker.Run(titleDoc, titleParameters) 17 | .Where(a => a.Lines.Length > 2).ToArray(); 18 | 19 | return base.Run(titleChunks, titleParameters); 20 | } 21 | 22 | private static MyDocument CreateTitlesDoc(Chunk[] chunks, Parameters p) 23 | { 24 | var sections = chunks 25 | .GroupBy(c => new { c.SectionNumber, c.SectionName }) 26 | .Select(g => new MySection(g.Key.SectionNumber, g.Key.SectionName, [CreateTitlesSong(g, p)])) 27 | .ToArray(); 28 | 29 | return new MyDocument(sections); 30 | } 31 | 32 | private static MySong CreateTitlesSong(IEnumerable chunks, Parameters parameters) 33 | { 34 | var songLines = chunks.Select((chunk, i) => 35 | chunk.Lines.First(l => l.LineType == LineType.Norm && !l.NotMy) with 36 | { 37 | //To colorize each page in a single color 38 | NumberForColor = (i + parameters.StarNumber) / parameters.StarNumber, 39 | IsFirst = false, 40 | IsLast = false 41 | }); 42 | 43 | return new(1, "Titles", [.. songLines]); 44 | } 45 | 46 | protected override string CreateNumber(Chunk chunk, int lineNumber) 47 | => $"title_{chunk.SectionNumber:00}.{(chunk.ScreenNumber + 1):000}"; 48 | } 49 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/Samples.cs: -------------------------------------------------------------------------------- 1 | namespace AnkiPoetry.BlazorWasm; 2 | 3 | public static class Samples 4 | { 5 | public const string HamletText = """ 6 | # Hamlet 7 | ## Monologue 1 8 | To be, or not to be, that is the question: 9 | Whether 'tis nobler in the mind to suffer 10 | The slings and arrows of outrageous fortune, 11 | Or to take Arms against a Sea of troubles, 12 | And by opposing end them: to die, to sleep 13 | No more; and by a sleep, to say we end 14 | The heart-ache, and the thousand natural shocks 15 | That Flesh is heir to? 'Tis a consummation 16 | Devoutly to be wished. To die, to sleep, 17 | To sleep, perchance to Dream; aye, there's the rub, 18 | For in that sleep of death, what dreams may come, 19 | When we have shuffled off this mortal coil, 20 | Must give us pause. There's the respect 21 | That makes Calamity of so long life: 22 | For who would bear the Whips and Scorns of time, 23 | The Oppressor's wrong, the proud man's Contumely, 24 | The pangs of despised Love, the Law's delay, 25 | The insolence of Office, and the spurns 26 | That patient merit of th'unworthy takes, 27 | When he himself might his Quietus make 28 | With a bare Bodkin? Who would Fardels bear, 29 | To grunt and sweat under a weary life, 30 | But that the dread of something after death, 31 | The undiscovered country, from whose bourn 32 | No traveller returns, puzzles the will, 33 | And makes us rather bear those ills we have, 34 | Than fly to others that we know not of? 35 | Thus conscience does make cowards of us all, 36 | And thus the native hue of Resolution 37 | Is sicklied o'er, with the pale cast of Thought, 38 | And enterprises of great pitch and moment, 39 | With this regard their Currents turn awry, 40 | And lose the name of Action. Soft you now, 41 | The fair Ophelia? Nymph, in thy Orisons 42 | Be all my sins remember'd. 43 | """; 44 | } 45 | -------------------------------------------------------------------------------- /AnkiPoetry.BlazorWasm/App.razor: -------------------------------------------------------------------------------- 1 | 6 |
7 |
Deck name:
8 |
Chunk size:
9 |
Word Wrap:
10 |
Colors:
11 |
Overlap:
12 |
Numbers:
13 |
Continuous:
14 |
15 |
16 | 17 |
18 |
19 |
Input:
20 |