DAMN! #435 that's a lot of code!

This commit is contained in:
tidusjar 2017-01-29 00:13:07 +00:00
parent 868301f552
commit d59d64234f
40 changed files with 1758 additions and 115 deletions

View file

@ -6,11 +6,11 @@ namespace Ombi.Api.Interfaces
{ {
public interface IEmbyApi public interface IEmbyApi
{ {
string ApiKey { get; }
EmbyItemContainer<EmbyMovieItem> GetAllMovies(string apiKey, string userId, Uri baseUri); EmbyItemContainer<EmbyMovieItem> GetAllMovies(string apiKey, string userId, Uri baseUri);
EmbyItemContainer<EmbySeriesItem> GetAllShows(string apiKey, string userId, Uri baseUri); EmbyItemContainer<EmbySeriesItem> GetAllShows(string apiKey, string userId, Uri baseUri);
EmbyItemContainer<EmbyEpisodeItem> GetAllEpisodes(string apiKey, string userId, Uri baseUri);
List<EmbyUser> GetUsers(Uri baseUri, string apiKey); List<EmbyUser> GetUsers(Uri baseUri, string apiKey);
EmbyItemContainer<EmbyLibrary> ViewLibrary(string apiKey, string userId, Uri baseUri); EmbyItemContainer<EmbyLibrary> ViewLibrary(string apiKey, string userId, Uri baseUri);
EmbyInformation GetInformation(string mediaId, EmbyMediaType type, string apiKey, string userId, Uri baseUri);
} }
} }

View file

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyChapter
{
public long StartPositionTicks { get; set; }
public string Name { get; set; }
}
}

View file

@ -0,0 +1,97 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyEpisodeInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
namespace Ombi.Api.Models.Emby
{
public class EmbyEpisodeInformation
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Etag { get; set; }
public DateTime DateCreated { get; set; }
public bool CanDelete { get; set; }
public bool CanDownload { get; set; }
public bool SupportsSync { get; set; }
public string Container { get; set; }
public string SortName { get; set; }
public DateTime PremiereDate { get; set; }
public EmbyExternalurl[] ExternalUrls { get; set; }
public EmbyMediasource[] MediaSources { get; set; }
public string Path { get; set; }
public string Overview { get; set; }
public object[] Taglines { get; set; }
public object[] Genres { get; set; }
public string[] SeriesGenres { get; set; }
public int CommunityRating { get; set; }
public int VoteCount { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public int IndexNumber { get; set; }
public int ParentIndexNumber { get; set; }
public object[] RemoteTrailers { get; set; }
public EmbyProviderids ProviderIds { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string ParentId { get; set; }
public string Type { get; set; }
public object[] People { get; set; }
public object[] Studios { get; set; }
public string ParentLogoItemId { get; set; }
public string ParentBackdropItemId { get; set; }
public string[] ParentBackdropImageTags { get; set; }
public int LocalTrailerCount { get; set; }
public EmbyUserdata UserData { get; set; }
public string SeriesName { get; set; }
public string SeriesId { get; set; }
public string SeasonId { get; set; }
public string DisplayPreferencesId { get; set; }
public object[] Tags { get; set; }
public object[] Keywords { get; set; }
public string SeriesPrimaryImageTag { get; set; }
public string SeasonName { get; set; }
public EmbyMediastream1[] MediaStreams { get; set; }
public string VideoType { get; set; }
public EmbyImagetags ImageTags { get; set; }
public object[] BackdropImageTags { get; set; }
public object[] ScreenshotImageTags { get; set; }
public string ParentLogoImageTag { get; set; }
public string SeriesStudio { get; set; }
public EmbySeriesstudioinfo SeriesStudioInfo { get; set; }
public string ParentThumbItemId { get; set; }
public string ParentThumbImageTag { get; set; }
public EmbyChapter[] Chapters { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public object[] LockedFields { get; set; }
public bool LockData { get; set; }
}
}

View file

@ -0,0 +1,69 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyEpisodeItem.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
namespace Ombi.Api.Models.Emby
{
public class EmbyEpisodeItem
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Container { get; set; }
public DateTime PremiereDate { get; set; }
public float CommunityRating { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public int IndexNumber { get; set; }
public int ParentIndexNumber { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public string ParentLogoItemId { get; set; }
public string ParentBackdropItemId { get; set; }
public string[] ParentBackdropImageTags { get; set; }
public int LocalTrailerCount { get; set; }
public EmbyUserdata UserData { get; set; }
public string SeriesName { get; set; }
public string SeriesId { get; set; }
public string SeasonId { get; set; }
public string SeriesPrimaryImageTag { get; set; }
public string SeasonName { get; set; }
public string VideoType { get; set; }
public EmbyImagetags ImageTags { get; set; }
public object[] BackdropImageTags { get; set; }
public string ParentLogoImageTag { get; set; }
public string ParentThumbItemId { get; set; }
public string ParentThumbImageTag { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public bool HasSubtitles { get; set; }
}
}

View file

@ -0,0 +1,42 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyExternalurl
{
public string Name { get; set; }
public string Url { get; set; }
}
}

View file

@ -0,0 +1,35 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyInformation
{
public EmbySeriesInformation SeriesInformation { get; set; }
public EmbyMovieInformation MovieInformation { get; set; }
public EmbyEpisodeInformation EpisodeInformation { get; set; }
}
}

View file

@ -0,0 +1,36 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyMediaType.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public enum EmbyMediaType
{
Movie = 0,
Series = 1,
Music = 2,
Episode = 3
}
}

View file

@ -0,0 +1,59 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyMediasource
{
public string Protocol { get; set; }
public string Id { get; set; }
public string Path { get; set; }
public string Type { get; set; }
public string Container { get; set; }
public string Name { get; set; }
public bool IsRemote { get; set; }
public string ETag { get; set; }
public long RunTimeTicks { get; set; }
public bool ReadAtNativeFramerate { get; set; }
public bool SupportsTranscoding { get; set; }
public bool SupportsDirectStream { get; set; }
public bool SupportsDirectPlay { get; set; }
public bool IsInfiniteStream { get; set; }
public bool RequiresOpening { get; set; }
public bool RequiresClosing { get; set; }
public bool SupportsProbing { get; set; }
public string VideoType { get; set; }
public EmbyMediastream[] MediaStreams { get; set; }
public object[] PlayableStreamFileNames { get; set; }
public object[] Formats { get; set; }
public int Bitrate { get; set; }
public EmbyRequiredhttpheaders RequiredHttpHeaders { get; set; }
public int DefaultAudioStreamIndex { get; set; }
}
}

View file

@ -0,0 +1,64 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyMediastream
{
public string Codec { get; set; }
public string Language { get; set; }
public string TimeBase { get; set; }
public string CodecTimeBase { get; set; }
public string NalLengthSize { get; set; }
public bool IsInterlaced { get; set; }
public bool IsAVC { get; set; }
public int BitRate { get; set; }
public int BitDepth { get; set; }
public int RefFrames { get; set; }
public bool IsDefault { get; set; }
public bool IsForced { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public float AverageFrameRate { get; set; }
public float RealFrameRate { get; set; }
public string Profile { get; set; }
public string Type { get; set; }
public string AspectRatio { get; set; }
public int Index { get; set; }
public bool IsExternal { get; set; }
public bool IsTextSubtitleStream { get; set; }
public bool SupportsExternalStream { get; set; }
public string PixelFormat { get; set; }
public int Level { get; set; }
public bool IsAnamorphic { get; set; }
public string DisplayTitle { get; set; }
public string ChannelLayout { get; set; }
public int Channels { get; set; }
public int SampleRate { get; set; }
}
}

View file

@ -0,0 +1,64 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyMediastream1
{
public string Codec { get; set; }
public string Language { get; set; }
public string TimeBase { get; set; }
public string CodecTimeBase { get; set; }
public string NalLengthSize { get; set; }
public bool IsInterlaced { get; set; }
public bool IsAVC { get; set; }
public int BitRate { get; set; }
public int BitDepth { get; set; }
public int RefFrames { get; set; }
public bool IsDefault { get; set; }
public bool IsForced { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public float AverageFrameRate { get; set; }
public float RealFrameRate { get; set; }
public string Profile { get; set; }
public string Type { get; set; }
public string AspectRatio { get; set; }
public int Index { get; set; }
public bool IsExternal { get; set; }
public bool IsTextSubtitleStream { get; set; }
public bool SupportsExternalStream { get; set; }
public string PixelFormat { get; set; }
public int Level { get; set; }
public bool IsAnamorphic { get; set; }
public string DisplayTitle { get; set; }
public string ChannelLayout { get; set; }
public int Channels { get; set; }
public int SampleRate { get; set; }
}
}

View file

