Переглянути джерело

fix double path concatenation

Luke Pulverenti 11 роки тому
батько
коміт
146c7ac4bf

+ 8 - 0
MediaBrowser.Model/ApiClient/IApiClient.cs

@@ -859,6 +859,14 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>System.String.</returns>
         string GetArtImageUrl(BaseItemDto item, ImageOptions options);
 
+        /// <summary>
+        /// Gets the thumb image URL.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="options">The options.</param>
+        /// <returns>System.String.</returns>
+        string GetThumbImageUrl(BaseItemDto item, ImageOptions options);
+        
         /// <summary>
         /// Gets the url needed to stream an audio file
         /// </summary>

+ 24 - 0
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -468,6 +468,30 @@ namespace MediaBrowser.Model.Dto
         /// </summary>
         /// <value>The parent art image tag.</value>
         public Guid? ParentArtImageTag { get; set; }
+
+        /// <summary>
+        /// Gets or sets the series thumb image tag.
+        /// </summary>
+        /// <value>The series thumb image tag.</value>
+        public Guid? SeriesThumbImageTag { get; set; }
+
+        /// <summary>
+        /// Gets or sets the series studio.
+        /// </summary>
+        /// <value>The series studio.</value>
+        public string SeriesStudio { get; set; }
+        
+        /// <summary>
+        /// Gets or sets the parent thumb item id.
+        /// </summary>
+        /// <value>The parent thumb item id.</value>
+        public string ParentThumbItemId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the parent thumb image tag.
+        /// </summary>
+        /// <value>The parent thumb image tag.</value>
+        public Guid? ParentThumbImageTag { get; set; }
         
         /// <summary>
         /// Gets or sets the chapters.

+ 1 - 0
MediaBrowser.Model/Querying/ItemSortBy.cs

@@ -83,5 +83,6 @@ namespace MediaBrowser.Model.Querying
         public const string MusicVideoCount = "MusicVideoCount";
         public const string SeriesSortName = "SeriesSortName";
         public const string VideoBitRate = "VideoBitRate";
+        public const string AirTime = "AirTime";
     }
 }

+ 1 - 1
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -386,7 +386,7 @@ namespace MediaBrowser.Providers.Movies
                     name = name.Replace(",", " ");
                     name = name.Replace(".", " ");
                     name = name.Replace("_", " ");
-                    name = name.Replace("-", "");
+                    name = name.Replace("-", " ");
 
                     // Search again if the new name is different
                     if (!string.Equals(name, originalName))

+ 20 - 0
MediaBrowser.Providers/TV/RemoteSeriesProvider.cs

@@ -295,6 +295,9 @@ namespace MediaBrowser.Providers.TV
 
             }).ConfigureAwait(false))
             {
+                // Delete existing files
+                DeleteXmlFiles(seriesDataPath);
+
                 // Copy to memory stream because we need a seekable stream
                 using (var ms = new MemoryStream())
                 {
@@ -315,6 +318,23 @@ namespace MediaBrowser.Providers.TV
             await ExtractEpisodes(seriesDataPath, Path.Combine(seriesDataPath, ConfigurationManager.Configuration.PreferredMetadataLanguage + ".xml"), lastTvDbUpdateTime).ConfigureAwait(false);
         }
 
+        private void DeleteXmlFiles(string path)
+        {
+            try
+            {
+                foreach (var file in new DirectoryInfo(path)
+                    .EnumerateFiles("*.xml", SearchOption.AllDirectories)
+                    .ToList())
+                {
+                    file.Delete();
+                }
+            }
+            catch (DirectoryNotFoundException)
+            {
+                // No biggie
+            }
+        }
+
         /// <summary>
         /// Sanitizes the XML file.
         /// </summary>

+ 96 - 39
MediaBrowser.Providers/TV/SeriesPostScanTask.cs

@@ -1,7 +1,6 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
@@ -25,13 +24,11 @@ namespace MediaBrowser.Providers.TV
         private readonly ILibraryManager _libraryManager;
         private readonly IServerConfigurationManager _config;
         private readonly ILogger _logger;
-        private readonly IDirectoryWatchers _directoryWatchers;
 
-        public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IDirectoryWatchers directoryWatchers, IServerConfigurationManager config)
+        public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
         {
             _libraryManager = libraryManager;
             _logger = logger;
-            _directoryWatchers = directoryWatchers;
             _config = config;
         }
 
