Add basic media minifying (only strips tags and checks for corruption).

master
Icedream 2014-12-11 06:25:36 +01:00
parent d247c85ee9
commit 1a4a771697
5 changed files with 193 additions and 21 deletions

View File

@ -3,9 +3,12 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using GarrysMod.AddonCreator.Hashing;
using Newtonsoft.Json;
using TagLib;
using File = System.IO.File;
namespace GarrysMod.AddonCreator.Addon
{
@ -24,6 +27,7 @@ namespace GarrysMod.AddonCreator.Addon
Files = new Dictionary<string, AddonFileInfo>();
RequiredContent = new List<string>();
Version = 1;
MinimizeMedia = true;
}
/// <summary>
@ -67,6 +71,16 @@ namespace GarrysMod.AddonCreator.Addon
/// </summary>
public List<string> RequiredContent { get; private set; }
/// <summary>
/// Indicates whether Lua files will have comments and unnecessary whitespace stripped out on export.
/// </summary>
public bool MinimizeLua { get; set; }
/// <summary>
/// Indicates whether media files will have all game-irrelevant information (like ID3 tags) stripped out on export.
/// </summary>
public bool MinimizeMedia { get; set; }
/// <summary>
/// Imports a gmod addon into this instance.
/// </summary>
@ -153,7 +167,7 @@ namespace GarrysMod.AddonCreator.Addon
var fileSize = sr.ReadInt64();
var fileHash = sr.ReadInt32();
Debug.WriteLine("\t#{2} : {0} ({1:0.0} kB)", filePath, (double)fileSize/1024, fileId);
Debug.WriteLine("\t#{2} : {0} ({1:0.0} kB)", filePath, (double) fileSize/1024, fileId);
Debug.Assert(fileId == expectedFileId);
expectedFileId++;
@ -177,7 +191,7 @@ namespace GarrysMod.AddonCreator.Addon
var fileHash = file.Value.Item2;
var filePosition = sr.BaseStream.Position;
Debug.WriteLine("Analyzing: {0} ({1:0.00} kB)", filePath, (double)fileSize / 1024);
Debug.WriteLine("Analyzing: {0} ({1:0.00} kB)", filePath, (double) fileSize/1024);
var fileContent = new byte[fileSize];
@ -226,12 +240,26 @@ namespace GarrysMod.AddonCreator.Addon
if (MinimizeLua)
files = files
// minimize lua code
.Select(f => f.Key.EndsWith(".lua", StringComparison.OrdinalIgnoreCase)
? new KeyValuePair<string, AddonFileInfo>(f.Key, new MinifiedLuaAddonFileInfo(f.Value))
: f)
.ToDictionary(i => i.Key, i => i.Value);
files = files
.Select(f => Assembly.LoadFrom("taglib-sharp.dll")
.GetTypes()
.Where(t => t.IsSubclassOf(typeof (TagLib.File)))
.Any(mediaSupport => mediaSupport.GetCustomAttributes(typeof (SupportedMimeType), false)
.Select(t => t as SupportedMimeType)
.Any(mediaSupportExt => mediaSupportExt.Extension != null
&& f.Key.ToLower().EndsWith("." +
(mediaSupportExt.Extension.TrimStart('.')
.ToLower()))))
? new KeyValuePair<string, AddonFileInfo>(f.Key,
new MinifiedMediaAddonFileInfo(f.Value, f.Key.Split('.').Last()) {StripTags = MinimizeMedia})
: f)
.ToDictionary(i => i.Key, i => i.Value);
// Check for errors and ignores in addon.json
var addonJson =
JsonConvert.DeserializeObject<AddonJson>(Encoding.UTF8.GetString(Files["addon.json"].GetContents()));
@ -311,7 +339,8 @@ namespace GarrysMod.AddonCreator.Addon
uint fileNum = 0;
foreach (var file in resultingFiles)
{
Console.WriteLine("Processing: {0} ({1:0.00} kB)", file.Key, (double)file.Value.Size / 1024);
Console.Write("Processing: {0}", file.Key);
Console.WriteLine(" ({0:0.00} kB)", (double) file.Value.Size/1024);
fileNum++;
sw.Write(fileNum);
@ -322,14 +351,41 @@ namespace GarrysMod.AddonCreator.Addon
sw.Write((uint) 0); // End of file list
// File contents
foreach (var file in resultingFiles)
foreach (var file in resultingFiles
.Where(file => file.Value.Size != 0))
{
if (file.Value.Size == 0)
continue;
#if DEBUG
Console.WriteLine("Packing: {0} ({1})", file.Key,
file.Value.GetType().Name.Replace("AddonFileInfo", ""));
#else
Console.WriteLine("Packing: {0}", file.Key);
#endif
sw.Write(file.Value.GetContents());
byte[] contents;
try
{
contents = file.Value.GetContents();
}
catch (CorruptFileException e)
{
var mediaFile = file.Value as MinifiedMediaAddonFileInfo;
if (mediaFile == null)
{
throw new Exception(); // what the fuck logic
}
var oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Warning: File {0} possibly corrupted - {1}", file.Key, e.Message);
Console.ForegroundColor = oldColor;
mediaFile.IgnoreCorrupted = true;
contents = mediaFile.GetContents();
}
sw.Write(contents);
}
// Addon CRC
@ -343,10 +399,5 @@ namespace GarrysMod.AddonCreator.Addon
}
}
}
/// <summary>
/// Indicates whether Lua files will have comments and unnecessary whitespace stripped out on export.
/// </summary>
public bool MinimizeLua { get; set; }
}
}