@ -0,0 +1,87 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
namespace Ombi.Api.Models.Emby
{
public class EmbyMovieInformation
{
public string Name { get; set; }
public string OriginalTitle { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Etag { get; set; }
public DateTime DateCreated { get; set; }
public bool CanDelete { get; set; }
public bool CanDownload { get; set; }
public bool SupportsSync { get; set; }
public string Container { get; set; }
public string SortName { get; set; }
public DateTime PremiereDate { get; set; }
public EmbyExternalurl[] ExternalUrls { get; set; }
public EmbyMediasource[] MediaSources { get; set; }
public string[] ProductionLocations { get; set; }
public string Path { get; set; }
public string OfficialRating { get; set; }
public string Overview { get; set; }
public string[] Taglines { get; set; }
public string[] Genres { get; set; }
public float CommunityRating { get; set; }
public int VoteCount { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsPlaceHolder { get; set; }
public EmbyRemotetrailer[] RemoteTrailers { get; set; }
public EmbyProviderids ProviderIds { get; set; }
public bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string ParentId { get; set; }
public string Type { get; set; }
public EmbyPerson[] People { get; set; }
public EmbyStudio[] Studios { get; set; }
public int LocalTrailerCount { get; set; }
public EmbyUserdata UserData { get; set; }
public string DisplayPreferencesId { get; set; }
public object[] Tags { get; set; }
public string[] Keywords { get; set; }
public EmbyMediastream1[] MediaStreams { get; set; }
public string VideoType { get; set; }
public EmbyImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public object[] ScreenshotImageTags { get; set; }
public EmbyChapter[] Chapters { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public string HomePageUrl { get; set; }
public int Budget { get; set; }
public int Revenue { get; set; }
public object[] LockedFields { get; set; }
public bool LockData { get; set; }
}
}

View file

@ -0,0 +1,39 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyPerson
{
public string Name { get; set; }
public string Id { get; set; }
public string Role { get; set; }
public string Type { get; set; }
public string PrimaryImageTag { get; set; }
}
}

View file

@ -0,0 +1,41 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyProviderids
{
public string Tmdb { get; set; }
public string Imdb { get; set; }
public string TmdbCollection { get; set; }
public string Tvdb { get; set; }
public string Zap2It { get; set; }
public string TvRage { get; set; }
}
}

View file

@ -0,0 +1,36 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyRemotetrailer
{
public string Url { get; set; }
public string Name { get; set; }
}
}

View file

@ -0,0 +1,36 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyRequiredhttpheaders
{
}
}

View file

@ -0,0 +1,83 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbySeriesInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
namespace Ombi.Api.Models.Emby
{
public class EmbySeriesInformation
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public string Etag { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateLastMediaAdded { get; set; }
public bool CanDelete { get; set; }
public bool CanDownload { get; set; }
public bool SupportsSync { get; set; }
public string SortName { get; set; }
public DateTime PremiereDate { get; set; }
public EmbyExternalurl[] ExternalUrls { get; set; }
public string Path { get; set; }
public string OfficialRating { get; set; }
public string Overview { get; set; }
public string ShortOverview { get; set; }
public object[] Taglines { get; set; }
public string[] Genres { get; set; }
public float CommunityRating { get; set; }
public int VoteCount { get; set; }
public long CumulativeRunTimeTicks { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public EmbyRemotetrailer[] RemoteTrailers { get; set; }
public EmbyProviderids ProviderIds { get; set; }
public bool IsFolder { get; set; }
public string ParentId { get; set; }
public string Type { get; set; }
public EmbyPerson[] People { get; set; }
public EmbyStudio[] Studios { get; set; }
public int LocalTrailerCount { get; set; }
public EmbyUserdata UserData { get; set; }
public int RecursiveItemCount { get; set; }
public int ChildCount { get; set; }
public string DisplayPreferencesId { get; set; }
public string Status { get; set; }
public string AirTime { get; set; }
public string[] AirDays { get; set; }
public object[] Tags { get; set; }
public object[] Keywords { get; set; }
public EmbyImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public object[] ScreenshotImageTags { get; set; }
public string LocationType { get; set; }
public string HomePageUrl { get; set; }
public object[] LockedFields { get; set; }
public bool LockData { get; set; }
}
}

View file

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyEpisodeInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbySeriesstudioinfo
{
public string Name { get; set; }
public string Id { get; set; }
}
}

View file

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MovieInformation.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Api.Models.Emby
{
public class EmbyStudio
{
public string Name { get; set; }
public string Id { get; set; }
}
}

View file

@ -49,15 +49,32 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Emby\EmbyChapter.cs" />
<Compile Include="Emby\EmbyConfiguration.cs" /> <Compile Include="Emby\EmbyConfiguration.cs" />
<Compile Include="Emby\EmbyEpisodeInformation.cs" />
<Compile Include="Emby\EmbyEpisodeItem.cs" />
<Compile Include="Emby\EmbyExternalurl.cs" />
<Compile Include="Emby\EmbyImagetags.cs" /> <Compile Include="Emby\EmbyImagetags.cs" />
<Compile Include="Emby\EmbyInformation.cs" />
<Compile Include="Emby\EmbyItem.cs" /> <Compile Include="Emby\EmbyItem.cs" />
<Compile Include="Emby\EmbyItemContainer.cs" /> <Compile Include="Emby\EmbyItemContainer.cs" />
<Compile Include="Emby\EmbyMediasource.cs" />
<Compile Include="Emby\EmbyMediastream.cs" />
<Compile Include="Emby\EmbyMediastream1.cs" />
<Compile Include="Emby\EmbyMediaType.cs" />
<Compile Include="Emby\EmbyMovieItem.cs" /> <Compile Include="Emby\EmbyMovieItem.cs" />
<Compile Include="Emby\EmbyPerson.cs" />
<Compile Include="Emby\EmbyPolicy.cs" /> <Compile Include="Emby\EmbyPolicy.cs" />
<Compile Include="Emby\EmbyProviderids.cs" />
<Compile Include="Emby\EmbyRemotetrailer.cs" />
<Compile Include="Emby\EmbyRequiredhttpheaders.cs" />
<Compile Include="Emby\EmbySeriesInformation.cs" />
<Compile Include="Emby\EmbySeriesItem.cs" /> <Compile Include="Emby\EmbySeriesItem.cs" />
<Compile Include="Emby\EmbySeriesstudioinfo.cs" />
<Compile Include="Emby\EmbyStudio.cs" />
<Compile Include="Emby\EmbyUser.cs" /> <Compile Include="Emby\EmbyUser.cs" />
<Compile Include="Emby\EmbyUserdata.cs" /> <Compile Include="Emby\EmbyUserdata.cs" />
<Compile Include="Emby\EmbyMovieInformation.cs" />
<Compile Include="Movie\CouchPotatoAdd.cs" /> <Compile Include="Movie\CouchPotatoAdd.cs" />
<Compile Include="Movie\CouchPotatoMovies.cs" /> <Compile Include="Movie\CouchPotatoMovies.cs" />
<Compile Include="Movie\CouchPotatoProfiles.cs" /> <Compile Include="Movie\CouchPotatoProfiles.cs" />

View file