@@ -53,7 +50,7 @@ namespace MediaBrowser.Providers.TV
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
-                await new MissingEpisodeProvider(_logger, _directoryWatchers, _config).Run(series, cancellationToken).ConfigureAwait(false);
+                await new MissingEpisodeProvider(_logger, _config).Run(series, cancellationToken).ConfigureAwait(false);
 
                 var episodes = series.RecursiveChildren
                     .OfType<Episode>()
@@ -88,14 +85,12 @@ namespace MediaBrowser.Providers.TV
     {
         private readonly IServerConfigurationManager _config;
         private readonly ILogger _logger;
-        private readonly IDirectoryWatchers _directoryWatchers;
 
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
-        public MissingEpisodeProvider(ILogger logger, IDirectoryWatchers directoryWatchers, IServerConfigurationManager config)
+        public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config)
         {
             _logger = logger;
-            _directoryWatchers = directoryWatchers;
             _config = config;
         }
 
@@ -141,19 +136,21 @@ namespace MediaBrowser.Providers.TV
                 .Where(i => i.Item1 != -1 && i.Item2 != -1)
                 .ToList();
 
-            var hasChanges = false;
+            var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(series, episodeLookup, cancellationToken).ConfigureAwait(false);
+
+            var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(series, episodeLookup, cancellationToken).ConfigureAwait(false);
+
+            var hasNewEpisodes = false;
 
             if (_config.Configuration.CreateVirtualMissingEpisodes || _config.Configuration.CreateVirtualFutureEpisodes)
             {
                 if (_config.Configuration.EnableInternetProviders)
                 {
-                    hasChanges = await AddMissingEpisodes(series, seriesDataPath, episodeLookup, cancellationToken).ConfigureAwait(false);
+                    hasNewEpisodes = await AddMissingEpisodes(series, seriesDataPath, episodeLookup, cancellationToken).ConfigureAwait(false);
                 }
             }
 
