begin work on daily episodes

pull/702/head
Luke Pulverenti 10 years ago
parent fef1d16cec
commit 42b1416602

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
@ -73,7 +74,7 @@ namespace MediaBrowser.Api
if (locationType == LocationType.FileSystem ||
locationType == LocationType.Offline)
{
if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder))
if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
{
var collectionType = _libraryManager.GetInheritedContentType(item);
if (string.IsNullOrWhiteSpace(collectionType))

@ -223,6 +223,10 @@ namespace MediaBrowser.Common.Implementations.Configuration
{
return Activator.CreateInstance(configurationType);
}
catch (DirectoryNotFoundException)
{
return Activator.CreateInstance(configurationType);
}
catch (Exception ex)
{
Logger.ErrorException("Error loading configuration file: {0}", ex, path);

@ -38,7 +38,10 @@ namespace MediaBrowser.Common.Implementations.Devices
_logger.Error("Invalid value found in device id file");
}
}
catch (FileNotFoundException ex)
catch (DirectoryNotFoundException)
{
}
catch (FileNotFoundException)
{
}
catch (Exception ex)

@ -101,6 +101,10 @@ namespace MediaBrowser.Common.Implementations.Security
{
contents = File.ReadAllLines(licenseFile);
}
catch (DirectoryNotFoundException)
{
(File.Create(licenseFile)).Close();
}
catch (FileNotFoundException)
{
(File.Create(licenseFile)).Close();

@ -1,4 +1,6 @@
using System;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@ -54,6 +56,15 @@ namespace MediaBrowser.Common.Extensions
return sb.ToString();
}
public static string RemoveDiacritics(this string text)
{
return String.Concat(
text.Normalize(NormalizationForm.FormD)
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
UnicodeCategory.NonSpacingMark)
).Normalize(NormalizationForm.FormC);
}
/// <summary>
/// Gets the M d5.
/// </summary>

@ -204,6 +204,10 @@ namespace MediaBrowser.Common.Plugins
{
return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path);
}
catch (DirectoryNotFoundException)
{
return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
}
catch (FileNotFoundException)
{
return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));

@ -1,11 +1,11 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.TV
{
@ -178,6 +178,15 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
[IgnoreDataMember]
public bool IsInSeasonFolder
{
get
{
return FindParent<Season>() != null;
}
}
[IgnoreDataMember]
public string SeriesName
{

@ -1,13 +1,12 @@
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Users;
using MoreLinq;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.TV
{
@ -156,24 +155,6 @@ namespace MediaBrowser.Controller.Entities.TV
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
private IEnumerable<Episode> GetEpisodes()
{
var series = Series;
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
{
var seasonNumber = IndexNumber;
if (seasonNumber.HasValue)
{
return series.RecursiveChildren.OfType<Episode>()
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value);
}
}
return Children.OfType<Episode>();
}
[IgnoreDataMember]
public bool IsMissingSeason
{
@ -221,16 +202,32 @@ namespace MediaBrowser.Controller.Entities.TV
var episodes = GetRecursiveChildren(user)
.OfType<Episode>();
if (IndexNumber.HasValue)
var series = Series;
if (IndexNumber.HasValue && series != null)
{
var series = Series;
return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
}
if (series != null)
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
{
var seasonNumber = IndexNumber;
var list = episodes.ToList();
if (seasonNumber.HasValue)
{
return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
}
else
{
list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
.Where(i => !i.ParentIndexNumber.HasValue));
}
}
episodes = list.DistinctBy(i => i.Id);
}
if (!includeMissingEpisodes)
{
episodes = episodes.Where(i => !i.IsMissingEpisode);
@ -245,6 +242,33 @@ namespace MediaBrowser.Controller.Entities.TV
.Cast<Episode>();
}
private IEnumerable<Episode> GetEpisodes()
{
var episodes = RecursiveChildren.OfType<Episode>();
var series = Series;
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
{
var seasonNumber = IndexNumber;
var list = episodes.ToList();
if (seasonNumber.HasValue)
{
list.AddRange(series.RecursiveChildren.OfType<Episode>()
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
}
else
{
list.AddRange(series.RecursiveChildren.OfType<Episode>()
.Where(i => !i.ParentIndexNumber.HasValue));
}
episodes = list.DistinctBy(i => i.Id);
}
return episodes;
}
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
return GetEpisodes(user);

@ -186,5 +186,12 @@ namespace MediaBrowser.Controller.Library
/// <param name="userId">The user identifier.</param>
/// <param name="userPolicy">The user policy.</param>
Task UpdateUserPolicy(string userId, UserPolicy userPolicy);
/// <summary>
/// Makes the valid username.
/// </summary>
/// <param name="username">The username.</param>
/// <returns>System.String.</returns>
string MakeValidUsername(string username);
}
}