@ -36,8 +36,6 @@ namespace Ombi.Api
{ {
public class EmbyApi : IEmbyApi public class EmbyApi : IEmbyApi
{ {
public string ApiKey => "4aa083121ab646bfa38aa5f7196056cf";
public EmbyApi() public EmbyApi()
{ {
Api = new ApiRequest(); Api = new ApiRequest();
@ -59,7 +57,7 @@ namespace Ombi.Api
Method = Method.GET Method = Method.GET
}; };
AddHeaders(request, ApiKey); AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetUsers for Emby, Retrying {0}", timespan), new[] { var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetUsers for Emby, Retrying {0}", timespan), new[] {
TimeSpan.FromSeconds (1), TimeSpan.FromSeconds (1),
@ -80,7 +78,7 @@ namespace Ombi.Api
}; };
request.AddUrlSegment("userId", userId); request.AddUrlSegment("userId", userId);
AddHeaders(request, ApiKey); AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling ViewLibrary for Emby, Retrying {0}", timespan), new[] { var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling ViewLibrary for Emby, Retrying {0}", timespan), new[] {
TimeSpan.FromSeconds (1), TimeSpan.FromSeconds (1),
@ -97,6 +95,58 @@ namespace Ombi.Api
return GetAll<EmbyMovieItem>("Movie", apiKey, userId, baseUri); return GetAll<EmbyMovieItem>("Movie", apiKey, userId, baseUri);
} }
public EmbyItemContainer<EmbyEpisodeItem> GetAllEpisodes(string apiKey, string userId, Uri baseUri)
{
return GetAll<EmbyEpisodeItem>("Episode", apiKey, userId, baseUri);
}
public EmbyInformation GetInformation(string mediaId, EmbyMediaType type, string apiKey, string userId, Uri baseUri)
{
var request = new RestRequest
{
Resource = "emby/users/{userId}/items/{mediaId}",
Method = Method.GET
};
request.AddUrlSegment("userId", userId);
request.AddUrlSegment("mediaId", mediaId);
AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetAll<T>({1}) for Emby, Retrying {0}", timespan, type), new[] {
TimeSpan.FromSeconds (1),
TimeSpan.FromSeconds(5)
});
switch (type)
{
case EmbyMediaType.Movie:
return new EmbyInformation
{
MovieInformation = policy.Execute(() => Api.ExecuteJson<EmbyMovieInformation>(request, baseUri))
};
case EmbyMediaType.Series:
return new EmbyInformation
{
SeriesInformation =
policy.Execute(() => Api.ExecuteJson<EmbySeriesInformation>(request, baseUri))
};
case EmbyMediaType.Music:
break;
case EmbyMediaType.Episode:
return new EmbyInformation
{
EpisodeInformation =
policy.Execute(() => Api.ExecuteJson<EmbyEpisodeInformation>(request, baseUri))
};
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
return new EmbyInformation();
}
public EmbyItemContainer<EmbySeriesItem> GetAllShows(string apiKey, string userId, Uri baseUri) public EmbyItemContainer<EmbySeriesItem> GetAllShows(string apiKey, string userId, Uri baseUri)
{ {
return GetAll<EmbySeriesItem>("Series", apiKey, userId, baseUri); return GetAll<EmbySeriesItem>("Series", apiKey, userId, baseUri);
@ -114,7 +164,7 @@ namespace Ombi.Api
request.AddQueryParameter("Recursive", true.ToString()); request.AddQueryParameter("Recursive", true.ToString());
request.AddQueryParameter("IncludeItemTypes", type); request.AddQueryParameter("IncludeItemTypes", type);
AddHeaders(request, ApiKey); AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetAll<T>({1}) for Emby, Retrying {0}", timespan, type), new[] { var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetAll<T>({1}) for Emby, Retrying {0}", timespan, type), new[] {

View file

@ -58,16 +58,20 @@ namespace Ombi.Core.Migration.Migrations
private void UpdatePlexSettings() private void UpdatePlexSettings()
{ {
#if !DEBUG
var s = PlexSettings.GetSettings(); var s = PlexSettings.GetSettings();
s.Enable = true; s.Enable = true;
PlexSettings.SaveSettings(s); PlexSettings.SaveSettings(s);
#endif
} }
private void UpdateCustomSettings() private void UpdateCustomSettings()
{ {
var settings = Customization.GetSettings(); var settings = Customization.GetSettings();
settings.NewSearch = true; // Use the new search settings.NewSearch = true; // Use the new search
Customization.SaveSettings(settings); Customization.SaveSettings(settings);
} }
} }
} }

View file

@ -47,5 +47,9 @@ namespace Ombi.Core.SettingModels
public int PlexContentCacher { get; set; } public int PlexContentCacher { get; set; }
public int PlexUserChecker { get; set; } public int PlexUserChecker { get; set; }
public int RadarrCacher { get; set; } public int RadarrCacher { get; set; }
public int EmbyEpisodeCacher { get; set; }
public int EmbyContentCacher { get; set; }
public int EmbyAvailabilityChecker { get; set; }
} }
} }

View file

@ -148,7 +148,7 @@ namespace Ombi.Services.Jobs
if (modifiedModel.Any()) if (modifiedModel.Any())
{ {
NotificationEngine.NotifyUsers(modifiedModel, embySettings.ApiKey, NotificationType.RequestAvailable); // TODO Emby //NotificationEngine.NotifyUsers(modifiedModel, embySettings.ApiKey, NotificationType.RequestAvailable); // TODO Emby
RequestService.BatchUpdate(modifiedModel); RequestService.BatchUpdate(modifiedModel);
} }
} }

View file

@ -0,0 +1,250 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: PlexAvailabilityChecker.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using Dapper;
using NLog;
using Ombi.Api.Interfaces;
using Ombi.Api.Models.Emby;
using Ombi.Core;
using Ombi.Core.SettingModels;
using Ombi.Helpers;
using Ombi.Services.Interfaces;
using Ombi.Services.Jobs.Interfaces;
using Ombi.Store.Models.Emby;
using Ombi.Store.Repository;
using Quartz;
using EmbyMediaType = Ombi.Api.Models.Emby.EmbyMediaType;
namespace Ombi.Services.Jobs
{
public class EmbyContentCacher : IJob, IEmbyContentCacher
{
public EmbyContentCacher(ISettingsService<EmbySettings> embySettings, IRequestService request, IEmbyApi emby, ICacheProvider cache,
IJobRecord rec, IRepository<EmbyEpisodes> repo,IRepository<EmbyContent> content)
{
Emby = embySettings;
RequestService = request;
EmbyApi = emby;
Cache = cache;
Job = rec;
EpisodeRepo = repo;
EmbyContent = content;
}
private ISettingsService<EmbySettings> Emby { get; }
private IRepository<EmbyEpisodes> EpisodeRepo { get; }
private IRequestService RequestService { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private IEmbyApi EmbyApi { get; }
private ICacheProvider Cache { get; }
private IJobRecord Job { get; }
private IRepository<EmbyContent> EmbyContent { get; }
public void CacheContent()
{
var embySettings = Emby.GetSettings();
if (!ValidateSettings(embySettings))
{
Log.Debug("Validation of emby settings failed.");
return;
}
CachedLibraries(embySettings);
}
public List<EmbyMovieItem> GetMovies()
{
var settings = Emby.GetSettings();
return EmbyApi.GetAllMovies(settings.ApiKey, settings.AdministratorId, settings.FullUri).Items;
}
public List<EmbySeriesItem> GetTvShows()
{
var settings = Emby.GetSettings();
return EmbyApi.GetAllShows(settings.ApiKey, settings.AdministratorId, settings.FullUri).Items;
}
private void CachedLibraries(EmbySettings embySettings)
{
if (!ValidateSettings(embySettings))
{
Log.Warn("The settings are not configured");
}
try
{
var movies = GetMovies();
foreach (var m in movies)
{
var movieInfo = EmbyApi.GetInformation(m.Id, EmbyMediaType.Movie, embySettings.ApiKey,
embySettings.AdministratorId, embySettings.FullUri).MovieInformation;
if (string.IsNullOrEmpty(movieInfo.ProviderIds.Imdb))
{
Log.Error("Provider Id on movie {0} is null", movieInfo.Name);
continue;
}
// Check if it exists
var item = EmbyContent.Custom(connection =>
{
connection.Open();
var media = connection.QueryFirstOrDefault<EmbyContent>("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { ProviderId = movieInfo.ProviderIds.Imdb, type = 0 });
connection.Dispose();
return media;
});
if (item == null)
{
// Doesn't exist, insert it
EmbyContent.Insert(new EmbyContent
{
ProviderId = movieInfo.ProviderIds.Imdb,
PremierDate = movieInfo.PremiereDate,
Title = movieInfo.Name,
Type = Store.Models.Plex.EmbyMediaType.Movie,
EmbyId = m.Id
});
}
}
var tv = GetTvShows();
foreach (var t in tv)
{
var tvInfo = EmbyApi.GetInformation(t.Id, EmbyMediaType.Series, embySettings.ApiKey,
embySettings.AdministratorId, embySettings.FullUri).SeriesInformation;
if (string.IsNullOrEmpty(tvInfo.ProviderIds?.Tvdb))
{
Log.Error("Provider Id on tv {0} is null", t.Name);
continue;
}
// Check if it exists
var item = EmbyContent.Custom(connection =>
{
connection.Open();
var media = connection.QueryFirstOrDefault<EmbyContent>("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { ProviderId = tvInfo.ProviderIds.Tvdb, type = 1 });
connection.Dispose();
return media;
});
if (item == null)
{
EmbyContent.Insert(new EmbyContent
{
ProviderId = tvInfo.ProviderIds.Tvdb,
PremierDate = tvInfo.PremiereDate,
Title = tvInfo.Name,
Type = Store.Models.Plex.EmbyMediaType.Series,
EmbyId = t.Id
});
}
}
//TODO Emby
//var albums = GetPlexAlbums(results);
//foreach (var a in albums)
//{
// if (string.IsNullOrEmpty(a.ProviderId))
// {
// Log.Error("Provider Id on album {0} is null", a.Title);
// continue;
// }
// // Check if it exists
// var item = EmbyContent.Custom(connection =>
// {
// connection.Open();
// var media = connection.QueryFirstOrDefault<PlexContent>("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { a.ProviderId, type = 2 });
// connection.Dispose();
// return media;
// });
// if (item == null)
// {
// EmbyContent.Insert(new PlexContent
// {
// ProviderId = a.ProviderId,
// ReleaseYear = a.ReleaseYear ?? string.Empty,
// Title = a.Title,
// Type = Store.Models.Plex.PlexMediaType.Artist,
// Url = a.Url
// });
// }
//}
}
catch (Exception ex)
{
Log.Error(ex, "Failed to obtain Emby libraries");
}
}
private bool ValidateSettings(EmbySettings emby)
{
if (emby.Enable)
{
if (emby?.Ip == null || string.IsNullOrEmpty(emby?.ApiKey))
{
Log.Warn("A setting is null, Ensure Emby is configured correctly, and we have a Emby Auth token.");
return false;
}
}
return emby.Enable;
}
public void Execute(IJobExecutionContext context)
{
Job.SetRunning(true, JobNames.EmbyCacher);
try
{
CacheContent();
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EmbyCacher);
Job.SetRunning(false, JobNames.EmbyCacher);
}
}
}
}

View file

@ -0,0 +1,167 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: PlexEpisodeCacher.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using Ombi.Api.Interfaces;
using Ombi.Api.Models.Emby;
using Ombi.Core;
using Ombi.Core.SettingModels;
using Ombi.Helpers;
using Ombi.Services.Interfaces;
using Ombi.Services.Jobs.Interfaces;
using Ombi.Store.Models.Emby;
using Ombi.Store.Repository;
using Quartz;
namespace Ombi.Services.Jobs
{
public class EmbyEpisodeCacher : IJob, IEmbyEpisodeCacher
{
public EmbyEpisodeCacher(ISettingsService<EmbySettings> embySettings, IEmbyApi emby, ICacheProvider cache,
IJobRecord rec, IRepository<EmbyEpisodes> repo, ISettingsService<ScheduledJobsSettings> jobs)
{
Emby = embySettings;
EmbyApi = emby;
Cache = cache;
Job = rec;
Repo = repo;
Jobs = jobs;
}
private ISettingsService<EmbySettings> Emby { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private IEmbyApi EmbyApi { get; }
private ICacheProvider Cache { get; }
private IJobRecord Job { get; }
private IRepository<EmbyEpisodes> Repo { get; }
private ISettingsService<ScheduledJobsSettings> Jobs { get; }
private const string TableName = "EmbyEpisodes";
public void CacheEpisodes(EmbySettings settings)
{
var allEpisodes = EmbyApi.GetAllEpisodes(settings.ApiKey, settings.AdministratorId, settings.FullUri);
var model = new List<EmbyEpisodes>();
foreach (var ep in allEpisodes.Items)
{
var epInfo = EmbyApi.GetInformation(ep.Id, EmbyMediaType.Episode, settings.ApiKey,
settings.AdministratorId, settings.FullUri);
model.Add(new EmbyEpisodes
{
EmbyId = ep.Id,
EpisodeNumber = ep.IndexNumber,
SeasonNumber = ep.ParentIndexNumber,
EpisodeTitle = ep.Name,
ParentId = ep.SeriesId,
ShowTitle = ep.SeriesName,
ProviderId = epInfo.EpisodeInformation.ProviderIds.Tmdb
});
}
// Delete all of the current items
Repo.DeleteAll(TableName);
// Insert the new items
var result = Repo.BatchInsert(model, TableName, typeof(EmbyEpisodes).GetPropertyNames());
if (!result)
{
Log.Error("Saving the emby episodes to the DB Failed");
}
}
public void Start()
{
try
{
var s = Emby.GetSettings();
if (!s.EnableEpisodeSearching)
{
return;
}
var jobs = Job.GetJobs();
var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EmbyEpisodeCacher, StringComparison.CurrentCultureIgnoreCase));
if (job != null)
{
if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours
{
return;
}
}
Job.SetRunning(true, JobNames.EmbyEpisodeCacher);
CacheEpisodes(s);
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EmbyEpisodeCacher);
Job.SetRunning(false, JobNames.EmbyEpisodeCacher);
}
}
public void Execute(IJobExecutionContext context)
{
try
{
var s = Emby.GetSettings();
if (!s.EnableEpisodeSearching)
{
return;
}
var jobs = Job.GetJobs();
var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EmbyEpisodeCacher, StringComparison.CurrentCultureIgnoreCase));
if (job != null)
{
if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours
{
return;
}
}
Job.SetRunning(true, JobNames.EmbyEpisodeCacher);
CacheEpisodes(s);
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EmbyEpisodeCacher);
Job.SetRunning(false, JobNames.EmbyEpisodeCacher);
}
}
}
}

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
using Ombi.Api.Models.Emby;
using Quartz;
namespace Ombi.Services.Jobs.Interfaces
{
public interface IEmbyContentCacher
{
void CacheContent();
void Execute(IJobExecutionContext context);
List<EmbyMovieItem> GetMovies();
List<EmbySeriesItem> GetTvShows();
}
}