-            var anyRemoved = await RemoveObsoleteMissingEpisodes(series, cancellationToken).ConfigureAwait(false);
-
-            if (hasChanges || anyRemoved)
+            if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
             {
                 await series.RefreshMetadata(cancellationToken, true).ConfigureAwait(false);
                 await series.ValidateChildren(new Progress<double>(), cancellationToken, true).ConfigureAwait(false);
@@ -231,7 +228,7 @@ namespace MediaBrowser.Providers.TV
         /// <summary>
         /// Removes the virtual entry after a corresponding physical version has been added
         /// </summary>
-        private async Task<bool> RemoveObsoleteMissingEpisodes(Series series, CancellationToken cancellationToken)
+        private async Task<bool> RemoveObsoleteOrMissingEpisodes(Series series, IEnumerable<Tuple<int, int>> episodeLookup, CancellationToken cancellationToken)
         {
             var existingEpisodes = series.RecursiveChildren
                 .OfType<Episode>()
@@ -250,10 +247,27 @@ namespace MediaBrowser.Providers.TV
                 {
                     if (i.IndexNumber.HasValue && i.ParentIndexNumber.HasValue)
                     {
-                        return physicalEpisodes.Any(p => p.ParentIndexNumber.HasValue && p.ParentIndexNumber.Value == i.ParentIndexNumber.Value && p.ContainsEpisodeNumber(i.IndexNumber.Value));
+                        var seasonNumber = i.ParentIndexNumber.Value;
+                        var episodeNumber = i.IndexNumber.Value;
+
+                        // If there's a physical episode with the same season and episode number, delete it
+                        if (physicalEpisodes.Any(p =>
+                                p.ParentIndexNumber.HasValue && p.ParentIndexNumber.Value == seasonNumber &&
+                                p.ContainsEpisodeNumber(episodeNumber)))
+                        {
+                            return true;
+                        }
+
+                        // If the episode no longer exists in the remote lookup, delete it
+                        if (!episodeLookup.Any(e => e.Item1 == seasonNumber && e.Item2 == episodeNumber))
+                        {
+                            return true;
+                        }
+
+                        return false;
                     }
 
-                    return false;
+                    return true;
                 })
                 .ToList();
 
@@ -261,7 +275,7 @@ namespace MediaBrowser.Providers.TV
 
             foreach (var episodeToRemove in episodesToRemove)
             {
-                _logger.Info("Removing {0} {1}x{2}", series.Name, episodeToRemove.ParentIndexNumber, episodeToRemove.IndexNumber);
+                _logger.Info("Removing missing/unaired episode {0} {1}x{2}", series.Name, episodeToRemove.ParentIndexNumber, episodeToRemove.IndexNumber);
 
                 await episodeToRemove.Parent.RemoveChild(episodeToRemove, cancellationToken).ConfigureAwait(false);
 
@@ -271,6 +285,67 @@ namespace MediaBrowser.Providers.TV
             return hasChanges;
         }
 
+        /// <summary>
+        /// Removes the obsolete or missing seasons.
+        /// </summary>
+        /// <param name="series">The series.</param>
+        /// <param name="episodeLookup">The episode lookup.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{System.Boolean}.</returns>
+        private async Task<bool> RemoveObsoleteOrMissingSeasons(Series series, IEnumerable<Tuple<int, int>> episodeLookup, CancellationToken cancellationToken)
+        {
+            var existingSeasons = series.Children
+                .OfType<Season>()
+                .ToList();
+
+            var physicalSeasons = existingSeasons
+                .Where(i => i.LocationType != LocationType.Virtual)
+                .ToList();
+
+            var virtualSeasons = existingSeasons
+                .Where(i => i.LocationType == LocationType.Virtual)
+                .ToList();
+
+            var seasonsToRemove = virtualSeasons
+                .Where(i =>
+                {
+                    if (i.IndexNumber.HasValue)
+                    {
+                        var seasonNumber = i.IndexNumber.Value;
+
+                        // If there's a physical season with the same number, delete it
+                        if (physicalSeasons.Any(p => p.IndexNumber.HasValue && p.IndexNumber.Value == seasonNumber))
+                        {
+                            return true;
+                        }
+
+                        // If the season no longer exists in the remote lookup, delete it
+                        if (episodeLookup.All(e => e.Item1 != seasonNumber))
+                        {
+                            return true;
+                        }
+
+                        return false;
+                    }
+
+                    return true;
+                })
+                .ToList();
+
+            var hasChanges = false;
+
+            foreach (var seasonToRemove in seasonsToRemove)
+            {
+                _logger.Info("Removing virtual season {0} {1}", series.Name, seasonToRemove.IndexNumber);
+
+                await seasonToRemove.Parent.RemoveChild(seasonToRemove, cancellationToken).ConfigureAwait(false);
+
+                hasChanges = true;
+            }
+
+            return hasChanges;
+        }
+        
         /// <summary>
         /// Adds the episode.
         /// </summary>
@@ -319,35 +394,17 @@ namespace MediaBrowser.Providers.TV
 
             var name = string.Format("Season {0}", seasonNumber.ToString(UsCulture));
 
-            var path = Path.Combine(series.Path, name);
-
             var season = new Season
             {
                 Name = name,
                 IndexNumber = seasonNumber,
-                Path = path,
                 Parent = series,
-                DisplayMediaType = typeof(Season).Name
+                DisplayMediaType = typeof(Season).Name,
+                Id = (series.Id + seasonNumber.ToString(UsCulture) + name).GetMBId(typeof(Season))
             };
 
-            _directoryWatchers.TemporarilyIgnore(path);
-
-            try
-            {
-                var info = Directory.CreateDirectory(path);
-
-                season.DateCreated = info.CreationTimeUtc;
-                season.DateModified = info.LastWriteTimeUtc;
-
-                await series.AddChild(season, cancellationToken).ConfigureAwait(false);
-
-                await season.RefreshMetadata(cancellationToken).ConfigureAwait(false);
-            }
-            finally
-            {
-                _directoryWatchers.RemoveTempIgnore(path);
-            }
-
+            await series.AddChild(season, cancellationToken).ConfigureAwait(false);
+            await season.RefreshMetadata(cancellationToken).ConfigureAwait(false);
 
             return season;
         }

+ 22 - 0
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -868,6 +868,19 @@ namespace MediaBrowser.Server.Implementations.Dto
                 }
             }
 
