From 6780e146a0bbea7065f478f957642a8ce50a6643 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 25 Aug 2014 22:30:52 -0400 Subject: remember display mirroring --- .../Localization/Server/server.json | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index df9e28b90..6b1f3d91a 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -602,7 +602,6 @@ "LabelNotificationEnabled": "Enable this notification", "LabelMonitorUsers": "Monitor activity from:", "LabelSendNotificationToUsers": "Send the notification to:", - "UsersNotNotifiedAboutSelfActivity": "Users will not be notified about their own activities.", "LabelUseNotificationServices": "Use the following services:", "CategoryUser": "User", "CategorySystem": "System", @@ -769,15 +768,15 @@ "LabelDisplayPluginsFor": "Display plugins for:", "PluginTabMediaBrowserClassic": "MB Classic", "PluginTabMediaBrowserTheater": "MB Theater", - "LabelEpisodeName": "Episode name", - "LabelSeriesName": "Series name", + "LabelEpisodeNamePlain": "Episode name", + "LabelSeriesNamePlain": "Series name", "ValueSeriesNamePeriod": "Series.name", "ValueSeriesNameUnderscore": "Series_name", "ValueEpisodeNamePeriod": "Episode.name", "ValueEpisodeNameUnderscore": "Episode_name", - "LabelSeasonNumber": "Season number", - "LabelEpisodeNumber": "Episode number", - "LabelEndingEpisodeNumber": "Ending episode number", + "LabelSeasonNumberPlain": "Season number", + "LabelEpisodeNumberPlain": "Episode number", + "LabelEndingEpisodeNumberPlain": "Ending episode number", "HeaderTypeText": "Enter Text", "LabelTypeText": "Text", "HeaderSearchForSubtitles": "Search for Subtitles", @@ -1100,5 +1099,11 @@ "OptionNoTrailer": "No Trailer", "OptionNoThemeSong": "No Theme Song", "OptionNoThemeVideo": "No Theme Video", - "LabelOneTimeDonationAmount": "Donation amount:" + "LabelOneTimeDonationAmount": "Donation amount:", + "OptionActor": "Actor", + "OptionComposer": "Composer", + "OptionDirector": "Director", + "OptionGuestStar": "Guest star", + "OptionProducer": "Producer", + "OptionWriter": "Writer" } -- cgit v1.2.3 From 24beffd7a11233010db5d936610da42944eacb2c Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Wed, 27 Aug 2014 14:55:51 -0400 Subject: Add new supporter item numbers --- MediaBrowser.Server.Implementations/Localization/Server/server.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 6b1f3d91a..35b1ef7f7 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1093,7 +1093,8 @@ "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", "TabSupporterClub": "Supporter Club", "HeaderDonationType": "Donation type:", - "OptionMakeOneTimeDonation": "Make a one-time donation", + "OptionMakeOneTimeDonation": "Make an additional donation", + "OptionOneTimeDescription": "This is an additional donation to the team to show extra support. It does not have any additional benefits.", "OptionLifeTimeSupporterClubMembership": "Lifetime supporter club membership", "HeaderSupporterBenefit": "Becoming a supporter club member provides additional benefits such as access to premium plugins, internet channel content, and more.", "OptionNoTrailer": "No Trailer", -- cgit v1.2.3 From 93ded925a7670b698c2f80a3027644a0e2b183f1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 27 Aug 2014 21:27:46 -0400 Subject: Fixes #901 - Improve captured photo metadata --- MediaBrowser.Controller/Entities/Photo.cs | 16 +- .../MediaBrowser.Model.Portable.csproj | 3 + .../MediaBrowser.Model.net35.csproj | 3 + MediaBrowser.Model/Drawing/ImageOrientation.cs | 16 + MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + .../MediaBrowser.Providers.csproj | 9 +- MediaBrowser.Providers/Photos/ExifReader.cs | 613 --------------------- MediaBrowser.Providers/Photos/ExifTags.cs | 132 ----- MediaBrowser.Providers/Photos/PhotoHelper.cs | 17 +- MediaBrowser.Providers/Photos/PhotoProvider.cs | 163 +++--- MediaBrowser.Providers/packages.config | 1 + .../EntryPoints/ExternalPortForwarding.cs | 18 +- .../Localization/Server/server.json | 4 +- .../FFMpeg/FFMpegDownloadInfo.cs | 13 +- 14 files changed, 154 insertions(+), 855 deletions(-) create mode 100644 MediaBrowser.Model/Drawing/ImageOrientation.cs delete mode 100644 MediaBrowser.Providers/Photos/ExifReader.cs delete mode 100644 MediaBrowser.Providers/Photos/ExifTags.cs (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 96995c315..542fbaa31 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using MediaBrowser.Model.Drawing; +using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { @@ -20,5 +21,18 @@ namespace MediaBrowser.Controller.Entities return Model.Entities.MediaType.Photo; } } + + public int? Width { get; set; } + public int? Height { get; set; } + public string CameraManufacturer { get; set; } + public string CameraModel { get; set; } + public string Software { get; set; } + public double? ExposureTime { get; set; } + public double? FocalLength { get; set; } + + public ImageOrientation? Orientation { get; set; } + + public double? Aperture { get; set; } + public double? ShutterSpeed { get; set; } } } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 99c4a4629..aaa44b009 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -287,6 +287,9 @@ Drawing\DrawingUtils.cs + + Drawing\ImageOrientation.cs + Drawing\ImageOutputFormat.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 919f676f1..6046d3606 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -250,6 +250,9 @@ Drawing\DrawingUtils.cs + + Drawing\ImageOrientation.cs + Drawing\ImageOutputFormat.cs diff --git a/MediaBrowser.Model/Drawing/ImageOrientation.cs b/MediaBrowser.Model/Drawing/ImageOrientation.cs new file mode 100644 index 000000000..3fdfaf7bf --- /dev/null +++ b/MediaBrowser.Model/Drawing/ImageOrientation.cs @@ -0,0 +1,16 @@ + +namespace MediaBrowser.Model.Drawing +{ + public enum ImageOrientation + { + None = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4, + LeftTop = 5, + RightTop = 6, + RightBottom = 7, + LeftBottom = 8, + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index bb93fa687..c3f02236f 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -81,6 +81,7 @@ + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 757c7a753..b69a4bc2f 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -56,6 +56,9 @@ ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll + + ..\packages\taglib.2.1.0.0\lib\policy.2.0.taglib-sharp.dll + @@ -64,6 +67,10 @@ + + ..\packages\taglib.2.1.0.0\lib\taglib-sharp.dll + True + @@ -142,8 +149,6 @@ - - diff --git a/MediaBrowser.Providers/Photos/ExifReader.cs b/MediaBrowser.Providers/Photos/ExifReader.cs deleted file mode 100644 index 8526a7f2a..000000000 --- a/MediaBrowser.Providers/Photos/ExifReader.cs +++ /dev/null @@ -1,613 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; - -namespace MediaBrowser.Providers.Photos -{ - /// - /// A class for reading Exif data from a JPEG file. The file will be open for reading for as long as the class exists. - /// - /// - public class ExifReader : IDisposable - { - private readonly FileStream fileStream = null; - private readonly BinaryReader reader = null; - - /// - /// The catalogue of tag ids and their absolute offsets within the - /// file - /// - private Dictionary catalogue; - - /// - /// Indicates whether to read data using big or little endian byte aligns - /// - private bool isLittleEndian; - - /// - /// The position in the filestream at which the TIFF header starts - /// - private long tiffHeaderStart; - - public ExifReader(string fileName) - { - // JPEG encoding uses big endian (i.e. Motorola) byte aligns. The TIFF encoding - // found later in the document will specify the byte aligns used for the - // rest of the document. - isLittleEndian = false; - - try - { - // Open the file in a stream - fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - reader = new BinaryReader(fileStream); - - // Make sure the file's a JPEG. - if (ReadUShort() != 0xFFD8) - throw new Exception("File is not a valid JPEG"); - - // Scan to the start of the Exif content - ReadToExifStart(); - - // Create an index of all Exif tags found within the document - CreateTagIndex(); - } - catch (Exception) - { - // If instantiation fails, make sure there's no mess left behind - Dispose(); - - throw; - } - } - - #region TIFF methods - - /// - /// Returns the length (in bytes) per component of the specified TIFF data type - /// - /// - private byte GetTIFFFieldLength(ushort tiffDataType) - { - switch (tiffDataType) - { - case 1: - case 2: - case 6: - return 1; - case 3: - case 8: - return 2; - case 4: - case 7: - case 9: - case 11: - return 4; - case 5: - case 10: - case 12: - return 8; - default: - throw new Exception(string.Format("Unknown TIFF datatype: {0}", tiffDataType)); - } - } - - #endregion - - #region Methods for reading data directly from the filestream - - /// - /// Gets a 2 byte unsigned integer from the file - /// - /// - private ushort ReadUShort() - { - return ToUShort(ReadBytes(2)); - } - - /// - /// Gets a 4 byte unsigned integer from the file - /// - /// - private uint ReadUint() - { - return ToUint(ReadBytes(4)); - } - - private string ReadString(int chars) - { - return Encoding.ASCII.GetString(ReadBytes(chars)); - } - - private byte[] ReadBytes(int byteCount) - { - return reader.ReadBytes(byteCount); - } - - /// - /// Reads some bytes from the specified TIFF offset - /// - /// - /// - /// - private byte[] ReadBytes(ushort tiffOffset, int byteCount) - { - // Keep the current file offset - long originalOffset = fileStream.Position; - - // Move to the TIFF offset and retrieve the data - fileStream.Seek(tiffOffset + tiffHeaderStart, SeekOrigin.Begin); - - byte[] data = reader.ReadBytes(byteCount); - - // Restore the file offset - fileStream.Position = originalOffset; - - return data; - } - - #endregion - - #region Data conversion methods for interpreting datatypes from a byte array - - /// - /// Converts 2 bytes to a ushort using the current byte aligns - /// - /// - private ushort ToUShort(byte[] data) - { - if (isLittleEndian != BitConverter.IsLittleEndian) - Array.Reverse(data); - - return BitConverter.ToUInt16(data, 0); - } - - /// - /// Converts 8 bytes to an unsigned rational using the current byte aligns. - /// - /// - /// - /// - private double ToURational(byte[] data) - { - var numeratorData = new byte[4]; - var denominatorData = new byte[4]; - - Array.Copy(data, numeratorData, 4); - Array.Copy(data, 4, denominatorData, 0, 4); - - uint numerator = ToUint(numeratorData); - uint denominator = ToUint(denominatorData); - - return numerator / (double)denominator; - } - - /// - /// Converts 8 bytes to a signed rational using the current byte aligns. - /// - /// - /// A TIFF rational contains 2 4-byte integers, the first of which is - /// the numerator, and the second of which is the denominator. - /// - /// - /// - private double ToRational(byte[] data) - { - var numeratorData = new byte[4]; - var denominatorData = new byte[4]; - - Array.Copy(data, numeratorData, 4); - Array.Copy(data, 4, denominatorData, 0, 4); - - int numerator = ToInt(numeratorData); - int denominator = ToInt(denominatorData); - - return numerator / (double)denominator; - } - - /// - /// Converts 4 bytes to a uint using the current byte aligns - /// - /// - private uint ToUint(byte[] data) - { - if (isLittleEndian != BitConverter.IsLittleEndian) - Array.Reverse(data); - - return BitConverter.ToUInt32(data, 0); - } - - /// - /// Converts 4 bytes to an int using the current byte aligns - /// - /// - private int ToInt(byte[] data) - { - if (isLittleEndian != BitConverter.IsLittleEndian) - Array.Reverse(data); - - return BitConverter.ToInt32(data, 0); - } - - private double ToDouble(byte[] data) - { - if (isLittleEndian != BitConverter.IsLittleEndian) - Array.Reverse(data); - - return BitConverter.ToDouble(data, 0); - } - - private float ToSingle(byte[] data) - { - if (isLittleEndian != BitConverter.IsLittleEndian) - Array.Reverse(data); - - return BitConverter.ToSingle(data, 0); - } - - private short ToShort(byte[] data) - { - if (isLittleEndian != BitConverter.IsLittleEndian) - Array.Reverse(data); - - return BitConverter.ToInt16(data, 0); - } - - private sbyte ToSByte(byte[] data) - { - // An sbyte should just be a byte with an offset range. - return (sbyte)(data[0] - byte.MaxValue); - } - - /// - /// Retrieves an array from a byte array using the supplied converter - /// to read each individual element from the supplied byte array - /// - /// - /// - /// - /// - private Array GetArray(byte[] data, int elementLengthBytes, ConverterMethod converter) - { - Array convertedData = Array.CreateInstance(typeof(T), data.Length / elementLengthBytes); - - var buffer = new byte[elementLengthBytes]; - - // Read each element from the array - for (int elementCount = 0; elementCount < data.Length / elementLengthBytes; elementCount++) - { - // Place the data for the current element into the buffer - Array.Copy(data, elementCount * elementLengthBytes, buffer, 0, elementLengthBytes); - - // Process the data and place it into the output array - convertedData.SetValue(converter(buffer), elementCount); - } - - return convertedData; - } - - /// - /// A delegate used to invoke any of the data conversion methods - /// - /// - /// - private delegate T ConverterMethod(byte[] data); - - #endregion - - #region Stream seek methods - used to get to locations within the JPEG - - /// - /// Scans to the Exif block - /// - private void ReadToExifStart() - { - // The file has a number of blocks (Exif/JFIF), each of which - // has a tag number followed by a length. We scan the document until the required tag (0xFFE1) - // is found. All tags start with FF, so a non FF tag indicates an error. - - // Get the next tag. - byte markerStart; - byte markerNumber = 0; - while (((markerStart = reader.ReadByte()) == 0xFF) && (markerNumber = reader.ReadByte()) != 0xE1) - { - // Get the length of the data. - ushort dataLength = ReadUShort(); - - // Jump to the end of the data (note that the size field includes its own size)! - reader.BaseStream.Seek(dataLength - 2, SeekOrigin.Current); - } - - // It's only success if we found the 0xFFE1 marker - if (markerStart != 0xFF || markerNumber != 0xE1) - throw new Exception("Could not find Exif data block"); - } - - /// - /// Reads through the Exif data and builds an index of all Exif tags in the document - /// - /// - private void CreateTagIndex() - { - // The next 4 bytes are the size of the Exif data. - ReadUShort(); - - // Next is the Exif data itself. It starts with the ASCII "Exif" followed by 2 zero bytes. - if (ReadString(4) != "Exif") - throw new Exception("Exif data not found"); - - // 2 zero bytes - if (ReadUShort() != 0) - throw new Exception("Malformed Exif data"); - - // We're now into the TIFF format - tiffHeaderStart = reader.BaseStream.Position; - - // What byte align will be used for the TIFF part of the document? II for Intel, MM for Motorola - isLittleEndian = ReadString(2) == "II"; - - // Next 2 bytes are always the same. - if (ReadUShort() != 0x002A) - throw new Exception("Error in TIFF data"); - - // Get the offset to the IFD (image file directory) - uint ifdOffset = ReadUint(); - - // Note that this offset is from the first byte of the TIFF header. Jump to the IFD. - fileStream.Position = ifdOffset + tiffHeaderStart; - - // Catalogue this first IFD (there will be another IFD) - CatalogueIFD(); - - // There's more data stored in the subifd, the offset to which is found in tag 0x8769. - // As with all TIFF offsets, it will be relative to the first byte of the TIFF header. - uint offset; - if (!GetTagValue(0x8769, out offset)) - throw new Exception("Unable to locate Exif data"); - - // Jump to the exif SubIFD - fileStream.Position = offset + tiffHeaderStart; - - // Add the subIFD to the catalogue too - CatalogueIFD(); - - // Go to the GPS IFD and catalogue that too. It's an optional - // section. - if (GetTagValue(0x8825, out offset)) - { - // Jump to the GPS SubIFD - fileStream.Position = offset + tiffHeaderStart; - - // Add the subIFD to the catalogue too - CatalogueIFD(); - } - } - - #endregion - - #region Exif data catalog and retrieval methods - - public bool GetTagValue(ExifTags tag, out T result) - { - return GetTagValue((ushort)tag, out result); - } - - /// - /// Retrieves an Exif value with the requested tag ID - /// - /// - /// - /// - public bool GetTagValue(ushort tagID, out T result) - { - ushort tiffDataType; - uint numberOfComponents; - byte[] tagData = GetTagBytes(tagID, out tiffDataType, out numberOfComponents); - - if (tagData == null) - { - result = default(T); - return false; - } - - byte fieldLength = GetTIFFFieldLength(tiffDataType); - - // Convert the data to the appropriate datatype. Note the weird boxing via object. - // The compiler doesn't like it otherwise. - switch (tiffDataType) - { - case 1: - // unsigned byte - if (numberOfComponents == 1) - result = (T)(object)tagData[0]; - else - result = (T)(object)tagData; - return true; - case 2: - // ascii string - string str = Encoding.ASCII.GetString(tagData); - - // There may be a null character within the string - int nullCharIndex = str.IndexOf('\0'); - if (nullCharIndex != -1) - str = str.Substring(0, nullCharIndex); - - // Special processing for dates. - if (typeof(T) == typeof(DateTime)) - { - result = - (T)(object)DateTime.ParseExact(str, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture); - return true; - } - - result = (T)(object)str; - return true; - case 3: - // unsigned short - if (numberOfComponents == 1) - result = (T)(object)ToUShort(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToUShort); - return true; - case 4: - // unsigned long - if (numberOfComponents == 1) - result = (T)(object)ToUint(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToUint); - return true; - case 5: - // unsigned rational - if (numberOfComponents == 1) - result = (T)(object)ToURational(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToURational); - return true; - case 6: - // signed byte - if (numberOfComponents == 1) - result = (T)(object)ToSByte(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToSByte); - return true; - case 7: - // undefined. Treat it as an unsigned integer. - if (numberOfComponents == 1) - result = (T)(object)ToUint(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToUint); - return true; - case 8: - // Signed short - if (numberOfComponents == 1) - result = (T)(object)ToShort(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToShort); - return true; - case 9: - // Signed long - if (numberOfComponents == 1) - result = (T)(object)ToInt(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToInt); - return true; - case 10: - // signed rational - if (numberOfComponents == 1) - result = (T)(object)ToRational(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToRational); - return true; - case 11: - // single float - if (numberOfComponents == 1) - result = (T)(object)ToSingle(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToSingle); - return true; - case 12: - // double float - if (numberOfComponents == 1) - result = (T)(object)ToDouble(tagData); - else - result = (T)(object)GetArray(tagData, fieldLength, ToDouble); - return true; - default: - throw new Exception(string.Format("Unknown TIFF datatype: {0}", tiffDataType)); - } - } - - /// - /// Gets the data in the specified tag ID, starting from before the IFD block. - /// - /// - /// The number of items which make up the data item - i.e. for a string, this will be the - /// number of characters in the string - /// - private byte[] GetTagBytes(ushort tagID, out ushort tiffDataType, out uint numberOfComponents) - { - // Get the tag's offset from the catalogue and do some basic error checks - if (fileStream == null || reader == null || catalogue == null || !catalogue.ContainsKey(tagID)) - { - tiffDataType = 0; - numberOfComponents = 0; - return null; - } - - long tagOffset = catalogue[tagID]; - - // Jump to the TIFF offset - fileStream.Position = tagOffset; - - // Read the tag number from the file - ushort currentTagID = ReadUShort(); - - if (currentTagID != tagID) - throw new Exception("Tag number not at expected offset"); - - // Read the offset to the Exif IFD - tiffDataType = ReadUShort(); - numberOfComponents = ReadUint(); - byte[] tagData = ReadBytes(4); - - // If the total space taken up by the field is longer than the - // 2 bytes afforded by the tagData, tagData will contain an offset - // to the actual data. - var dataSize = (int)(numberOfComponents * GetTIFFFieldLength(tiffDataType)); - - if (dataSize > 4) - { - ushort offsetAddress = ToUShort(tagData); - return ReadBytes(offsetAddress, dataSize); - } - - // The value is stored in the tagData starting from the left - Array.Resize(ref tagData, dataSize); - - return tagData; - } - - /// - /// Records all Exif tags and their offsets within - /// the file from the current IFD - /// - private void CatalogueIFD() - { - if (catalogue == null) - catalogue = new Dictionary(); - - // Assume we're just before the IFD. - - // First 2 bytes is the number of entries in this IFD - ushort entryCount = ReadUShort(); - - for (ushort currentEntry = 0; currentEntry < entryCount; currentEntry++) - { - ushort currentTagNumber = ReadUShort(); - - // Record this in the catalogue - catalogue[currentTagNumber] = fileStream.Position - 2; - - // Go to the end of this item (10 bytes, as each entry is 12 bytes long) - reader.BaseStream.Seek(10, SeekOrigin.Current); - } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - // Make sure the file handle is released - if (reader != null) - reader.Close(); - if (fileStream != null) - fileStream.Close(); - } - - #endregion - } -} diff --git a/MediaBrowser.Providers/Photos/ExifTags.cs b/MediaBrowser.Providers/Photos/ExifTags.cs deleted file mode 100644 index 39e153f2e..000000000 --- a/MediaBrowser.Providers/Photos/ExifTags.cs +++ /dev/null @@ -1,132 +0,0 @@ - -namespace MediaBrowser.Providers.Photos -{ - /// - /// All exif tags as per the Exif standard 2.2, JEITA CP-2451 - /// - public enum ExifTags : ushort - { - // IFD0 items - ImageWidth = 0x100, - ImageLength = 0x101, - BitsPerSample = 0x102, - Compression = 0x103, - PhotometricInterpretation = 0x106, - ImageDescription = 0x10E, - Make = 0x10F, - Model = 0x110, - StripOffsets = 0x111, - Orientation = 0x112, - SamplesPerPixel = 0x115, - RowsPerStrip = 0x116, - StripByteCounts = 0x117, - XResolution = 0x11A, - YResolution = 0x11B, - PlanarConfiguration = 0x11C, - ResolutionUnit = 0x128, - TransferFunction = 0x12D, - Software = 0x131, - DateTime = 0x132, - Artist = 0x13B, - WhitePoint = 0x13E, - PrimaryChromaticities = 0x13F, - JPEGInterchangeFormat = 0x201, - JPEGInterchangeFormatLength = 0x202, - YCbCrCoefficients = 0x211, - YCbCrSubSampling = 0x212, - YCbCrPositioning = 0x213, - ReferenceBlackWhite = 0x214, - Copyright = 0x8298, - - // SubIFD items - ExposureTime = 0x829A, - FNumber = 0x829D, - ExposureProgram = 0x8822, - SpectralSensitivity = 0x8824, - ISOSpeedRatings = 0x8827, - OECF = 0x8828, - ExifVersion = 0x9000, - DateTimeOriginal = 0x9003, - DateTimeDigitized = 0x9004, - ComponentsConfiguration = 0x9101, - CompressedBitsPerPixel = 0x9102, - ShutterSpeedValue = 0x9201, - ApertureValue = 0x9202, - BrightnessValue = 0x9203, - ExposureBiasValue = 0x9204, - MaxApertureValue = 0x9205, - SubjectDistance = 0x9206, - MeteringMode = 0x9207, - LightSource = 0x9208, - Flash = 0x9209, - FocalLength = 0x920A, - SubjectArea = 0x9214, - MakerNote = 0x927C, - UserComment = 0x9286, - SubsecTime = 0x9290, - SubsecTimeOriginal = 0x9291, - SubsecTimeDigitized = 0x9292, - FlashpixVersion = 0xA000, - ColorSpace = 0xA001, - PixelXDimension = 0xA002, - PixelYDimension = 0xA003, - RelatedSoundFile = 0xA004, - FlashEnergy = 0xA20B, - SpatialFrequencyResponse = 0xA20C, - FocalPlaneXResolution = 0xA20E, - FocalPlaneYResolution = 0xA20F, - FocalPlaneResolutionUnit = 0xA210, - SubjectLocation = 0xA214, - ExposureIndex = 0xA215, - SensingMethod = 0xA217, - FileSource = 0xA300, - SceneType = 0xA301, - CFAPattern = 0xA302, - CustomRendered = 0xA401, - ExposureMode = 0xA402, - WhiteBalance = 0xA403, - DigitalZoomRatio = 0xA404, - FocalLengthIn35mmFilm = 0xA405, - SceneCaptureType = 0xA406, - GainControl = 0xA407, - Contrast = 0xA408, - Saturation = 0xA409, - Sharpness = 0xA40A, - DeviceSettingDescription = 0xA40B, - SubjectDistanceRange = 0xA40C, - ImageUniqueID = 0xA420, - - // GPS subifd items - GPSVersionID = 0x0, - GPSLatitudeRef = 0x1, - GPSLatitude = 0x2, - GPSLongitudeRef = 0x3, - GPSLongitude = 0x4, - GPSAltitudeRef = 0x5, - GPSAltitude = 0x6, - GPSTimeStamp = 0x7, - GPSSatellites = 0x8, - GPSStatus = 0x9, - GPSMeasureMode = 0xA, - GPSDOP = 0xB, - GPSSpeedRef = 0xC, - GPSSpeed = 0xD, - GPSTrackRef = 0xE, - GPSTrack = 0xF, - GPSImgDirectionRef = 0x10, - GPSImgDirection = 0x11, - GPSMapDatum = 0x12, - GPSDestLatitudeRef = 0x13, - GPSDestLatitude = 0x14, - GPSDestLongitudeRef = 0x15, - GPSDestLongitude = 0x16, - GPSDestBearingRef = 0x17, - GPSDestBearing = 0x18, - GPSDestDistanceRef = 0x19, - GPSDestDistance = 0x1A, - GPSProcessingMethod = 0x1B, - GPSAreaInformation = 0x1C, - GPSDateStamp = 0x1D, - GPSDifferential = 0x1E - } -} diff --git a/MediaBrowser.Providers/Photos/PhotoHelper.cs b/MediaBrowser.Providers/Photos/PhotoHelper.cs index a5ce6f81f..2334c792e 100644 --- a/MediaBrowser.Providers/Photos/PhotoHelper.cs +++ b/MediaBrowser.Providers/Photos/PhotoHelper.cs @@ -1,25 +1,10 @@ -using MediaBrowser.Controller.Entities; -using System; -using System.Collections.Generic; +using System; using System.Text; namespace MediaBrowser.Providers.Photos { public static class PhotoHelper { - public static List ShuffleList(List list) - { - var rnd = new Random(DateTime.Now.Second); - for (var i = 1; i < list.Count; i++) - { - var pos = rnd.Next(i + 1); - var x = list[i]; - list[i] = list[pos]; - list[pos] = x; - } - return list; - } - public static string Dec2Frac(double dbl) { char neg = ' '; diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs index c0f53e0c3..01d36b541 100644 --- a/MediaBrowser.Providers/Photos/PhotoProvider.cs +++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs @@ -5,9 +5,13 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; -using System.Globalization; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using TagLib; +using TagLib.IFD; +using TagLib.IFD.Entries; +using TagLib.IFD.Tags; namespace MediaBrowser.Providers.Photos { @@ -27,100 +31,101 @@ namespace MediaBrowser.Providers.Photos item.SetImagePath(ImageType.Primary, item.Path); item.SetImagePath(ImageType.Backdrop, item.Path); - if (item.Path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || item.Path.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)) + // Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs + + try { - try - { - using (var reader = new ExifReader(item.Path)) - { - double aperture = 0; - double shutterSpeed = 0; + var file = File.Create(item.Path); - DateTime dateTaken; + var image = file as TagLib.Image.File; - string manufacturer; - string model; + var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; - reader.GetTagValue(ExifTags.FNumber, out aperture); - reader.GetTagValue(ExifTags.ExposureTime, out shutterSpeed); - reader.GetTagValue(ExifTags.DateTimeOriginal, out dateTaken); + if (tag != null) + { + var structure = tag.Structure; - reader.GetTagValue(ExifTags.Make, out manufacturer); - reader.GetTagValue(ExifTags.Model, out model); + if (structure != null) + { + var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry; - if (dateTaken > DateTime.MinValue) + if (exif != null) { - item.DateCreated = dateTaken; - item.PremiereDate = dateTaken; - item.ProductionYear = dateTaken.Year; + var exifStructure = exif.Structure; + + if (exifStructure != null) + { + var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry; + + if (entry != null) + { + double val = entry.Value.Numerator; + val /= entry.Value.Denominator; + item.Aperture = val; + } + + entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry; + + if (entry != null) + { + double val = entry.Value.Numerator; + val /= entry.Value.Denominator; + item.ShutterSpeed = val; + } + } } + } + } - var cameraModel = manufacturer ?? string.Empty; - cameraModel += " "; - cameraModel += model ?? string.Empty; + item.CameraManufacturer = image.ImageTag.Make; + item.CameraModel = image.ImageTag.Model; - var size = _imageProcessor.GetImageSize(item.Path); - var xResolution = size.Width; - var yResolution = size.Height; + var rating = image.ImageTag.Rating; + if (rating.HasValue) + { + item.CommunityRating = rating; + } + else + { + item.CommunityRating = null; + } - item.Overview = "Taken " + dateTaken.ToString("F") + "\n" + - (!string.IsNullOrWhiteSpace(cameraModel) ? "With a " + cameraModel : "") + - (aperture > 0 && shutterSpeed > 0 ? " at f" + aperture.ToString(CultureInfo.InvariantCulture) + " and " + PhotoHelper.Dec2Frac(shutterSpeed) + "s" : "") + "\n" - + (xResolution > 0 ? "\n
Resolution: " + xResolution + "x" + yResolution : ""); - } + item.Overview = image.ImageTag.Comment; + if (!string.IsNullOrWhiteSpace(image.ImageTag.Title)) + { + item.Name = image.ImageTag.Title; } - catch (Exception e) + + var dateTaken = image.ImageTag.DateTime; + if (dateTaken.HasValue) { - _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path); + item.DateCreated = dateTaken.Value; + item.PremiereDate = dateTaken.Value; + item.ProductionYear = dateTaken.Value.Year; } - } - //// Get additional tags from xmp - //try - //{ - // using (var fs = new FileStream(item.Path, FileMode.Open, FileAccess.Read)) - // { - // var bf = BitmapFrame.Create(fs); - - // if (bf != null) - // { - // var data = (BitmapMetadata)bf.Metadata; - // if (data != null) - // { - - // DateTime dateTaken; - // var cameraModel = ""; - - // DateTime.TryParse(data.DateTaken, out dateTaken); - // if (dateTaken > DateTime.MinValue) item.DateCreated = dateTaken; - // cameraModel = data.CameraModel; - - // item.PremiereDate = dateTaken; - // item.ProductionYear = dateTaken.Year; - // item.Overview = "Taken " + dateTaken.ToString("F") + "\n" + - // (cameraModel != "" ? "With a " + cameraModel : "") + - // (aperture > 0 && shutterSpeed > 0 ? " at f" + aperture.ToString(CultureInfo.InvariantCulture) + " and " + PhotoHelper.Dec2Frac(shutterSpeed) + "s" : "") + "\n" - // + (bf.Width > 0 ? "\n
Resolution: " + (int)bf.Width + "x" + (int)bf.Height : ""); - - // var photo = item as Photo; - // if (data.Keywords != null) item.Genres = photo.Tags = new List(data.Keywords); - // item.Name = !string.IsNullOrWhiteSpace(data.Title) ? data.Title : item.Name; - // item.CommunityRating = data.Rating; - // if (!string.IsNullOrWhiteSpace(data.Subject)) photo.AddTagline(data.Subject); - // } - // } - - // } - //} - //catch (NotSupportedException) - //{ - // // No problem - move on - //} - //catch (Exception e) - //{ - // _logger.ErrorException("Error trying to read extended data from {0}", e, item.Path); - //} + var size = _imageProcessor.GetImageSize(item.Path); + item.Height = Convert.ToInt32(size.Height); + item.Width = Convert.ToInt32(size.Width); + + item.Genres = image.ImageTag.Genres.ToList(); + item.Tags = image.ImageTag.Keywords.ToList(); + item.Software = image.ImageTag.Software; + + Model.Drawing.ImageOrientation orientation; + if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation)) + { + item.Orientation = orientation; + } + + item.ExposureTime = image.ImageTag.ExposureTime; + item.FocalLength = image.ImageTag.FocalLength; + } + catch (Exception e) + { + _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path); + } const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport; return Task.FromResult(result); diff --git a/MediaBrowser.Providers/packages.config b/MediaBrowser.Providers/packages.config index 9d3b60ff5..29a802156 100644 --- a/MediaBrowser.Providers/packages.config +++ b/MediaBrowser.Providers/packages.config @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 42191a270..2d050d4a7 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints // Mono.Nat does never rise this event. The event is there however it is useless. // You could remove it with no risk. - // NatUtility.DeviceLost += NatUtility_DeviceLost; + NatUtility.DeviceLost += NatUtility_DeviceLost; // it is hard to say what one should do when an unhandled exception is raised @@ -71,7 +71,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints _isStarted = true; - _timer = new Timer(s => _createdRules = new List(), null, TimeSpan.FromHours(6), TimeSpan.FromHours(6)); + _timer = new Timer(s => _createdRules = new List(), null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10)); } } @@ -123,7 +123,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints if (!_createdRules.Contains(address)) { _createdRules.Add(address); - + var info = _appHost.GetSystemInfo(); CreatePortMap(device, info.HttpServerPortNumber); @@ -141,11 +141,11 @@ namespace MediaBrowser.Server.Implementations.EntryPoints } // As I said before, this method will be never invoked. You can remove it. - //void NatUtility_DeviceLost(object sender, DeviceEventArgs e) - //{ - // var device = e.Device; - // _logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString()); - //} + void NatUtility_DeviceLost(object sender, DeviceEventArgs e) + { + var device = e.Device; + _logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString()); + } public void Dispose() { @@ -167,7 +167,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints // This is not a significant improvement NatUtility.StopDiscovery(); NatUtility.DeviceFound -= NatUtility_DeviceFound; - //NatUtility.DeviceLost -= NatUtility_DeviceLost; + NatUtility.DeviceLost -= NatUtility_DeviceLost; NatUtility.UnhandledException -= NatUtility_UnhandledException; } // Statements in try-block will no fail because StopDiscovery is a one-line diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 6b1f3d91a..0a9209bfe 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1105,5 +1105,7 @@ "OptionDirector": "Director", "OptionGuestStar": "Guest star", "OptionProducer": "Producer", - "OptionWriter": "Writer" + "OptionWriter": "Writer", + "LabelAirDays": "Air days:", + "LabelAirTime": "Air time:" } diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs index 97a3ee190..7a74e9689 100644 --- a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs +++ b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg switch (arg) { case "Version": - return "20140612"; + return "20140827"; case "FFMpegFilename": return "ffmpeg.exe"; case "FFProbeFilename": @@ -111,9 +111,18 @@ namespace MediaBrowser.ServerApplication.FFMpeg switch (pid) { case PlatformID.Win32NT: + if (PlatformDetection.IsX86_64) + { + return new[] + { + "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20140827-git-9e8ab36-win64-static.7z", + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20140612-git-3a1c895-win32-static.7z" + }; + } + return new[] { - "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20140612-git-3a1c895-win32-static.7z", + "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20140827-git-9e8ab36-win32-static.7z", "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20140612-git-3a1c895-win32-static.7z" }; -- cgit v1.2.3 From 7e636a977a47f67af9bebfcbb6ebc89035ad91bd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Aug 2014 20:49:25 -0400 Subject: fixes #903 - Display image info on web client detail page --- MediaBrowser.Controller/Entities/Audio/Audio.cs | 30 +------ .../Entities/Audio/MusicAlbum.cs | 27 +----- MediaBrowser.Controller/Entities/Photo.cs | 4 +- .../MediaBrowser.Model.Portable.csproj | 6 -- .../MediaBrowser.Model.net35.csproj | 6 -- MediaBrowser.Model/ApiClient/IApiClient.cs | 24 ------ MediaBrowser.Model/Dlna/AudioOptions.cs | 9 +- MediaBrowser.Model/Drawing/ImageOrientation.cs | 1 - MediaBrowser.Model/Dto/BaseItemDto.cs | 14 ++- MediaBrowser.Model/Dto/StreamOptions.cs | 64 -------------- MediaBrowser.Model/Dto/VideoStreamOptions.cs | 99 ---------------------- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 - .../MediaInfo/FFProbeProvider.cs | 9 ++ .../Music/AlbumMetadataService.cs | 16 ++-- .../Music/AudioDbAlbumProvider.cs | 5 +- MediaBrowser.Providers/Music/Extensions.cs | 10 +-- MediaBrowser.Providers/Photos/PhotoProvider.cs | 31 +++++-- .../Dto/DtoService.cs | 22 ++++- .../Localization/Server/server.json | 8 +- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 23 files changed, 105 insertions(+), 294 deletions(-) delete mode 100644 MediaBrowser.Model/Dto/StreamOptions.cs delete mode 100644 MediaBrowser.Model/Dto/VideoStreamOptions.cs (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 7d54e012c..3ffdf744d 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.Entities.Audio public Audio() { Artists = new List(); + AlbumArtists = new List(); Tags = new List(); } @@ -90,12 +91,14 @@ namespace MediaBrowser.Controller.Entities.Audio /// The artist. public List Artists { get; set; } + public List AlbumArtists { get; set; } + [IgnoreDataMember] public List AllArtists { get { - var list = AlbumArtists; + var list = AlbumArtists.ToList(); list.AddRange(Artists); @@ -104,36 +107,11 @@ namespace MediaBrowser.Controller.Entities.Audio } } - [IgnoreDataMember] - public List AlbumArtists - { - get - { - var list = new List(); - - if (!string.IsNullOrEmpty(AlbumArtist)) - { - list.Add(AlbumArtist); - } - - return list; - } - set - { - AlbumArtist = value.FirstOrDefault(); - } - } - /// /// Gets or sets the album. /// /// The album. public string Album { get; set; } - /// - /// Gets or sets the album artist. - /// - /// The album artist. - public string AlbumArtist { get; set; } /// /// Gets the type of the media. diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 152d76782..82cd618dd 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -17,8 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio public MusicAlbum() { - Artists = new List(); SoundtrackIds = new List(); + Artists = new List(); + AlbumArtists = new List(); } public override bool SupportsAddingToPlaylist @@ -40,7 +41,7 @@ namespace MediaBrowser.Controller.Entities.Audio { get { - var list = AlbumArtists; + var list = AlbumArtists.ToList(); list.AddRange(Artists); @@ -49,25 +50,7 @@ namespace MediaBrowser.Controller.Entities.Audio } } - [IgnoreDataMember] - public List AlbumArtists - { - get - { - var list = new List(); - - if (!string.IsNullOrEmpty(AlbumArtist)) - { - list.Add(AlbumArtist); - } - - return list; - } - set - { - AlbumArtist = value.FirstOrDefault(); - } - } + public List AlbumArtists { get; set; } /// /// Gets the tracks. @@ -139,8 +122,6 @@ namespace MediaBrowser.Controller.Entities.Audio return AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase); } - public string AlbumArtist { get; set; } - public List Artists { get; set; } /// diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 542fbaa31..aa9e63791 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -24,14 +24,12 @@ namespace MediaBrowser.Controller.Entities public int? Width { get; set; } public int? Height { get; set; } - public string CameraManufacturer { get; set; } + public string CameraMake { get; set; } public string CameraModel { get; set; } public string Software { get; set; } public double? ExposureTime { get; set; } public double? FocalLength { get; set; } - public ImageOrientation? Orientation { get; set; } - public double? Aperture { get; set; } public double? ShutterSpeed { get; set; } } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index aaa44b009..62f2a7425 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -341,9 +341,6 @@ Dto\RecommendationType.cs - - Dto\StreamOptions.cs - Dto\StudioDto.cs @@ -356,9 +353,6 @@ Dto\UserItemDataDto.cs - - Dto\VideoStreamOptions.cs - Entities\BaseItemInfo.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 6046d3606..715331436 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -304,9 +304,6 @@ Dto\RecommendationType.cs - - Dto\StreamOptions.cs - Dto\StudioDto.cs @@ -319,9 +316,6 @@ Dto\UserItemDataDto.cs - - Dto\VideoStreamOptions.cs - Entities\BaseItemInfo.cs diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 3aa9b73b9..a9d0f480c 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -61,30 +61,6 @@ namespace MediaBrowser.Model.ApiClient Task GetAsync(string url, CancellationToken cancellationToken = default(CancellationToken)) where T : class; - /// - /// Gets the url needed to stream an audio file - /// - /// The options. - /// System.String. - /// options - string GetAudioStreamUrl(StreamOptions options); - - /// - /// Gets the url needed to stream a video file - /// - /// The options. - /// System.String. - /// options - string GetVideoStreamUrl(VideoStreamOptions options); - - /// - /// Formulates a url for streaming video using the HLS protocol - /// - /// The options. - /// System.String. - /// options - string GetHlsVideoStreamUrl(VideoStreamOptions options); - /// /// Reports the capabilities. /// diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs index 309b67543..dd6dad261 100644 --- a/MediaBrowser.Model/Dlna/AudioOptions.cs +++ b/MediaBrowser.Model/Dlna/AudioOptions.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Dto; +using System.Collections.Generic; namespace MediaBrowser.Model.Dlna { @@ -8,6 +8,11 @@ namespace MediaBrowser.Model.Dlna /// public class AudioOptions { + public AudioOptions() + { + Context = EncodingContext.Streaming; + } + public string ItemId { get; set; } public List MediaSources { get; set; } public DeviceProfile Profile { get; set; } diff --git a/MediaBrowser.Model/Drawing/ImageOrientation.cs b/MediaBrowser.Model/Drawing/ImageOrientation.cs index 3fdfaf7bf..c320a8224 100644 --- a/MediaBrowser.Model/Drawing/ImageOrientation.cs +++ b/MediaBrowser.Model/Drawing/ImageOrientation.cs @@ -3,7 +3,6 @@ namespace MediaBrowser.Model.Drawing { public enum ImageOrientation { - None = 0, TopLeft = 1, TopRight = 2, BottomRight = 3, diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 0dfd27a72..360d2d862 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Library; using MediaBrowser.Model.Providers; @@ -721,6 +722,17 @@ namespace MediaBrowser.Model.Dto /// true if [enable internet providers]; otherwise, false. public bool? LockData { get; set; } + public int? Width { get; set; } + public int? Height { get; set; } + public string CameraMake { get; set; } + public string CameraModel { get; set; } + public string Software { get; set; } + public double? ExposureTime { get; set; } + public double? FocalLength { get; set; } + public ImageOrientation? ImageOrientation { get; set; } + public double? Aperture { get; set; } + public double? ShutterSpeed { get; set; } + /// /// Gets a value indicating whether this instance can resume. /// diff --git a/MediaBrowser.Model/Dto/StreamOptions.cs b/MediaBrowser.Model/Dto/StreamOptions.cs deleted file mode 100644 index 9cf301270..000000000 --- a/MediaBrowser.Model/Dto/StreamOptions.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace MediaBrowser.Model.Dto -{ - /// - /// Class StreamOptions - /// - public class StreamOptions - { - /// - /// Gets or sets the audio bit rate. - /// - /// The audio bit rate. - public int? AudioBitRate { get; set; } - - /// - /// Gets or sets the audio codec. - /// Omit to copy the original stream - /// - /// The audio encoding format. - public string AudioCodec { get; set; } - - /// - /// Gets or sets the item id. - /// - /// The item id. - public string ItemId { get; set; } - - /// - /// Gets or sets the max audio channels. - /// - /// The max audio channels. - public int? MaxAudioChannels { get; set; } - - /// - /// Gets or sets the max audio sample rate. - /// - /// The max audio sample rate. - public int? MaxAudioSampleRate { get; set; } - - /// - /// Gets or sets the start time ticks. - /// - /// The start time ticks. - public long? StartTimeTicks { get; set; } - - /// - /// Gets or sets a value indicating whether the original media should be served statically - /// Only used with progressive streaming - /// - /// true if static; otherwise, false. - public bool? Static { get; set; } - - /// - /// Gets or sets the output file extension. - /// - /// The output file extension. - public string OutputFileExtension { get; set; } - - /// - /// Gets or sets the device id. - /// - /// The device id. - public string DeviceId { get; set; } - } -} diff --git a/MediaBrowser.Model/Dto/VideoStreamOptions.cs b/MediaBrowser.Model/Dto/VideoStreamOptions.cs deleted file mode 100644 index 73dc70018..000000000 --- a/MediaBrowser.Model/Dto/VideoStreamOptions.cs +++ /dev/null @@ -1,99 +0,0 @@ -namespace MediaBrowser.Model.Dto -{ - /// - /// Class VideoStreamOptions - /// - public class VideoStreamOptions : StreamOptions - { - /// - /// Gets or sets the video codec. - /// Omit to copy - /// - /// The video codec. - public string VideoCodec { get; set; } - - /// - /// Gets or sets the video bit rate. - /// - /// The video bit rate. - public int? VideoBitRate { get; set; } - - /// - /// Gets or sets the width. - /// - /// The width. - public int? Width { get; set; } - - /// - /// Gets or sets the height. - /// - /// The height. - public int? Height { get; set; } - - /// - /// Gets or sets the width of the max. - /// - /// The width of the max. - public int? MaxWidth { get; set; } - - /// - /// Gets or sets the height of the max. - /// - /// The height of the max. - public int? MaxHeight { get; set; } - - /// - /// Gets or sets the frame rate. - /// - /// The frame rate. - public double? FrameRate { get; set; } - - /// - /// Gets or sets the index of the audio stream. - /// - /// The index of the audio stream. - public int? AudioStreamIndex { get; set; } - - /// - /// Gets or sets the index of the video stream. - /// - /// The index of the video stream. - public int? VideoStreamIndex { get; set; } - - /// - /// Gets or sets the index of the subtitle stream. - /// - /// The index of the subtitle stream. - public int? SubtitleStreamIndex { get; set; } - - /// - /// Gets or sets the profile. - /// - /// The profile. - public string Profile { get; set; } - - /// - /// Gets or sets the level. - /// - /// The level. - public string Level { get; set; } - - /// - /// Gets or sets the baseline stream audio bit rate. - /// - /// The baseline stream audio bit rate. - public int? BaselineStreamAudioBitRate { get; set; } - - /// - /// Gets or sets a value indicating whether [append baseline stream]. - /// - /// true if [append baseline stream]; otherwise, false. - public bool AppendBaselineStream { get; set; } - - /// - /// Gets or sets the time stamp offset ms. Only used with HLS. - /// - /// The time stamp offset ms. - public int? TimeStampOffsetMs { get; set; } - } -} \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index c3f02236f..a760cba05 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -152,7 +152,6 @@ - @@ -285,7 +284,6 @@ - diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 33b69d71a..e3324fe82 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -168,6 +168,15 @@ namespace MediaBrowser.Providers.MediaInfo return true; } + if (item is Audio) + { + // Moved to plural AlbumArtists + if (date < new DateTime(2014, 8, 28)) + { + return true; + } + } + if (item.SupportsLocalMetadata) { var video = item as Video; diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index f049c79e1..a3d9b5642 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -9,8 +9,6 @@ using MediaBrowser.Providers.Manager; using System; using System.Collections.Generic; using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.Music { @@ -104,17 +102,15 @@ namespace MediaBrowser.Providers.Music { var updateType = ItemUpdateType.None; - var albumArtist = songs + var albumArtists = songs .SelectMany(i => i.AlbumArtists) - .FirstOrDefault(i => !string.IsNullOrEmpty(i)); + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); - if (!string.IsNullOrEmpty(albumArtist)) + if (!item.AlbumArtists.SequenceEqual(albumArtists, StringComparer.OrdinalIgnoreCase)) { - if (!string.Equals(item.AlbumArtist, albumArtist, StringComparison.Ordinal)) - { - item.AlbumArtist = albumArtist; - updateType = updateType | ItemUpdateType.MetadataDownload; - } + item.AlbumArtists = albumArtists; + updateType = updateType | ItemUpdateType.MetadataDownload; } return updateType; diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs index ab9ac2331..3667d70cf 100644 --- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs @@ -70,7 +70,10 @@ namespace MediaBrowser.Providers.Music private void ProcessResult(MusicAlbum item, Album result) { - item.AlbumArtist = result.strArtist; + if (!string.IsNullOrWhiteSpace(result.strArtist)) + { + item.AlbumArtists = new List { result.strArtist }; + } if (!string.IsNullOrEmpty(result.intYearReleased)) { diff --git a/MediaBrowser.Providers/Music/Extensions.cs b/MediaBrowser.Providers/Music/Extensions.cs index b14a1ba09..c83e69165 100644 --- a/MediaBrowser.Providers/Music/Extensions.cs +++ b/MediaBrowser.Providers/Music/Extensions.cs @@ -8,15 +8,15 @@ namespace MediaBrowser.Providers.Music { public static string GetAlbumArtist(this AlbumInfo info) { - var id = info.AlbumArtists.FirstOrDefault(); + var id = info.SongInfos.SelectMany(i => i.AlbumArtists) + .FirstOrDefault(i => !string.IsNullOrEmpty(i)); - if (string.IsNullOrEmpty(id)) + if (!string.IsNullOrEmpty(id)) { - return info.SongInfos.SelectMany(i => i.AlbumArtists) - .FirstOrDefault(i => !string.IsNullOrEmpty(i)); + return id; } - return id; + return info.AlbumArtists.FirstOrDefault(); } public static string GetReleaseGroupId(this AlbumInfo info) diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs index 01d36b541..123c91d07 100644 --- a/MediaBrowser.Providers/Photos/PhotoProvider.cs +++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs @@ -29,7 +29,6 @@ namespace MediaBrowser.Providers.Photos public Task FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken) { item.SetImagePath(ImageType.Primary, item.Path); - item.SetImagePath(ImageType.Backdrop, item.Path); // Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs @@ -77,7 +76,7 @@ namespace MediaBrowser.Providers.Photos } } - item.CameraManufacturer = image.ImageTag.Make; + item.CameraMake = image.ImageTag.Make; item.CameraModel = image.ImageTag.Model; var rating = image.ImageTag.Rating; @@ -105,18 +104,21 @@ namespace MediaBrowser.Providers.Photos item.ProductionYear = dateTaken.Value.Year; } - var size = _imageProcessor.GetImageSize(item.Path); - item.Height = Convert.ToInt32(size.Height); - item.Width = Convert.ToInt32(size.Width); - item.Genres = image.ImageTag.Genres.ToList(); item.Tags = image.ImageTag.Keywords.ToList(); item.Software = image.ImageTag.Software; - Model.Drawing.ImageOrientation orientation; - if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation)) + if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None) { - item.Orientation = orientation; + item.Orientation = null; + } + else + { + Model.Drawing.ImageOrientation orientation; + if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation)) + { + item.Orientation = orientation; + } } item.ExposureTime = image.ImageTag.ExposureTime; @@ -127,6 +129,10 @@ namespace MediaBrowser.Providers.Photos _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path); } + var size = _imageProcessor.GetImageSize(item.Path); + item.Height = Convert.ToInt32(size.Height); + item.Width = Convert.ToInt32(size.Width); + const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport; return Task.FromResult(result); } @@ -138,6 +144,13 @@ namespace MediaBrowser.Providers.Photos public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { + // Moved to plural AlbumArtists + if (date < new DateTime(2014, 8, 28)) + { + // Revamped vaptured metadata + return true; + } + return item.DateModified > date; } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 8bfd4ea1e..61517ce6e 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -357,6 +357,19 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.SeriesName = item.SeriesName; } + private void SetPhotoProperties(BaseItemDto dto, Photo item) + { + dto.Width = item.Width; + dto.Height = item.Height; + dto.CameraMake = item.CameraMake; + dto.CameraModel = item.CameraModel; + dto.Software = item.Software; + dto.ExposureTime = item.ExposureTime; + dto.FocalLength = item.FocalLength; + dto.ImageOrientation = item.Orientation; + dto.Aperture = item.Aperture; + dto.ShutterSpeed = item.ShutterSpeed; + } private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item) { @@ -1187,21 +1200,24 @@ namespace MediaBrowser.Server.Implementations.Dto } var book = item as Book; - if (book != null) { SetBookProperties(dto, book); } - var tvChannel = item as LiveTvChannel; + var photo = item as Photo; + if (photo != null) + { + SetPhotoProperties(dto, photo); + } + var tvChannel = item as LiveTvChannel; if (tvChannel != null) { dto.MediaSources = tvChannel.GetMediaSources(true).ToList(); } var channelItem = item as IChannelItem; - if (channelItem != null) { dto.ChannelId = channelItem.ChannelId; diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index adaa30719..21eb0c1c9 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1093,8 +1093,8 @@ "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.", "TabSupporterClub": "Supporter Club", "HeaderDonationType": "Donation type:", - "OptionMakeOneTimeDonation": "Make an additional donation", - "OptionOneTimeDescription": "This is an additional donation to the team to show extra support. It does not have any additional benefits.", + "OptionMakeOneTimeDonation": "Make a separate donation", + "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.", "OptionLifeTimeSupporterClubMembership": "Lifetime supporter club membership", "HeaderSupporterBenefit": "Becoming a supporter club member provides additional benefits such as access to premium plugins, internet channel content, and more.", "OptionNoTrailer": "No Trailer", @@ -1108,5 +1108,7 @@ "OptionProducer": "Producer", "OptionWriter": "Writer", "LabelAirDays": "Air days:", - "LabelAirTime": "Air time:" + "LabelAirTime": "Air time:", + "HeaderMediaInfo": "Media Info", + "HeaderPhotoInfo": "Photo Info" } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index e843c6298..935d26750 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.427 + 3.0.428 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 90a66b3c7..4c3626c8d 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.427 + 3.0.428 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index a444d4c33..67127ea77 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.427 + 3.0.428 MediaBrowser.Model - Signed Edition Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index dadc51dff..23743e2d0 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.427 + 3.0.428 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + -- cgit v1.2.3