View file

@ -0,0 +1,12 @@
using Ombi.Core.SettingModels;
using Quartz;
namespace Ombi.Services.Jobs.Interfaces
{
public interface IEmbyEpisodeCacher
{
void CacheEpisodes(EmbySettings settings);
void Execute(IJobExecutionContext context);
void Start();
}
}

View file

@ -37,9 +37,11 @@ namespace Ombi.Services.Jobs
public const string PlexChecker = "Plex Availability Cacher"; public const string PlexChecker = "Plex Availability Cacher";
public const string EmbyChecker = "Emby Availability Cacher"; public const string EmbyChecker = "Emby Availability Cacher";
public const string PlexCacher = "Plex Cacher"; public const string PlexCacher = "Plex Cacher";
public const string EmbyCacher = "Emby Cacher";
public const string StoreCleanup = "Database Cleanup"; public const string StoreCleanup = "Database Cleanup";
public const string RequestLimitReset = "Request Limit Reset"; public const string RequestLimitReset = "Request Limit Reset";
public const string EpisodeCacher = "Plex Episode Cacher"; public const string EpisodeCacher = "Plex Episode Cacher";
public const string EmbyEpisodeCacher = "Emby Episode Cacher";
public const string RecentlyAddedEmail = "Recently Added Email Notification"; public const string RecentlyAddedEmail = "Recently Added Email Notification";
public const string FaultQueueHandler = "Request Fault Queue Handler"; public const string FaultQueueHandler = "Request Fault Queue Handler";
public const string PlexUserChecker = "Plex User Checker"; public const string PlexUserChecker = "Plex User Checker";

View file

@ -93,11 +93,15 @@
<Compile Include="Interfaces\IStoreBackup.cs" /> <Compile Include="Interfaces\IStoreBackup.cs" />
<Compile Include="Interfaces\IStoreCleanup.cs" /> <Compile Include="Interfaces\IStoreCleanup.cs" />
<Compile Include="Interfaces\IUserRequestLimitResetter.cs" /> <Compile Include="Interfaces\IUserRequestLimitResetter.cs" />
<Compile Include="Jobs\IEmbyAvailabilityChecker.cs" /> <Compile Include="Jobs\Interfaces\IEmbyEpisodeCacher.cs" />
<Compile Include="Jobs\IFaultQueueHandler.cs" /> <Compile Include="Jobs\Interfaces\IEmbyContentCacher.cs" />
<Compile Include="Jobs\IPlexEpisodeCacher.cs" /> <Compile Include="Jobs\Interfaces\IEmbyAvailabilityChecker.cs" />
<Compile Include="Jobs\IPlexUserChecker.cs" /> <Compile Include="Jobs\Interfaces\IFaultQueueHandler.cs" />
<Compile Include="Jobs\Interfaces\IPlexEpisodeCacher.cs" />
<Compile Include="Jobs\Interfaces\IPlexUserChecker.cs" />
<Compile Include="Jobs\EmbyAvailabilityChecker.cs" /> <Compile Include="Jobs\EmbyAvailabilityChecker.cs" />
<Compile Include="Jobs\EmbyContentCacher.cs" />
<Compile Include="Jobs\EmbyEpisodeCacher.cs" />
<Compile Include="Jobs\RadarrCacher.cs" /> <Compile Include="Jobs\RadarrCacher.cs" />
<Compile Include="Jobs\WatcherCacher.cs" /> <Compile Include="Jobs\WatcherCacher.cs" />
<Compile Include="Jobs\HtmlTemplateGenerator.cs" /> <Compile Include="Jobs\HtmlTemplateGenerator.cs" />

View file

@ -49,7 +49,7 @@
<button ng-click="updateUser()" class="btn btn-primary-outline">Update</button> <button ng-click="updateUser()" class="btn btn-primary-outline">Update</button>
<button ng-click="deleteUser()" class="btn btn-danger-outline">Delete</button> <button ng-show="selectedUser.type == 1" ng-click="deleteUser()" class="btn btn-danger-outline">Delete</button>
<button ng-click="closeSidebarClick()" style="float: right; margin-right: 10px;" class="btn btn-danger-outline">Close</button> <button ng-click="closeSidebarClick()" style="float: right; margin-right: 10px;" class="btn btn-danger-outline">Close</button>
</div> </div>
</div> </div>

View file