+            // If there is no thumb, indicate what parent has one in case the Ui wants to allow inheritance
+            if (!dto.HasThumb)
+            {
+                var parentWithImage = GetParentImageItem(item, ImageType.Thumb, owner);
+
+                if (parentWithImage != null)
+                {
+                    dto.ParentThumbItemId = GetDtoId(parentWithImage);
+
+                    dto.ParentThumbImageTag = GetImageCacheTag(parentWithImage, ImageType.Thumb, parentWithImage.GetImage(ImageType.Thumb));
+                }
+            }
+
             if (fields.Contains(ItemFields.Path))
             {
                 dto.Path = item.Path;
@@ -1022,6 +1035,13 @@ namespace MediaBrowser.Server.Implementations.Dto
 
                 dto.SeriesId = GetDtoId(series);
                 dto.SeriesName = series.Name;
+                dto.AirTime = series.AirTime;
+                dto.SeriesStudio = series.Studios.FirstOrDefault();
+
+                if (series.HasImage(ImageType.Thumb))
+                {
+                    dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb, series.GetImage(ImageType.Thumb));
+                }
             }
 
             // Add SeasonInfo
@@ -1033,6 +1053,8 @@ namespace MediaBrowser.Server.Implementations.Dto
 
                 dto.SeriesId = GetDtoId(series);
                 dto.SeriesName = series.Name;
+                dto.AirTime = series.AirTime;
+                dto.SeriesStudio = series.Studios.FirstOrDefault();
             }
 
             var game = item as Game;

+ 1 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -186,6 +186,7 @@
     </Compile>
     <Compile Include="Session\SessionWebSocketListener.cs" />
     <Compile Include="Session\WebSocketController.cs" />
+    <Compile Include="Sorting\AirTimeComparer.cs" />
     <Compile Include="Sorting\AlbumArtistComparer.cs" />
     <Compile Include="Sorting\AlbumComparer.cs" />
     <Compile Include="Sorting\AlbumCountComparer.cs" />

+ 48 - 0
MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs

@@ -0,0 +1,48 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Querying;
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    public class AirTimeComparer : IBaseItemComparer
+    {
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return DateTime.Compare(GetValue(x), GetValue(y));
+        }
+
+        /// <summary>
+        /// Gets the value.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>System.String.</returns>
+        private DateTime GetValue(BaseItem x)
+        {
+            var series = (x as Series) ?? x.FindParent<Series>();
+
+            DateTime result;
+            if (series != null && DateTime.TryParse(series.AirTime, out result))
+            {
+                return result;
+            } 
+            return DateTime.MinValue;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.AirTime; }
+        }
+    }
+}

+ 1 - 0
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -513,6 +513,7 @@ namespace MediaBrowser.WebDashboard.Api
                                       "tvrecommended.js",
                                       "tvshows.js",
                                       "tvstudios.js",
+                                      "tvupcoming.js",
                                       "updatepasswordpage.js",
                                       "userimagepage.js",
                                       "userprofilespage.js",

+ 18 - 1
MediaBrowser.WebDashboard/ApiClient.js

@@ -2018,11 +2018,28 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
 
             options.imageType = "logo";
 
-            var logoItemId = item.HasLogo ? item.Id : item.ParentLogoItemId;
+            var logoItemId = item.ImageTags && item.ImageTags.Logo ? item.Id : item.ParentLogoItemId;
 
             return logoItemId ? self.getImageUrl(logoItemId, options) : null;
         };
 
+        self.getThumbImageUrl = function (item, options) {
+
+            if (!item) {
+                throw new Error("null item");
+            }
+
+            options = options || {
+
+            };
+
+            options.imageType = "thumb";
+
+            var itemId = item.ImageTags && item.ImageTags.Thumb ? item.Id : item.ParentThumbItemId;
+
+            return itemId ? self.getImageUrl(itemId, options) : null;
+        };
+
         /**
          * Constructs an array of backdrop image url's for an item
          * If the item doesn't have any backdrops, it will inherit them from a parent

+ 6 - 0
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -341,12 +341,18 @@
     <Content Include="dashboard-ui\scripts\metadatatv.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\scripts\tvupcoming.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\wizardservice.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="dashboard-ui\scripts\wizardsettings.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\tvupcoming.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\wizardservice.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>

+ 1 - 1
MediaBrowser.WebDashboard/packages.config

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.180" targetFramework="net45" />
+  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.181" targetFramework="net45" />
   <package id="ServiceStack.Common" version="3.9.62" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" />
 </packages>