Add project files

This commit is contained in:
2026-06-17 22:09:16 +02:00
parent a7e1aa2127
commit d78e7612d3
5 changed files with 291 additions and 0 deletions

194
Program.cs Normal file
View File

@@ -0,0 +1,194 @@
using System.Diagnostics;
using System.Net;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
namespace WSiPBookDownloader;
internal class BookMissingException : Exception
{
public int BookId { get; }
public BookMissingException(int bookId)
: base($"Book with ID {bookId} does not exist.")
{
BookId = bookId;
}
}
internal class Program
{
private static readonly HttpClient httpClient = new
(
new HttpClientHandler
{
AllowAutoRedirect = false,
}
)
{
BaseAddress = new Uri("https://appwsipnet.eduranga.pl/"),
};
private static readonly Lock _consoleLock = new();
private static void Log(string message, ConsoleColor? color = null)
{
lock (_consoleLock)
{
if (color.HasValue)
Console.ForegroundColor = color.Value;
Console.WriteLine(message);
Console.ResetColor();
}
}
static async Task Main(string[] args)
{
if (args.Length < 2 || args.Length > 4)
{
Log("Usage: [outputDirectory] [startBookId] [endBookId] [--only-covers]", ConsoleColor.DarkRed);
return;
}
var outputDirectory = args[0];
if (!Path.Exists(outputDirectory))
{
Log($"Output directory \"{outputDirectory}\" does not exist.", ConsoleColor.DarkRed);
return;
}
var startBookId = int.Parse(args[1]);
var endBookId = (args.Length >= 3 && int.TryParse(args[2], out var parsedEndBookId))
? parsedEndBookId
: startBookId;
var onlyCovers = args.FirstOrDefault(arg => arg.Equals("--only-covers", StringComparison.OrdinalIgnoreCase)) != null;
var bookIds = Enumerable.Range(startBookId, endBookId - startBookId + 1);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = onlyCovers ? 100 : 10 };
await Parallel.ForEachAsync(bookIds, parallelOptions, async (bookId, cancellationToken) =>
{
var outputPath = Path.Combine(outputDirectory, $"{bookId}.pdf");
if (File.Exists(outputPath))
{
Log($"[!] Book with ID {bookId} already downloaded, skipping...", ConsoleColor.Yellow);
return;
}
Log($"[?] Starting download of book with ID {bookId}", ConsoleColor.Cyan);
var jpgDir = Path.Combine(Path.GetTempPath(), "WSiPBookDownloader", bookId.ToString());
try
{
if (onlyCovers)
{
await DownloadBookCoverJpg(bookId, outputDirectory, cancellationToken);
Log($"[✓] Downloaded book cover {bookId}", ConsoleColor.DarkGreen);
return;
}
await DownloadBookJpg(bookId, jpgDir, cancellationToken);
BuildPdf(bookId, jpgDir, outputPath);
Log($"[✓] Downloaded book {bookId}", ConsoleColor.DarkGreen);
}
catch (Exception ex)
{
Log($"[×] Failed to download book {bookId}:\n {ex.Message}", ConsoleColor.DarkRed);
} finally
{
if (Directory.Exists(jpgDir))
Directory.Delete(jpgDir, recursive: true);
}
});
}
private static async Task DownloadBookCoverJpg(int bookId, string outputDir, CancellationToken cancellationToken = default)
{
var outputPath = Path.Combine(outputDir, $"{bookId}.jpg");
if (File.Exists(outputPath))
{
Debug.WriteLine($"Cover for book {bookId} already exists, skipping...");
return;
}
var response = await httpClient.GetAsync($"e-podreczniki/podglad/{bookId}/files/mobile/1.jpg", cancellationToken);
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.Found)
throw new BookMissingException(bookId);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsByteArrayAsync(cancellationToken);
Directory.CreateDirectory(outputDir);
await File.WriteAllBytesAsync(outputPath, content, cancellationToken);
Debug.WriteLine($"Downloaded cover for book {bookId}");
}
private static async Task DownloadBookJpg(int bookId, string outputDir, CancellationToken cancellationToken = default)
{
var currentPage = 1;
while (true)
{
var outputPath = Path.Combine(outputDir, $"{currentPage}.jpg");
if (File.Exists(outputPath))
{
Debug.WriteLine($"Page {currentPage} of book {bookId} already exists, skipping...");
currentPage++;
continue;
}
var response = await httpClient.GetAsync($"e-podreczniki/podglad/{bookId}/files/mobile/{currentPage}.jpg", cancellationToken);
if (
(response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.NotFound) &&
currentPage > 1
)
{
Debug.WriteLine($"No more pages for book {bookId}, stopping...");
break;
} else if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.Found)
throw new BookMissingException(bookId);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsByteArrayAsync(cancellationToken);
Directory.CreateDirectory(outputDir);
await File.WriteAllBytesAsync(outputPath, content, cancellationToken);
Debug.WriteLine($"Downloaded page {currentPage} of book {bookId}");
currentPage++;
}
}
private static void BuildPdf(int bookId, string jpgDir, string outputPath)
{
var pages = Directory.GetFiles(jpgDir, "*.jpg")
.OrderBy(file => int.Parse(Path.GetFileNameWithoutExtension(file)))
.ToList();
using var document = new PdfDocument();
document.Options.FlateEncodeMode = PdfFlateEncodeMode.BestCompression;
document.Options.UseFlateDecoderForJpegImages = PdfUseFlateDecoderForJpegImages.Never;
foreach (var pagePath in pages)
{
using var stream = new MemoryStream(File.ReadAllBytes(pagePath));
using var image = XImage.FromStream(stream);
var pdfPage = document.AddPage();
pdfPage.Width = XUnit.FromPoint(image.PointWidth);
pdfPage.Height = XUnit.FromPoint(image.PointHeight);
using var gfx = XGraphics.FromPdfPage(pdfPage);
gfx.DrawImage(image, 0, 0, image.PointWidth, image.PointHeight);
Debug.WriteLine($"Added page {Path.GetFileNameWithoutExtension(pagePath)} to PDF for book {bookId}");
}
Directory.CreateDirectory(Path.GetDirectoryName(outputPath)!);
document.Save(outputPath);
}
}