Files
sbt-downloader/Program.cs
2024-03-30 12:26:32 +01:00

141 lines
5.3 KiB
C#

using PowerArgs;
using Newtonsoft.Json.Linq;
using System.Net;
using System;
namespace SBT_Downloader
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to the Sound Booth Theater Personal Archiving Tool!");
try
{
var parsed = Args.Parse<MyArgs>(args);
Console.WriteLine("Downloading book now...");
(List<string> mp3Urls, List<string> chapters) = ParseHar(parsed.Har);
DownloadMp3s(mp3Urls, chapters, parsed);
}
catch (ArgException ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ArgUsage.GenerateUsageFromTemplate<MyArgs>());
}
}
static (List<string> mp3Urls, List<string> chapters) ParseHar(string har)
{
try
{
string harContents = LoadHar(har);
JObject harObject = JObject.Parse(harContents);
List<JToken?> requestObjects = ParseRequests(harObject);
List<string> mp3Urls = ParseUrls(requestObjects);
List<string> chapters = ParseChapters(mp3Urls);
return (mp3Urls, chapters);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Environment.Exit(0);
return (new List<string>(), new List<string>());
}
}
private static List<JToken?> ParseRequests(JObject harObject)
{
List<JToken?> requests = harObject["log"]["entries"]
.Where(x => x.SelectToken("_resourceType").ToString() == "media")
.Select(y => y.SelectToken("request"))
.DistinctBy(z => z.SelectToken("url")).ToList();
return requests;
}
private static List<string> ParseChapters(List<string> mp3Urls)
{
List<string> chapters = new();
foreach (string url in mp3Urls)
{
Uri uri = new(url);
string fixedUri = uri.AbsoluteUri.Replace(uri.Query, string.Empty);
List<string> urlTokens = fixedUri.Split("/").ToList();
//string series = urlTokens[5];
//string title = urlTokens[6];
//string episode = urlTokens[7];
var chapterTokens = urlTokens.Last().Split("_").ToList();
chapterTokens.RemoveRange(0,5);
string chapterLastToken = chapterTokens.Last().Split(".").First();
chapterTokens[^1] = chapterLastToken;
chapters.Add(string.Join(" ", chapterTokens));
}
return chapters;
}
static List<string> ParseUrls(List<JToken> requestList)
{
List<string> urls = requestList.Select(x => x.SelectToken("url").ToString()).ToList();
Console.WriteLine(urls.Count + " total requests");
return urls;
}
private static void DownloadMp3s(List<string> mp3Urls, List<string> chapters, MyArgs arguments)
{
Parallel.ForEach(
mp3Urls,
new ParallelOptions { MaxDegreeOfParallelism = 10 },
(url, state, index) =>
{
int chapterNumber = (int)index + 1;
string chapterName = chapters[(int)index];
string fileName = $"{chapterNumber} {chapterName}.mp3";
using var client = new WebClient();
Console.WriteLine("Downloading file #" + index);
client.DownloadFile(url, fileName);
TagFile(chapterName, chapterNumber, chapters.Count, arguments);
});
}
private static void TagFile(string chapterName, int chapterNumber, int chapterCount, MyArgs arguments)
{
Console.WriteLine($"Tagging chapter {chapterNumber} ({chapterCount})");
var file = TagLib.File.Create($"{chapterNumber} {chapterName}.mp3");
file.Tag.Album = arguments.Title.IsNullOrEmpty() ? string.Empty : arguments.Title;
List<string> artistsList = new List<string>();
if (!arguments.Author.IsNullOrEmpty()) artistsList.Add(arguments.Author);
if (!arguments.Narrator.IsNullOrEmpty()) artistsList.Add(arguments.Narrator);
file.Tag.AlbumArtists = artistsList.ToArray();
file.Tag.Title = chapterName;
file.Tag.Track = (uint)chapterNumber;
file.Tag.TrackCount = (uint)chapterCount;
file.Save();
}
static string LoadHar(string harFileName)
{
string harContents;
try
{
using StreamReader streamReader = new(harFileName);
harContents = streamReader.ReadToEnd();
return harContents;
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
Environment.Exit(0);
return string.Empty;
}
}
}
}