@ -28,8 +28,6 @@ namespace MediaBrowser.LocalMetadata
var path = file.FullName;
//await XmlProviderUtils.XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
result.Item = new T();
@ -45,10 +43,6 @@ namespace MediaBrowser.LocalMetadata
{
result.HasMetadata = false;
}
finally
{
//XmlProviderUtils.XmlParsingResourcePool.Release();
}
return result;
}

@ -612,6 +612,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
catch (FileNotFoundException)
{
}
catch (DirectoryNotFoundException)
{
}
catch (IOException ex)
{

@ -505,15 +505,6 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;PublicSystemInfo&gt;.</returns>
Task<PublicSystemInfo> GetPublicSystemInfoAsync(CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Gets a person
/// </summary>
/// <param name="name">The name.</param>
/// <param name="userId">The user id.</param>
/// <returns>Task{BaseItemDto}.</returns>
/// <exception cref="ArgumentNullException">userId</exception>
Task<BaseItemDto> GetPersonAsync(string name, string userId);
/// <summary>
/// Gets a list of plugins installed on the server
@ -967,15 +958,6 @@ namespace MediaBrowser.Model.ApiClient
/// <exception cref="ArgumentNullException">item</exception>
string GetPersonImageUrl(BaseItemPerson item, ImageOptions options);
/// <summary>
/// Gets an image url that can be used to download an image from the api
/// </summary>
/// <param name="name">The name of the person</param>
/// <param name="options">The options.</param>
/// <returns>System.String.</returns>
/// <exception cref="ArgumentNullException">name</exception>
string GetPersonImageUrl(string name, ImageOptions options);
/// <summary>
/// Gets an image url that can be used to download an image from the api
/// </summary>

@ -106,6 +106,10 @@ namespace MediaBrowser.Providers.Movies
{
// No biggie. Don't blow up
}
catch (DirectoryNotFoundException)
{
// No biggie. Don't blow up
}
}
var language = item.GetPreferredMetadataLanguage();

@ -82,6 +82,10 @@ namespace MediaBrowser.Providers.Music
catch (FileNotFoundException)
{
}
catch (DirectoryNotFoundException)
{
}
}

@ -90,6 +90,10 @@ namespace MediaBrowser.Providers.Music
catch (FileNotFoundException)
{
}
catch (DirectoryNotFoundException)
{
}
}

@ -83,6 +83,10 @@ namespace MediaBrowser.Providers.People
{
return null;
}
catch (DirectoryNotFoundException)
{
return null;
}
}
private RemoteImageInfo GetImageInfo(string xmlFile, string personName, CancellationToken cancellationToken)

@ -98,6 +98,10 @@ namespace MediaBrowser.Providers.TV
{
// No biggie. Don't blow up
}
catch (DirectoryNotFoundException)
{
// No biggie. Don't blow up
}
}
}

@ -106,6 +106,10 @@ namespace MediaBrowser.Providers.TV
{
// No biggie. Don't blow up
}
catch (DirectoryNotFoundException)
{
// No biggie. Don't blow up
}
}
var language = item.GetPreferredMetadataLanguage();