View File

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using TagLib;
using File = System.IO.File;
namespace GarrysMod.AddonCreator.Addon
{
/// <summary>
/// Represents a media addon file with the possibility of stripping tags and checking for corruptions.
/// </summary>
public class MinifiedMediaAddonFileInfo : AddonFileInfo
{
private readonly string _tempFile;
private bool _processed;
~MinifiedMediaAddonFileInfo()
{
File.Delete(_tempFile);
}
/// <summary>
/// Creates a new <see cref="MinifiedMediaAddonFileInfo"/> instance using the given addon file.
/// </summary>
/// <param name="file">The addon file, supposedly a media file</param>
public MinifiedMediaAddonFileInfo(AddonFileInfo file, string extension)
{
_tempFile = Path.GetTempFileName();
var dirName = Path.GetDirectoryName(_tempFile);
if (dirName == null)
throw new InvalidOperationException("Temporary directory is NULL");
// Fix extension, needed for TagLib to detect file format properly
var newTempFile = Path.Combine(
dirName,
Path.GetFileNameWithoutExtension(_tempFile) + "." + extension);
File.Move(_tempFile, newTempFile);
_tempFile = newTempFile;
using (var s = new FileStream(_tempFile, FileMode.OpenOrCreate, FileAccess.Write))
{
var buffer = file.GetContents();
s.Write(buffer, 0, buffer.Length);
}
}
/// <summary>
/// Indicates whether tags should be stripped or not.
/// </summary>
public bool StripTags { get; set; }
/// <summary>
/// Indicates whether to ignore possible file corruption.
/// </summary>
public bool IgnoreCorrupted { get; set; }
/// <summary>
/// Processes the media file, applies any wanted stripping and returns the new file contents.
/// </summary>
/// <returns>The contents of the media file with optional applied stripping</returns>
/// <exception cref="CorruptFileException">Will be thrown when TagLib detects possible media file corruptions</exception>
public override byte[] GetContents()
{
if (_processed)
{
using (var s = new FileStream(_tempFile, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[s.Length];
s.Read(buffer, 0, buffer.Length);
return buffer;
}
}
using (var tags = TagLib.File.Create(_tempFile))
{
if (tags.PossiblyCorrupt && !IgnoreCorrupted)
{
throw new CorruptFileException(string.Join("; ", tags.CorruptionReasons));
}
if (StripTags)
{
tags.RemoveTags(TagTypes.AllTags);
}
tags.Save();
}
_processed = true;
// This will now return the file contents instead
return GetContents();
}
}
}

View File

@ -48,8 +48,14 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.6.0.5\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="policy.2.0.taglib-sharp">
<HintPath>..\..\packages\taglib.2.1.0.0\lib\policy.2.0.taglib-sharp.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="taglib-sharp">
<HintPath>..\..\packages\taglib.2.1.0.0\lib\taglib-sharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Addon\AddonFile.cs" />
@ -57,6 +63,7 @@
<Compile Include="Addon\AddonJson.cs" />
<Compile Include="Addon\AddonWhitelist.cs" />
<Compile Include="Addon\MinifiedLuaAddonFileInfo.cs" />
<Compile Include="Addon\MinifiedMediaAddonFileInfo.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Addon\JsonAddonFileInfo.cs" />
<Compile Include="Hashing\Crc32.cs" />

View File

@ -2,7 +2,6 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using GarrysMod.AddonCreator.Addon;
namespace GarrysMod.AddonCreator
@ -12,6 +11,7 @@ namespace GarrysMod.AddonCreator
private static void Main(string[] args)
{
var minimizeLua = false;
var minimizeMedia = true;
while (args.Any())
{
@ -25,6 +25,14 @@ namespace GarrysMod.AddonCreator
minimizeLua = false;
args = args.Skip(1).ToArray();
break;
case "--minimize-media":
minimizeMedia = true;
args = args.Skip(1).ToArray();
break;
case "--no-minimize-media":
minimizeMedia = false;
args = args.Skip(1).ToArray();
break;
case "create":
{
if (args.Length < 3)
@ -34,7 +42,7 @@ namespace GarrysMod.AddonCreator
var folder = new DirectoryInfo(args[1]);
var output = args[2];
var addon = new AddonFile {MinimizeLua = minimizeLua};
var addon = new AddonFile {MinimizeLua = minimizeLua, MinimizeMedia = minimizeMedia};
if (!folder.Exists)
{
@ -143,7 +151,8 @@ namespace GarrysMod.AddonCreator
}
default:
Console.WriteLine("Usage: {0} <options> <command> <arguments>", Process.GetCurrentProcess().ProcessName);
Console.WriteLine("Usage: {0} <options> <command> <arguments>",
Process.GetCurrentProcess().ProcessName);
Console.WriteLine();
Console.WriteLine("Commands:");
Console.WriteLine("\t{0}\t{1}", "extract", "Extracts a GMA file and shows information about it.");
@ -152,8 +161,14 @@ namespace GarrysMod.AddonCreator
Console.WriteLine("\t\tArguments: Input folder path, output GMA file path");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine("\t{0}\t{1}", "--minimize-lua", "Causes exported GMAs to have all Lua comments and unneeded whitespace in Lua stripped out.");
Console.WriteLine("\t{0}\t{1}", "--no-minimize-lua", "(default) Will prevent Lua files getting minimized.");
Console.WriteLine("\t{0}\t{1}", "--minimize-lua",
"Causes exported GMAs to have all Lua comments and unneeded whitespace in Lua stripped out.");
Console.WriteLine("\t{0}\t{1}", "--no-minimize-lua",
"(default) Will prevent Lua files getting minimized.");
Console.WriteLine("\t{0}\t{1}", "--minimize-media",
"(default) Causes exported GMAs to have all media tags stripped out.");
Console.WriteLine("\t{0}\t{1}", "--no-minimize-media",
"Will prevent media files getting minimized.");
Console.WriteLine();
return;
}

View File

@ -2,4 +2,5 @@
<packages>
<package id="Newtonsoft.Json" version="6.0.5" targetFramework="net40" />
<package id="taglib" version="2.1.0.0" targetFramework="net40" />
</packages>