@ -55,9 +55,6 @@ namespace Ombi.UI.Jobs
private IEnumerable<IJobDetail> CreateJobs() private IEnumerable<IJobDetail> CreateJobs()
{ {
var settingsService = Service.Resolve<ISettingsService<ScheduledJobsSettings>>();
var s = settingsService.GetSettings();
var jobs = new List<IJobDetail>(); var jobs = new List<IJobDetail>();
var jobList = new List<IJobDetail> var jobList = new List<IJobDetail>
@ -76,6 +73,11 @@ namespace Ombi.UI.Jobs
JobBuilder.Create<RecentlyAdded>().WithIdentity("RecentlyAddedModel", "Email").Build(), JobBuilder.Create<RecentlyAdded>().WithIdentity("RecentlyAddedModel", "Email").Build(),
JobBuilder.Create<FaultQueueHandler>().WithIdentity("FaultQueueHandler", "Fault").Build(), JobBuilder.Create<FaultQueueHandler>().WithIdentity("FaultQueueHandler", "Fault").Build(),
JobBuilder.Create<RadarrCacher>().WithIdentity("RadarrCacher", "Cache").Build(), JobBuilder.Create<RadarrCacher>().WithIdentity("RadarrCacher", "Cache").Build(),
JobBuilder.Create<EmbyEpisodeCacher>().WithIdentity("EmbyEpisodeCacher", "Emby").Build(),
JobBuilder.Create<EmbyAvailabilityChecker>().WithIdentity("EmbyAvailabilityChecker", "Emby").Build(),
JobBuilder.Create<EmbyContentCacher>().WithIdentity("EmbyContentCacher", "Emby").Build(),
}; };
jobs.AddRange(jobList); jobs.AddRange(jobList);
@ -175,6 +177,18 @@ namespace Ombi.UI.Jobs
{ {
s.RadarrCacher = 60; s.RadarrCacher = 60;
} }
if (s.EmbyContentCacher == 0)
{
s.EmbyContentCacher = 60;
}
if (s.EmbyAvailabilityChecker == 0)
{
s.EmbyAvailabilityChecker = 60;
}
if (s.EmbyEpisodeCacher == 0)
{
s.EmbyEpisodeCacher = 11;
}
var triggers = new List<ITrigger>(); var triggers = new List<ITrigger>();
@ -280,6 +294,30 @@ namespace Ombi.UI.Jobs
.WithSimpleSchedule(x => x.WithIntervalInHours(s.FaultQueueHandler).RepeatForever()) .WithSimpleSchedule(x => x.WithIntervalInHours(s.FaultQueueHandler).RepeatForever())
.Build(); .Build();
//Emby
var embyEpisode =
TriggerBuilder.Create()
.WithIdentity("EmbyEpisodeCacher", "Emby")
//.StartAt(DateBuilder.FutureDate(10, IntervalUnit.Minute))
.StartAt(DateBuilder.FutureDate(10, IntervalUnit.Minute))
.WithSimpleSchedule(x => x.WithIntervalInHours(s.EmbyEpisodeCacher).RepeatForever())
.Build();
var embyContentCacher =
TriggerBuilder.Create()
.WithIdentity("EmbyContentCacher", "Emby")
.StartNow()
.WithSimpleSchedule(x => x.WithIntervalInHours(s.EmbyContentCacher).RepeatForever())
.Build();
var embyAvailabilityChecker =
TriggerBuilder.Create()
.WithIdentity("EmbyAvailabilityChecker", "Emby")
.StartAt(DateBuilder.FutureDate(5, IntervalUnit.Minute))
.WithSimpleSchedule(x => x.WithIntervalInHours(s.EmbyAvailabilityChecker).RepeatForever())
.Build();
triggers.Add(rencentlyAdded); triggers.Add(rencentlyAdded);
triggers.Add(plexAvailabilityChecker); triggers.Add(plexAvailabilityChecker);
triggers.Add(srCacher); triggers.Add(srCacher);
@ -294,6 +332,9 @@ namespace Ombi.UI.Jobs
triggers.Add(plexCacher); triggers.Add(plexCacher);
triggers.Add(plexUserChecker); triggers.Add(plexUserChecker);
triggers.Add(radarrCacher); triggers.Add(radarrCacher);
triggers.Add(embyEpisode);
triggers.Add(embyAvailabilityChecker);
triggers.Add(embyContentCacher);
return triggers; return triggers;
} }

View file

@ -447,11 +447,19 @@ namespace Ombi.UI.Modules.Admin
return Response.AsJson(valid.SendJsonError()); return Response.AsJson(valid.SendJsonError());
} }
var embySettings = await EmbySettings.GetSettingsAsync();
if (plexSettings.Enable)
if (embySettings.Enable)
{ {
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Emby is enabled, we cannot enable Plex and Emby" }); var embySettings = await EmbySettings.GetSettingsAsync();
if (embySettings.Enable)
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = "Emby is enabled, we cannot enable Plex and Emby"
});
}
} }
if (string.IsNullOrEmpty(plexSettings.MachineIdentifier)) if (string.IsNullOrEmpty(plexSettings.MachineIdentifier))
@ -485,10 +493,18 @@ namespace Ombi.UI.Modules.Admin
return Response.AsJson(valid.SendJsonError()); return Response.AsJson(valid.SendJsonError());
} }
var plexSettings = await PlexService.GetSettingsAsync(); if (emby.Enable)
if (plexSettings.Enable)
{ {
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Plex is enabled, we cannot enable Plex and Emby" }); var plexSettings = await PlexService.GetSettingsAsync();
if (plexSettings.Enable)
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = "Plex is enabled, we cannot enable Plex and Emby"
});
}
} }
// Get the users // Get the users

View file

@ -33,6 +33,7 @@ using Ombi.Core.SettingModels;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Services.Interfaces; using Ombi.Services.Interfaces;
using Ombi.Services.Jobs; using Ombi.Services.Jobs;
using Ombi.Services.Jobs.Interfaces;
using Ombi.UI.Models; using Ombi.UI.Models;
using ISecurityExtensions = Ombi.Core.ISecurityExtensions; using ISecurityExtensions = Ombi.Core.ISecurityExtensions;
@ -44,7 +45,8 @@ namespace Ombi.UI.Modules.Admin
ISecurityExtensions security, IPlexContentCacher contentCacher, ISonarrCacher sonarrCacher, IWatcherCacher watcherCacher, ISecurityExtensions security, IPlexContentCacher contentCacher, ISonarrCacher sonarrCacher, IWatcherCacher watcherCacher,
IRadarrCacher radarrCacher, ICouchPotatoCacher cpCacher, IStoreBackup store, ISickRageCacher srCacher, IAvailabilityChecker plexChceker, IRadarrCacher radarrCacher, ICouchPotatoCacher cpCacher, IStoreBackup store, ISickRageCacher srCacher, IAvailabilityChecker plexChceker,
IStoreCleanup cleanup, IUserRequestLimitResetter requestLimit, IPlexEpisodeCacher episodeCacher, IRecentlyAdded recentlyAdded, IStoreCleanup cleanup, IUserRequestLimitResetter requestLimit, IPlexEpisodeCacher episodeCacher, IRecentlyAdded recentlyAdded,
IFaultQueueHandler faultQueueHandler, IPlexUserChecker plexUserChecker) : base("admin", settingsService, security) IFaultQueueHandler faultQueueHandler, IPlexUserChecker plexUserChecker, IEmbyAvailabilityChecker embyAvailabilityChecker, IEmbyEpisodeCacher embyEpisode,
IEmbyContentCacher embyContentCacher) : base("admin", settingsService, security)
{ {
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx); Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
@ -62,6 +64,9 @@ namespace Ombi.UI.Modules.Admin
RecentlyAdded = recentlyAdded; RecentlyAdded = recentlyAdded;
FaultQueueHandler = faultQueueHandler; FaultQueueHandler = faultQueueHandler;
PlexUserChecker = plexUserChecker; PlexUserChecker = plexUserChecker;
EmbyAvailabilityChecker = embyAvailabilityChecker;
EmbyContentCacher = embyContentCacher;
EmbyEpisodeCacher = embyEpisode;
Post["/schedulerun", true] = async (x, ct) => await ScheduleRun((string)Request.Form.key); Post["/schedulerun", true] = async (x, ct) => await ScheduleRun((string)Request.Form.key);
} }
@ -80,6 +85,9 @@ namespace Ombi.UI.Modules.Admin
private IRecentlyAdded RecentlyAdded { get; } private IRecentlyAdded RecentlyAdded { get; }
private IFaultQueueHandler FaultQueueHandler { get; } private IFaultQueueHandler FaultQueueHandler { get; }
private IPlexUserChecker PlexUserChecker { get; } private IPlexUserChecker PlexUserChecker { get; }
private IEmbyAvailabilityChecker EmbyAvailabilityChecker { get; }
private IEmbyContentCacher EmbyContentCacher { get; }
private IEmbyEpisodeCacher EmbyEpisodeCacher { get; }
private async Task<Response> ScheduleRun(string key) private async Task<Response> ScheduleRun(string key)
@ -142,6 +150,18 @@ namespace Ombi.UI.Modules.Admin
{ {
RequestLimit.Start(); RequestLimit.Start();
} }
if (key.Equals(JobNames.EmbyEpisodeCacher, StringComparison.CurrentCultureIgnoreCase))
{
EmbyEpisodeCacher.Start();
}
if (key.Equals(JobNames.EmbyCacher, StringComparison.CurrentCultureIgnoreCase))
{
EmbyContentCacher.CacheContent();
}
if (key.Equals(JobNames.EmbyChecker, StringComparison.CurrentCultureIgnoreCase))
{
EmbyAvailabilityChecker.CheckAndUpdateAll();
}
return Response.AsJson(new JsonResponseModel { Result = true }); return Response.AsJson(new JsonResponseModel { Result = true });