@ -2,6 +2,7 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@ -22,14 +23,16 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager)
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
{
_logger = logger;
_config = config;
_libraryManager = libraryManager;
_localization = localization;
}
public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken)
@ -93,16 +96,16 @@ namespace MediaBrowser.Providers.TV
var hasBadData = HasInvalidContent(group);
var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup, false)
var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup)
.ConfigureAwait(false);
var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup, false)
var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup)
.ConfigureAwait(false);
var hasNewEpisodes = false;
var hasNewSeasons = false;
foreach (var series in group.Where(s => s.ContainsEpisodesWithoutSeasonFolders))
foreach (var series in group)
{
hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
}
@ -165,14 +168,15 @@ namespace MediaBrowser.Providers.TV
/// <returns></returns>
private async Task<bool> AddDummySeasonFolders(Series series, CancellationToken cancellationToken)
{
var existingEpisodes = series.RecursiveChildren
var episodesInSeriesFolder = series.RecursiveChildren
.OfType<Episode>()
.Where(i => !i.IsInSeasonFolder)
.ToList();
var hasChanges = false;
// Loop through the unique season numbers
foreach (var seasonNumber in existingEpisodes.Select(i => i.ParentIndexNumber ?? -1)
foreach (var seasonNumber in episodesInSeriesFolder.Select(i => i.ParentIndexNumber ?? -1)
.Where(i => i >= 0)
.Distinct()
.ToList())
@ -188,6 +192,20 @@ namespace MediaBrowser.Providers.TV
}
}
// Unknown season - create a dummy season to put these under
if (episodesInSeriesFolder.Any(i => !i.ParentIndexNumber.HasValue))
{
var hasSeason = series.Children.OfType<Season>()
.Any(i => !i.IndexNumber.HasValue);
if (!hasSeason)
{
await AddSeason(series, null, cancellationToken).ConfigureAwait(false);
hasChanges = true;
}
}
return hasChanges;
}
@ -292,8 +310,7 @@ namespace MediaBrowser.Providers.TV
/// Removes the virtual entry after a corresponding physical version has been added
/// </summary>
private async Task<bool> RemoveObsoleteOrMissingEpisodes(IEnumerable<Series> series,
IEnumerable<Tuple<int, int>> episodeLookup,
bool forceRemoveAll)
IEnumerable<Tuple<int, int>> episodeLookup)
{
var existingEpisodes = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
@ -312,11 +329,6 @@ namespace MediaBrowser.Providers.TV
var episodesToRemove = virtualEpisodes
.Where(i =>
{
if (forceRemoveAll)
{
return true;
}
if (i.Episode.IndexNumber.HasValue && i.Episode.ParentIndexNumber.HasValue)
{
var seasonNumber = i.Episode.ParentIndexNumber.Value + i.SeasonOffset;
@ -362,11 +374,9 @@ namespace MediaBrowser.Providers.TV
/// </summary>
/// <param name="series">The series.</param>
/// <param name="episodeLookup">The episode lookup.</param>
/// <param name="forceRemoveAll">if set to <c>true</c> [force remove all].</param>
/// <returns>Task{System.Boolean}.</returns>
private async Task<bool> RemoveObsoleteOrMissingSeasons(IEnumerable<Series> series,
IEnumerable<Tuple<int, int>> episodeLookup,
bool forceRemoveAll)
IEnumerable<Tuple<int, int>> episodeLookup)
{
var existingSeasons = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
@ -385,11 +395,6 @@ namespace MediaBrowser.Providers.TV
var seasonsToRemove = virtualSeasons
.Where(i =>
{
if (forceRemoveAll)
{
return true;
}
if (i.Season.IndexNumber.HasValue)
{
var seasonNumber = i.Season.IndexNumber.Value + i.SeasonOffset;
@ -409,7 +414,9 @@ namespace MediaBrowser.Providers.TV
return false;
}
return true;
// Season does not have a number
// Remove if there are no episodes directly in series without a season number
return i.Season.Series.RecursiveChildren.OfType<Episode>().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
})
.ToList();
@ -472,20 +479,22 @@ namespace MediaBrowser.Providers.TV
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Season}.</returns>
private async Task<Season> AddSeason(Series series,
int seasonNumber,
int? seasonNumber,
CancellationToken cancellationToken)
{
_logger.Info("Creating Season {0} entry for {1}", seasonNumber, series.Name);
var seasonName = seasonNumber == 0 ?
_config.Configuration.SeasonZeroDisplayName :
(seasonNumber.HasValue ? string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.Value.ToString(UsCulture)) : _localization.GetLocalizedString("NameSeasonUnknown"));
var name = seasonNumber == 0 ? _config.Configuration.SeasonZeroDisplayName : string.Format("Season {0}", seasonNumber.ToString(UsCulture));
_logger.Info("Creating Season {0} entry for {1}", seasonName, series.Name);
var season = new Season
{
Name = name,
Name = seasonName,
IndexNumber = seasonNumber,
Parent = series,
DisplayMediaType = typeof(Season).Name,
Id = (series.Id + seasonNumber.ToString(UsCulture) + name).GetMBId(typeof(Season))
Id = (series.Id + (seasonNumber ?? -1).ToString(UsCulture) + seasonName).GetMBId(typeof(Season))
};
await series.AddChild(season, cancellationToken).ConfigureAwait(false);

@ -1,11 +1,12 @@
using System.Collections.Generic;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -25,12 +26,14 @@ namespace MediaBrowser.Providers.TV
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private readonly ILocalizationManager _localization;
public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, ILocalizationManager localization)
{
_libraryManager = libraryManager;
_logger = logger;
_config = config;
_localization = localization;
}
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
@ -47,7 +50,7 @@ namespace MediaBrowser.Providers.TV
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
await new MissingEpisodeProvider(_logger, _config, _libraryManager).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
var numComplete = 0;

@ -72,6 +72,10 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
catch (DirectoryNotFoundException)
{
// Don't fail the provider because this will just keep on going and going.
}
}
return list;
@ -101,6 +105,10 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
catch (DirectoryNotFoundException)
{
// Don't fail the provider because this will just keep on going and going.
}
}
return result;
@ -208,8 +216,9 @@ namespace MediaBrowser.Providers.TV
/// Fetches the episode data.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="identity">The identity.</param>
/// <param name="seriesDataPath">The series data path.</param>
/// <param name="seriesProviderIds"></param>
/// <param name="seriesProviderIds">The series provider ids.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
private Episode FetchEpisodeData(EpisodeInfo id, EpisodeIdentity identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
@ -279,6 +288,10 @@ namespace MediaBrowser.Providers.TV
{
break;
}
catch (DirectoryNotFoundException)
{
break;
}
episodeNumber++;
}

