aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-01-01 13:26:31 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-01-01 13:26:31 -0500
commitb9d17c9bc765a0c59d81db6277300a6860bf8421 (patch)
tree8a7c538cb73c27b7e06f0055ce4f0bb45175e7aa
parent88b638fbd69ed99bde7065f66af433b015977cb7 (diff)
add more methods to file system interface
-rw-r--r--MediaBrowser.Api/EnvironmentService.cs89
-rw-r--r--MediaBrowser.Api/Images/ImageRequest.cs7
-rw-r--r--MediaBrowser.Api/Images/ImageWriter.cs1
-rw-r--r--MediaBrowser.Api/Library/LibraryHelpers.cs43
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs6
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs20
-rw-r--r--MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs160
-rw-r--r--MediaBrowser.Common/IO/IFileSystem.cs22
-rw-r--r--MediaBrowser.Common/Net/INetworkManager.cs3
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs5
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs27
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs125
-rw-r--r--MediaBrowser.Controller/Entities/IHasImages.cs6
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs26
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs52
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs (renamed from MediaBrowser.Controller/LiveTv/LiveTvRecording.cs)15
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj4
-rw-r--r--MediaBrowser.Model/LiveTv/RecordingInfoDto.cs12
-rw-r--r--MediaBrowser.Model/LiveTv/RecordingQuery.cs6
-rw-r--r--MediaBrowser.Mono.userprefs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs9
-rw-r--r--MediaBrowser.Providers/Music/LastfmBaseProvider.cs8
-rw-r--r--MediaBrowser.Providers/Music/LastfmHelper.cs21
-rw-r--r--MediaBrowser.Providers/Savers/AlbumXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/ArtistXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/FolderXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/GameXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/MovieXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/SeasonXmlSaver.cs2
-rw-r--r--MediaBrowser.Providers/Savers/SeriesXmlSaver.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs43
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs36
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs (renamed from MediaBrowser.Server.Implementations/Drawing/WatchedIndicatorDrawer.cs)18
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs55
-rw-r--r--MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs25
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs30
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs35
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs81
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs8
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj3
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ImageSaver.cs2
-rw-r--r--MediaBrowser.Server.Mono/Networking/NetworkManager.cs5
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs2
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs34
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs1
-rw-r--r--MediaBrowser.WebDashboard/ApiClient.js41
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj6
-rw-r--r--MediaBrowser.WebDashboard/packages.config2
54 files changed, 704 insertions, 426 deletions
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
index dfdd0daf0..aac708520 100644
--- a/MediaBrowser.Api/EnvironmentService.cs
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -46,6 +46,18 @@ namespace MediaBrowser.Api
public bool IncludeHidden { get; set; }
}
+ [Route("/Environment/NetworkShares", "GET")]
+ [Api(Description = "Gets shares from a network device")]
+ public class GetNetworkShares : IReturn<List<FileSystemEntryInfo>>
+ {
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ [ApiMember(Name = "Path", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Path { get; set; }
+ }
+
/// <summary>
/// Class GetDrives
/// </summary>
@@ -64,11 +76,25 @@ namespace MediaBrowser.Api
{
}
+ [Route("/Environment/ParentPath", "GET")]
+ [Api(Description = "Gets the parent path of a given path")]
+ public class GetParentPath : IReturn<string>
+ {
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ [ApiMember(Name = "Path", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string Path { get; set; }
+ }
+
/// <summary>
/// Class EnvironmentService
/// </summary>
public class EnvironmentService : BaseApiService
{
+ const char UncSeparator = '\\';
+
/// <summary>
/// The _network manager
/// </summary>
@@ -105,13 +131,9 @@ namespace MediaBrowser.Api
throw new ArgumentNullException("Path");
}
- // If it's not a drive trim trailing slashes.
- if (!path.EndsWith(":\\"))
- {
- path = path.TrimEnd('\\');
- }
+ var networkPrefix = UncSeparator.ToString(CultureInfo.InvariantCulture) + UncSeparator.ToString(CultureInfo.InvariantCulture);
- if (path.StartsWith(NetworkPrefix, StringComparison.OrdinalIgnoreCase) && path.LastIndexOf('\\') == 1)
+ if (path.StartsWith(networkPrefix, StringComparison.OrdinalIgnoreCase) && path.LastIndexOf(UncSeparator) == 1)
{
return ToOptimizedResult(GetNetworkShares(path).OrderBy(i => i.Path).ToList());
}
@@ -119,6 +141,15 @@ namespace MediaBrowser.Api
return ToOptimizedResult(GetFileSystemEntries(request).OrderBy(i => i.Path).ToList());
}
+ public object Get(GetNetworkShares request)
+ {
+ var path = request.Path;
+
+ var shares = GetNetworkShares(path).OrderBy(i => i.Path).ToList();
+
+ return ToOptimizedResult(shares);
+ }
+
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -154,26 +185,14 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetNetworkDevices request)
{
- var result = GetNetworkDevices().OrderBy(i => i.Path).ToList();
+ var result = _networkManager.GetNetworkDevices()
+ .OrderBy(i => i.Path)
+ .ToList();
return ToOptimizedResult(result);
}
/// <summary>
- /// Gets the network computers.
- /// </summary>
- /// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
- private IEnumerable<FileSystemEntryInfo> GetNetworkDevices()
- {
- return _networkManager.GetNetworkDevices().Select(c => new FileSystemEntryInfo
- {
- Name = c,
- Path = NetworkPrefix + c,
- Type = FileSystemEntryType.NetworkComputer
- });
- }
-
- /// <summary>
/// Gets the name.
/// </summary>
/// <param name="drive">The drive.</param>
@@ -223,7 +242,7 @@ namespace MediaBrowser.Api
{
return false;
}
-
+
return true;
});
@@ -236,13 +255,27 @@ namespace MediaBrowser.Api
}).ToList();
}
- /// <summary>
- /// Gets the network prefix.
- /// </summary>
- /// <value>The network prefix.</value>
- private string NetworkPrefix
+ public object Get(GetParentPath request)
{
- get { return Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture) + Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture); }
+ var parent = Path.GetDirectoryName(request.Path);
+
+ if (string.IsNullOrEmpty(parent))
+ {
+ // Check if unc share
+ var index = request.Path.LastIndexOf(UncSeparator);
+
+ if (index != -1 && request.Path.IndexOf(UncSeparator) == 0)
+ {
+ parent = request.Path.Substring(0, index);
+
+ if (string.IsNullOrWhiteSpace(parent.TrimStart(UncSeparator)))
+ {
+ parent = null;
+ }
+ }
+ }
+
+ return parent;
}
}
}
diff --git a/MediaBrowser.Api/Images/ImageRequest.cs b/MediaBrowser.Api/Images/ImageRequest.cs
index 0d4c1ff1b..718d5f402 100644
--- a/MediaBrowser.Api/Images/ImageRequest.cs
+++ b/MediaBrowser.Api/Images/ImageRequest.cs
@@ -59,8 +59,11 @@ namespace MediaBrowser.Api.Images
[ApiMember(Name = "AddPlayedIndicator", Description = "Optional. Add a played indicator", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool AddPlayedIndicator { get; set; }
- [ApiMember(Name = "PercentPlayed", Description = "Optional percent to render for the percent played overlay", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public int? PercentPlayed { get; set; }
+ [ApiMember(Name = "PercentPlayed", Description = "Optional percent to render for the percent played overlay", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public double? PercentPlayed { get; set; }
+
+ [ApiMember(Name = "UnplayedCount", Description = "Optional unplayed count overlay to render", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? UnplayedCount { get; set; }
[ApiMember(Name = "BackgroundColor", Description = "Optional. Apply a background color for transparent images.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string BackgroundColor { get; set; }
diff --git a/MediaBrowser.Api/Images/ImageWriter.cs b/MediaBrowser.Api/Images/ImageWriter.cs
index 2ace05125..2f161709a 100644
--- a/MediaBrowser.Api/Images/ImageWriter.cs
+++ b/MediaBrowser.Api/Images/ImageWriter.cs
@@ -91,6 +91,7 @@ namespace MediaBrowser.Api.Images
OutputFormat = Request.Format,
AddPlayedIndicator = Request.AddPlayedIndicator,
PercentPlayed = Request.PercentPlayed,
+ UnplayedCount = Request.UnplayedCount,
BackgroundColor = Request.BackgroundColor
};
diff --git a/MediaBrowser.Api/Library/LibraryHelpers.cs b/MediaBrowser.Api/Library/LibraryHelpers.cs
index fb986605c..e40cb7dd4 100644
--- a/MediaBrowser.Api/Library/LibraryHelpers.cs
+++ b/MediaBrowser.Api/Library/LibraryHelpers.cs
@@ -65,17 +65,10 @@ namespace MediaBrowser.Api.Library
throw new DirectoryNotFoundException("The path does not exist.");
}
- // Strip off trailing slash, but not on drives
- path = path.TrimEnd(Path.DirectorySeparatorChar);
- if (path.EndsWith(":", StringComparison.OrdinalIgnoreCase))
- {
- path += Path.DirectorySeparatorChar;
- }
-
var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
- ValidateNewMediaPath(fileSystem, rootFolderPath, path, appPaths);
+ ValidateNewMediaPath(fileSystem, rootFolderPath, path);
var shortcutFilename = Path.GetFileNameWithoutExtension(path);
@@ -96,25 +89,18 @@ namespace MediaBrowser.Api.Library
/// <param name="fileSystem">The file system.</param>
/// <param name="currentViewRootFolderPath">The current view root folder path.</param>
/// <param name="mediaPath">The media path.</param>
- /// <param name="appPaths">The app paths.</param>
/// <exception cref="System.ArgumentException">
/// </exception>
- private static void ValidateNewMediaPath(IFileSystem fileSystem, string currentViewRootFolderPath, string mediaPath, IServerApplicationPaths appPaths)
+ private static void ValidateNewMediaPath(IFileSystem fileSystem, string currentViewRootFolderPath, string mediaPath)
{
- var duplicate = Directory.EnumerateFiles(appPaths.RootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
- .Select(fileSystem.ResolveShortcut)
- .FirstOrDefault(p => !IsNewPathValid(mediaPath, p, false));
-
- if (!string.IsNullOrEmpty(duplicate))
- {
- throw new ArgumentException(string.Format("The path cannot be added to the library because {0} already exists.", duplicate));
- }
+ var pathsInCurrentVIew = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
+ .Select(fileSystem.ResolveShortcut)
+ .ToList();
// Don't allow duplicate sub-paths within the same user library, or it will result in duplicate items
// See comments in IsNewPathValid
- duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
- .Select(fileSystem.ResolveShortcut)
- .FirstOrDefault(p => !IsNewPathValid(mediaPath, p, true));
+ var duplicate = pathsInCurrentVIew
+ .FirstOrDefault(p => !IsNewPathValid(fileSystem, mediaPath, p));
if (!string.IsNullOrEmpty(duplicate))
{
@@ -122,9 +108,8 @@ namespace MediaBrowser.Api.Library
}
// Make sure the current root folder doesn't already have a shortcut to the same path
- duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, ShortcutFileSearch, SearchOption.AllDirectories)
- .Select(fileSystem.ResolveShortcut)
- .FirstOrDefault(p => mediaPath.Equals(p, StringComparison.OrdinalIgnoreCase));
+ duplicate = pathsInCurrentVIew
+ .FirstOrDefault(p => string.Equals(mediaPath, p, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(duplicate))
{
@@ -135,30 +120,30 @@ namespace MediaBrowser.Api.Library
/// <summary>
/// Validates that a new path can be added based on an existing path
/// </summary>
+ /// <param name="fileSystem">The file system.</param>
/// <param name="newPath">The new path.</param>
/// <param name="existingPath">The existing path.</param>
- /// <param name="enforceSubPathRestriction">if set to <c>true</c> [enforce sub path restriction].</param>
/// <returns><c>true</c> if [is new path valid] [the specified new path]; otherwise, <c>false</c>.</returns>
- private static bool IsNewPathValid(string newPath, string existingPath, bool enforceSubPathRestriction)
+ private static bool IsNewPathValid(IFileSystem fileSystem, string newPath, string existingPath)
{
// Example: D:\Movies is the existing path
// D:\ cannot be added
// Neither can D:\Movies\Kids
// A D:\Movies duplicate is ok here since that will be caught later
- if (newPath.Equals(existingPath, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(newPath, existingPath, StringComparison.OrdinalIgnoreCase))
{
return true;
}
// If enforceSubPathRestriction is true, validate the D:\Movies\Kids scenario
- if (enforceSubPathRestriction && newPath.StartsWith(existingPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ if (fileSystem.ContainsSubPath(existingPath, newPath))
{
return false;
}
// Validate the D:\ scenario
- if (existingPath.StartsWith(newPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ if (fileSystem.ContainsSubPath(newPath, existingPath))
{
return false;
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 61883ddaa..ae9c79c0e 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -61,6 +61,9 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Limit { get; set; }
+
+ [ApiMember(Name = "IsRecording", Description = "Optional filter by recordings that are currently active, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ public bool? IsRecording { get; set; }
}
[Route("/LiveTv/Recordings/Groups", "GET")]
@@ -274,7 +277,8 @@ namespace MediaBrowser.Api.LiveTv
UserId = request.UserId,
GroupId = request.GroupId,
StartIndex = request.StartIndex,
- Limit = request.Limit
+ Limit = request.Limit,
+ IsRecording = request.IsRecording
}, CancellationToken.None).Result;
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 1e2ae58b2..999260b8d 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -197,10 +197,6 @@ namespace MediaBrowser.Api.Playback
{
args += string.Format("-map 0:{0}", state.VideoStream.Index);
}
- else if (!state.HasMediaStreams)
- {
- args += string.Format("-map 0:{0}", 0);
- }
else
{
args += "-map -0:v";
@@ -210,10 +206,6 @@ namespace MediaBrowser.Api.Playback
{
args += string.Format(" -map 0:{0}", state.AudioStream.Index);
}
- else if (!state.HasMediaStreams)
- {
- args += string.Format(" -map 0:{0}", 1);
- }
else
{
@@ -871,7 +863,7 @@ namespace MediaBrowser.Api.Playback
RequestedUrl = url
};
- BaseItem item;
+ Guid itemId;
if (string.Equals(request.Type, "Recording", StringComparison.OrdinalIgnoreCase))
{
@@ -900,7 +892,7 @@ namespace MediaBrowser.Api.Playback
state.IsRemote = true;
}
- item = recording;
+ itemId = recording.Id;
}
else if (string.Equals(request.Type, "Channel", StringComparison.OrdinalIgnoreCase))
{
@@ -916,11 +908,11 @@ namespace MediaBrowser.Api.Playback
state.IsRemote = true;
- item = channel;
+ itemId = channel.Id;
}
else
{
- item = DtoService.GetItemByDtoId(request.Id);
+ var item = DtoService.GetItemByDtoId(request.Id);
state.MediaPath = item.Path;
state.IsRemote = item.LocationType == LocationType.Remote;
@@ -937,13 +929,15 @@ namespace MediaBrowser.Api.Playback
? new List<string>()
: video.PlayableStreamFileNames.ToList();
}
+
+ itemId = item.Id;
}
var videoRequest = request as VideoStreamRequest;
var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery
{
- ItemId = item.Id
+ ItemId = itemId
}).ToList();
diff --git a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
index 616981d50..d00494bac 100644
--- a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
+++ b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
@@ -82,6 +82,16 @@ namespace MediaBrowser.Common.Implementations.IO
throw new ArgumentNullException("target");
}
+ if (string.IsNullOrEmpty(shortcutPath))
+ {
+ throw new ArgumentNullException("shortcutPath");
+ }
+
+ if (string.IsNullOrEmpty(target))
+ {
+ throw new ArgumentNullException("target");
+ }
+
File.WriteAllText(shortcutPath, target);
}
@@ -92,6 +102,11 @@ namespace MediaBrowser.Common.Implementations.IO
/// <returns>FileSystemInfo.</returns>
public FileSystemInfo GetFileSystemInfo(string path)
{
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
// Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
if (Path.HasExtension(path))
{
@@ -172,7 +187,6 @@ namespace MediaBrowser.Common.Implementations.IO
/// Gets the creation time UTC.
/// </summary>
/// <param name="info">The info.</param>
- /// <param name="logger">The logger.</param>
/// <returns>DateTime.</returns>
public DateTime GetLastWriteTimeUtc(FileSystemInfo info)
{
@@ -224,6 +238,16 @@ namespace MediaBrowser.Common.Implementations.IO
/// <param name="file2">The file2.</param>
public void SwapFiles(string file1, string file2)
{
+ if (string.IsNullOrEmpty(file1))
+ {
+ throw new ArgumentNullException("file1");
+ }
+
+ if (string.IsNullOrEmpty(file2))
+ {
+ throw new ArgumentNullException("file2");
+ }
+
var temp1 = Path.GetTempFileName();
var temp2 = Path.GetTempFileName();
@@ -247,6 +271,11 @@ namespace MediaBrowser.Common.Implementations.IO
/// <param name="path">The path.</param>
private void RemoveHiddenAttribute(string path)
{
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
var currentFile = new FileInfo(path);
// This will fail if the file is hidden
@@ -258,127 +287,52 @@ namespace MediaBrowser.Common.Implementations.IO
}
}
}
- }
- /// <summary>
- /// Adapted from http://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java
- /// </summary>
- internal class WindowsShortcut
- {
- public bool IsDirectory { get; private set; }
- public bool IsLocal { get; private set; }
- public string ResolvedPath { get; private set; }
-
- public WindowsShortcut(string file)
+ public bool ContainsSubPath(string parentPath, string path)
{
- ParseLink(File.ReadAllBytes(file), Encoding.UTF8);
- }
-
- private static bool isMagicPresent(byte[] link)
- {
-
- const int magic = 0x0000004C;
- const int magic_offset = 0x00;
-
- return link.Length >= 32 && bytesToDword(link, magic_offset) == magic;
- }
-
- /**
- * Gobbles up link data by parsing it and storing info in member fields
- * @param link all the bytes from the .lnk file
- */
- private void ParseLink(byte[] link, Encoding encoding)
- {
- if (!isMagicPresent(link))
- throw new IOException("Invalid shortcut; magic is missing", 0);
-
- // get the flags byte
- byte flags = link[0x14];
-
- // get the file attributes byte
- const int file_atts_offset = 0x18;
- byte file_atts = link[file_atts_offset];
- byte is_dir_mask = (byte)0x10;
- if ((file_atts & is_dir_mask) > 0)
- {
- IsDirectory = true;
- }
- else
+ if (string.IsNullOrEmpty(parentPath))
{
- IsDirectory = false;
+ throw new ArgumentNullException("parentPath");
}
- // if the shell settings are present, skip them
- const int shell_offset = 0x4c;
- const byte has_shell_mask = (byte)0x01;
- int shell_len = 0;
- if ((flags & has_shell_mask) > 0)
+ if (string.IsNullOrEmpty(path))
{
- // the plus 2 accounts for the length marker itself
- shell_len = bytesToWord(link, shell_offset) + 2;
+ throw new ArgumentNullException("path");
}
+
+ return path.IndexOf(parentPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) != -1;
+ }
- // get to the file settings
- int file_start = 0x4c + shell_len;
-
- const int file_location_info_flag_offset_offset = 0x08;
- int file_location_info_flag = link[file_start + file_location_info_flag_offset_offset];
- IsLocal = (file_location_info_flag & 2) == 0;
- // get the local volume and local system values
- //final int localVolumeTable_offset_offset = 0x0C;
- const int basename_offset_offset = 0x10;
- const int networkVolumeTable_offset_offset = 0x14;
- const int finalname_offset_offset = 0x18;
- int finalname_offset = link[file_start + finalname_offset_offset] + file_start;
- String finalname = getNullDelimitedString(link, finalname_offset, encoding);
- if (IsLocal)
+ public bool IsRootPath(string path)
+ {
+ if (string.IsNullOrEmpty(path))
{
- int basename_offset = link[file_start + basename_offset_offset] + file_start;
- String basename = getNullDelimitedString(link, basename_offset, encoding);
- ResolvedPath = basename + finalname;
+ throw new ArgumentNullException("path");
}
- else
+
+ var parent = Path.GetDirectoryName(path);
+
+ if (!string.IsNullOrEmpty(parent))
{
- int networkVolumeTable_offset = link[file_start + networkVolumeTable_offset_offset] + file_start;
- int shareName_offset_offset = 0x08;
- int shareName_offset = link[networkVolumeTable_offset + shareName_offset_offset]
- + networkVolumeTable_offset;
- String shareName = getNullDelimitedString(link, shareName_offset, encoding);
- ResolvedPath = shareName + "\\" + finalname;
+ return false;
}
+
+ return true;
}
- private static string getNullDelimitedString(byte[] bytes, int off, Encoding encoding)
+ public string NormalizePath(string path)
{
- int len = 0;
-
- // count bytes until the null character (0)
- while (true)
+ if (string.IsNullOrEmpty(path))
{
- if (bytes[off + len] == 0)
- {
- break;
- }
- len++;
+ throw new ArgumentNullException("path");
}
- return encoding.GetString(bytes, off, len);
- }
-
- /*
- * convert two bytes into a short note, this is little endian because it's
- * for an Intel only OS.
- */
- private static int bytesToWord(byte[] bytes, int off)
- {
- return ((bytes[off + 1] & 0xff) << 8) | (bytes[off] & 0xff);
- }
+ if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase))
+ {
+ return path;
+ }
- private static int bytesToDword(byte[] bytes, int off)
- {
- return (bytesToWord(bytes, off + 2) << 16) | bytesToWord(bytes, off);
+ return path.TrimEnd(Path.DirectorySeparatorChar);
}
-
}
-
}
diff --git a/MediaBrowser.Common/IO/IFileSystem.cs b/MediaBrowser.Common/IO/IFileSystem.cs
index 8fba63195..f721e80ea 100644
--- a/MediaBrowser.Common/IO/IFileSystem.cs
+++ b/MediaBrowser.Common/IO/IFileSystem.cs
@@ -81,5 +81,27 @@ namespace MediaBrowser.Common.IO
/// <param name="file1">The file1.</param>
/// <param name="file2">The file2.</param>
void SwapFiles(string file1, string file2);
+
+ /// <summary>
+ /// Determines whether [contains sub path] [the specified parent path].
+ /// </summary>
+ /// <param name="parentPath">The parent path.</param>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [contains sub path] [the specified parent path]; otherwise, <c>false</c>.</returns>
+ bool ContainsSubPath(string parentPath, string path);
+
+ /// <summary>
+ /// Determines whether [is root path] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is root path] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsRootPath(string path);
+
+ /// <summary>
+ /// Normalizes the path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.String.</returns>
+ string NormalizePath(string path);
}
}
diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs
index 0d644b909..b5f1c8294 100644
--- a/MediaBrowser.Common/Net/INetworkManager.cs
+++ b/MediaBrowser.Common/Net/INetworkManager.cs
@@ -1,3 +1,4 @@
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using System.Collections.Generic;
using System.Net;
@@ -35,7 +36,7 @@ namespace MediaBrowser.Common.Net
/// Gets available devices within the domain
/// </summary>
/// <returns>PC's in the Domain</returns>
- IEnumerable<string> GetNetworkDevices();
+ IEnumerable<FileSystemEntryInfo> GetNetworkDevices();
/// <summary>
/// Parses the specified endpointstring.
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index 506d6fd3d..93293b34d 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -37,8 +37,10 @@ namespace MediaBrowser.Controller.Drawing
public bool AddPlayedIndicator { get; set; }
- public int? PercentPlayed { get; set; }
+ public int? UnplayedCount { get; set; }
+ public double? PercentPlayed { get; set; }
+
public string BackgroundColor { get; set; }
public bool HasDefaultOptions()
@@ -56,6 +58,7 @@ namespace MediaBrowser.Controller.Drawing
IsOutputFormatDefault &&
!AddPlayedIndicator &&
!PercentPlayed.HasValue &&
+ !UnplayedCount.HasValue &&
string.IsNullOrEmpty(BackgroundColor);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 11562b3d7..dbda4a243 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -156,7 +156,7 @@ namespace MediaBrowser.Controller.Entities
public DateTime DateModified { get; set; }
public DateTime DateLastSaved { get; set; }
-
+
/// <summary>
/// The logger
/// </summary>
@@ -327,21 +327,18 @@ namespace MediaBrowser.Controller.Entities
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
- args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
+ var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot)
{
- var paths = args.FileSystemDictionary.Keys.ToList();
+ var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys);
- foreach (var subPath in paths
- .Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && paths.Any(i => subPath.StartsWith(i.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))))
- {
- Logger.Info("Ignoring duplicate path: {0}", subPath);
- args.FileSystemDictionary.Remove(subPath);
- }
+ fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
}
+
+ args.FileSystemDictionary = fileSystemDictionary;
}
//update our dates
@@ -1016,14 +1013,18 @@ namespace MediaBrowser.Controller.Entities
return lang;
}
+ public virtual bool IsSaveLocalMetadataEnabled()
+ {
+ return ConfigurationManager.Configuration.SaveLocalMeta;
+ }
+
/// <summary>
/// Determines if a given user has access to this item
/// </summary>
/// <param name="user">The user.</param>
- /// <param name="localizationManager">The localization manager.</param>
/// <returns><c>true</c> if [is parental allowed] [the specified user]; otherwise, <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">user</exception>
- public bool IsParentalAllowed(User user, ILocalizationManager localizationManager)
+ public bool IsParentalAllowed(User user)
{
if (user == null)
{
@@ -1049,7 +1050,7 @@ namespace MediaBrowser.Controller.Entities
return !GetBlockUnratedValue(user.Configuration);
}
- var value = localizationManager.GetRatingLevel(rating);
+ var value = LocalizationManager.GetRatingLevel(rating);
// Could not determine the integer value
if (!value.HasValue)
@@ -1084,7 +1085,7 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("user");
}
- return IsParentalAllowed(user, LocalizationManager);
+ return IsParentalAllowed(user);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 912b8fa93..a85157a26 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -519,85 +519,84 @@ namespace MediaBrowser.Controller.Entities
await Task.WhenAll(tasks).ConfigureAwait(false);
}
- Tuple<BaseItem, bool> currentTuple = tuple;
-
- tasks.Add(Task.Run(async () =>
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var child = currentTuple.Item1;
- try
- {
- //refresh it
- await child.RefreshMetadata(cancellationToken, forceSave: currentTuple.Item2, forceRefresh: forceRefreshMetadata, resetResolveArgs: false).ConfigureAwait(false);
- }
- catch (IOException ex)
- {
- Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name);
- }
+ tasks.Add(RefreshChild(tuple, progress, percentages, list.Count, cancellationToken, recursive, forceRefreshMetadata));
+ }
- // Refresh children if a folder and the item changed or recursive is set to true
- var refreshChildren = child.IsFolder && (currentTuple.Item2 || (recursive.HasValue && recursive.Value));
+ cancellationToken.ThrowIfCancellationRequested();
- if (refreshChildren)
- {
- // Don't refresh children if explicitly set to false
- if (recursive.HasValue && recursive.Value == false)
- {
- refreshChildren = false;
- }
- }
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+ }
- if (refreshChildren)
- {
- cancellationToken.ThrowIfCancellationRequested();
+ private async Task RefreshChild(Tuple<BaseItem, bool> currentTuple, IProgress<double> progress, Dictionary<Guid, double> percentages, int childCount, CancellationToken cancellationToken, bool? recursive, bool forceRefreshMetadata = false)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- var innerProgress = new ActionableProgress<double>();
+ var child = currentTuple.Item1;
+ try
+ {
+ //refresh it
+ await child.RefreshMetadata(cancellationToken, forceSave: currentTuple.Item2, forceRefresh: forceRefreshMetadata, resetResolveArgs: false).ConfigureAwait(false);
+ }
+ catch (IOException ex)
+ {
+ Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name);
+ }
- innerProgress.RegisterAction(p =>
- {
- lock (percentages)
- {
- percentages[child.Id] = p / 100;
+ // Refresh children if a folder and the item changed or recursive is set to true
+ var refreshChildren = child.IsFolder && (currentTuple.Item2 || (recursive.HasValue && recursive.Value));
- var percent = percentages.Values.Sum();
- percent /= list.Count;
+ if (refreshChildren)
+ {
+ // Don't refresh children if explicitly set to false
+ if (recursive.HasValue && recursive.Value == false)
+ {
+ refreshChildren = false;
+ }
+ }
- progress.Report((90 * percent) + 10);
- }
- });
+ if (refreshChildren)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false);
+ var innerProgress = new ActionableProgress<double>();
- try
- {
- // Some folder providers are unable to refresh until children have been refreshed.
- await child.RefreshMetadata(cancellationToken, resetResolveArgs: false).ConfigureAwait(false);
- }
- catch (IOException ex)
- {
- Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name);
- }
- }
- else
+ innerProgress.RegisterAction(p =>
+ {
+ lock (percentages)
{
- lock (percentages)
- {
- percentages[child.Id] = 1;
+ percentages[child.Id] = p / 100;
- var percent = percentages.Values.Sum();
- percent /= list.Count;
+ var percent = percentages.Values.Sum();
+ percent /= childCount;
- progress.Report((90 * percent) + 10);
- }
+ progress.Report((90 * percent) + 10);
}
+ });
- }, cancellationToken));
+ await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false);
+
+ try
+ {
+ // Some folder providers are unable to refresh until children have been refreshed.
+ await child.RefreshMetadata(cancellationToken, resetResolveArgs: false).ConfigureAwait(false);
+ }
+ catch (IOException ex)
+ {
+ Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name);
+ }
}
+ else
+ {
+ lock (percentages)
+ {
+ percentages[child.Id] = 1;
- cancellationToken.ThrowIfCancellationRequested();
+ var percent = percentages.Values.Sum();
+ percent /= childCount;
- await Task.WhenAll(tasks).ConfigureAwait(false);
+ progress.Report((90 * percent) + 10);
+ }
+ }
}
/// <summary>
@@ -646,7 +645,7 @@ namespace MediaBrowser.Controller.Entities
private bool ContainsPath(string parent, string path)
{
- return string.Equals(parent, path, StringComparison.OrdinalIgnoreCase) || path.IndexOf(parent.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) != -1;
+ return string.Equals(parent, path, StringComparison.OrdinalIgnoreCase) || FileSystem.ContainsSubPath(parent, path);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
index d800acd9b..a7cd76a66 100644
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ b/MediaBrowser.Controller/Entities/IHasImages.cs
@@ -16,8 +16,8 @@ namespace MediaBrowser.Controller.Entities
/// Gets the path.
/// </summary>
/// <value>The path.</value>
- string Path { get; }
-
+ string Path { get; set; }
+
/// <summary>
/// Gets the identifier.
/// </summary>
@@ -100,7 +100,7 @@ namespace MediaBrowser.Controller.Entities
{
return item.HasImage(imageType, 0);
}
-
+
/// <summary>
/// Sets the image path.
/// </summary>
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index ae34621cb..036ac7e81 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -320,5 +320,12 @@ namespace MediaBrowser.Controller.Library
/// <param name="items">The items.</param>
/// <returns>IEnumerable{System.String}.</returns>
IEnumerable<string> GetAllArtists(IEnumerable<BaseItem> items);
+
+ /// <summary>
+ /// Normalizes the root path list.
+ /// </summary>
+ /// <param name="paths">The paths.</param>
+ /// <returns>IEnumerable{System.String}.</returns>
+ IEnumerable<string> NormalizeRootPathList(IEnumerable<string> paths);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index c26e29d94..87ac0d4dc 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -153,7 +153,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>LiveTvRecording.</returns>
- Task<LiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken);
+ Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken);
/// <summary>
/// Gets the recording stream.
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
new file mode 100644
index 000000000..d9bceb6ca
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
@@ -0,0 +1,26 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public interface ILiveTvRecording : IHasImages, IHasMediaStreams
+ {
+ string ServiceName { get; set; }
+
+ string MediaType { get; }
+
+ LocationType LocationType { get; }
+
+ RecordingInfo RecordingInfo { get; set; }
+
+ string GetClientTypeName();
+
+ string GetUserDataKey();
+
+ bool IsParentalAllowed(User user);
+
+ Task<bool> RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true);
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
new file mode 100644
index 000000000..8676540fd
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
@@ -0,0 +1,52 @@
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class LiveTvAudioRecording : Audio, ILiveTvRecording
+ {
+ /// <summary>
+ /// Gets the user data key.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ public override string GetUserDataKey()
+ {
+ return GetClientTypeName() + "-" + Name;
+ }
+
+ public RecordingInfo RecordingInfo { get; set; }
+
+ public string ServiceName { get; set; }
+
+ public override string MediaType
+ {
+ get
+ {
+ return Model.Entities.MediaType.Audio;
+ }
+ }
+
+ public override LocationType LocationType
+ {
+ get
+ {
+ if (!string.IsNullOrEmpty(Path))
+ {
+ return base.LocationType;
+ }
+
+ return LocationType.Remote;
+ }
+ }
+
+ public override string GetClientTypeName()
+ {
+ return "Recording";
+ }
+
+ public override bool IsSaveLocalMetadataEnabled()
+ {
+ return false;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
index 1c453ab5a..9dfc7f828 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
@@ -1,10 +1,9 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Controller.LiveTv
{
- public class LiveTvRecording : BaseItem
+ public class LiveTvVideoRecording : Video, ILiveTvRecording
{
/// <summary>
/// Gets the user data key.
@@ -23,7 +22,7 @@ namespace MediaBrowser.Controller.LiveTv
{
get
{
- return RecordingInfo.ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
+ return Model.Entities.MediaType.Video;
}
}
@@ -31,6 +30,11 @@ namespace MediaBrowser.Controller.LiveTv
{
get
{
+ if (!string.IsNullOrEmpty(Path))
+ {
+ return base.LocationType;
+ }
+
return LocationType.Remote;
}
}
@@ -39,5 +43,10 @@ namespace MediaBrowser.Controller.LiveTv
{
return "Recording";
}
+
+ public override bool IsSaveLocalMetadataEnabled()
+ {
+ return false;
+ }
}
}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 0c5c0a5cd..25ea9979c 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -108,6 +108,8 @@
<Compile Include="Library\ItemUpdateType.cs" />
<Compile Include="Library\IUserDataManager.cs" />
<Compile Include="Library\UserDataSaveEventArgs.cs" />
+ <Compile Include="LiveTv\ILiveTvRecording.cs" />
+ <Compile Include="LiveTv\LiveTvAudioRecording.cs" />
<Compile Include="LiveTv\LiveTvChannel.cs" />
<Compile Include="LiveTv\ChannelInfo.cs" />
<Compile Include="LiveTv\ILiveTvManager.cs" />
@@ -115,7 +117,7 @@
<Compile Include="LiveTv\LiveTvException.cs" />
<Compile Include="LiveTv\StreamResponseInfo.cs" />
<Compile Include="LiveTv\LiveTvProgram.cs" />
- <Compile Include="LiveTv\LiveTvRecording.cs" />
+ <Compile Include="LiveTv\LiveTvVideoRecording.cs" />
<Compile Include="LiveTv\ProgramInfo.cs" />
<Compile Include="LiveTv\RecordingInfo.cs" />
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
diff --git a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
index 47accbec5..0ef5c9dc0 100644
--- a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
@@ -52,6 +52,18 @@ namespace MediaBrowser.Model.LiveTv
public string Name { get; set; }
/// <summary>
+ /// Gets or sets the type of the location.
+ /// </summary>
+ /// <value>The type of the location.</value>
+ public LocationType LocationType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the media streams.
+ /// </summary>
+ /// <value>The media streams.</value>
+ public List<MediaStream> MediaStreams { get; set; }
+
+ /// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
index e63a250e6..731247672 100644
--- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
@@ -40,6 +40,12 @@
/// </summary>
/// <value>The limit.</value>
public int? Limit { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is recording.
+ /// </summary>
+ /// <value><c>null</c> if [is recording] contains no value, <c>true</c> if [is recording]; otherwise, <c>false</c>.</value>
+ public bool? IsRecording { get; set; }
}
public class RecordingGroupQuery
diff --git a/MediaBrowser.Mono.userprefs b/MediaBrowser.Mono.userprefs
index 1815e61ca..51af96f9f 100644
--- a/MediaBrowser.Mono.userprefs
+++ b/MediaBrowser.Mono.userprefs
@@ -1,8 +1,9 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release Mono" />
- <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mono\app.config">
+ <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mono\Networking\NetworkManager.cs">
<Files>
- <File FileName="MediaBrowser.Server.Mono\app.config" Line="5" Column="20" />
+ <File FileName="MediaBrowser.Server.Mono\app.config" Line="1" Column="1" />
+ <File FileName="MediaBrowser.Server.Mono\Networking\NetworkManager.cs" Line="6" Column="34" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 5782e3e63..fd78a7565 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -191,7 +191,7 @@ namespace MediaBrowser.Providers.MediaInfo
var filename = item.Album ?? string.Empty;
filename += item.Artists.FirstOrDefault() ?? string.Empty;
- filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks + "_primary";
+ filename += album == null ? item.Id.ToString("N") + "_primary" + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks + "_primary";
filename = filename.GetMD5() + ".jpg";
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index b248fcb40..dc7c7c139 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -86,15 +86,6 @@ namespace MediaBrowser.Providers.Music
}
/// <summary>
- /// Gets a value indicating whether [save local meta].
- /// </summary>
- /// <value><c>true</c> if [save local meta]; otherwise, <c>false</c>.</value>
- protected virtual bool SaveLocalMeta
- {
- get { return ConfigurationManager.Configuration.SaveLocalMeta; }
- }
-
- /// <summary>
/// Gets a value indicating whether [refresh on version change].
/// </summary>
/// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
diff --git a/MediaBrowser.Providers/Music/LastfmBaseProvider.cs b/MediaBrowser.Providers/Music/LastfmBaseProvider.cs
index 26796f7e4..cab9e7e39 100644
--- a/MediaBrowser.Providers/Music/LastfmBaseProvider.cs
+++ b/MediaBrowser.Providers/Music/LastfmBaseProvider.cs
@@ -68,14 +68,6 @@ namespace MediaBrowser.Providers.Music
/// <value>The HTTP client.</value>
protected IHttpClient HttpClient { get; private set; }
- protected virtual bool SaveLocalMeta
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
/// <summary>
/// Gets a value indicating whether [requires internet].
/// </summary>
diff --git a/MediaBrowser.Providers/Music/LastfmHelper.cs b/MediaBrowser.Providers/Music/LastfmHelper.cs
index df02cee5b..1b8d0c5f6 100644
--- a/MediaBrowser.Providers/Music/LastfmHelper.cs
+++ b/MediaBrowser.Providers/Music/LastfmHelper.cs
@@ -31,11 +31,6 @@ namespace MediaBrowser.Providers.Music
artist.ProductionYear = yearFormed;
}
-
- if (data.tags != null && !artist.LockedFields.Contains(MetadataFields.Tags))
- {
- AddTags(artist, data.tags);
- }
string imageSize;
artist.LastFmImageUrl = GetImageUrl(data, out imageSize);
@@ -100,11 +95,6 @@ namespace MediaBrowser.Providers.Music
}
}
- if (data.toptags != null && !item.LockedFields.Contains(MetadataFields.Tags))
- {
- AddTags(item, data.toptags);
- }
-
var album = (MusicAlbum)item;
string imageSize;
@@ -112,16 +102,5 @@ namespace MediaBrowser.Providers.Music
album.LastFmImageUrl = GetImageUrl(data, out imageSize);
album.LastFmImageSize = imageSize;
}
-
- private static void AddTags(BaseItem item, LastfmTags tags)
- {
- var itemTags = (from tag in tags.tag where !string.IsNullOrEmpty(tag.name) select tag.name).ToList();
-
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- hasTags.Tags = itemTags;
- }
- }
}
}
diff --git a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs
index 8dd6940c5..5e4401cff 100644
--- a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is MusicAlbum;
}
diff --git a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs
index 924a5a88e..6b801f1e2 100644
--- a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
if (item is MusicArtist)
{
diff --git a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs
index c2e607f6a..712276bcd 100644
--- a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is BoxSet;
}
diff --git a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs
index 91e769994..4e2139bb6 100644
--- a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is Episode;
}
diff --git a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs
index 9c1e6f38e..7ad13905d 100644
--- a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
if (!(item is Series) && !(item is BoxSet) && !(item is MusicArtist) && !(item is MusicAlbum) &&
!(item is Season))
diff --git a/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs b/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs
index 496bb51d0..7089b8e1b 100644
--- a/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs
@@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is GameSystem;
}
diff --git a/MediaBrowser.Providers/Savers/GameXmlSaver.cs b/MediaBrowser.Providers/Savers/GameXmlSaver.cs
index 03c3a2916..5dd7617e0 100644
--- a/MediaBrowser.Providers/Savers/GameXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/GameXmlSaver.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is Game;
}
diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
index f10e24dc1..3fc4579e3 100644
--- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs
@@ -39,7 +39,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
var trailer = item as Trailer;
diff --git a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs
index c96f71b0a..0a9f2e4f6 100644
--- a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs
@@ -30,7 +30,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is Season;
}
diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
index 7f37ba1ce..131d568a1 100644
--- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
+++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Savers
var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload;
// If new metadata has been downloaded and save local is on
- if (_config.Configuration.SaveLocalMeta && (wasMetadataEdited || wasMetadataDownloaded))
+ if (item.IsSaveLocalMetadataEnabled() && (wasMetadataEdited || wasMetadataDownloaded))
{
return item is Series;
}
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index 7ddf63cf8..0568f681a 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -172,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
var quality = options.Quality ?? 90;
- var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.BackgroundColor);
+ var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
try
{
@@ -241,7 +241,9 @@ namespace MediaBrowser.Server.Implementations.Drawing
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
- thumbnailGraph.CompositingMode = string.IsNullOrEmpty(options.BackgroundColor) && !options.PercentPlayed.HasValue && !options.AddPlayedIndicator ? CompositingMode.SourceCopy : CompositingMode.SourceOver;
+ thumbnailGraph.CompositingMode = string.IsNullOrEmpty(options.BackgroundColor) && !options.UnplayedCount.HasValue && !options.AddPlayedIndicator && !options.PercentPlayed.HasValue ?
+ CompositingMode.SourceCopy :
+ CompositingMode.SourceOver;
SetBackgroundColor(thumbnailGraph, options);
@@ -347,28 +349,31 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// <param name="options">The options.</param>
private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options)
{
- if (!options.AddPlayedIndicator && !options.PercentPlayed.HasValue)
+ if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && !options.PercentPlayed.HasValue)
{
return;
}
try
{
- var percentOffset = 0;
-
if (options.AddPlayedIndicator)
{
var currentImageSize = new Size(imageWidth, imageHeight);
- new WatchedIndicatorDrawer().Process(graphics, currentImageSize);
+ new PlayedIndicatorDrawer().DrawPlayedIndicator(graphics, currentImageSize);
+ }
+ else if (options.UnplayedCount.HasValue)
+ {
+ var currentImageSize = new Size(imageWidth, imageHeight);
- percentOffset = 0 - WatchedIndicatorDrawer.IndicatorWidth;
+ new UnplayedCountIndicator().DrawUnplayedCountIndicator(graphics, currentImageSize, options.UnplayedCount.Value);
}
+
if (options.PercentPlayed.HasValue)
{
var currentImageSize = new Size(imageWidth, imageHeight);
- new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed.Value, percentOffset);
+ new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed.Value);
}
}
catch (Exception ex)
@@ -466,9 +471,14 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
/// <summary>
+ /// Increment this when indicator drawings change
+ /// </summary>
+ private const string IndicatorVersion = "1";
+
+ /// <summary>
/// Gets the cache file path based on a set of parameters
/// </summary>
- private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageOutputFormat format, bool addPlayedIndicator, int? percentPlayed, string backgroundColor)
+ private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageOutputFormat format, bool addPlayedIndicator, double? percentPlayed, int? unwatchedCount, string backgroundColor)
{
var filename = originalPath;
@@ -485,16 +495,31 @@ namespace MediaBrowser.Server.Implementations.Drawing
filename += "f=" + format;
}
+ var hasIndicator = false;
+
if (addPlayedIndicator)
{
filename += "pl=true";
+ hasIndicator = true;
}
if (percentPlayed.HasValue)
{
filename += "p=" + percentPlayed.Value;
+ hasIndicator = true;
}
+ if (unwatchedCount.HasValue)
+ {
+ filename += "p=" + unwatchedCount.Value;
+ hasIndicator = true;
+ }
+
+ if (hasIndicator)
+ {
+ filename += "iv=" + IndicatorVersion;
+ }
+
if (!string.IsNullOrEmpty(backgroundColor))
{
filename += "b=" + backgroundColor;
diff --git a/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs b/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
index e2f5b6129..c621ace43 100644
--- a/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
@@ -1,36 +1,34 @@
-using System.Drawing;
-using System.Globalization;
+using System;
+using System.Drawing;
namespace MediaBrowser.Server.Implementations.Drawing
{
public class PercentPlayedDrawer
{
- private const int IndicatorWidth = 80;
- private const int IndicatorHeight = 50;
- private const int FontSize = 30;
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ private const int IndicatorHeight = 10;
- public void Process(Graphics graphics, Size imageSize, int percent, int rightOffset)
+ public void Process(Graphics graphics, Size imageSize, double percent)
{
- var x = imageSize.Width - IndicatorWidth + rightOffset;
+ var y = imageSize.Height - IndicatorHeight;
- using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 102, 192, 16)))
+ using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 0, 0, 0)))
{
- graphics.FillRectangle(backdroundBrush, x, 0, IndicatorWidth, IndicatorHeight);
+ const int innerX = 0;
+ var innerY = y;
+ var innerWidth = imageSize.Width;
+ var innerHeight = imageSize.Height;
- var text = string.Format("{0}%", percent.ToString(_usCulture));
+ graphics.FillRectangle(backdroundBrush, innerX, innerY, innerWidth, innerHeight);
- x = imageSize.Width - (percent < 10 ? 66 : 75) + rightOffset;
-
- using (var font = new Font(FontFamily.GenericSansSerif, FontSize, FontStyle.Regular, GraphicsUnit.Pixel))
+ using (var foregroundBrush = new SolidBrush(Color.FromArgb(82, 181, 75)))
{
- using (var fontBrush = new SolidBrush(Color.White))
- {
- graphics.DrawString(text, font, fontBrush, x, 6);
- }
+ double foregroundWidth = innerWidth;
+ foregroundWidth *= percent;
+ foregroundWidth /= 100;
+
+ graphics.FillRectangle(foregroundBrush, innerX, innerY, Convert.ToInt32(Math.Round(foregroundWidth)), innerHeight);
}
}
-
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Drawing/WatchedIndicatorDrawer.cs b/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs
index c889db304..7be187396 100644
--- a/MediaBrowser.Server.Implementations/Drawing/WatchedIndicatorDrawer.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs
@@ -2,33 +2,31 @@
namespace MediaBrowser.Server.Implementations.Drawing
{
- public class WatchedIndicatorDrawer
+ public class PlayedIndicatorDrawer
{
private const int IndicatorHeight = 50;
public const int IndicatorWidth = 50;
private const int FontSize = 50;
+ private const int OffsetFromTopRightCorner = 10;
- public void Process(Graphics graphics, Size imageSize)
+ public void DrawPlayedIndicator(Graphics graphics, Size imageSize)
{
- var x = imageSize.Width - IndicatorWidth;
+ var x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
- using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 204, 51, 51)))
+ using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 82, 181, 75)))
{
- graphics.FillRectangle(backdroundBrush, x, 0, IndicatorWidth, IndicatorHeight);
+ graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight);
- const string text = "a";
-
- x = imageSize.Width - 55;
+ x = imageSize.Width - 55 - OffsetFromTopRightCorner;
using (var font = new Font("Webdings", FontSize, FontStyle.Regular, GraphicsUnit.Pixel))
{
using (var fontBrush = new SolidBrush(Color.White))
{
- graphics.DrawString(text, font, fontBrush, x, -2);
+ graphics.DrawString("a", font, fontBrush, x, OffsetFromTopRightCorner - 2);
}
}
}
-
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs b/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs
new file mode 100644
index 000000000..11d812a43
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Drawing
+{
+ public class UnplayedCountIndicator
+ {
+ private const int IndicatorHeight = 50;
+ public const int IndicatorWidth = 50;
+ private const int OffsetFromTopRightCorner = 10;
+
+ public void DrawUnplayedCountIndicator(Graphics graphics, Size imageSize, int count)
+ {
+ var x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
+
+ using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 82, 181, 75)))
+ {
+ graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight);
+
+ var text = count.ToString();
+
+ x = imageSize.Width - 50 - OffsetFromTopRightCorner;
+ var y = OffsetFromTopRightCorner + 7;
+ var fontSize = 30;
+
+ if (text.Length == 1)
+ {
+ x += 11;
+ }
+ else if (text.Length == 2)
+ {
+ x += 3;
+ }
+ else if (text.Length == 3)
+ {
+ //x += 1;
+ y += 3;
+ fontSize = 24;
+ }
+
+ using (var font = new Font("Sans-Serif", fontSize, FontStyle.Regular, GraphicsUnit.Pixel))
+ {
+ using (var fontBrush = new SolidBrush(Color.White))
+ {
+ graphics.DrawString(text, font, fontBrush, x, y);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
index 5268faa4f..98a87d03d 100644
--- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
using System;
@@ -30,6 +31,13 @@ namespace MediaBrowser.Server.Implementations.Library
}.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
+ private readonly IFileSystem _fileSystem;
+
+ public CoreResolutionIgnoreRule(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
/// <summary>
/// Shoulds the ignore.
/// </summary>
@@ -60,23 +68,12 @@ namespace MediaBrowser.Server.Implementations.Library
return false;
}
- // Drives will sometimes be hidden
- if (args.Path.EndsWith(Path.VolumeSeparatorChar + "\\", StringComparison.OrdinalIgnoreCase))
+ // Sometimes these are marked hidden
+ if (_fileSystem.IsRootPath(args.Path))
{
return false;
}
- // Shares will sometimes be hidden
- if (args.Path.StartsWith("\\", StringComparison.OrdinalIgnoreCase))
- {
- // Look for a share, e.g. \\server\movies
- // Is there a better way to detect if a path is a share without using native code?
- if (args.Path.Substring(2).Split(Path.DirectorySeparatorChar).Length == 2)
- {
- return false;
- }
- }
-
return true;
}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 1a52bb224..8e4e71fd4 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -499,21 +499,18 @@ namespace MediaBrowser.Server.Implementations.Library
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
- args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
+ var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot)
{
- var paths = args.FileSystemDictionary.Keys.ToList();
+ var paths = NormalizeRootPathList(fileSystemDictionary.Keys);
- foreach (var subPath in paths
- .Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && paths.Any(i => subPath.StartsWith(i.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))))
- {
- _logger.Info("Ignoring duplicate path: {0}", subPath);
- args.FileSystemDictionary.Remove(subPath);
- }
+ fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
}
+
+ args.FileSystemDictionary = fileSystemDictionary;
}
// Check to see if we should resolve based on our contents
@@ -525,6 +522,23 @@ namespace MediaBrowser.Server.Implementations.Library
return ResolveItem(args);
}
+ public IEnumerable<string> NormalizeRootPathList(IEnumerable<string> paths)
+ {
+ var list = paths.Select(_fileSystem.NormalizePath)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath)))
+ .ToList();
+
+ foreach (var dupe in dupes)
+ {
+ _logger.Info("Found duplicate path: {0}", dupe);
+ }
+
+ return list.Except(dupes, StringComparer.OrdinalIgnoreCase);
+ }
+
/// <summary>
/// Determines whether a path should be ignored based on its contents - called after the contents have been read
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 0b2d0c5e9..5857088d2 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -4,11 +4,13 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -21,13 +23,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly IUserDataManager _userDataManager;
private readonly IDtoService _dtoService;
+ private readonly IItemRepository _itemRepo;
- public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger)
+ public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger, IItemRepository itemRepo)
{
_dtoService = dtoService;
_userDataManager = userDataManager;
_imageProcessor = imageProcessor;
_logger = logger;
+ _itemRepo = itemRepo;
}
public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service, LiveTvProgram program, LiveTvChannel channel)
@@ -180,7 +184,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return status.ToString();
}
- public RecordingInfoDto GetRecordingInfoDto(LiveTvRecording recording, LiveTvChannel channel, ILiveTvService service, User user = null)
+ public RecordingInfoDto GetRecordingInfoDto(ILiveTvRecording recording, LiveTvChannel channel, ILiveTvService service, User user = null)
{
var info = recording.RecordingInfo;
@@ -216,7 +220,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
IsNews = info.IsNews,
IsKids = info.IsKids,
IsPremiere = info.IsPremiere,
- RunTimeTicks = (info.EndDate - info.StartDate).Ticks
+ RunTimeTicks = (info.EndDate - info.StartDate).Ticks,
+ LocationType = recording.LocationType,
+
+ MediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
+ {
+ ItemId = recording.Id
+
+ }).ToList()
};
var imageTag = GetImageTag(recording);
@@ -330,7 +341,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return dto;
}
- private Guid? GetImageTag(BaseItem info)
+ private Guid? GetImageTag(IHasImages info)
{
var path = info.PrimaryImagePath;
@@ -351,39 +362,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return null;
}
+ private const string InternalVersionNumber = "2";
+
public Guid GetInternalChannelId(string serviceName, string externalId)
{
- var name = serviceName + externalId;
+ var name = serviceName + externalId + InternalVersionNumber;
return name.ToLower().GetMBId(typeof(LiveTvChannel));
}
public Guid GetInternalTimerId(string serviceName, string externalId)
{
- var name = serviceName + externalId;
+ var name = serviceName + externalId + InternalVersionNumber;
return name.ToLower().GetMD5();
}
public Guid GetInternalSeriesTimerId(string serviceName, string externalId)
{
- var name = serviceName + externalId;
+ var name = serviceName + externalId + InternalVersionNumber;
return name.ToLower().GetMD5();
}
public Guid GetInternalProgramId(string serviceName, string externalId)
{
- var name = serviceName + externalId;
+ var name = serviceName + externalId + InternalVersionNumber;
- return name.ToLower().GetMD5();
+ return name.ToLower().GetMBId(typeof(LiveTvProgram));
}
public Guid GetInternalRecordingId(string serviceName, string externalId)
{
- var name = serviceName + externalId;
+ var name = serviceName + externalId + InternalVersionNumber;
- return name.ToLower().GetMD5();
+ return name.ToLower().GetMBId(typeof(ILiveTvRecording));
}
public async Task<TimerInfo> GetTimerInfo(TimerInfoDto dto, bool isNew, ILiveTvManager liveTv, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 218c930df..c6e5a315d 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -6,8 +6,8 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
@@ -31,7 +31,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly IItemRepository _itemRepo;
private readonly IUserManager _userManager;
- private readonly ILocalizationManager _localization;
private readonly LiveTvDtoService _tvDtoService;
private readonly List<ILiveTvService> _services = new List<ILiveTvService>();
@@ -39,16 +38,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private Dictionary<Guid, LiveTvChannel> _channels = new Dictionary<Guid, LiveTvChannel>();
private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
- public LiveTvManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, ILocalizationManager localization, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager)
+ public LiveTvManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager)
{
_appPaths = appPaths;
_fileSystem = fileSystem;
_logger = logger;
_itemRepo = itemRepo;
- _localization = localization;
_userManager = userManager;
- _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger);
+ _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, _itemRepo);
}
/// <summary>
@@ -82,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (user != null)
{
channels = channels
- .Where(i => i.IsParentalAllowed(user, _localization))
+ .Where(i => i.IsParentalAllowed(user))
.OrderBy(i =>
{
double number = 0;
@@ -144,7 +142,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return obj;
}
- public async Task<LiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken)
+ public async Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken)
{
var service = ActiveService;
@@ -255,23 +253,46 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return item;
}
- private async Task<LiveTvRecording> GetRecording(RecordingInfo info, string serviceName, CancellationToken cancellationToken)
+ private async Task<ILiveTvRecording> GetRecording(RecordingInfo info, string serviceName, CancellationToken cancellationToken)
{
var isNew = false;
var id = _tvDtoService.GetInternalRecordingId(serviceName, info.Id);
- var item = _itemRepo.RetrieveItem(id) as LiveTvRecording;
+ var item = _itemRepo.RetrieveItem(id) as ILiveTvRecording;
if (item == null)
{
- item = new LiveTvRecording
+ if (info.ChannelType == ChannelType.TV)
{
- Name = info.Name,
- Id = id,
- DateCreated = DateTime.UtcNow,
- DateModified = DateTime.UtcNow
- };
+ item = new LiveTvVideoRecording
+ {
+ Name = info.Name,
+ Id = id,
+ DateCreated = DateTime.UtcNow,
+ DateModified = DateTime.UtcNow,
+ VideoType = VideoType.VideoFile
+ };
+ }
+ else
+ {
+ item = new LiveTvAudioRecording
+ {
+ Name = info.Name,
+ Id = id,
+ DateCreated = DateTime.UtcNow,
+ DateModified = DateTime.UtcNow
+ };
+ }
+
+ if (!string.IsNullOrEmpty(info.Path))
+ {
+ item.Path = info.Path;
+ }
+ else if (!string.IsNullOrEmpty(info.Url))
+ {
+ item.Path = info.Url;
+ }
isNew = true;
}
@@ -331,7 +352,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (user != null)
{
- programs = programs.Where(i => i.IsParentalAllowed(user, _localization));
+ programs = programs.Where(i => i.IsParentalAllowed(user));
}
var returnArray = programs
@@ -450,10 +471,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId));
- var list = new List<RecordingInfo>();
-
var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
- list.AddRange(recordings);
if (!string.IsNullOrEmpty(query.ChannelId))
{
@@ -461,9 +479,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var currentServiceName = service.Name;
- list = list
- .Where(i => _tvDtoService.GetInternalChannelId(currentServiceName, i.ChannelId) == guid)
- .ToList();
+ recordings = recordings
+ .Where(i => _tvDtoService.GetInternalChannelId(currentServiceName, i.ChannelId) == guid);
}
if (!string.IsNullOrEmpty(query.Id))
@@ -472,27 +489,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var currentServiceName = service.Name;
- list = list
- .Where(i => _tvDtoService.GetInternalRecordingId(currentServiceName, i.Id) == guid)
- .ToList();
+ recordings = recordings
+ .Where(i => _tvDtoService.GetInternalRecordingId(currentServiceName, i.Id) == guid);
}
if (!string.IsNullOrEmpty(query.GroupId))
{
var guid = new Guid(query.GroupId);
- list = list.Where(i => GetRecordingGroupIds(i).Contains(guid))
- .ToList();
+ recordings = recordings.Where(i => GetRecordingGroupIds(i).Contains(guid));
+ }
+
+ if (query.IsRecording.HasValue)
+ {
+ var val = query.IsRecording.Value;
+ recordings = recordings.Where(i => (i.Status == RecordingStatus.InProgress) == val);
}
- IEnumerable<LiveTvRecording> entities = await GetEntities(list, service.Name, cancellationToken).ConfigureAwait(false);
+ IEnumerable<ILiveTvRecording> entities = await GetEntities(recordings, service.Name, cancellationToken).ConfigureAwait(false);
entities = entities.OrderByDescending(i => i.RecordingInfo.StartDate);
if (user != null)
{
var currentUser = user;
- entities = entities.Where(i => i.IsParentalAllowed(currentUser, _localization));
+ entities = entities.Where(i => i.IsParentalAllowed(currentUser));
}
if (query.StartIndex.HasValue)
@@ -520,7 +541,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
};
}
- private Task<LiveTvRecording[]> GetEntities(IEnumerable<RecordingInfo> recordings, string serviceName, CancellationToken cancellationToken)
+ private Task<ILiveTvRecording[]> GetEntities(IEnumerable<RecordingInfo> recordings, string serviceName, CancellationToken cancellationToken)
{
var tasks = recordings.Select(i => GetRecording(i, serviceName, cancellationToken));
diff --git a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs
index 0b5ec285e..9f6ab85a4 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public override bool Supports(BaseItem item)
{
- return item is LiveTvRecording;
+ return item is ILiveTvRecording;
}
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
@@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
try
{
- changed = await DownloadImage((LiveTvRecording)item, cancellationToken).ConfigureAwait(false);
+ changed = await DownloadImage((ILiveTvRecording)item, cancellationToken).ConfigureAwait(false);
}
catch (HttpException ex)
{
@@ -74,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return changed;
}
- private async Task<bool> DownloadImage(LiveTvRecording item, CancellationToken cancellationToken)
+ private async Task<bool> DownloadImage(ILiveTvRecording item, CancellationToken cancellationToken)
{
var recordingInfo = item.RecordingInfo;
@@ -133,7 +133,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
// Dummy up the original url
var url = item.ServiceName + recordingInfo.Id;
- await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false);
+ await _providerManager.SaveImage((BaseItem)item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false);
return true;
}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 86dd0bc75..0efd3c236 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -100,7 +100,8 @@
<Compile Include="Configuration\ServerConfigurationManager.cs" />
<Compile Include="Drawing\ImageHeader.cs" />
<Compile Include="Drawing\PercentPlayedDrawer.cs" />
- <Compile Include="Drawing\WatchedIndicatorDrawer.cs" />
+ <Compile Include="Drawing\PlayedIndicatorDrawer.cs" />
+ <Compile Include="Drawing\UnplayedCountIndicator.cs" />
<Compile Include="Dto\DtoService.cs" />
<Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
<Compile Include="EntryPoints\LoadRegistrations.cs" />
diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
index 0346aba97..ec797b688 100644
--- a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
@@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.Providers
throw new ArgumentNullException("mimeType");
}
- var saveLocally = _config.Configuration.SaveLocalMeta && item.Parent != null && !(item is Audio);
+ var saveLocally = item.IsSaveLocalMetadataEnabled() && item.Parent != null && !(item is Audio);
if (item is IItemByName || item is User)
{
diff --git a/MediaBrowser.Server.Mono/Networking/NetworkManager.cs b/MediaBrowser.Server.Mono/Networking/NetworkManager.cs
index 174d061bf..a1cdf87e4 100644
--- a/MediaBrowser.Server.Mono/Networking/NetworkManager.cs
+++ b/MediaBrowser.Server.Mono/Networking/NetworkManager.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Implementations.Networking;
using MediaBrowser.Common.Net;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
@@ -26,9 +27,9 @@ namespace MediaBrowser.ServerApplication.Networking
/// Gets a list of network devices
/// </summary>
/// PC's in the Domain</returns>
- public IEnumerable<string> GetNetworkDevices()
+ public IEnumerable<FileSystemEntryInfo> GetNetworkDevices()
{
- return new List<string> ();
+ return new List<FileSystemEntryInfo> ();
}
}
}
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 514fbe6c1..fc1319136 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -272,7 +272,7 @@ namespace MediaBrowser.ServerApplication
DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);
RegisterSingleInstance(DtoService);
- LiveTvManager = new LiveTvManager(ApplicationPaths, FileSystemManager, Logger, ItemRepository, ImageProcessor, LocalizationManager, UserDataManager, DtoService, UserManager);
+ LiveTvManager = new LiveTvManager(ApplicationPaths, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager);
RegisterSingleInstance(LiveTvManager);
progress.Report(15);
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
index 4799dcc72..e80c8ff3f 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -1,5 +1,8 @@
-using MediaBrowser.Common.Implementations.Networking;
+using System.Globalization;
+using System.IO;
+using MediaBrowser.Common.Implementations.Networking;
using MediaBrowser.Common.Net;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
@@ -79,7 +82,7 @@ namespace MediaBrowser.ServerApplication.Networking
/// </summary>
/// <returns>Arraylist that represents all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER
/// PC's in the Domain</returns>
- public IEnumerable<string> GetNetworkDevices()
+ private IEnumerable<string> GetNetworkDevicesInternal()
{
//local fields
const int MAX_PREFERRED_LENGTH = -1;
@@ -131,6 +134,33 @@ namespace MediaBrowser.ServerApplication.Networking
NativeMethods.NetApiBufferFree(buffer);
}
}
+
+ /// <summary>
+ /// Gets available devices within the domain
+ /// </summary>
+ /// <returns>PC's in the Domain</returns>
+ public IEnumerable<FileSystemEntryInfo> GetNetworkDevices()
+ {
+ return GetNetworkDevicesInternal().Select(c => new FileSystemEntryInfo
+ {
+ Name = c,
+ Path = NetworkPrefix + c,
+ Type = FileSystemEntryType.NetworkComputer
+ });
+ }
+
+ /// <summary>
+ /// Gets the network prefix.
+ /// </summary>
+ /// <value>The network prefix.</value>
+ private string NetworkPrefix
+ {
+ get
+ {
+ var separator = Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture);
+ return separator + separator;
+ }
+ }
}
}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 7743cc527..9d8fb5675 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -498,6 +498,7 @@ namespace MediaBrowser.WebDashboard.Api
"livetvnewrecording.js",
"livetvprogram.js",
"livetvrecording.js",
+ "livetvrecordinglist.js",
"livetvrecordings.js",
"livetvtimer.js",
"livetvseriestimer.js",
diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js
index 274be16b9..592cf2bad 100644
--- a/MediaBrowser.WebDashboard/ApiClient.js
+++ b/MediaBrowser.WebDashboard/ApiClient.js
@@ -873,6 +873,47 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
};
/**
+ * Gets shares from a network device
+ */
+ self.getNetworkShares = function (path) {
+
+ if (!path) {
+ throw new Error("null path");
+ }
+
+ var options = {};
+ options.path = path;
+
+ var url = self.getUrl("Environment/NetworkShares", options);
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ /**
+ * Gets the parent of a given path
+ */
+ self.getParentPath = function (path) {
+
+ if (!path) {
+ throw new Error("null path");
+ }
+
+ var options = {};
+ options.path = path;
+
+ var url = self.getUrl("Environment/ParentPath", options);
+
+ return self.ajax({
+ type: "GET",
+ url: url
+ });
+ };
+
+ /**
* Gets a list of physical drives from the server
*/
self.getDrives = function () {
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index e11c8390f..e650e48a8 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -154,6 +154,9 @@
<Content Include="dashboard-ui\livetvrecording.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\livetvrecordinglist.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\livetvseriestimer.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -424,6 +427,9 @@
<Content Include="dashboard-ui\scripts\livetvrecording.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\livetvrecordinglist.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\livetvseriestimer.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 4cc0c4d55..7c295df9d 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MediaBrowser.ApiClient.Javascript" version="3.0.213" targetFramework="net45" />
+ <package id="MediaBrowser.ApiClient.Javascript" version="3.0.216" targetFramework="net45" />
</packages> \ No newline at end of file