View file

@ -50,9 +50,11 @@ using Ombi.Helpers;
using Ombi.Helpers.Analytics; using Ombi.Helpers.Analytics;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Services.Interfaces; using Ombi.Services.Interfaces;
using Ombi.Services.Jobs;
using Ombi.Services.Notification; using Ombi.Services.Notification;
using Ombi.Store; using Ombi.Store;
using Ombi.Store.Models; using Ombi.Store.Models;
using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex; using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.UI.Helpers; using Ombi.UI.Helpers;
@ -68,7 +70,7 @@ namespace Ombi.UI.Modules
public class SearchModule : BaseAuthModule public class SearchModule : BaseAuthModule
{ {
public SearchModule(ICacheProvider cache, public SearchModule(ICacheProvider cache,
ISettingsService<PlexRequestSettings> prSettings, IAvailabilityChecker checker, ISettingsService<PlexRequestSettings> prSettings, IAvailabilityChecker plexChecker,
IRequestService request, ISonarrApi sonarrApi, ISettingsService<SonarrSettings> sonarrSettings, IRequestService request, ISonarrApi sonarrApi, ISettingsService<SonarrSettings> sonarrSettings,
ISettingsService<SickRageSettings> sickRageService, ISickRageApi srApi, ISettingsService<SickRageSettings> sickRageService, ISickRageApi srApi,
INotificationService notify, IMusicBrainzApi mbApi, IHeadphonesApi hpApi, INotificationService notify, IMusicBrainzApi mbApi, IHeadphonesApi hpApi,
@ -77,7 +79,8 @@ namespace Ombi.UI.Modules
ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth, ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth,
IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email, IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email,
IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content, IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content,
ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi, ISettingsService<CustomizationSettings> cus) ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi, ISettingsService<CustomizationSettings> cus,
IEmbyAvailabilityChecker embyChecker, IRepository<EmbyContent> embyContent, ISettingsService<EmbySettings> embySettings)
: base("search", prSettings, security) : base("search", prSettings, security)
{ {
Auth = auth; Auth = auth;
@ -86,7 +89,7 @@ namespace Ombi.UI.Modules
PrService = prSettings; PrService = prSettings;
MovieApi = new TheMovieDbApi(); MovieApi = new TheMovieDbApi();
Cache = cache; Cache = cache;
Checker = checker; PlexChecker = plexChecker;
CpCacher = cpCacher; CpCacher = cpCacher;
SonarrCacher = sonarrCacher; SonarrCacher = sonarrCacher;
SickRageCacher = sickRageCacher; SickRageCacher = sickRageCacher;
@ -112,6 +115,9 @@ namespace Ombi.UI.Modules
RadarrCacher = radarrCacher; RadarrCacher = radarrCacher;
TraktApi = traktApi; TraktApi = traktApi;
CustomizationSettings = cus; CustomizationSettings = cus;
EmbyChecker = embyChecker;
EmbyContentRepository = embyContent;
EmbySettings = embySettings;
Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad(); Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad();
@ -143,6 +149,7 @@ namespace Ombi.UI.Modules
private IWatcherCacher WatcherCacher { get; } private IWatcherCacher WatcherCacher { get; }
private IMovieSender MovieSender { get; } private IMovieSender MovieSender { get; }
private IRepository<PlexContent> PlexContentRepository { get; } private IRepository<PlexContent> PlexContentRepository { get; }
private IRepository<EmbyContent> EmbyContentRepository { get; }
private TvMazeApi TvApi { get; } private TvMazeApi TvApi { get; }
private IPlexApi PlexApi { get; } private IPlexApi PlexApi { get; }
private TheMovieDbApi MovieApi { get; } private TheMovieDbApi MovieApi { get; }
@ -152,13 +159,15 @@ namespace Ombi.UI.Modules
private IRequestService RequestService { get; } private IRequestService RequestService { get; }
private ICacheProvider Cache { get; } private ICacheProvider Cache { get; }
private ISettingsService<AuthenticationSettings> Auth { get; } private ISettingsService<AuthenticationSettings> Auth { get; }
private ISettingsService<EmbySettings> EmbySettings { get; }
private ISettingsService<PlexSettings> PlexService { get; } private ISettingsService<PlexSettings> PlexService { get; }
private ISettingsService<PlexRequestSettings> PrService { get; } private ISettingsService<PlexRequestSettings> PrService { get; }
private ISettingsService<SonarrSettings> SonarrService { get; } private ISettingsService<SonarrSettings> SonarrService { get; }
private ISettingsService<SickRageSettings> SickRageService { get; } private ISettingsService<SickRageSettings> SickRageService { get; }
private ISettingsService<HeadphonesSettings> HeadphonesService { get; } private ISettingsService<HeadphonesSettings> HeadphonesService { get; }
private ISettingsService<EmailNotificationSettings> EmailNotificationSettings { get; } private ISettingsService<EmailNotificationSettings> EmailNotificationSettings { get; }
private IAvailabilityChecker Checker { get; } private IAvailabilityChecker PlexChecker { get; }
private IEmbyAvailabilityChecker EmbyChecker { get; }
private ICouchPotatoCacher CpCacher { get; } private ICouchPotatoCacher CpCacher { get; }
private ISonarrCacher SonarrCacher { get; } private ISonarrCacher SonarrCacher { get; }
private ISickRageCacher SickRageCacher { get; } private ISickRageCacher SickRageCacher { get; }
@ -269,8 +278,7 @@ namespace Ombi.UI.Modules
var cpCached = CpCacher.QueuedIds(); var cpCached = CpCacher.QueuedIds();
var watcherCached = WatcherCacher.QueuedIds(); var watcherCached = WatcherCacher.QueuedIds();
var radarrCached = RadarrCacher.QueuedIds(); var radarrCached = RadarrCacher.QueuedIds();
var content = PlexContentRepository.GetAll();
var plexMovies = Checker.GetPlexMovies(content);
var viewMovies = new List<SearchMovieViewModel>(); var viewMovies = new List<SearchMovieViewModel>();
var counter = 0; var counter = 0;
foreach (var movie in apiMovies) foreach (var movie in apiMovies)
@ -292,8 +300,7 @@ namespace Ombi.UI.Modules
VoteAverage = movie.VoteAverage, VoteAverage = movie.VoteAverage,
VoteCount = movie.VoteCount VoteCount = movie.VoteCount
}; };
var imdbId = string.Empty;
if (counter <= 5) // Let's only do it for the first 5 items if (counter <= 5) // Let's only do it for the first 5 items
{ {
var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id); var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id);
@ -313,14 +320,35 @@ namespace Ombi.UI.Modules
counter++; counter++;
} }
var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies); var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies);
var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString(),
imdbId); var plexSettings = await PlexService.GetSettingsAsync();
if (plexMovie != null) var embySettings = await EmbySettings.GetSettingsAsync();
if (plexSettings.Enable)
{ {
viewMovie.Available = true; var content = PlexContentRepository.GetAll();
viewMovie.PlexUrl = plexMovie.Url; var plexMovies = PlexChecker.GetPlexMovies(content);
var plexMovie = PlexChecker.GetMovie(plexMovies.ToArray(), movie.Title,
movie.ReleaseDate?.Year.ToString(),
viewMovie.ImdbId);
if (plexMovie != null)
{
viewMovie.Available = true;
viewMovie.PlexUrl = plexMovie.Url;
}
}
if (embySettings.Enable)
{
var embyContent = EmbyContentRepository.GetAll();
var embyMovies = EmbyChecker.GetEmbyMovies(embyContent);
var embyMovie = EmbyChecker.GetMovie(embyMovies.ToArray(), movie.Title,
movie.ReleaseDate?.Year.ToString(), viewMovie.ImdbId);
if (embyMovie != null)
{
viewMovie.Available = true;
}
} }
else if (dbMovies.ContainsKey(movie.Id) && canSee) // compare to the requests db else if (dbMovies.ContainsKey(movie.Id) && canSee) // compare to the requests db
{ {
@ -335,7 +363,7 @@ namespace Ombi.UI.Modules
viewMovie.Approved = true; viewMovie.Approved = true;
viewMovie.Requested = true; viewMovie.Requested = true;
} }
else if(watcherCached.Contains(imdbId) && canSee) // compare to the watcher db else if (watcherCached.Contains(viewMovie.ImdbId) && canSee) // compare to the watcher db
{ {
viewMovie.Approved = true; viewMovie.Approved = true;
viewMovie.Requested = true; viewMovie.Requested = true;
@ -507,7 +535,7 @@ namespace Ombi.UI.Modules
var sonarrCached = SonarrCacher.QueuedIds().ToList(); var sonarrCached = SonarrCacher.QueuedIds().ToList();
var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays
var content = PlexContentRepository.GetAll(); var content = PlexContentRepository.GetAll();
var plexTvShows = Checker.GetPlexTvShows(content).ToList(); var plexTvShows = PlexChecker.GetPlexTvShows(content).ToList();
foreach (var show in shows) foreach (var show in shows)
{ {
@ -516,7 +544,7 @@ namespace Ombi.UI.Modules
providerId = show.Id.ToString(); providerId = show.Id.ToString();
} }
var plexShow = Checker.GetTvShow(plexTvShows.ToArray(), show.SeriesName, show.FirstAired?.Substring(0, 4), var plexShow = PlexChecker.GetTvShow(plexTvShows.ToArray(), show.SeriesName, show.FirstAired?.Substring(0, 4),
providerId); providerId);
if (plexShow != null) if (plexShow != null)
{ {
@ -571,7 +599,7 @@ namespace Ombi.UI.Modules
var sonarrCached = SonarrCacher.QueuedIds(); var sonarrCached = SonarrCacher.QueuedIds();
var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays
var content = PlexContentRepository.GetAll(); var content = PlexContentRepository.GetAll();
var plexTvShows = Checker.GetPlexTvShows(content); var plexTvShows = PlexChecker.GetPlexTvShows(content);
var viewTv = new List<SearchTvShowViewModel>(); var viewTv = new List<SearchTvShowViewModel>();
foreach (var t in apiTv) foreach (var t in apiTv)
@ -611,7 +639,7 @@ namespace Ombi.UI.Modules
providerId = viewT.Id.ToString(); providerId = viewT.Id.ToString();
} }
var plexShow = Checker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), var plexShow = PlexChecker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4),
providerId); providerId);
if (plexShow != null) if (plexShow != null)
{ {
@ -658,7 +686,7 @@ namespace Ombi.UI.Modules
var dbAlbum = allResults.ToDictionary(x => x.MusicBrainzId); var dbAlbum = allResults.ToDictionary(x => x.MusicBrainzId);
var content = PlexContentRepository.GetAll(); var content = PlexContentRepository.GetAll();
var plexAlbums = Checker.GetPlexAlbums(content); var plexAlbums = PlexChecker.GetPlexAlbums(content);
var viewAlbum = new List<SearchMusicViewModel>(); var viewAlbum = new List<SearchMusicViewModel>();
foreach (var a in apiAlbums) foreach (var a in apiAlbums)
@ -678,7 +706,7 @@ namespace Ombi.UI.Modules
DateTime release; DateTime release;
DateTimeHelper.CustomParse(a.ReleaseEvents?.FirstOrDefault()?.date, out release); DateTimeHelper.CustomParse(a.ReleaseEvents?.FirstOrDefault()?.date, out release);
var artist = a.ArtistCredit?.FirstOrDefault()?.artist; var artist = a.ArtistCredit?.FirstOrDefault()?.artist;
var plexAlbum = Checker.GetAlbum(plexAlbums.ToArray(), a.title, release.ToString("yyyy"), artist?.name); var plexAlbum = PlexChecker.GetAlbum(plexAlbums.ToArray(), a.title, release.ToString("yyyy"), artist?.name);
if (plexAlbum != null) if (plexAlbum != null)
{ {
viewA.Available = true; viewA.Available = true;
@ -760,8 +788,8 @@ namespace Ombi.UI.Modules
{ {
var content = PlexContentRepository.GetAll(); var content = PlexContentRepository.GetAll();
var movies = Checker.GetPlexMovies(content); var movies = PlexChecker.GetPlexMovies(content);
if (Checker.IsMovieAvailable(movies.ToArray(), movieInfo.Title, movieInfo.ReleaseDate?.Year.ToString())) if (PlexChecker.IsMovieAvailable(movies.ToArray(), movieInfo.Title, movieInfo.ReleaseDate?.Year.ToString()))
{ {
return return
Response.AsJson(new JsonResponseModel Response.AsJson(new JsonResponseModel
@ -1043,68 +1071,137 @@ namespace Ombi.UI.Modules
try try
{ {
var content = PlexContentRepository.GetAll();
var shows = Checker.GetPlexTvShows(content);
var providerId = string.Empty;
var plexSettings = await PlexService.GetSettingsAsync(); var plexSettings = await PlexService.GetSettingsAsync();
if (plexSettings.AdvancedSearch) if (plexSettings.Enable)
{ {
providerId = showId.ToString(); var content = PlexContentRepository.GetAll();
} var shows = PlexChecker.GetPlexTvShows(content);
if (episodeRequest)
{
var cachedEpisodesTask = await Checker.GetEpisodes();
var cachedEpisodes = cachedEpisodesTask.ToList();
foreach (var d in difference) // difference is from an existing request
{
if (
cachedEpisodes.Any(
x =>
x.SeasonNumber == d.SeasonNumber && x.EpisodeNumber == d.EpisodeNumber &&
x.ProviderId == providerId))
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message =
$"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}"
});
}
}
var diff = await GetEpisodeRequestDifference(showId, model); var providerId = string.Empty;
model.Episodes = diff.ToList(); if (plexSettings.AdvancedSearch)
}
else
{
if (plexSettings.EnableTvEpisodeSearching)
{ {
foreach (var s in showInfo.Season) providerId = showId.ToString();
}
if (episodeRequest)
{
var cachedEpisodesTask = await PlexChecker.GetEpisodes();
var cachedEpisodes = cachedEpisodesTask.ToList();
foreach (var d in difference) // difference is from an existing request
{ {
var result = Checker.IsEpisodeAvailable(showId.ToString(), s.SeasonNumber, s.EpisodeNumber); if (
if (result) cachedEpisodes.Any(
x =>
x.SeasonNumber == d.SeasonNumber && x.EpisodeNumber == d.EpisodeNumber &&
x.ProviderId == providerId))
{ {
return return
Response.AsJson(new JsonResponseModel Response.AsJson(new JsonResponseModel
{ {
Result = false, Result = false,
Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}" Message =
$"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}"
}); });
} }
} }
var diff = await GetEpisodeRequestDifference(showId, model);
model.Episodes = diff.ToList();
} }
else if (Checker.IsTvShowAvailable(shows.ToArray(), showInfo.name, showInfo.premiered?.Substring(0, 4), else
providerId, model.SeasonList))
{ {
return if (plexSettings.EnableTvEpisodeSearching)
Response.AsJson(new JsonResponseModel {
foreach (var s in showInfo.Season)
{ {
Result = false, var result = PlexChecker.IsEpisodeAvailable(showId.ToString(), s.SeasonNumber,
Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}" s.EpisodeNumber);
}); if (result)
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}"
});
}
}
}
else if (PlexChecker.IsTvShowAvailable(shows.ToArray(), showInfo.name,
showInfo.premiered?.Substring(0, 4),
providerId, model.SeasonList))
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}"
});
}
} }
} }
var embySettings = await EmbySettings.GetSettingsAsync();
if (embySettings.Enable)
{
var embyContent = EmbyContentRepository.GetAll();
var embyMovies = EmbyChecker.GetEmbyTvShows(embyContent);
var providerId = showId.ToString();
if (episodeRequest)
{
var cachedEpisodesTask = await EmbyChecker.GetEpisodes();
var cachedEpisodes = cachedEpisodesTask.ToList();
foreach (var d in difference) // difference is from an existing request
{
if (
cachedEpisodes.Any(
x =>
x.SeasonNumber == d.SeasonNumber && x.EpisodeNumber == d.EpisodeNumber &&
x.ProviderId == providerId))
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message =
$"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}"
});
}
}
var diff = await GetEpisodeRequestDifference(showId, model);
model.Episodes = diff.ToList();
}
else
{
if (embySettings.EnableEpisodeSearching)
{
foreach (var s in showInfo.Season)
{
var result = EmbyChecker.IsEpisodeAvailable(showId.ToString(), s.SeasonNumber,
s.EpisodeNumber);
if (result)
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = $"{fullShowName} is already in Emby!"
});
}
}
}
else if (EmbyChecker.IsTvShowAvailable(embyMovies.ToArray(), showInfo.name,
showInfo.premiered?.Substring(0, 4),
providerId, model.SeasonList))
{
return
Response.AsJson(new JsonResponseModel
{
Result = false,
Message = $"{fullShowName} is already in Emby!"
});
}
}
}
} }
catch (Exception) catch (Exception)
{ {
@ -1261,8 +1358,8 @@ namespace Ombi.UI.Modules
var content = PlexContentRepository.GetAll(); var content = PlexContentRepository.GetAll();
var albums = Checker.GetPlexAlbums(content); var albums = PlexChecker.GetPlexAlbums(content);
var alreadyInPlex = Checker.IsAlbumAvailable(albums.ToArray(), albumInfo.title, release.ToString("yyyy"), var alreadyInPlex = PlexChecker.IsAlbumAvailable(albums.ToArray(), albumInfo.title, release.ToString("yyyy"),
artist.name); artist.name);
if (alreadyInPlex) if (alreadyInPlex)
@ -1390,7 +1487,8 @@ namespace Ombi.UI.Modules
var existingRequest = requests.FirstOrDefault(x => x.Type == RequestType.TvShow && x.TvDbId == providerId.ToString()); var existingRequest = requests.FirstOrDefault(x => x.Type == RequestType.TvShow && x.TvDbId == providerId.ToString());
var show = await Task.Run(() => TvApi.ShowLookupByTheTvDbId(providerId)); var show = await Task.Run(() => TvApi.ShowLookupByTheTvDbId(providerId));
var tvMaxeEpisodes = await Task.Run(() => TvApi.EpisodeLookup(show.id)); var tvMazeEpisodesTask = await Task.Run(() => TvApi.EpisodeLookup(show.id));
var tvMazeEpisodes = tvMazeEpisodesTask.ToList();
var sonarrEpisodes = new List<SonarrEpisodes>(); var sonarrEpisodes = new List<SonarrEpisodes>();
if (sonarrEnabled) if (sonarrEnabled)
@ -1400,26 +1498,59 @@ namespace Ombi.UI.Modules
sonarrEpisodes = sonarrEp?.ToList() ?? new List<SonarrEpisodes>(); sonarrEpisodes = sonarrEp?.ToList() ?? new List<SonarrEpisodes>();
} }
var plexCacheTask = await Checker.GetEpisodes(providerId); var plexSettings = await PlexService.GetSettingsAsync();
var plexCache = plexCacheTask.ToList(); if (plexSettings.Enable)
foreach (var ep in tvMaxeEpisodes)
{ {
var requested = existingRequest?.Episodes var plexCacheTask = await PlexChecker.GetEpisodes(providerId);
.Any(episodesModel => var plexCache = plexCacheTask.ToList();
ep.number == episodesModel.EpisodeNumber && ep.season == episodesModel.SeasonNumber) ?? false; foreach (var ep in tvMazeEpisodes)
var alreadyInPlex = plexCache.Any(x => x.EpisodeNumber == ep.number && x.SeasonNumber == ep.season);
var inSonarr = sonarrEpisodes.Any(x => x.seasonNumber == ep.season && x.episodeNumber == ep.number && x.hasFile);
model.Add(new EpisodeListViewModel
{ {
Id = show.id, var requested = existingRequest?.Episodes
SeasonNumber = ep.season, .Any(episodesModel =>
EpisodeNumber = ep.number, ep.number == episodesModel.EpisodeNumber &&
Requested = requested || alreadyInPlex || inSonarr, ep.season == episodesModel.SeasonNumber) ?? false;
Name = ep.name,
EpisodeId = ep.id var alreadyInPlex = plexCache.Any(x => x.EpisodeNumber == ep.number && x.SeasonNumber == ep.season);
}); var inSonarr =
sonarrEpisodes.Any(x => x.seasonNumber == ep.season && x.episodeNumber == ep.number && x.hasFile);
model.Add(new EpisodeListViewModel
{
Id = show.id,
SeasonNumber = ep.season,
EpisodeNumber = ep.number,
Requested = requested || alreadyInPlex || inSonarr,
Name = ep.name,
EpisodeId = ep.id
});
}
}
var embySettings = await EmbySettings.GetSettingsAsync();
if (embySettings.Enable)
{
var embyCacheTask = await EmbyChecker.GetEpisodes(providerId);
var cache = embyCacheTask.ToList();
foreach (var ep in tvMazeEpisodes)
{
var requested = existingRequest?.Episodes
.Any(episodesModel =>
ep.number == episodesModel.EpisodeNumber &&
ep.season == episodesModel.SeasonNumber) ?? false;
var alreadyInEmby = cache.Any(x => x.EpisodeNumber == ep.number && x.SeasonNumber == ep.season);
var inSonarr =
sonarrEpisodes.Any(x => x.seasonNumber == ep.season && x.episodeNumber == ep.number && x.hasFile);
model.Add(new EpisodeListViewModel
{
Id = show.id,
SeasonNumber = ep.season,
EpisodeNumber = ep.number,
Requested = requested || alreadyInEmby || inSonarr,
Name = ep.name,
EpisodeId = ep.id
});
}
} }
return model; return model;
@ -1651,3 +1782,4 @@ namespace Ombi.UI.Modules
} }
} }
} }