@ -94,6 +94,10 @@ namespace MediaBrowser.Providers.TV
{
// No tvdb data yet. Don't blow up
}
catch (DirectoryNotFoundException)
{
// No tvdb data yet. Don't blow up
}
}
return new RemoteImageInfo[] { };

@ -87,6 +87,10 @@ namespace MediaBrowser.Providers.TV
{
// No tvdb data yet. Don't blow up
}
catch (DirectoryNotFoundException)
{
// No tvdb data yet. Don't blow up
}
}
return new RemoteImageInfo[] { };

@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@ -789,7 +790,7 @@ namespace MediaBrowser.Server.Implementations.Connect
if (user == null)
{
// Add user
user = await _userManager.CreateUser(connectEntry.UserName).ConfigureAwait(false);
user = await _userManager.CreateUser(_userManager.MakeValidUsername(connectEntry.UserName)).ConfigureAwait(false);
user.ConnectUserName = connectEntry.UserName;
user.ConnectUserId = connectEntry.UserId;

@ -78,6 +78,11 @@ namespace MediaBrowser.Server.Implementations.Drawing
// No biggie
sizeDictionary = new Dictionary<Guid, ImageSize>();
}
catch (DirectoryNotFoundException)
{
// No biggie
sizeDictionary = new Dictionary<Guid, ImageSize>();
}
catch (Exception ex)
{
logger.ErrorException("Error parsing image size cache file", ex);

@ -459,11 +459,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
private bool IsSameEpisode(string sourcePath, string newPath)
{
var sourceFileInfo = new FileInfo(sourcePath);
var destinationFileInfo = new FileInfo(newPath);
try
{
var sourceFileInfo = new FileInfo(sourcePath);
var destinationFileInfo = new FileInfo(newPath);
if (sourceFileInfo.Length == destinationFileInfo.Length)
{
return true;
@ -473,6 +473,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
return false;
}
catch (DirectoryNotFoundException)
{
return false;
}
return false;
}

@ -1755,9 +1755,12 @@ namespace MediaBrowser.Server.Implementations.Library
var resolver = new EpisodeResolver(new ExtendedNamingOptions(),
new Naming.Logging.NullLogger());
var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ?
FileInfoType.Directory :
FileInfoType.File;
var locationType = episode.LocationType;
var fileType = /*args.IsDirectory ? FileInfoType.Directory :*/ FileInfoType.File;
var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
resolver.Resolve(episode.Path, fileType) :
new Naming.TV.EpisodeInfo();
@ -1769,29 +1772,42 @@ namespace MediaBrowser.Server.Implementations.Library
var changed = false;
if (!episode.IndexNumber.HasValue)
if (episodeInfo.IsByDate)
{
episode.IndexNumber = episodeInfo.EpisodeNumber;
if (episode.IndexNumber.HasValue)
{
episode.IndexNumber = null;
changed = true;
}
}
if (!episode.IndexNumberEnd.HasValue)
{
episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
if (episode.IndexNumberEnd.HasValue)
{
episode.IndexNumberEnd = null;
changed = true;
}
}
if (!episode.ParentIndexNumber.HasValue)
{
episode.ParentIndexNumber = episodeInfo.SeasonNumber;
if (!episode.PremiereDate.HasValue)
{
if (episodeInfo.Year.HasValue && episodeInfo.Month.HasValue && episodeInfo.Day.HasValue)
{
episode.PremiereDate = new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value).ToUniversalTime();
}
if (episode.PremiereDate.HasValue)
{
changed = true;
}
}
if (!episode.ProductionYear.HasValue)
{
episode.ProductionYear = episodeInfo.Year;
if (episode.ProductionYear.HasValue)
{
changed = true;
}
}
if (!episode.ParentIndexNumber.HasValue)
{
@ -1801,11 +1817,53 @@ namespace MediaBrowser.Server.Implementations.Library
{
episode.ParentIndexNumber = season.IndexNumber;
}
if (episode.ParentIndexNumber.HasValue)
{
changed = true;
}
}
}
else
{
if (!episode.IndexNumber.HasValue)
{
episode.IndexNumber = episodeInfo.EpisodeNumber;
if (episode.IndexNumber.HasValue)
{
changed = true;
}
}
if (episode.ParentIndexNumber.HasValue)
if (!episode.IndexNumberEnd.HasValue)
{
changed = true;
episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
if (episode.IndexNumberEnd.HasValue)
{
changed = true;
}
}
if (!episode.ParentIndexNumber.HasValue)
{
episode.ParentIndexNumber = episodeInfo.SeasonNumber;
if (!episode.ParentIndexNumber.HasValue)
{
var season = episode.Season;
if (season != null)
{
episode.ParentIndexNumber = season.IndexNumber;
}
}
if (episode.ParentIndexNumber.HasValue)
{
changed = true;
}
}
}

@ -1,7 +1,5 @@
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.IO;
using System.Linq;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV

@ -171,6 +171,38 @@ namespace MediaBrowser.Server.Implementations.Library
return AuthenticateUser(username, passwordSha1, null, remoteEndPoint);
}
public bool IsValidUsername(string username)
{
// Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
return username.All(IsValidCharacter);
}
private bool IsValidCharacter(char i)
{
return char.IsLetterOrDigit(i) || char.Equals(i, '-') || char.Equals(i, '_') || char.Equals(i, '\'') ||
char.Equals(i, '.');
}
public string MakeValidUsername(string username)
{
if (IsValidUsername(username))
{
return username;
}
// Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
var builder = new StringBuilder();
foreach (var c in username)
{
if (IsValidCharacter(c))
{
builder.Append(c);
}
}
return builder.ToString();
}
public async Task<bool> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint)
{
if (string.IsNullOrWhiteSpace(username))
@ -178,7 +210,8 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("username");
}
var user = Users.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
var user = Users
.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
if (user == null)
{
@ -203,20 +236,6 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
// Maybe user accidently entered connect credentials. let's be flexible
if (!success && user.ConnectLinkType.HasValue && !string.IsNullOrWhiteSpace(passwordMd5))
{
try
{
await _connectFactory().Authenticate(user.ConnectUserName, passwordMd5).ConfigureAwait(false);
success = true;
}
catch
{
}
}
// Update LastActivityDate and LastLoginDate, then save
if (success)
{
@ -273,7 +292,7 @@ namespace MediaBrowser.Server.Implementations.Library
// There always has to be at least one user.
if (users.Count == 0)
{
var name = Environment.UserName;
var name = MakeValidUsername(Environment.UserName);
var user = InstantiateNewUser(name, false);
@ -477,6 +496,11 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("name");
}
if (!IsValidUsername(name))
{
throw new ArgumentException("Only alphanumeric characters are allowed.");
}
if (Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name));
@ -803,6 +827,10 @@ namespace MediaBrowser.Server.Implementations.Library
return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path);
}
}
catch (DirectoryNotFoundException)
{
return GetDefaultPolicy(user);
}
catch (FileNotFoundException)
{
return GetDefaultPolicy(user);
@ -840,6 +868,8 @@ namespace MediaBrowser.Server.Implementations.Library
var path = GetPolifyFilePath(user);
Directory.CreateDirectory(Path.GetDirectoryName(path));
lock (_policySyncLock)
{
_xmlSerializer.SerializeToFile(userPolicy, path);
@ -900,6 +930,10 @@ namespace MediaBrowser.Server.Implementations.Library
return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path);
}
}
catch (DirectoryNotFoundException)
{
return new UserConfiguration();
}
catch (FileNotFoundException)
{
return new UserConfiguration();
@ -930,6 +964,8 @@ namespace MediaBrowser.Server.Implementations.Library
config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
}
Directory.CreateDirectory(Path.GetDirectoryName(path));
lock (_configSyncLock)
{
_xmlSerializer.SerializeToFile(config, path);

@ -419,7 +419,7 @@
"HeaderMediaLocations": "Media Locations",
"LabelFolderTypeValue": "Folder type: {0}",
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
"FolderTypeMixed": "Mixed videos",
"FolderTypeMixed": "Mixed content",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@ -658,5 +658,5 @@
"LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
"MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
"MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
"MessageMixedContentHelp": "Content will be displayed with as a plain folder structure"
"MessageMixedContentHelp": "Content will be displayed as a plain folder structure"
}

