diff --git a/src/CCVTAC.Main/CCVTAC.Main.fsproj b/src/CCVTAC.Main/CCVTAC.Main.fsproj
index 96883f7..0ce451a 100644
--- a/src/CCVTAC.Main/CCVTAC.Main.fsproj
+++ b/src/CCVTAC.Main/CCVTAC.Main.fsproj
@@ -40,7 +40,7 @@
-
+
diff --git a/src/CCVTAC.Main/Commands.fs b/src/CCVTAC.Main/Commands.fs
index a91d825..a96b485 100644
--- a/src/CCVTAC.Main/Commands.fs
+++ b/src/CCVTAC.Main/Commands.fs
@@ -1,6 +1,6 @@
namespace CCVTAC.Main
-open CCFSharpUtils
+open CCFSharpUtils.Text
open System
module Commands =
diff --git a/src/CCVTAC.Main/Downloading/Downloading.fs b/src/CCVTAC.Main/Downloading/Downloading.fs
index 5f8f89c..b7b0ad9 100644
--- a/src/CCVTAC.Main/Downloading/Downloading.fs
+++ b/src/CCVTAC.Main/Downloading/Downloading.fs
@@ -1,6 +1,6 @@
namespace CCVTAC.Main.Downloading
-open CCFSharpUtils
+open CCFSharpUtils.Text
module Downloading =
diff --git a/src/CCVTAC.Main/Downloading/Updater.fs b/src/CCVTAC.Main/Downloading/Updater.fs
index 9aa8133..3d937e6 100644
--- a/src/CCVTAC.Main/Downloading/Updater.fs
+++ b/src/CCVTAC.Main/Downloading/Updater.fs
@@ -3,7 +3,7 @@ namespace CCVTAC.Main.Downloading
open CCVTAC.Main
open CCVTAC.Main.ExternalTools
open CCVTAC.Main.Settings.Settings
-open CCFSharpUtils
+open CCFSharpUtils.Text
module Updater =
diff --git a/src/CCVTAC.Main/ExternalTools/Runner.fs b/src/CCVTAC.Main/ExternalTools/Runner.fs
index 0659090..9ce28ec 100644
--- a/src/CCVTAC.Main/ExternalTools/Runner.fs
+++ b/src/CCVTAC.Main/ExternalTools/Runner.fs
@@ -1,7 +1,8 @@
namespace CCVTAC.Main.ExternalTools
open CCVTAC.Main
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open Startwatch.Library
open System
open System.Diagnostics
diff --git a/src/CCVTAC.Main/History.fs b/src/CCVTAC.Main/History.fs
index 8f2b021..c803126 100644
--- a/src/CCVTAC.Main/History.fs
+++ b/src/CCVTAC.Main/History.fs
@@ -1,7 +1,8 @@
namespace CCVTAC.Main
open CCVTAC.Main.IoUtilities.Files
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open System
open System.IO
open System.Text.Json
@@ -11,7 +12,7 @@ type History(filePath: string, displayCount: int) =
let separator = ';'
- member private _.FilePath = filePath
+ member private _.FileInfo = FileInfo filePath
member private _.DisplayCount = displayCount
/// Write a URL and its related data to the history file.
@@ -20,16 +21,16 @@ type History(filePath: string, displayCount: int) =
let serializedTime = JsonSerializer.Serialize(entryTime).Replace("\"", "")
let text = serializedTime + string separator + url + String.newLine
- match appendToFile this.FilePath text with
+ match appendToFile this.FileInfo text with
| Ok _ -> printer.Debug $"Added \"%s{url}\" to the history log."
- | Error err -> printer.Error $"Failed to write \"%s{url}\" to the history log at \"{this.FilePath}\": {err}"
+ | Error err -> printer.Error $"Failed to write \"%s{url}\" to the history log at \"{this.FileInfo}\": {err}"
with exn ->
printer.Error $"Could not append URL(s) to history log: {exn.Message}"
member this.ShowRecent(printer: Printer) : unit =
try
let lines =
- File.ReadAllLines this.FilePath
+ File.ReadAllLines this.FileInfo.FullName
|> Seq.takeLast this.DisplayCount
|> Seq.toList
diff --git a/src/CCVTAC.Main/InputHelper.fs b/src/CCVTAC.Main/InputHelper.fs
index 84b7738..80c346b 100644
--- a/src/CCVTAC.Main/InputHelper.fs
+++ b/src/CCVTAC.Main/InputHelper.fs
@@ -52,13 +52,11 @@ module InputHelper =
inputs
|> List.map (fun input ->
{ Text = input
- Category = if input[0] = Commands.prefix
- then InputCategory.Command
- else InputCategory.Url })
+ Category = if input[0] = Commands.prefix then Command else Url })
let countCategories (inputs: CategorizedInput list) : CategoryCounts =
inputs
|> List.groupBy _.Category
- |> List.map (fun (k, grp) -> k, grp |> Seq.length)
+ |> List.map (fun (category, items) -> category, Seq.length items)
|> Map.ofSeq
|> CategoryCounts
diff --git a/src/CCVTAC.Main/IoUtilities/Directories.fs b/src/CCVTAC.Main/IoUtilities/Directories.fs
index 1b75ccf..acd98fa 100644
--- a/src/CCVTAC.Main/IoUtilities/Directories.fs
+++ b/src/CCVTAC.Main/IoUtilities/Directories.fs
@@ -2,6 +2,8 @@ namespace CCVTAC.Main.IoUtilities
open CCVTAC.Main
open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open System.IO
open System.Text
@@ -96,4 +98,3 @@ module Directories =
|> Ok
with exn ->
Error $"Error accessing or creating directory \"%s{dirName}\": %s{exn.Message}"
-
diff --git a/src/CCVTAC.Main/IoUtilities/Files.fs b/src/CCVTAC.Main/IoUtilities/Files.fs
index 9dbefdd..442dea5 100644
--- a/src/CCVTAC.Main/IoUtilities/Files.fs
+++ b/src/CCVTAC.Main/IoUtilities/Files.fs
@@ -1,6 +1,7 @@
namespace CCVTAC.Main.IoUtilities
open CCFSharpUtils
+open CCFSharpUtils.Text
open System.IO
module Files =
@@ -18,5 +19,5 @@ module Files =
let readAllText (filePath: string) : Result =
ofTry (fun _ -> File.ReadAllText filePath)
- let appendToFile (filePath: string) (text: string) : Result =
- ofTry (fun _ -> File.AppendAllText(filePath, text))
+ let appendToFile (file: FileInfo) (text: string) : Result =
+ ofTry (fun _ -> File.AppendAllText(file.FullName, text))
diff --git a/src/CCVTAC.Main/Orchestrator.fs b/src/CCVTAC.Main/Orchestrator.fs
index 4fff70b..6192d11 100644
--- a/src/CCVTAC.Main/Orchestrator.fs
+++ b/src/CCVTAC.Main/Orchestrator.fs
@@ -7,7 +7,8 @@ open CCVTAC.Main.PostProcessing
open CCVTAC.Main.Settings
open CCVTAC.Main.Settings.Settings
open CCVTAC.Main.Settings.Settings.LiveUpdating
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open Startwatch.Library
open System
diff --git a/src/CCVTAC.Main/PostProcessing/Deleter.fs b/src/CCVTAC.Main/PostProcessing/Deleter.fs
index 36ca2a0..c0a64c8 100644
--- a/src/CCVTAC.Main/PostProcessing/Deleter.fs
+++ b/src/CCVTAC.Main/PostProcessing/Deleter.fs
@@ -1,7 +1,7 @@
namespace CCVTAC.Main.PostProcessing
open CCVTAC.Main
-open CCFSharpUtils
+open CCFSharpUtils.Text
open System.IO
module Deleter =
diff --git a/src/CCVTAC.Main/PostProcessing/MetadataUtilities.fs b/src/CCVTAC.Main/PostProcessing/MetadataUtilities.fs
index 3916349..37174e8 100644
--- a/src/CCVTAC.Main/PostProcessing/MetadataUtilities.fs
+++ b/src/CCVTAC.Main/PostProcessing/MetadataUtilities.fs
@@ -1,7 +1,6 @@
namespace CCVTAC.Main.PostProcessing
-open CCVTAC.Main
-open CCFSharpUtils
+open CCFSharpUtils.Text
open System
open System.Text
diff --git a/src/CCVTAC.Main/PostProcessing/Mover.fs b/src/CCVTAC.Main/PostProcessing/Mover.fs
index b783b7b..f3674c1 100644
--- a/src/CCVTAC.Main/PostProcessing/Mover.fs
+++ b/src/CCVTAC.Main/PostProcessing/Mover.fs
@@ -7,6 +7,8 @@ open CCVTAC.Main.PostProcessing
open CCVTAC.Main.PostProcessing.Tagging
open CCVTAC.Main.Settings.Settings
open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open TaggingSet
open System
open System.IO
diff --git a/src/CCVTAC.Main/PostProcessing/PostProcessing.fs b/src/CCVTAC.Main/PostProcessing/PostProcessing.fs
index 62550a7..103e0e9 100644
--- a/src/CCVTAC.Main/PostProcessing/PostProcessing.fs
+++ b/src/CCVTAC.Main/PostProcessing/PostProcessing.fs
@@ -5,7 +5,8 @@ open CCVTAC.Main.IoUtilities
open CCVTAC.Main.PostProcessing.Tagging
open CCVTAC.Main.PostProcessing.Tagging.TaggingSet
open CCVTAC.Main.Settings.Settings
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open Startwatch.Library
open System.IO
open System.Linq
diff --git a/src/CCVTAC.Main/PostProcessing/Renamer.fs b/src/CCVTAC.Main/PostProcessing/Renamer.fs
index ecb1c4f..96c6eb7 100644
--- a/src/CCVTAC.Main/PostProcessing/Renamer.fs
+++ b/src/CCVTAC.Main/PostProcessing/Renamer.fs
@@ -1,9 +1,9 @@
namespace CCVTAC.Main.PostProcessing
open CCVTAC.Main
-open CCVTAC.Main.IoUtilities
open CCVTAC.Main.Settings.Settings
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open System
open System.IO
open System.Text
@@ -11,6 +11,7 @@ open System.Text.RegularExpressions
open Startwatch.Library
module Renamer =
+ open CCVTAC.Main.IoUtilities
let private toNormalizationForm (form: string) =
match form.Trim().ToUpperInvariant() with
diff --git a/src/CCVTAC.Main/PostProcessing/Tagging/Tagger.fs b/src/CCVTAC.Main/PostProcessing/Tagging/Tagger.fs
index 4f442ec..5a0bcfc 100644
--- a/src/CCVTAC.Main/PostProcessing/Tagging/Tagger.fs
+++ b/src/CCVTAC.Main/PostProcessing/Tagging/Tagger.fs
@@ -5,9 +5,9 @@ open CCVTAC.Main.Settings.Settings
open CCVTAC.Main.PostProcessing
open CCVTAC.Main.PostProcessing.Tagging
open CCVTAC.Main.Downloading.Downloading
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open Startwatch.Library
-open TaggingSet
open MetadataUtilities
open System
open System.IO
diff --git a/src/CCVTAC.Main/PostProcessing/Tagging/TaggingSet.fs b/src/CCVTAC.Main/PostProcessing/Tagging/TaggingSet.fs
index 474e240..79ac234 100644
--- a/src/CCVTAC.Main/PostProcessing/Tagging/TaggingSet.fs
+++ b/src/CCVTAC.Main/PostProcessing/Tagging/TaggingSet.fs
@@ -1,8 +1,9 @@
namespace CCVTAC.Main.PostProcessing.Tagging
open CCVTAC.Main.IoUtilities
-open CCFSharpUtils
+open CCFSharpUtils.Collections
open CCFSharpUtils.Operators
+open CCFSharpUtils.Text
open FsToolkit.ErrorHandling
open System.IO
open System.Text.RegularExpressions
@@ -32,17 +33,6 @@ module TaggingSet =
ImageFile = i }
let private createValidated (videoId, fileNames) : Result =
- let ensureNotEmpty xs errorMsg : Validation<'a list, string> =
- if List.isNotEmpty xs
- then Ok xs
- else Error [errorMsg]
-
- let ensureExactlyOne xs emptyErrorMsg multipleErrorMsg : Validation<'a, string> =
- match xs with
- | [] -> Error [emptyErrorMsg]
- | [x] -> Ok x
- | _ -> Error [multipleErrorMsg]
-
let hasSupportedAudioExt (fileName: string) =
match Path.GetExtension fileName with
| Null -> false
@@ -55,39 +45,51 @@ module TaggingSet =
Files.imageFileExts
|> List.collect (fun ext -> fileNames |> Files.filterByExt ext)
- Validation.map3
- (fun a j i -> create videoId a j i)
- (ensureNotEmpty audioFiles
- $"No supported audio files found for video ID {videoId}.")
- (ensureExactlyOne jsonFiles
- $"No JSON file found for video ID {videoId}."
- $"Multiple JSON files found for video ID {videoId}.")
- (ensureExactlyOne imageFiles
- $"No image file found for video ID {videoId}."
- $"Multiple image files found for video ID {videoId}.")
+ // Validation.map3
+ // (fun a j i -> create videoId a j i)
+ // (List.ensureNotEmptyV audioFiles
+ // $"No supported audio files found for video ID {videoId}.")
+ // (List.ensureOneV jsonFiles
+ // $"No JSON file found for video ID {videoId}."
+ // $"Multiple JSON files found for video ID {videoId}.")
+ // (List.ensureOneV imageFiles
+ // $"No image file found for video ID {videoId}."
+ // $"Multiple image files found for video ID {videoId}.")
- /// Creates a collection of TaggingSets from a collection of file paths related to several video IDs.
- /// Any extra, unnecessary files will be ignored.
- /// Any validation errors will be accumulated and return in an Error.
+ validation {
+ let! a = List.ensureNotEmptyV audioFiles
+ $"No supported audio files found for video ID {videoId}."
+ and! j = List.ensureOneV jsonFiles
+ $"No JSON file found for video ID {videoId}."
+ $"Multiple JSON files found for video ID {videoId}."
+ and! i = List.ensureOneV imageFiles
+ $"No image file found for video ID {videoId}."
+ $"Multiple image files found for video ID {videoId}."
+ return create videoId a j i
+ }
+
+ /// Creates a collection of TaggingSets from a collection of file paths related to video IDs.
+ /// Irrelevant files are ignored. Validation errors are accumulated and returned in an Error.
let createSets filePaths : Result =
if Seq.isEmpty filePaths then
Error ["No file paths to create a tagging set were provided."]
else
- let isRelevantFile fileName : Match option =
+ let relevantFileInfo fileName =
// Regex group 0 is the full filename, and group 1 contains the video ID.
let fileNamesHavingVideoIdsRgx =
Regex(@".+\[([\w_\-]{11})\](?:.*)?\.(\w+)", RegexOptions.Compiled)
- fileName |> Rgx.trySuccessMatch fileNamesHavingVideoIdsRgx
-
- let fileName (m: Match) = m.Groups[0].Value
- let videoId (m: Match) = m.Groups[1].Value
+ fileName
+ |> Rgx.trySuccessMatch fileNamesHavingVideoIdsRgx
+ |> Option.map (fun m ->
+ {| FileName = m.Groups[0].Value
+ VideoId = m.Groups[1].Value |} )
filePaths
|> List.ofSeq
- |> List.choose isRelevantFile
- |> List.groupBy videoId
- |> List.mapSnd fileName
+ |> List.choose relevantFileInfo
+ |> List.groupBy _.VideoId
+ |> List.mapSnd _.FileName
|> List.map createValidated
|> List.sequenceResultA
|!! List.collect id
diff --git a/src/CCVTAC.Main/Printer.fs b/src/CCVTAC.Main/Printer.fs
index e4a9e88..bbe820d 100644
--- a/src/CCVTAC.Main/Printer.fs
+++ b/src/CCVTAC.Main/Printer.fs
@@ -1,6 +1,7 @@
namespace CCVTAC.Main
open CCFSharpUtils
+open CCFSharpUtils.Text
open System
open System.Collections.Generic
open System.Linq
diff --git a/src/CCVTAC.Main/Program.fs b/src/CCVTAC.Main/Program.fs
index 4a68add..6f78df7 100644
--- a/src/CCVTAC.Main/Program.fs
+++ b/src/CCVTAC.Main/Program.fs
@@ -5,7 +5,8 @@ open CCVTAC.Main.IoUtilities
open CCVTAC.Main.Settings
open CCVTAC.Main.Settings.Settings
open Settings.IO
-open CCFSharpUtils
+open CCFSharpUtils.Collections
+open CCFSharpUtils.Text
open Spectre.Console
open System
open System.IO
diff --git a/src/CCVTAC.Main/ResultTracker.fs b/src/CCVTAC.Main/ResultTracker.fs
index 1aab17f..2787c2a 100644
--- a/src/CCVTAC.Main/ResultTracker.fs
+++ b/src/CCVTAC.Main/ResultTracker.fs
@@ -1,6 +1,7 @@
namespace CCVTAC.Main
open CCFSharpUtils
+open CCFSharpUtils.Text
open System
open System.Collections.Generic
diff --git a/src/CCVTAC.Main/Settings/Settings.fs b/src/CCVTAC.Main/Settings/Settings.fs
index 40ae149..1388721 100644
--- a/src/CCVTAC.Main/Settings/Settings.fs
+++ b/src/CCVTAC.Main/Settings/Settings.fs
@@ -1,8 +1,9 @@
namespace CCVTAC.Main.Settings
open CCVTAC.Main
-open CCFSharpUtils
+open CCFSharpUtils.Text
open Spectre.Console
+open FSharpPlus
open System
open System.Text.Json.Serialization
@@ -185,7 +186,7 @@ module Settings =
fileInfo.FullName
|> File.ReadAllText
|> deserialize
- |> Result.bind validate
+ >>= validate
with
| :? FileNotFoundException -> Error $"File \"{fileInfo.FullName}\" was not found."
| :? JsonException as e -> Error $"Parse error in \"{fileInfo.FullName}\": {e.Message}"
diff --git a/src/CCVTAC.Tests/CCVTAC.Tests.fsproj b/src/CCVTAC.Tests/CCVTAC.Tests.fsproj
index 47529a3..7be8ea2 100644
--- a/src/CCVTAC.Tests/CCVTAC.Tests.fsproj
+++ b/src/CCVTAC.Tests/CCVTAC.Tests.fsproj
@@ -8,13 +8,13 @@
-
+
-
+
diff --git a/src/CCVTAC.Tests/TagDetectionTests.fs b/src/CCVTAC.Tests/PostProcessing/Tagging/TagDetectionTests.fs
similarity index 99%
rename from src/CCVTAC.Tests/TagDetectionTests.fs
rename to src/CCVTAC.Tests/PostProcessing/Tagging/TagDetectionTests.fs
index 10ece0b..6159704 100644
--- a/src/CCVTAC.Tests/TagDetectionTests.fs
+++ b/src/CCVTAC.Tests/PostProcessing/Tagging/TagDetectionTests.fs
@@ -3,7 +3,7 @@ module TagDetectionTests
open CCVTAC.Main.PostProcessing.Tagging
open CCVTAC.Main.PostProcessing
open CCVTAC.Main.Settings.Settings
-open CCFSharpUtils
+open CCFSharpUtils.Text
open System
open Xunit
diff --git a/src/CCVTAC.Tests/PostProcessing/Tagging/TaggingSetTests.fs b/src/CCVTAC.Tests/PostProcessing/Tagging/TaggingSetTests.fs
index 679c0e1..bbefc5c 100644
--- a/src/CCVTAC.Tests/PostProcessing/Tagging/TaggingSetTests.fs
+++ b/src/CCVTAC.Tests/PostProcessing/Tagging/TaggingSetTests.fs
@@ -93,6 +93,7 @@ module TaggingSetInstantiationTests =
Assert.Equal(expected, actual)
+
[]
let ``parses multiple files from playlist`` () =
let dir = Path.Combine("user", "Downloads", "Audio", "tmp")