View file

@ -31,6 +31,7 @@ using Ombi.Core.Queue;
using Ombi.Helpers.Analytics; using Ombi.Helpers.Analytics;
using Ombi.Services.Interfaces; using Ombi.Services.Interfaces;
using Ombi.Services.Jobs; using Ombi.Services.Jobs;
using Ombi.Services.Jobs.Interfaces;
using Ombi.UI.Jobs; using Ombi.UI.Jobs;
using Quartz; using Quartz;
using Quartz.Impl; using Quartz.Impl;
@ -60,6 +61,8 @@ namespace Ombi.UI.NinjectModules
Bind<IPlexUserChecker>().To<PlexUserChecker>(); Bind<IPlexUserChecker>().To<PlexUserChecker>();
Bind<IEmbyAvailabilityChecker>().To<EmbyAvailabilityChecker>(); Bind<IEmbyAvailabilityChecker>().To<EmbyAvailabilityChecker>();
Bind<IEmbyContentCacher>().To<EmbyContentCacher>();
Bind<IEmbyEpisodeCacher>().To<EmbyEpisodeCacher>();
Bind<IAnalytics>().To<Analytics>(); Bind<IAnalytics>().To<Analytics>();

View file

@ -161,7 +161,7 @@
<div class="col-md-7 col-xs-7"> <div class="col-md-7 col-xs-7">
{{#if available}} {{#if available}}
<span class="label label-success">@UI.Search_Available_on_plex</span> <span class="label label-success">@UI.Search_Available</span>
{{else}} {{else}}
{{#if approved}} {{#if approved}}
<span class="label label-info">@UI.Search_Processing_Request</span> <span class="label label-info">@UI.Search_Processing_Request</span>
@ -207,7 +207,9 @@
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button> <button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button>
<br /> <br />
<br /> <br />
{{#if url}}
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a> <a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{/if}}
{{else}} {{else}}
{{#if_eq requested true}} {{#if_eq requested true}}
<button style="text-align: right" class="btn btn-primary-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button> <button style="text-align: right" class="btn btn-primary-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>
@ -325,7 +327,7 @@
<span class="label label-info" target="_blank">Release Date: {{releaseDate}}</span> <span class="label label-info" target="_blank">Release Date: {{releaseDate}}</span>
{{/if}} {{/if}}
{{#if available}} {{#if available}}
<span class="label label-success">@UI.Search_Available_on_plex</span> <span class="label label-success">@UI.Search_Available</span>
{{else}} {{else}}
{{#if approved}} {{#if approved}}
<span class="label label-info">@UI.Search_Processing_Request</span> <span class="label label-info">@UI.Search_Processing_Request</span>
@ -357,9 +359,11 @@
{{#if_eq type "movie"}} {{#if_eq type "movie"}}
{{#if_eq available true}} {{#if_eq available true}}
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button> <button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button>
{{#if url}}
<br /> <br />
<br /> <br />
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a> <a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{/if}}
{{else}} {{else}}
{{#if_eq requested true}} {{#if_eq requested true}}
<button style="text-align: right" class="btn btn-primary-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button> <button style="text-align: right" class="btn btn-primary-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>
@ -396,9 +400,11 @@
</div> </div>
{{/if_eq}} {{/if_eq}}
{{#if available}} {{#if available}}
{{#if url}}
<br /> <br />
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a> <a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{/if}} {{/if}}
{{/if}}
{{/if_eq}} {{/if_eq}}
{{/if_eq}} {{/if_eq}}
@ -432,7 +438,7 @@
<!-- Music Results template --> <!-- Music Results template -->
<script id="music-template" type="text/x-handlebars-template"> <script id="music-template" type="text/x-handlebars-template">
<div class="row"> <div class="row">
<div id="{{id}}imageDiv" class="col-sm-2"> <div id="{{id}}imageDiv" class="col-sm-2">
{{#if coverArtUrl}} {{#if coverArtUrl}}
@ -458,7 +464,9 @@
<input name="{{type}}Id" type="text" value="{{id}}" hidden="hidden" /> <input name="{{type}}Id" type="text" value="{{id}}" hidden="hidden" />
{{#if_eq available true}} {{#if_eq available true}}
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br /> <button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br />
{{#if url}}
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a> <a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{/if}}
{{else}} {{else}}
{{#if_eq requested true}} {{#if_eq requested true}}
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button> <button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Requested</button>