@ -37,7 +37,7 @@
"ButtonOk": "Ok",
"ButtonCancel": "Cancel",
"ButtonNew": "New",
"FolderTypeMixed": "Mixed videos",
"FolderTypeMixed": "Mixed content",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
@ -48,7 +48,7 @@
"FolderTypeBooks": "Books",
"FolderTypeTvShows": "TV",
"FolderTypeInherit": "Inherit",
"LabelContentType": "Content type:",
"LabelContentType": "Content type:",
"HeaderSetupLibrary": "Setup your media library",
"ButtonAddMediaFolder": "Add media folder",
"LabelFolderType": "Folder type:",
@ -1307,5 +1307,8 @@
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
"TitleSync": "Sync",
"OptionAllowSyncContent": "Allow syncing media to devices"
"OptionAllowSyncContent": "Allow syncing media to devices",
"NameSeasonUnknown": "Season Unknown",
"NameSeasonNumber": "Season {0}",
"LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"
}

@ -26,6 +26,14 @@ namespace MediaBrowser.Server.Implementations.News
{
return GetProductNewsInternal(query);
}
catch (DirectoryNotFoundException)
{
// No biggie
return new QueryResult<NewsItem>
{
Items = new NewsItem[] { }
};
}
catch (FileNotFoundException)
{
// No biggie

@ -256,6 +256,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
catch (FileNotFoundException)
{
}
catch (DirectoryNotFoundException)
{
}
writer.WriteEndElement();

Loading…
Cancel
Save