Merge pull request #1029 from tidusjar/dev

Emby!
pull/1186/head
Jamie 8 years ago committed by GitHub
commit f4d615c494

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using Ombi.Api.Models.Emby;
namespace Ombi.Api.Interfaces
{
public interface IEmbyApi
{
EmbyItemContainer<EmbyMovieItem> GetAllMovies(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);
EmbyItemContainer<EmbyLibrary> ViewLibrary(string apiKey, string userId, Uri baseUri);
EmbyInformation GetInformation(string mediaId, EmbyMediaType type, string apiKey, string userId, Uri baseUri);
EmbyUser LogIn(string username, string password, string apiKey, Uri baseUri);
}
}

@ -56,6 +56,7 @@
<Compile Include="IApiRequest.cs" /> <Compile Include="IApiRequest.cs" />
<Compile Include="ICouchPotatoApi.cs" /> <Compile Include="ICouchPotatoApi.cs" />
<Compile Include="IDiscordApi.cs" /> <Compile Include="IDiscordApi.cs" />
<Compile Include="IEmbyApi.cs" />
<Compile Include="IHeadphonesApi.cs" /> <Compile Include="IHeadphonesApi.cs" />
<Compile Include="IMusicBrainzApi.cs" /> <Compile Include="IMusicBrainzApi.cs" />
<Compile Include="INetflixApi.cs" /> <Compile Include="INetflixApi.cs" />

@ -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; }
}
}

@ -0,0 +1,47 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyUser.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 EmbyConfiguration
{
public bool PlayDefaultAudioTrack { get; set; }
public bool DisplayMissingEpisodes { get; set; }
public bool DisplayUnairedEpisodes { get; set; }
public object[] GroupedFolders { get; set; }
public string SubtitleMode { get; set; }
public bool DisplayCollectionsView { get; set; }
public bool EnableLocalPassword { get; set; }
public object[] OrderedViews { get; set; }
public object[] LatestItemsExcludes { get; set; }
public bool HidePlayedInLatest { get; set; }
public bool RememberAudioSelections { get; set; }
public bool RememberSubtitleSelections { get; set; }
public bool EnableNextEpisodeAutoPlay { get; set; }
}
}

@ -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 EmbyMediastream[] 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; }
}
}

@ -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; }
}
}

@ -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; }
}
}

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyLibrary.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 EmbyImagetags
{
public string Primary { get; set; }
public string Logo { get; set; }
public string Thumb { get; set; }
public string Banner { get; set; }
}
}

@ -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; }
}
}

@ -0,0 +1,47 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyLibrary.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 EmbyLibrary
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public bool HasDynamicCategories { get; set; }
public string PlayAccess { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public EmbyUserdata UserData { get; set; }
public int ChildCount { get; set; }
public string CollectionType { get; set; }
public string OriginalCollectionType { get; set; }
public EmbyImagetags ImageTags { get; set; }
public object[] BackdropImageTags { get; set; }
public string LocationType { get; set; }
}
}

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyItemContainer.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.Collections.Generic;
namespace Ombi.Api.Models.Emby
{
public class EmbyItemContainer<T>
{
public List<T> Items { get; set; }
public int TotalRecordCount { get; set; }
}
}

@ -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
}
}

@ -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; }
}
}

@ -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; }
}
}

@ -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 EmbyMediastream[] 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; }
}
}

@ -0,0 +1,59 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyMovieItem.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 EmbyMovieItem
{
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 object[] ProductionLocations { get; set; }
public string OfficialRating { 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 bool IsHD { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public int LocalTrailerCount { get; set; }
public EmbyUserdata UserData { get; set; }
public string VideoType { get; set; }
public EmbyImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public string LocationType { get; set; }
public string MediaType { get; set; }
public bool HasSubtitles { get; set; }
public int CriticRating { get; set; }
}
}

@ -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; }
}
}

@ -0,0 +1,63 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyUser.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 EmbyPolicy
{
public bool IsAdministrator { get; set; }
public bool IsHidden { get; set; }
public bool IsDisabled { get; set; }
public object[] BlockedTags { get; set; }
public bool EnableUserPreferenceAccess { get; set; }
public object[] AccessSchedules { get; set; }
public object[] BlockUnratedItems { get; set; }
public bool EnableRemoteControlOfOtherUsers { get; set; }
public bool EnableSharedDeviceControl { get; set; }
public bool EnableLiveTvManagement { get; set; }
public bool EnableLiveTvAccess { get; set; }
public bool EnableMediaPlayback { get; set; }
public bool EnableAudioPlaybackTranscoding { get; set; }
public bool EnableVideoPlaybackTranscoding { get; set; }
public bool EnablePlaybackRemuxing { get; set; }
public bool EnableContentDeletion { get; set; }
public bool EnableContentDownloading { get; set; }
public bool EnableSync { get; set; }
public bool EnableSyncTranscoding { get; set; }
public object[] EnabledDevices { get; set; }
public bool EnableAllDevices { get; set; }
public object[] EnabledChannels { get; set; }
public bool EnableAllChannels { get; set; }
public object[] EnabledFolders { get; set; }
public bool EnableAllFolders { get; set; }
public int InvalidLoginAttemptCount { get; set; }
public bool EnablePublicSharing { get; set; }
}
}

@ -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; }
}
}

@ -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; }
}
}

@ -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
{
}
}

@ -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; }
}
}

@ -0,0 +1,56 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbySeriesItem.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 EmbySeriesItem
{
public string Name { get; set; }
public string ServerId { get; set; }
public string Id { get; set; }
public DateTime PremiereDate { get; set; }
public string OfficialRating { get; set; }
public float CommunityRating { get; set; }
public long RunTimeTicks { get; set; }
public string PlayAccess { get; set; }
public int ProductionYear { get; set; }
public bool IsFolder { get; set; }
public string Type { get; set; }
public int LocalTrailerCount { get; set; }
public EmbyUserdata UserData { get; set; }
public int ChildCount { get; set; }
public string Status { get; set; }
public string AirTime { get; set; }
public string[] AirDays { get; set; }
public EmbyImagetags ImageTags { get; set; }
public string[] BackdropImageTags { get; set; }
public string LocationType { get; set; }
public DateTime EndDate { get; set; }
}
}

@ -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; }
}
}

@ -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; }
}
}

@ -0,0 +1,53 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyUser.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 EmbyUser
{
public string Name { get; set; }
public string ServerId { get; set; }
public string ConnectUserName { get; set; }
public string ConnectUserId { get; set; }
public string ConnectLinkType { get; set; }
public string Id { get; set; }
public bool HasPassword { get; set; }
public bool HasConfiguredPassword { get; set; }
public bool HasConfiguredEasyPassword { get; set; }
public DateTime LastLoginDate { get; set; }
public DateTime LastActivityDate { get; set; }
public EmbyConfiguration Configuration { get; set; }
public EmbyPolicy Policy { get; set; }
}
public class EmbyUserLogin
{
public EmbyUser User { get; set; }
}
}

@ -0,0 +1,42 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyLibrary.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 EmbyUserdata
{
public int PlaybackPositionTicks { get; set; }
public int PlayCount { get; set; }
public bool IsFavorite { get; set; }
public bool Played { get; set; }
public string Key { get; set; }
public DateTime LastPlayedDate { get; set; }
public int UnplayedItemCount { get; set; }
}
}

@ -49,6 +49,31 @@
<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\EmbyEpisodeInformation.cs" />
<Compile Include="Emby\EmbyEpisodeItem.cs" />
<Compile Include="Emby\EmbyExternalurl.cs" />
<Compile Include="Emby\EmbyImagetags.cs" />
<Compile Include="Emby\EmbyInformation.cs" />
<Compile Include="Emby\EmbyItem.cs" />
<Compile Include="Emby\EmbyItemContainer.cs" />
<Compile Include="Emby\EmbyMediasource.cs" />
<Compile Include="Emby\EmbyMediastream.cs" />
<Compile Include="Emby\EmbyMediaType.cs" />
<Compile Include="Emby\EmbyMovieItem.cs" />
<Compile Include="Emby\EmbyPerson.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\EmbySeriesstudioinfo.cs" />
<Compile Include="Emby\EmbyStudio.cs" />
<Compile Include="Emby\EmbyUser.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" />

@ -0,0 +1,232 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyApi.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.Net;
using Newtonsoft.Json;
using NLog;
using Ombi.Api.Interfaces;
using Ombi.Api.Models.Emby;
using Ombi.Helpers;
using RestSharp;
namespace Ombi.Api
{
public class EmbyApi : IEmbyApi
{
public EmbyApi()
{
Api = new ApiRequest();
}
private ApiRequest Api { get; }
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Returns all users from the Emby Instance
/// </summary>
/// <param name="baseUri"></param>
/// <param name="apiKey"></param>
public List<EmbyUser> GetUsers(Uri baseUri, string apiKey)
{
var request = new RestRequest
{
Resource = "emby/users",
Method = Method.GET
};
AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetUsers for Emby, Retrying {0}", timespan), new[] {
TimeSpan.FromSeconds (1),
TimeSpan.FromSeconds(5)
});
var obj = policy.Execute(() => Api.ExecuteJson<List<EmbyUser>>(request, baseUri));
return obj;
}
public EmbyItemContainer<EmbyLibrary> ViewLibrary(string apiKey, string userId, Uri baseUri)
{
var request = new RestRequest
{
Resource = "emby/users/{userId}/items",
Method = Method.GET
};
request.AddUrlSegment("userId", userId);
AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling ViewLibrary for Emby, Retrying {0}", timespan), new[] {
TimeSpan.FromSeconds (1),
TimeSpan.FromSeconds(5)
});
var obj = policy.Execute(() => Api.ExecuteJson<EmbyItemContainer<EmbyLibrary>>(request, baseUri));
return obj;
}
public EmbyItemContainer<EmbyMovieItem> GetAllMovies(string apiKey, string userId, Uri 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)
{
return GetAll<EmbySeriesItem>("Series", apiKey, userId, baseUri);
}
public EmbyUser LogIn(string username, string password, string apiKey, Uri baseUri)
{
var request = new RestRequest
{
Resource = "emby/users/authenticatebyname",
Method = Method.POST
};
var body = new
{
username,
password = StringHasher.GetSha1Hash(password).ToLower(),
passwordMd5 = StringHasher.CalcuateMd5Hash(password)
};
request.AddJsonBody(body);
request.AddHeader("X-Emby-Authorization",
$"MediaBrowser Client=\"Ombi\", Device=\"Ombi\", DeviceId=\"{AssemblyHelper.GetProductVersion()}\", Version=\"{AssemblyHelper.GetAssemblyVersion()}\"");
AddHeaders(request, apiKey);
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling LogInfor Emby, Retrying {0}", timespan), new[] {
TimeSpan.FromSeconds (1),
TimeSpan.FromSeconds(5)
});
var obj = policy.Execute(() => Api.Execute(request, baseUri));
if (obj.StatusCode == HttpStatusCode.Unauthorized)
{
return null;
}
return JsonConvert.DeserializeObject<EmbyUserLogin>(obj.Content)?.User;
}
private EmbyItemContainer<T> GetAll<T>(string type, string apiKey, string userId, Uri baseUri)
{
var request = new RestRequest
{
Resource = "emby/users/{userId}/items",
Method = Method.GET
};
request.AddUrlSegment("userId", userId);
request.AddQueryParameter("Recursive", true.ToString());
request.AddQueryParameter("IncludeItemTypes", type);
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)
});
var obj = policy.Execute(() => Api.ExecuteJson<EmbyItemContainer<T>>(request, baseUri));
return obj;
}
private static void AddHeaders(IRestRequest req, string apiKey)
{
if (!string.IsNullOrEmpty(apiKey))
{
req.AddHeader("X-MediaBrowser-Token", apiKey);
}
req.AddHeader("Accept", "application/json");
req.AddHeader("Content-Type", "application/json");
req.AddHeader("Device", "Ombi");
}
}
}

@ -70,10 +70,14 @@
<HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath> <HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="WebSocket4Net, Version=0.14.1.0, Culture=neutral, PublicKeyToken=eb4e154b696bf72a, processorArchitecture=MSIL">
<HintPath>..\packages\WebSocket4Net.0.14.1\lib\net45\WebSocket4Net.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ApiRequest.cs" /> <Compile Include="ApiRequest.cs" />
<Compile Include="DiscordApi.cs" /> <Compile Include="DiscordApi.cs" />
<Compile Include="EmbyApi.cs" />
<Compile Include="NetflixRouletteApi.cs" /> <Compile Include="NetflixRouletteApi.cs" />
<Compile Include="RadarrApi.cs" /> <Compile Include="RadarrApi.cs" />
<Compile Include="TraktApi.cs" /> <Compile Include="TraktApi.cs" />

@ -9,4 +9,5 @@
<package id="System.Net.Http" version="4.0.0" targetFramework="net45" /> <package id="System.Net.Http" version="4.0.0" targetFramework="net45" />
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" /> <package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
<package id="TraktApiSharp" version="0.8.0" targetFramework="net45" /> <package id="TraktApiSharp" version="0.8.0" targetFramework="net45" />
<package id="WebSocket4Net" version="0.14.1" targetFramework="net45" />
</packages> </packages>

@ -37,6 +37,7 @@ using Ombi.Helpers;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Store; using Ombi.Store;
using Ombi.Store.Models; using Ombi.Store.Models;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
namespace Ombi.Core.Migration.Migrations namespace Ombi.Core.Migration.Migrations
@ -46,7 +47,7 @@ namespace Ombi.Core.Migration.Migrations
{ {
public Version1100(IUserRepository userRepo, IRequestService requestService, ISettingsService<LogSettings> log, public Version1100(IUserRepository userRepo, IRequestService requestService, ISettingsService<LogSettings> log,
IPlexApi plexApi, ISettingsService<PlexSettings> plexService, IPlexApi plexApi, ISettingsService<PlexSettings> plexService,
IPlexUserRepository plexusers, ISettingsService<PlexRequestSettings> prSettings, IExternalUserRepository<PlexUsers> plexusers, ISettingsService<PlexRequestSettings> prSettings,
ISettingsService<UserManagementSettings> umSettings, ISettingsService<UserManagementSettings> umSettings,
ISettingsService<ScheduledJobsSettings> sjs, IRepository<UsersToNotify> usersToNotify) ISettingsService<ScheduledJobsSettings> sjs, IRepository<UsersToNotify> usersToNotify)
{ {
@ -69,7 +70,7 @@ namespace Ombi.Core.Migration.Migrations
private ISettingsService<LogSettings> Log { get; } private ISettingsService<LogSettings> Log { get; }
private IPlexApi PlexApi { get; } private IPlexApi PlexApi { get; }
private ISettingsService<PlexSettings> PlexSettings { get; } private ISettingsService<PlexSettings> PlexSettings { get; }
private IPlexUserRepository PlexUsers { get; } private IExternalUserRepository<PlexUsers> PlexUsers { get; }
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; } private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
private ISettingsService<UserManagementSettings> UserManagementSettings { get; } private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
private ISettingsService<ScheduledJobsSettings> ScheduledJobSettings { get; } private ISettingsService<ScheduledJobsSettings> ScheduledJobSettings { get; }

@ -36,29 +36,42 @@ namespace Ombi.Core.Migration.Migrations
[Migration(22000, "v2.20.0.0")] [Migration(22000, "v2.20.0.0")]
public class Version2200 : BaseMigration, IMigration public class Version2200 : BaseMigration, IMigration
{ {
public Version2200(ISettingsService<CustomizationSettings> custom) public Version2200(ISettingsService<CustomizationSettings> custom, ISettingsService<PlexSettings> ps)
{ {
Customization = custom; Customization = custom;
PlexSettings = ps;
} }
public int Version => 22000; public int Version => 22000;
private ISettingsService<CustomizationSettings> Customization { get; set; } private ISettingsService<CustomizationSettings> Customization { get; set; }
private ISettingsService<PlexSettings> PlexSettings { get; set; }
private static Logger Logger = LogManager.GetCurrentClassLogger(); private static Logger Logger = LogManager.GetCurrentClassLogger();
public void Start(IDbConnection con) public void Start(IDbConnection con)
{ {
UpdatePlexSettings();
//UpdateCustomSettings(); Turned off the migration for now until the search has been improved on. //UpdateCustomSettings(); Turned off the migration for now until the search has been improved on.
//UpdateSchema(con, Version); //UpdateSchema(con, Version);
} }
private void UpdatePlexSettings()
{
#if !DEBUG
var s = PlexSettings.GetSettings();
s.Enable = true;
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);
} }
} }
} }

@ -22,7 +22,7 @@ namespace Ombi.Core
Func<NancyContext, Response> HttpStatusCodeIfNot(HttpStatusCode statusCode, Func<NancyContext, bool> test); Func<NancyContext, Response> HttpStatusCodeIfNot(HttpStatusCode statusCode, Func<NancyContext, bool> test);
bool IsLoggedIn(NancyContext context); bool IsLoggedIn(NancyContext context);
bool IsNormalUser(IUserIdentity user); bool IsNormalUser(IUserIdentity user);
bool IsPlexUser(IUserIdentity user); bool IsExternalUser(IUserIdentity user);
bool HasPermissions(string userName, Permissions perm); bool HasPermissions(string userName, Permissions perm);
/// <summary> /// <summary>

@ -123,6 +123,7 @@
<Compile Include="SecurityExtensions.cs" /> <Compile Include="SecurityExtensions.cs" />
<Compile Include="SettingModels\AuthenticationSettings.cs" /> <Compile Include="SettingModels\AuthenticationSettings.cs" />
<Compile Include="SettingModels\DiscordNotificationSettings.cs" /> <Compile Include="SettingModels\DiscordNotificationSettings.cs" />
<Compile Include="SettingModels\EmbySettings.cs" />
<Compile Include="SettingModels\RadarrSettings.cs" /> <Compile Include="SettingModels\RadarrSettings.cs" />
<Compile Include="SettingModels\WatcherSettings.cs" /> <Compile Include="SettingModels\WatcherSettings.cs" />
<Compile Include="SettingModels\ExternalSettings.cs" /> <Compile Include="SettingModels\ExternalSettings.cs" />

@ -105,7 +105,7 @@ namespace Ombi.Core.Queue
public IEnumerable<RequestQueue> GetQueue() public IEnumerable<RequestQueue> GetQueue()
{ {
var items = RequestQueue.GetAll(); var items = RequestQueue.GetAll();
return items; return items;
} }

@ -36,23 +36,28 @@ using Ombi.Core.SettingModels;
using Ombi.Core.Users; using Ombi.Core.Users;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
namespace Ombi.Core namespace Ombi.Core
{ {
public class SecurityExtensions : ISecurityExtensions public class SecurityExtensions : ISecurityExtensions
{ {
public SecurityExtensions(IUserRepository userRepository, IResourceLinker linker, IPlexUserRepository plexUsers, ISettingsService<UserManagementSettings> umSettings) public SecurityExtensions(IUserRepository userRepository, IResourceLinker linker, IExternalUserRepository<PlexUsers> plexUsers, ISettingsService<UserManagementSettings> umSettings,
IExternalUserRepository<EmbyUsers> embyUsers)
{ {
UserRepository = userRepository; UserRepository = userRepository;
Linker = linker; Linker = linker;
PlexUsers = plexUsers; PlexUsers = plexUsers;
UserManagementSettings = umSettings; UserManagementSettings = umSettings;
EmbyUsers = embyUsers;
} }
private IUserRepository UserRepository { get; } private IUserRepository UserRepository { get; }
private IResourceLinker Linker { get; } private IResourceLinker Linker { get; }
private IPlexUserRepository PlexUsers { get; } private IExternalUserRepository<PlexUsers> PlexUsers { get; }
private IExternalUserRepository<EmbyUsers> EmbyUsers { get; }
private ISettingsService<UserManagementSettings> UserManagementSettings { get; } private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
public bool IsLoggedIn(NancyContext context) public bool IsLoggedIn(NancyContext context)
@ -69,16 +74,18 @@ namespace Ombi.Core
return realUser || plexUser; return realUser || plexUser;
} }
public bool IsPlexUser(IUserIdentity user) public bool IsExternalUser(IUserIdentity user)
{ {
if (user == null) if (user == null)
{ {
return false; return false;
} }
var plexUser = PlexUsers.GetUserByUsername(user.UserName); var plexUser = PlexUsers.GetUserByUsername(user.UserName);
return plexUser != null; var embyUser = EmbyUsers.GetUserByUsername(user.UserName);
}
return plexUser != null || embyUser != null;
}
public bool IsNormalUser(IUserIdentity user) public bool IsNormalUser(IUserIdentity user)
{ {
if (user == null) if (user == null)
@ -106,6 +113,12 @@ namespace Ombi.Core
return !string.IsNullOrEmpty(plexUser.UserAlias) ? plexUser.UserAlias : plexUser.Username; return !string.IsNullOrEmpty(plexUser.UserAlias) ? plexUser.UserAlias : plexUser.Username;
} }
var embyUser = EmbyUsers.GetUserByUsername(username);
if (embyUser != null)
{
return !string.IsNullOrEmpty(embyUser.UserAlias) ? embyUser.UserAlias : embyUser.Username;
}
var dbUser = UserRepository.GetUserByUsername(username); var dbUser = UserRepository.GetUserByUsername(username);
if (dbUser != null) if (dbUser != null)
{ {
@ -302,6 +315,12 @@ namespace Ombi.Core
return permissions; return permissions;
} }
var embyUsers = EmbyUsers.GetUserByUsername(userName);
if (embyUsers != null)
{
return (Permissions) embyUsers.Permissions;
}
return 0; return 0;
} }
} }

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: CouchPotatoSettings.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.Core.SettingModels
{
public sealed class EmbySettings : ExternalSettings
{
public bool Enable { get; set; }
public string ApiKey { get; set; }
public string AdministratorId { get; set; }
public bool EnableEpisodeSearching { get; set; }
}
}

@ -33,6 +33,8 @@ namespace Ombi.Core.SettingModels
{ {
AdvancedSearch = true; AdvancedSearch = true;
} }
public bool Enable { get; set; }
public bool AdvancedSearch { get; set; } public bool AdvancedSearch { get; set; }
public bool EnableTvEpisodeSearching { get; set; } public bool EnableTvEpisodeSearching { get; set; }

@ -47,5 +47,10 @@ 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; }
public int EmbyUserChecker { get; set; }
} }
} }

@ -30,22 +30,26 @@ using System.Linq;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
namespace Ombi.Core.Users namespace Ombi.Core.Users
{ {
public class UserHelper : IUserHelper public class UserHelper : IUserHelper
{ {
public UserHelper(IUserRepository userRepository, IPlexUserRepository plexUsers, ISecurityExtensions security) public UserHelper(IUserRepository userRepository, IExternalUserRepository<PlexUsers> plexUsers, IExternalUserRepository<EmbyUsers> emby, ISecurityExtensions security)
{ {
LocalUserRepository = userRepository; LocalUserRepository = userRepository;
PlexUserRepository = plexUsers; PlexUserRepository = plexUsers;
Security = security; Security = security;
EmbyUserRepository = emby;
} }
private IUserRepository LocalUserRepository { get; } private IUserRepository LocalUserRepository { get; }
private IPlexUserRepository PlexUserRepository { get; } private IExternalUserRepository<PlexUsers> PlexUserRepository { get; }
private ISecurityExtensions Security { get; } private ISecurityExtensions Security { get; }
private IExternalUserRepository<EmbyUsers> EmbyUserRepository { get; }
public IEnumerable<UserHelperModel> GetUsers() public IEnumerable<UserHelperModel> GetUsers()
@ -53,7 +57,8 @@ namespace Ombi.Core.Users
var model = new List<UserHelperModel>(); var model = new List<UserHelperModel>();
var localUsers = LocalUserRepository.GetAll(); var localUsers = LocalUserRepository.GetAll();
var plexUsers = PlexUserRepository.GetAll(); var plexUsers = PlexUserRepository.GetAll().ToList();
var embyUsers = EmbyUserRepository.GetAll().ToList();
foreach (var user in localUsers) foreach (var user in localUsers)
{ {
@ -68,14 +73,30 @@ namespace Ombi.Core.Users
}); });
} }
model.AddRange(plexUsers.Select(user => new UserHelperModel if (plexUsers.Any())
{ {
Type = UserType.LocalUser, model.AddRange(plexUsers.Select(user => new UserHelperModel
Username = user.Username, {
UserAlias = user.UserAlias, Type = UserType.PlexUser,
EmailAddress = user.EmailAddress, Username = user.Username,
Permissions = (Permissions)user.Permissions UserAlias = user.UserAlias,
})); EmailAddress = user.EmailAddress,
Permissions = (Permissions) user.Permissions
}));
}
if (embyUsers.Any())
{
model.AddRange(embyUsers.Select(user => new UserHelperModel
{
Type = UserType.EmbyUser,
Username = user.Username,
UserAlias = user.UserAlias,
EmailAddress = user.EmailAddress,
Permissions = (Permissions)user.Permissions
}));
}
return model; return model;
} }
@ -86,9 +107,11 @@ namespace Ombi.Core.Users
var localUsers = LocalUserRepository.GetAll().ToList(); var localUsers = LocalUserRepository.GetAll().ToList();
var plexUsers = PlexUserRepository.GetAll().ToList(); var plexUsers = PlexUserRepository.GetAll().ToList();
var embyUsers = EmbyUserRepository.GetAll().ToList();
var filteredLocal = localUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission)); var filteredLocal = localUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission));
var filteredPlex = plexUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission)); var filteredPlex = plexUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission));
var filteredEmby = embyUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission));
foreach (var user in filteredLocal) foreach (var user in filteredLocal)
@ -107,7 +130,17 @@ namespace Ombi.Core.Users
model.AddRange(filteredPlex.Select(user => new UserHelperModel model.AddRange(filteredPlex.Select(user => new UserHelperModel
{ {
Type = UserType.LocalUser, Type = UserType.PlexUser,
Username = user.Username,
UserAlias = user.UserAlias,
EmailAddress = user.EmailAddress,
Permissions = (Permissions)user.Permissions,
Features = (Features)user.Features
}));
model.AddRange(filteredEmby.Select(user => new UserHelperModel
{
Type = UserType.EmbyUser,
Username = user.Username, Username = user.Username,
UserAlias = user.UserAlias, UserAlias = user.UserAlias,
EmailAddress = user.EmailAddress, EmailAddress = user.EmailAddress,
@ -115,6 +148,7 @@ namespace Ombi.Core.Users
Features = (Features)user.Features Features = (Features)user.Features
})); }));
return model; return model;
} }
@ -124,9 +158,11 @@ namespace Ombi.Core.Users
var localUsers = LocalUserRepository.GetAll().ToList(); var localUsers = LocalUserRepository.GetAll().ToList();
var plexUsers = PlexUserRepository.GetAll().ToList(); var plexUsers = PlexUserRepository.GetAll().ToList();
var embyUsers = PlexUserRepository.GetAll().ToList();
var filteredLocal = localUsers.Where(x => ((Features)x.Features).HasFlag(features)); var filteredLocal = localUsers.Where(x => ((Features)x.Features).HasFlag(features));
var filteredPlex = plexUsers.Where(x => ((Features)x.Features).HasFlag(features)); var filteredPlex = plexUsers.Where(x => ((Features)x.Features).HasFlag(features));
var filteredEmby = embyUsers.Where(x => ((Features)x.Features).HasFlag(features));
foreach (var user in filteredLocal) foreach (var user in filteredLocal)
@ -145,7 +181,17 @@ namespace Ombi.Core.Users
model.AddRange(filteredPlex.Select(user => new UserHelperModel model.AddRange(filteredPlex.Select(user => new UserHelperModel
{ {
Type = UserType.LocalUser, Type = UserType.PlexUser,
Username = user.Username,
UserAlias = user.UserAlias,
EmailAddress = user.EmailAddress,
Permissions = (Permissions)user.Permissions,
Features = (Features)user.Features
}));
model.AddRange(filteredEmby.Select(user => new UserHelperModel
{
Type = UserType.EmbyUser,
Username = user.Username, Username = user.Username,
UserAlias = user.UserAlias, UserAlias = user.UserAlias,
EmailAddress = user.EmailAddress, EmailAddress = user.EmailAddress,

@ -25,6 +25,7 @@
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
@ -49,5 +50,10 @@ namespace Ombi.Helpers
return sb.ToString(); return sb.ToString();
} }
} }
public static string GetSha1Hash(string input)
{
return string.Join("", (new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input))).Select(x => x.ToString("x2")).ToArray());
}
} }
} }

@ -30,6 +30,7 @@ namespace Ombi.Helpers
public enum UserType public enum UserType
{ {
PlexUser, PlexUser,
LocalUser LocalUser,
EmbyUser
} }
} }

@ -249,7 +249,7 @@
// }); // });
// CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies); // CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
// SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>()); // SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
// var movies = Checker.GetPlexMovies(); // var movies = Checker.GetEmbyMovies();
// Assert.That(movies.Any(x => x.ProviderId == "1212")); // Assert.That(movies.Any(x => x.ProviderId == "1212"));
// } // }
@ -267,7 +267,7 @@
// }); // });
// SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>()); // SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
// CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv); // CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
// var movies = Checker.GetPlexTvShows(); // var movies = Checker.GetEmbyTvShows();
// Assert.That(movies.Any(x => x.ProviderId == "1212")); // Assert.That(movies.Any(x => x.ProviderId == "1212"));
// } // }

@ -0,0 +1,6 @@
namespace Ombi.Services.Interfaces
{
public interface IEmbyNotificationEngine : INotificationEngine
{
}
}

@ -34,7 +34,7 @@ namespace Ombi.Services.Interfaces
{ {
public interface INotificationEngine public interface INotificationEngine
{ {
Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey, NotificationType type); Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, NotificationType type);
Task NotifyUsers(RequestedModel modelChanged, string apiKey, NotificationType type); Task NotifyUsers(RequestedModel modelChanged, NotificationType type);
} }
} }

@ -0,0 +1,6 @@
namespace Ombi.Services.Interfaces
{
public interface IPlexNotificationEngine : INotificationEngine
{
}
}

@ -0,0 +1,357 @@
#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 System.Linq;
using System.Threading.Tasks;
using Dapper;
using NLog;
using Ombi.Api.Interfaces;
using Ombi.Api.Models.Plex;
using Ombi.Core;
using Ombi.Core.Models;
using Ombi.Core.SettingModels;
using Ombi.Helpers;
using Ombi.Services.Interfaces;
using Ombi.Services.Models;
using Ombi.Store;
using Ombi.Store.Models;
using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository;
using Quartz;
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
namespace Ombi.Services.Jobs
{
public class EmbyAvailabilityChecker : IJob, IEmbyAvailabilityChecker
{
public EmbyAvailabilityChecker(ISettingsService<EmbySettings> embySettings, IRequestService request, IEmbyApi emby, ICacheProvider cache,
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<EmbyEpisodes> repo, IEmbyNotificationEngine e, IRepository<EmbyContent> content)
{
Emby = embySettings;
RequestService = request;
EmbyApi = emby;
Cache = cache;
Notification = notify;
Job = rec;
UserNotifyRepo = users;
EpisodeRepo = repo;
NotificationEngine = e;
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 INotificationService Notification { get; }
private IJobRecord Job { get; }
private IRepository<UsersToNotify> UserNotifyRepo { get; }
private INotificationEngine NotificationEngine { get; }
private IRepository<EmbyContent> EmbyContent { get; }
public void CheckAndUpdateAll()
{
var embySettings = Emby.GetSettings();
if (!ValidateSettings(embySettings))
{
Log.Debug("Validation of the Emby settings failed.");
return;
}
var content = EmbyContent.GetAll().ToList();
var movies = GetEmbyMovies(content).ToArray();
var shows = GetEmbyTvShows(content).ToArray();
var albums = GetEmbyMusic(content).ToArray();
var requests = RequestService.GetAll();
var requestedModels = requests as RequestedModel[] ?? requests.Where(x => !x.Available).ToArray();
if (!requestedModels.Any())
{
Log.Debug("There are no requests to check.");
return;
}
var modifiedModel = new List<RequestedModel>();
foreach (var r in requestedModels)
{
var releaseDate = r.ReleaseDate == DateTime.MinValue ? string.Empty : r.ReleaseDate.ToString("yyyy");
bool matchResult;
switch (r.Type)
{
case RequestType.Movie:
matchResult = IsMovieAvailable(movies, r.Title, releaseDate, r.ImdbId);
break;
case RequestType.TvShow:
if (!embySettings.EnableEpisodeSearching)
{
matchResult = IsTvShowAvailable(shows, r.Title, releaseDate, r.TvDbId, r.SeasonList);
}
else
{
matchResult = r.Episodes.Any() ?
r.Episodes.All(x => IsEpisodeAvailable(r.TvDbId, x.SeasonNumber, x.EpisodeNumber)) :
IsTvShowAvailable(shows, r.Title, releaseDate, r.TvDbId, r.SeasonList);
}
break;
case RequestType.Album:
//matchResult = IsAlbumAvailable(albums, r.Title, r.ReleaseDate.Year.ToString(), r.ArtistName); // TODO Emby
matchResult = false;
break;
default:
throw new ArgumentOutOfRangeException();
}
if (matchResult)
{
r.Available = true;
modifiedModel.Add(r);
continue;
}
}
Log.Debug("Requests that will be updated count {0}", modifiedModel.Count);
if (modifiedModel.Any())
{
NotificationEngine.NotifyUsers(modifiedModel, NotificationType.RequestAvailable);
RequestService.BatchUpdate(modifiedModel);
}
}
public IEnumerable<EmbyContent> GetEmbyMovies(IEnumerable<EmbyContent> content)
{
return content.Where(x => x.Type == EmbyMediaType.Movie);
}
public bool IsMovieAvailable(EmbyContent[] embyMovies, string title, string year, string providerId)
{
var movie = GetMovie(embyMovies, title, year, providerId);
return movie != null;
}
public EmbyContent GetMovie(EmbyContent[] embyMovies, string title, string year, string providerId)
{
if (embyMovies.Length == 0)
{
return null;
}
foreach (var movie in embyMovies)
{
if (string.IsNullOrEmpty(movie.Title) || movie.PremierDate == DateTime.MinValue)
{
continue;
}
if (!string.IsNullOrEmpty(movie.ProviderId) &&
movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
{
return movie;
}
if (movie.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
movie.PremierDate.Year.ToString().Equals(year, StringComparison.CurrentCultureIgnoreCase))
{
return movie;
}
}
return null;
}
public IEnumerable<EmbyContent> GetEmbyTvShows(IEnumerable<EmbyContent> content)
{
return content.Where(x => x.Type == EmbyMediaType.Series);
}
public bool IsTvShowAvailable(EmbyContent[] embyShows, string title, string year, string providerId, int[] seasons = null)
{
var show = GetTvShow(embyShows, title, year, providerId, seasons);
return show != null;
}
public EmbyContent GetTvShow(EmbyContent[] embyShows, string title, string year, string providerId,
int[] seasons = null)
{
foreach (var show in embyShows)
{
//if (show.ProviderId == providerId && seasons != null) // TODO Emby
//{
// var showSeasons = ByteConverterHelper.ReturnObject<int[]>(show.Seasons);
// if (seasons.Any(season => showSeasons.Contains(season)))
// {
// return show;
// }
// return null;
//}
if (!string.IsNullOrEmpty(show.ProviderId) &&
show.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase))
{
return show;
}
if (show.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase) &&
show.PremierDate.Year.ToString().Equals(year, StringComparison.CurrentCultureIgnoreCase))
{
return show;
}
}
return null;
}
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
{
var ep = EpisodeRepo.Custom(
connection =>
{
connection.Open();
var result = connection.Query<EmbyEpisodes>("select * from EmbyEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId });
return result;
}).ToList();
if (!ep.Any())
{
Log.Info("Episode cache info is not available. tvdbid: {0}, season: {1}, episode: {2}", theTvDbId, season, episode);
return false;
}
foreach (var result in ep)
{
if (result.ProviderId.Equals(theTvDbId) && result.EpisodeNumber == episode && result.SeasonNumber == season)
{
return true;
}
}
return false;
}
/// <summary>
/// Gets the episode's db in the cache.
/// </summary>
/// <returns></returns>
public async Task<IEnumerable<EmbyEpisodes>> GetEpisodes()
{
var episodes = await EpisodeRepo.GetAllAsync();
if (episodes == null)
{
return new HashSet<EmbyEpisodes>();
}
return episodes;
}
/// <summary>
/// Gets the episode's stored in the db and then filters on the TheTvDBId.
/// </summary>
/// <param name="theTvDbId">The tv database identifier.</param>
/// <returns></returns>
public async Task<IEnumerable<EmbyEpisodes>> GetEpisodes(int theTvDbId)
{
var ep = await EpisodeRepo.CustomAsync(async connection =>
{
connection.Open();
var result = await connection.QueryAsync<EmbyEpisodes>("select * from EmbyEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId });
return result;
});
var embyEpisodes = ep as EmbyEpisodes[] ?? ep.ToArray();
if (!embyEpisodes.Any())
{
Log.Info("Episode db info is not available.");
return new List<EmbyEpisodes>();
}
return embyEpisodes;
}
public IEnumerable<EmbyContent> GetEmbyMusic(IEnumerable<EmbyContent> content)
{
return content.Where(x => x.Type == EmbyMediaType.Music);
}
private bool ValidateSettings(EmbySettings emby)
{
if (emby.Enable)
{
if (string.IsNullOrEmpty(emby?.Ip) || string.IsNullOrEmpty(emby?.ApiKey) || string.IsNullOrEmpty(emby?.AdministratorId))
{
Log.Warn("A setting is null, Ensure Emby is configured correctly");
return false;
}
}
return emby.Enable;
}
public void Execute(IJobExecutionContext context)
{
Job.SetRunning(true, JobNames.EmbyChecker);
try
{
CheckAndUpdateAll();
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EmbyChecker);
Job.SetRunning(false, JobNames.EmbyChecker);
}
}
public void Start()
{
Job.SetRunning(true, JobNames.EmbyChecker);
try
{
CheckAndUpdateAll();
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Job.Record(JobNames.EmbyChecker);
Job.SetRunning(false, JobNames.EmbyChecker);
}
}
}
}

@ -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);
}
}
}
}

@ -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);
}
}
}
}

@ -0,0 +1,136 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: StoreCleanup.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.Linq;
using NLog;
using Ombi.Api.Interfaces;
using Ombi.Core;
using Ombi.Core.SettingModels;
using Ombi.Core.Users;
using Ombi.Helpers.Permissions;
using Ombi.Services.Interfaces;
using Ombi.Store.Models.Emby;
using Ombi.Store.Repository;
using Quartz;
namespace Ombi.Services.Jobs
{
public class EmbyUserChecker : IJob, IEmbyUserChecker
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public EmbyUserChecker(IExternalUserRepository<EmbyUsers> plexUsers, IEmbyApi embyApi, IJobRecord rec, ISettingsService<EmbySettings> embyS, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings,
IRequestService requestService, IUserRepository localUser)
{
Repo = plexUsers;
JobRecord = rec;
EmbyApi = embyApi;
EmbySettings = embyS;
PlexRequestSettings = prSettings;
UserManagementSettings = umSettings;
RequestService = requestService;
LocalUserRepository = localUser;
}
private IJobRecord JobRecord { get; }
private IEmbyApi EmbyApi { get; }
private IExternalUserRepository<EmbyUsers> Repo { get; }
private ISettingsService<EmbySettings> EmbySettings { get; }
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
private IRequestService RequestService { get; }
private IUserRepository LocalUserRepository { get; }
public void Start()
{
JobRecord.SetRunning(true, JobNames.EmbyUserChecker);
try
{
var settings = EmbySettings.GetSettings();
if (string.IsNullOrEmpty(settings.ApiKey) || !settings.Enable)
{
return;
}
var embyUsers = EmbyApi.GetUsers(settings.FullUri, settings.ApiKey);
var userManagementSettings = UserManagementSettings.GetSettings();
var dbUsers = Repo.GetAll().ToList();
// Regular users
foreach (var user in embyUsers)
{
var dbUser = dbUsers.FirstOrDefault(x => x.EmbyUserId == user.Id);
if (dbUser != null)
{
// we already have a user
continue;
}
// Looks like it's a new user!
var m = new EmbyUsers
{
EmbyUserId = user.Id,
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
Features = UserManagementHelper.GetFeatures(userManagementSettings),
UserAlias = string.Empty,
Username = user.Name,
LoginId = Guid.NewGuid().ToString()
};
// If it's the admin, give them the admin permission
if (user.Policy.IsAdministrator)
{
if (!((Permissions) m.Permissions).HasFlag(Permissions.Administrator))
{
m.Permissions += (int)Permissions.Administrator;
}
}
Repo.Insert(m);
}
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
JobRecord.SetRunning(false, JobNames.EmbyUserChecker);
JobRecord.Record(JobNames.EmbyUserChecker);
}
}
public void Execute(IJobExecutionContext context)
{
Start();
}
}
}

@ -0,0 +1,10 @@
using Quartz;
namespace Ombi.Services.Jobs
{
public interface IEmbyUserChecker
{
void Execute(IJobExecutionContext context);
void Start();
}
}

@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Store.Models.Emby;
using Quartz;
namespace Ombi.Services.Jobs
{
public interface IEmbyAvailabilityChecker
{
void CheckAndUpdateAll();
void Execute(IJobExecutionContext context);
IEnumerable<EmbyContent> GetEmbyMovies(IEnumerable<EmbyContent> content);
IEnumerable<EmbyContent> GetEmbyMusic(IEnumerable<EmbyContent> content);
IEnumerable<EmbyContent> GetEmbyTvShows(IEnumerable<EmbyContent> content);
Task<IEnumerable<EmbyEpisodes>> GetEpisodes();
Task<IEnumerable<EmbyEpisodes>> GetEpisodes(int theTvDbId);
EmbyContent GetMovie(EmbyContent[] embyMovies, string title, string year, string providerId);
EmbyContent GetTvShow(EmbyContent[] embyShows, string title, string year, string providerId, int[] seasons = null);
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
bool IsMovieAvailable(EmbyContent[] embyMovies, string title, string year, string providerId);
bool IsTvShowAvailable(EmbyContent[] embyShows, string title, string year, string providerId, int[] seasons = null);
void Start();
}
}

@ -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();
}
}

@ -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();
}
}

@ -35,13 +35,17 @@ namespace Ombi.Services.Jobs
public const string RadarrCacher = "Radarr Cacher"; public const string RadarrCacher = "Radarr Cacher";
public const string SrCacher = "SickRage Cacher"; public const string SrCacher = "SickRage Cacher";
public const string PlexChecker = "Plex Availability Cacher"; public const string PlexChecker = "Plex 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";
public const string EmbyUserChecker = "Emby User Checker";
} }
} }

@ -51,7 +51,7 @@ namespace Ombi.Services.Jobs
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
{ {
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache, public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, INotificationEngine e, IRepository<PlexContent> content) INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, IPlexNotificationEngine e, IRepository<PlexContent> content)
{ {
Plex = plexSettings; Plex = plexSettings;
RequestService = request; RequestService = request;
@ -152,7 +152,7 @@ namespace Ombi.Services.Jobs
if (modifiedModel.Any()) if (modifiedModel.Any())
{ {
NotificationEngine.NotifyUsers(modifiedModel, plexSettings.PlexAuthToken, NotificationType.RequestAvailable); NotificationEngine.NotifyUsers(modifiedModel, NotificationType.RequestAvailable);
RequestService.BatchUpdate(modifiedModel); RequestService.BatchUpdate(modifiedModel);
} }
} }
@ -388,7 +388,7 @@ namespace Ombi.Services.Jobs
currentItem.RatingKey); currentItem.RatingKey);
// We do not want "all episodes" this as a season // We do not want "all episodes" this as a season
var filtered = seasons.Directory.Where( x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase)); var filtered = seasons.Directory.Where(x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase));
t1.Seasons.AddRange(filtered); t1.Seasons.AddRange(filtered);
} }
@ -447,12 +447,15 @@ namespace Ombi.Services.Jobs
private bool ValidateSettings(PlexSettings plex) private bool ValidateSettings(PlexSettings plex)
{ {
if (plex?.Ip == null || plex?.PlexAuthToken == null) if (plex.Enable)
{ {
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token."); if (plex?.Ip == null || plex?.PlexAuthToken == null)
return false; {
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token.");
return false;
}
} }
return true; return plex.Enable;
} }
public void Execute(IJobExecutionContext context) public void Execute(IJobExecutionContext context)

@ -48,7 +48,7 @@ namespace Ombi.Services.Jobs
public class PlexContentCacher : IJob, IPlexContentCacher public class PlexContentCacher : IJob, IPlexContentCacher
{ {
public PlexContentCacher(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache, public PlexContentCacher(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, INotificationEngine e, IRepository<PlexContent> content) INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, IPlexNotificationEngine e, IRepository<PlexContent> content)
{ {
Plex = plexSettings; Plex = plexSettings;
RequestService = request; RequestService = request;
@ -385,12 +385,15 @@ namespace Ombi.Services.Jobs
private bool ValidateSettings(PlexSettings plex) private bool ValidateSettings(PlexSettings plex)
{ {
if (plex?.Ip == null || plex?.PlexAuthToken == null) if (plex.Enable)
{ {
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token."); if (plex?.Ip == null || plex?.PlexAuthToken == null)
return false; {
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token.");
return false;
}
} }
return true; return plex.Enable;
} }
public void Execute(IJobExecutionContext context) public void Execute(IJobExecutionContext context)

@ -38,8 +38,10 @@ using Ombi.Core.SettingModels;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Services.Interfaces; using Ombi.Services.Interfaces;
using Ombi.Store.Models; using Ombi.Store.Models;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Quartz; using Quartz;
using PlexMediaType = Ombi.Api.Models.Plex.PlexMediaType;
namespace Ombi.Services.Jobs namespace Ombi.Services.Jobs
{ {

@ -37,6 +37,7 @@ using Ombi.Core.Users;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Services.Interfaces; using Ombi.Services.Interfaces;
using Ombi.Store.Models; using Ombi.Store.Models;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Quartz; using Quartz;
@ -46,7 +47,7 @@ namespace Ombi.Services.Jobs
{ {
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public PlexUserChecker(IPlexUserRepository plexUsers, IPlexApi plexAPi, IJobRecord rec, ISettingsService<PlexSettings> plexSettings, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings, public PlexUserChecker(IExternalUserRepository<PlexUsers> plexUsers, IPlexApi plexAPi, IJobRecord rec, ISettingsService<PlexSettings> plexSettings, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings,
IRequestService requestService, IUserRepository localUser) IRequestService requestService, IUserRepository localUser)
{ {
Repo = plexUsers; Repo = plexUsers;
@ -61,7 +62,7 @@ namespace Ombi.Services.Jobs
private IJobRecord JobRecord { get; } private IJobRecord JobRecord { get; }
private IPlexApi PlexApi { get; } private IPlexApi PlexApi { get; }
private IPlexUserRepository Repo { get; } private IExternalUserRepository<PlexUsers> Repo { get; }
private ISettingsService<PlexSettings> PlexSettings { get; } private ISettingsService<PlexSettings> PlexSettings { get; }
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; } private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
private ISettingsService<UserManagementSettings> UserManagementSettings { get; } private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
@ -75,7 +76,7 @@ namespace Ombi.Services.Jobs
try try
{ {
var settings = PlexSettings.GetSettings(); var settings = PlexSettings.GetSettings();
if (string.IsNullOrEmpty(settings.PlexAuthToken)) if (string.IsNullOrEmpty(settings.PlexAuthToken) || !settings.Enable)
{ {
return; return;
} }

@ -200,16 +200,17 @@ namespace Ombi.Services.Jobs
html = template.LoadTemplate(sb.ToString()); html = template.LoadTemplate(sb.ToString());
Log.Debug("Loaded the template"); Log.Debug("Loaded the template");
} }
Send(newletterSettings, html, plexSettings, testEmail); string escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray());
Log.Debug(escapedHtml);
Send(newletterSettings, escapedHtml, plexSettings, testEmail);
} }
private void GenerateMovieHtml(List<RecentlyAddedChild> movies, PlexSettings plexSettings, StringBuilder sb) private void GenerateMovieHtml(List<RecentlyAddedChild> movies, PlexSettings plexSettings, StringBuilder sb)
{ {
var orderedMovies = movies.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList() ?? new List<RecentlyAddedChild>(); var orderedMovies = movies.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList() ?? new List<RecentlyAddedChild>();
sb.Append("<h1>New Movies:</h1><br/><br/>"); sb.Append("<h1>New Movies:</h1><br /><br />");
sb.Append( sb.Append(
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">"); "<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
foreach (var movie in orderedMovies) foreach (var movie in orderedMovies)
@ -259,13 +260,13 @@ namespace Ombi.Services.Jobs
} }
} }
sb.Append("</table><br/><br/>"); sb.Append("</table><br /><br />");
} }
private void GenerateMovieHtml(List<Metadata> movies, PlexSettings plexSettings, StringBuilder sb) private void GenerateMovieHtml(List<Metadata> movies, PlexSettings plexSettings, StringBuilder sb)
{ {
var orderedMovies = movies.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList() ?? new List<Metadata>(); var orderedMovies = movies.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList() ?? new List<Metadata>();
sb.Append("<h1>New Movies:</h1><br/><br/>"); sb.Append("<h1>New Movies:</h1><br /><br />");
sb.Append( sb.Append(
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">"); "<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
foreach (var movie in orderedMovies) foreach (var movie in orderedMovies)
@ -315,14 +316,14 @@ namespace Ombi.Services.Jobs
} }
} }
sb.Append("</table><br/><br/>"); sb.Append("</table><br /><br />");
} }
private void GenerateTvHtml(List<RecentlyAddedChild> tv, PlexSettings plexSettings, StringBuilder sb) private void GenerateTvHtml(List<RecentlyAddedChild> tv, PlexSettings plexSettings, StringBuilder sb)
{ {
var orderedTv = tv.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList(); var orderedTv = tv.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList();
// TV // TV
sb.Append("<h1>New Episodes:</h1><br/><br/>"); sb.Append("<h1>New Episodes:</h1><br /><br />");
sb.Append( sb.Append(
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">"); "<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
foreach (var t in orderedTv) foreach (var t in orderedTv)
@ -375,14 +376,14 @@ namespace Ombi.Services.Jobs
EndLoopHtml(sb); EndLoopHtml(sb);
} }
} }
sb.Append("</table><br/><br/>"); sb.Append("</table><br /><br />");
} }
private void GenerateTvHtml(List<Metadata> tv, PlexSettings plexSettings, StringBuilder sb) private void GenerateTvHtml(List<Metadata> tv, PlexSettings plexSettings, StringBuilder sb)
{ {
var orderedTv = tv.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList(); var orderedTv = tv.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList();
// TV // TV
sb.Append("<h1>New Episodes:</h1><br/><br/>"); sb.Append("<h1>New Episodes:</h1><br /><br />");
sb.Append( sb.Append(
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">"); "<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
foreach (var t in orderedTv) foreach (var t in orderedTv)
@ -435,7 +436,7 @@ namespace Ombi.Services.Jobs
EndLoopHtml(sb); EndLoopHtml(sb);
} }
} }
sb.Append("</table><br/><br/>"); sb.Append("</table><br /><br />");
} }
private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false) private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false)
@ -516,10 +517,12 @@ namespace Ombi.Services.Jobs
private void EndLoopHtml(StringBuilder sb) private void EndLoopHtml(StringBuilder sb)
{ {
//NOTE: BR have to be in TD's as per html spec or it will be put outside of the table...
//Source: http://stackoverflow.com/questions/6588638/phantom-br-tag-rendered-by-browsers-prior-to-table-tag
sb.Append("<hr />");
sb.Append("<br />");
sb.Append("<br />");
sb.Append("</td>"); sb.Append("</td>");
sb.Append("<hr>");
sb.Append("<br>");
sb.Append("<br>");
sb.Append("</tr>"); sb.Append("</tr>");
} }

@ -149,8 +149,8 @@
</tr> </tr>
<tr> <tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top"> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top">
<br/> <br />
<br/> <br />
<p style="font-family: sans-serif; font-size: 20px; font-weight: normal; margin: 0; Margin-bottom: 15px;">Here is a list of Movies and TV Shows that have recently been added to Plex!</p> <p style="font-family: sans-serif; font-size: 20px; font-weight: normal; margin: 0; Margin-bottom: 15px;">Here is a list of Movies and TV Shows that have recently been added to Plex!</p>
</td> </td>

@ -0,0 +1,212 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NLog;
using Ombi.Api.Interfaces;
using Ombi.Core;
using Ombi.Core.Models;
using Ombi.Core.SettingModels;
using Ombi.Core.Users;
using Ombi.Helpers.Permissions;
using Ombi.Services.Interfaces;
using Ombi.Store;
using Ombi.Store.Models;
using Ombi.Store.Models.Emby;
using Ombi.Store.Repository;
namespace Ombi.Services.Notification
{
public class EmbyNotificationEngine : IEmbyNotificationEngine
{
public EmbyNotificationEngine(IEmbyApi p, IRepository<UsersToNotify> repo, ISettingsService<EmbySettings> embySettings, INotificationService service, IUserHelper userHelper, IExternalUserRepository<EmbyUsers> embyUsers)
{
EmbyApi = p;
UserNotifyRepo = repo;
Notification = service;
UserHelper = userHelper;
EmbySettings = embySettings;
EmbyUserRepo = embyUsers;
}
private IEmbyApi EmbyApi { get; }
private IRepository<UsersToNotify> UserNotifyRepo { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private INotificationService Notification { get; }
private IUserHelper UserHelper { get; }
private ISettingsService<EmbySettings> EmbySettings { get; }
private IExternalUserRepository<EmbyUsers> EmbyUserRepo { get; }
public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, NotificationType type)
{
try
{
var embySettings = await EmbySettings.GetSettingsAsync();
var embyUsers = EmbyApi.GetUsers(embySettings.FullUri, embySettings.ApiKey);
var userAccount = embyUsers.FirstOrDefault(x => x.Policy.IsAdministrator);
var adminUsername = userAccount?.Name ?? string.Empty;
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
Log.Debug("Notifying Users Count {0}", users.Count);
foreach (var model in modelChanged)
{
var selectedUsers = new List<string>();
foreach (var u in users)
{
var requestUser = model.RequestedUsers.FirstOrDefault(
x => x.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase) || x.Equals(u.UserAlias, StringComparison.CurrentCultureIgnoreCase));
if (string.IsNullOrEmpty(requestUser))
{
continue;
}
// Make sure we do not already have the user
if (!selectedUsers.Contains(requestUser))
{
selectedUsers.Add(requestUser);
}
}
foreach (var user in selectedUsers)
{
var localUser =
users.FirstOrDefault(x =>
x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase) ||
x.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase));
Log.Info("Notifying user {0}", user);
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
{
Log.Info("This user is the Plex server owner");
await PublishUserNotification(userAccount?.Name, localUser?.EmailAddress, model.Title, model.PosterPath, type, model.Type);
return;
}
// So if the request was from an alias, then we need to use the local user (since that contains the alias).
// If we do not have a local user, then we should be using the Emby user if that user exists.
// This will execute most of the time since Emby and Local users will most always be in the database.
if (localUser != null)
{
if (string.IsNullOrEmpty(localUser?.EmailAddress))
{
Log.Info("There is no email address for this Local user ({0}), cannot send notification", localUser.Username);
continue;
}
Log.Info("Sending notification to: {0} at: {1}, for : {2}", localUser, localUser.EmailAddress, model.Title);
await PublishUserNotification(localUser.Username, localUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
}
else
{
var embyUser = EmbyUserRepo.GetUserByUsername(user);
var email = embyUsers.FirstOrDefault(x => x.Name.Equals(user, StringComparison.CurrentCultureIgnoreCase));
if (string.IsNullOrEmpty(embyUser?.EmailAddress)) // TODO this needs to be the email
{
Log.Info("There is no email address for this Emby user ({0}), cannot send notification", email?.Name);
// We do not have a plex user that requested this!
continue;
}
Log.Info("Sending notification to: {0} at: {1}, for : {2}", embyUser?.Username, embyUser?.EmailAddress, model.Title);
await PublishUserNotification(email?.Name, embyUser?.EmailAddress, model.Title, model.PosterPath, type, model.Type);
}
}
}
}
catch (Exception e)
{
Log.Error(e);
}
}
public async Task NotifyUsers(RequestedModel model, NotificationType type)
{
try
{
var embySettings = await EmbySettings.GetSettingsAsync();
var embyUsers = EmbyApi.GetUsers(embySettings.FullUri, embySettings.ApiKey);
var userAccount = embyUsers.FirstOrDefault(x => x.Policy.IsAdministrator);
var adminUsername = userAccount.Name ?? string.Empty;
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
Log.Debug("Notifying Users Count {0}", users.Count);
// Get the usernames or alias depending if they have an alias
var userNamesWithFeature = users.Select(x => x.UsernameOrAlias).ToList();
Log.Debug("Users with the feature count {0}", userNamesWithFeature.Count);
Log.Debug("Usernames: ");
foreach (var u in userNamesWithFeature)
{
Log.Debug(u);
}
Log.Debug("Users in the requested model count: {0}", model.AllUsers.Count);
Log.Debug("usernames from model: ");
foreach (var modelAllUser in model.AllUsers)
{
Log.Debug(modelAllUser);
}
if (model.AllUsers == null || !model.AllUsers.Any())
{
Log.Debug("There are no users in the model.AllUsers, no users to notify");
return;
}
var usersToNotify = userNamesWithFeature.Intersect(model.AllUsers, StringComparer.CurrentCultureIgnoreCase).ToList();
if (!usersToNotify.Any())
{
Log.Debug("Could not find any users after the .Intersect()");
}
Log.Debug("Users being notified for this request count {0}", users.Count);
foreach (var user in usersToNotify)
{
var embyUser = EmbyUserRepo.GetUserByUsername(user);
Log.Info("Notifying user {0}", user);
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
{
Log.Info("This user is the Emby server owner");
await PublishUserNotification(userAccount.Name, embyUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
return;
}
var email = embyUsers.FirstOrDefault(x => x.Name.Equals(user, StringComparison.CurrentCultureIgnoreCase));
if (email == null)
{
Log.Info("There is no email address for this Emby user, cannot send notification");
// We do not have a emby user that requested this!
continue;
}
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Name, embyUser.EmailAddress, model.Title);
await PublishUserNotification(email.Name, embyUser.EmailAddress, model.Title, model.PosterPath, type, model.Type);
}
}
catch (Exception e)
{
Log.Error(e);
}
}
private async Task PublishUserNotification(string username, string email, string title, string img, NotificationType type, RequestType requestType)
{
var notificationModel = new NotificationModel
{
User = username,
UserEmail = email,
NotificationType = type,
Title = title,
ImgSrc = requestType == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300/{img}" : img
};
// Send the notification to the user.
await Notification.Publish(notificationModel);
}
}
}

@ -1,7 +1,7 @@
#region Copyright #region Copyright
// /************************************************************************ // /************************************************************************
// Copyright (c) 2016 Jamie Rees // Copyright (c) 2016 Jamie Rees
// File: NotificationEngine.cs // File: PlexNotificationEngine.cs
// Created By: Jamie Rees // Created By: Jamie Rees
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
@ -31,7 +31,9 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NLog; using NLog;
using Ombi.Api.Interfaces; using Ombi.Api.Interfaces;
using Ombi.Core;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.SettingModels;
using Ombi.Core.Users; using Ombi.Core.Users;
using Ombi.Helpers.Permissions; using Ombi.Helpers.Permissions;
using Ombi.Services.Interfaces; using Ombi.Services.Interfaces;
@ -41,14 +43,15 @@ using Ombi.Store.Repository;
namespace Ombi.Services.Notification namespace Ombi.Services.Notification
{ {
public class NotificationEngine : INotificationEngine public class PlexNotificationEngine : IPlexNotificationEngine
{ {
public NotificationEngine(IPlexApi p, IRepository<UsersToNotify> repo, INotificationService service, IUserHelper userHelper) public PlexNotificationEngine(IPlexApi p, IRepository<UsersToNotify> repo, INotificationService service, IUserHelper userHelper, ISettingsService<PlexSettings> ps)
{ {
PlexApi = p; PlexApi = p;
UserNotifyRepo = repo; UserNotifyRepo = repo;
Notification = service; Notification = service;
UserHelper = userHelper; UserHelper = userHelper;
PlexSettings = ps;
} }
private IPlexApi PlexApi { get; } private IPlexApi PlexApi { get; }
@ -56,13 +59,15 @@ namespace Ombi.Services.Notification
private static Logger Log = LogManager.GetCurrentClassLogger(); private static Logger Log = LogManager.GetCurrentClassLogger();
private INotificationService Notification { get; } private INotificationService Notification { get; }
private IUserHelper UserHelper { get; } private IUserHelper UserHelper { get; }
private ISettingsService<PlexSettings> PlexSettings { get; }
public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey, NotificationType type) public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, NotificationType type)
{ {
try try
{ {
var plexUser = PlexApi.GetUsers(apiKey); var settings = await PlexSettings.GetSettingsAsync();
var userAccount = PlexApi.GetAccount(apiKey); var plexUser = PlexApi.GetUsers(settings.PlexAuthToken);
var userAccount = PlexApi.GetAccount(settings.PlexAuthToken);
var adminUsername = userAccount.Username ?? string.Empty; var adminUsername = userAccount.Username ?? string.Empty;
@ -161,12 +166,13 @@ namespace Ombi.Services.Notification
} }
} }
public async Task NotifyUsers(RequestedModel model, string apiKey, NotificationType type) public async Task NotifyUsers(RequestedModel model, NotificationType type)
{ {
try try
{ {
var plexUser = PlexApi.GetUsers(apiKey); var settings = await PlexSettings.GetSettingsAsync();
var userAccount = PlexApi.GetAccount(apiKey); var plexUser = PlexApi.GetUsers(settings.PlexAuthToken);
var userAccount = PlexApi.GetAccount(settings.PlexAuthToken);
var adminUsername = userAccount.Username ?? string.Empty; var adminUsername = userAccount.Username ?? string.Empty;

@ -86,6 +86,8 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Interfaces\IEmbyNotificationEngine.cs" />
<Compile Include="Interfaces\IPlexNotificationEngine.cs" />
<Compile Include="Interfaces\IRadarrCacher.cs" /> <Compile Include="Interfaces\IRadarrCacher.cs" />
<Compile Include="Interfaces\IWatcherCacher.cs" /> <Compile Include="Interfaces\IWatcherCacher.cs" />
<Compile Include="Interfaces\IJobRecord.cs" /> <Compile Include="Interfaces\IJobRecord.cs" />
@ -93,9 +95,17 @@
<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\IFaultQueueHandler.cs" /> <Compile Include="Jobs\IEmbyUserChecker.cs" />
<Compile Include="Jobs\IPlexEpisodeCacher.cs" /> <Compile Include="Jobs\Interfaces\IEmbyEpisodeCacher.cs" />
<Compile Include="Jobs\IPlexUserChecker.cs" /> <Compile Include="Jobs\Interfaces\IEmbyContentCacher.cs" />
<Compile Include="Jobs\Interfaces\IEmbyAvailabilityChecker.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\EmbyContentCacher.cs" />
<Compile Include="Jobs\EmbyEpisodeCacher.cs" />
<Compile Include="Jobs\EmbyUserChecker.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" />
@ -129,7 +139,8 @@
<Compile Include="Interfaces\INotificationService.cs" /> <Compile Include="Interfaces\INotificationService.cs" />
<Compile Include="Models\SonarrCachedResult.cs" /> <Compile Include="Models\SonarrCachedResult.cs" />
<Compile Include="Notification\EmailMessageNotification.cs" /> <Compile Include="Notification\EmailMessageNotification.cs" />
<Compile Include="Notification\NotificationEngine.cs" /> <Compile Include="Notification\EmbyNotificationEngine.cs" />
<Compile Include="Notification\PlexNotificationEngine.cs" />
<Compile Include="Notification\NotificationModel.cs" /> <Compile Include="Notification\NotificationModel.cs" />
<Compile Include="Notification\NotificationService.cs" /> <Compile Include="Notification\NotificationService.cs" />
<Compile Include="Notification\PushoverNotification.cs" /> <Compile Include="Notification\PushoverNotification.cs" />

@ -0,0 +1,43 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: Emby.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 Dapper.Contrib.Extensions;
using Ombi.Store.Models.Plex;
namespace Ombi.Store.Models.Emby
{
[Table(nameof(EmbyContent))]
public class EmbyContent : Entity
{
public string Title { get; set; }
public string EmbyId { get; set; }
public DateTime PremierDate { get; set; }
public string ProviderId { get; set; }
public EmbyMediaType Type { get; set; }
}
}

@ -0,0 +1,43 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: EmbyEpisodes.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 Dapper.Contrib.Extensions;
namespace Ombi.Store.Models.Emby
{
[Table(nameof(EmbyEpisodes))]
public class EmbyEpisodes : Entity
{
public string EpisodeTitle { get; set; }
public string ShowTitle { get; set; }
public string EmbyId { get; set; }
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string ParentId { get; set; }
public string ProviderId { get; set; }
}
}

@ -0,0 +1,35 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: PlexMediaType .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.Store.Models.Plex
{
public enum EmbyMediaType
{
Movie = 0,
Series = 1,
Music = 2
}
}

@ -0,0 +1,43 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: PlexUsers.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 Dapper.Contrib.Extensions;
namespace Ombi.Store.Models.Emby
{
[Table(nameof(EmbyUsers))]
public class EmbyUsers : Entity
{
public string EmbyUserId { get; set; }
public string UserAlias { get; set; }
public int Permissions { get; set; }
public int Features { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public string LoginId { get; set; }
}
}

@ -27,7 +27,7 @@
using Dapper.Contrib.Extensions; using Dapper.Contrib.Extensions;
namespace Ombi.Store.Models namespace Ombi.Store.Models.Plex
{ {
[Table("PlexEpisodes")] [Table("PlexEpisodes")]
public class PlexEpisodes : Entity public class PlexEpisodes : Entity

@ -26,9 +26,8 @@
#endregion #endregion
using Dapper.Contrib.Extensions; using Dapper.Contrib.Extensions;
using Newtonsoft.Json;
namespace Ombi.Store.Models namespace Ombi.Store.Models.Plex
{ {
[Table(nameof(PlexUsers))] [Table(nameof(PlexUsers))]
public class PlexUsers : Entity public class PlexUsers : Entity

@ -65,11 +65,15 @@
<Compile Include="DbConfiguration.cs" /> <Compile Include="DbConfiguration.cs" />
<Compile Include="Entity.cs" /> <Compile Include="Entity.cs" />
<Compile Include="IPlexDatabase.cs" /> <Compile Include="IPlexDatabase.cs" />
<Compile Include="Models\Emby\EmbyContent.cs" />
<Compile Include="Models\Emby\EmbyEpisodes.cs" />
<Compile Include="Models\IssueBlobs.cs" /> <Compile Include="Models\IssueBlobs.cs" />
<Compile Include="Models\PlexEpisodes.cs" /> <Compile Include="Models\Plex\PlexEpisodes.cs" />
<Compile Include="Models\PlexUsers.cs" /> <Compile Include="Models\Emby\EmbyUsers.cs" />
<Compile Include="Models\Plex\PlexUsers.cs" />
<Compile Include="Models\Plex\MetadataItems.cs" /> <Compile Include="Models\Plex\MetadataItems.cs" />
<Compile Include="Models\Plex\PlexContent.cs" /> <Compile Include="Models\Plex\PlexContent.cs" />
<Compile Include="Models\Emby\EmbyMediaType.cs" />
<Compile Include="Models\Plex\PlexMediaType .cs" /> <Compile Include="Models\Plex\PlexMediaType .cs" />
<Compile Include="Models\RequestQueue.cs" /> <Compile Include="Models\RequestQueue.cs" />
<Compile Include="Models\ScheduledJobs.cs" /> <Compile Include="Models\ScheduledJobs.cs" />
@ -77,6 +81,8 @@
<Compile Include="Models\UsersToNotify.cs" /> <Compile Include="Models\UsersToNotify.cs" />
<Compile Include="PlexDatabase.cs" /> <Compile Include="PlexDatabase.cs" />
<Compile Include="Repository\BaseGenericRepository.cs" /> <Compile Include="Repository\BaseGenericRepository.cs" />
<Compile Include="Repository\BaseExternalUserRepository.cs" />
<Compile Include="Repository\IExternalUserRepository.cs" />
<Compile Include="Repository\IRequestRepository.cs" /> <Compile Include="Repository\IRequestRepository.cs" />
<Compile Include="Repository\ISettingsRepository.cs" /> <Compile Include="Repository\ISettingsRepository.cs" />
<Compile Include="ISqliteConfiguration.cs" /> <Compile Include="ISqliteConfiguration.cs" />
@ -88,7 +94,6 @@
<Compile Include="Repository\SettingsJsonRepository.cs" /> <Compile Include="Repository\SettingsJsonRepository.cs" />
<Compile Include="Repository\RequestJsonRepository.cs" /> <Compile Include="Repository\RequestJsonRepository.cs" />
<Compile Include="Repository\GenericRepository.cs" /> <Compile Include="Repository\GenericRepository.cs" />
<Compile Include="Repository\PlexUserRepository.cs" />
<Compile Include="Repository\UserRepository.cs" /> <Compile Include="Repository\UserRepository.cs" />
<Compile Include="RequestedModel.cs" /> <Compile Include="RequestedModel.cs" />
<Compile Include="UserEntity.cs" /> <Compile Include="UserEntity.cs" />

@ -26,18 +26,18 @@
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.Data; using System.Data;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapper; using Dapper;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Models; using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex;
namespace Ombi.Store.Repository namespace Ombi.Store.Repository
{ {
public class PlexUserRepository : BaseGenericRepository<PlexUsers>, IPlexUserRepository public class BaseExternalUserRepository<T> : BaseGenericRepository<T>, IExternalUserRepository<T> where T : Entity
{ {
public PlexUserRepository(ISqliteConfiguration config, ICacheProvider cache) : base(config,cache) public BaseExternalUserRepository(ISqliteConfiguration config, ICacheProvider cache) : base(config,cache)
{ {
DbConfig = config; DbConfig = config;
} }
@ -45,53 +45,69 @@ namespace Ombi.Store.Repository
private ISqliteConfiguration DbConfig { get; } private ISqliteConfiguration DbConfig { get; }
private IDbConnection Db => DbConfig.DbConnection(); private IDbConnection Db => DbConfig.DbConnection();
public PlexUsers GetUser(string userGuid) private string TableName
{ {
var sql = @"SELECT * FROM PlexUsers get
{
if (typeof(T) == typeof(PlexUsers))
{
return "PlexUsers";
}
if (typeof(T) == typeof(EmbyUsers))
{
return "EmbyUsers";
}
return string.Empty;
}
}
public T GetUser(string userGuid)
{
var sql = $@"SELECT * FROM {TableName}
WHERE PlexUserId = @UserGuid WHERE PlexUserId = @UserGuid
COLLATE NOCASE"; COLLATE NOCASE";
return Db.QueryFirstOrDefault<PlexUsers>(sql, new {UserGuid = userGuid}); return Db.QueryFirstOrDefault<T>(sql, new {UserGuid = userGuid});
} }
public PlexUsers GetUserByUsername(string username) public T GetUserByUsername(string username)
{ {
var sql = @"SELECT * FROM PlexUsers var sql = $@"SELECT * FROM {TableName}
WHERE Username = @UserName WHERE Username = @UserName
COLLATE NOCASE"; COLLATE NOCASE";
return Db.QueryFirstOrDefault<PlexUsers>(sql, new {UserName = username}); return Db.QueryFirstOrDefault<T>(sql, new {UserName = username});
} }
public async Task<PlexUsers> GetUserAsync(string userguid) public async Task<T> GetUserAsync(string userguid)
{ {
var sql = @"SELECT * FROM PlexUsers var sql = $@"SELECT * FROM {TableName}
WHERE PlexUserId = @UserGuid WHERE PlexUserId = @UserGuid
COLLATE NOCASE"; COLLATE NOCASE";
return await Db.QueryFirstOrDefaultAsync<PlexUsers>(sql, new {UserGuid = userguid}); return await Db.QueryFirstOrDefaultAsync<T>(sql, new {UserGuid = userguid});
} }
#region abstract implementation #region abstract implementation
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member #pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
[Obsolete] [Obsolete]
public override PlexUsers Get(string id) public override T Get(string id)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
[Obsolete] [Obsolete]
public override Task<PlexUsers> GetAsync(int id) public override Task<T> GetAsync(int id)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
[Obsolete] [Obsolete]
public override PlexUsers Get(int id) public override T Get(int id)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
[Obsolete] [Obsolete]
public override Task<PlexUsers> GetAsync(string id) public override Task<T> GetAsync(string id)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
@ -99,22 +115,5 @@ namespace Ombi.Store.Repository
#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member #pragma warning restore CS0809 // Obsolete member overrides non-obsolete member
#endregion #endregion
} }
public interface IPlexUserRepository
{
PlexUsers GetUser(string userGuid);
PlexUsers GetUserByUsername(string username);
Task<PlexUsers> GetUserAsync(string userguid);
IEnumerable<PlexUsers> Custom(Func<IDbConnection, IEnumerable<PlexUsers>> func);
long Insert(PlexUsers entity);
void Delete(PlexUsers entity);
IEnumerable<PlexUsers> GetAll();
bool UpdateAll(IEnumerable<PlexUsers> entity);
bool Update(PlexUsers entity);
Task<IEnumerable<PlexUsers>> GetAllAsync();
Task<bool> UpdateAsync(PlexUsers users);
Task<int> InsertAsync(PlexUsers users);
}
} }

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
namespace Ombi.Store.Repository
{
public interface IExternalUserRepository<T> where T : Entity
{
T Get(string id);
T Get(int id);
Task<T> GetAsync(string id);
Task<T> GetAsync(int id);
T GetUser(string userGuid);
Task<T> GetUserAsync(string userguid);
T GetUserByUsername(string username);
IEnumerable<T> Custom(Func<IDbConnection, IEnumerable<T>> func);
long Insert(T entity);
void Delete(T entity);
IEnumerable<T> GetAll();
bool UpdateAll(IEnumerable<T> entity);
bool Update(T entity);
Task<IEnumerable<T>> GetAllAsync();
Task<bool> UpdateAsync(T users);
Task<int> InsertAsync(T users);
}
}

@ -124,6 +124,20 @@ CREATE TABLE IF NOT EXISTS PlexUsers
); );
CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON PlexUsers (Id); CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON PlexUsers (Id);
CREATE TABLE IF NOT EXISTS EmbyUsers
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
EmbyUserId varchar(100) NOT NULL,
UserAlias varchar(100) NOT NULL,
Permissions INTEGER,
Features INTEGER,
Username VARCHAR(100),
EmailAddress VARCHAR(100),
LoginId VARCHAR(100)
);
CREATE UNIQUE INDEX IF NOT EXISTS EmbyUsers_Id ON EmbyUsers (Id);
BEGIN; BEGIN;
CREATE TABLE IF NOT EXISTS PlexEpisodes CREATE TABLE IF NOT EXISTS PlexEpisodes
( (
@ -164,4 +178,29 @@ CREATE TABLE IF NOT EXISTS PlexContent
); );
CREATE UNIQUE INDEX IF NOT EXISTS PlexContent_Id ON PlexContent (Id); CREATE UNIQUE INDEX IF NOT EXISTS PlexContent_Id ON PlexContent (Id);
CREATE TABLE IF NOT EXISTS EmbyEpisodes
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
EpisodeTitle VARCHAR(100) NOT NULL,
ShowTitle VARCHAR(100) NOT NULL,
EmbyId VARCHAR(100) NOT NULL,
SeasonNumber INTEGER NOT NULL,
EpisodeNumber INTEGER NOT NULL,
ParentId VARCHAR(100) NOT NULL,
ProviderId VARCHAR(100) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS EmbyEpisodes_Id ON EmbyEpisodes (Id);
CREATE TABLE IF NOT EXISTS EmbyContent
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Title VARCHAR(100) NOT NULL,
PremierDate VARCHAR(100) NOT NULL,
EmbyId VARCHAR(100) NOT NULL,
ProviderId VARCHAR(100) NOT NULL,
Type INTEGER NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS EmbyEpisodes_Id ON EmbyEpisodes (Id);
COMMIT; COMMIT;

@ -26,6 +26,8 @@
#endregion #endregion
using Nancy.Cryptography; using Nancy.Cryptography;
using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
namespace Ombi.UI.Authentication namespace Ombi.UI.Authentication
@ -47,7 +49,8 @@ namespace Ombi.UI.Authentication
/// <summary>Gets or sets the username/identifier mapper</summary> /// <summary>Gets or sets the username/identifier mapper</summary>
public IUserRepository LocalUserRepository { get; set; } public IUserRepository LocalUserRepository { get; set; }
public IPlexUserRepository PlexUserRepository { get; set; } public IExternalUserRepository<PlexUsers> PlexUserRepository { get; set; }
public IExternalUserRepository<EmbyUsers> EmbyUserRepository { get; set; }
/// <summary>Gets or sets RequiresSSL property</summary> /// <summary>Gets or sets RequiresSSL property</summary>
/// <value>The flag that indicates whether SSL is required</value> /// <value>The flag that indicates whether SSL is required</value>

@ -42,6 +42,8 @@ using Ombi.Core;
using Ombi.Core.SettingModels; using Ombi.Core.SettingModels;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store; using Ombi.Store;
using Ombi.Store.Models.Emby;
using Ombi.Store.Models.Plex;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.UI.Authentication; using Ombi.UI.Authentication;
using Ombi.UI.Helpers; using Ombi.UI.Helpers;
@ -88,7 +90,8 @@ namespace Ombi.UI
var config = new CustomAuthenticationConfiguration var config = new CustomAuthenticationConfiguration
{ {
RedirectUrl = redirect, RedirectUrl = redirect,
PlexUserRepository = container.Get<IPlexUserRepository>(), PlexUserRepository = container.Get<IExternalUserRepository<PlexUsers>>(),
EmbyUserRepository = container.Get<IExternalUserRepository<EmbyUsers>>(),
LocalUserRepository = container.Get<IUserRepository>() LocalUserRepository = container.Get<IUserRepository>()
}; };

@ -12,7 +12,10 @@
<strong>Email Address: </strong><span ng-bind="selectedUser.emailAddress"></span> <strong>Email Address: </strong><span ng-bind="selectedUser.emailAddress"></span>
</div> </div>
<div> <div>
<strong>User Type: </strong><span ng-bind="selectedUser.type === 1 ? 'Local User' : 'Plex User'"></span> <strong>User Type: </strong>
<span ng-if="selectedUser.type === 1">Local User</span>
<span ng-if="selectedUser.type === 2">Emby User</span>
<span ng-if="selectedUser.type === 3">Plex User</span>
</div> </div>
<br /> <br />
<br /> <br />
@ -49,7 +52,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>

@ -75,7 +75,9 @@
{{u.permissionsFormattedString}} {{u.permissionsFormattedString}}
</td> </td>
<td ng-hide="hideColumns"> <td ng-hide="hideColumns">
{{u.type === 1 ? 'Local User' : 'Plex User'}} <span ng-if="u.type === 1">Local User</span>
<span ng-if="u.type === 3">Plex User</span>
<span ng-if="u.type === 2">Emby User</span>
</td> </td>
<td ng-hide="hideColumns" ng-bind="u.lastLoggedIn === minDate ? 'Never' : formatDate(u.lastLoggedIn)"></td> <td ng-hide="hideColumns" ng-bind="u.lastLoggedIn === minDate ? 'Never' : formatDate(u.lastLoggedIn)"></td>
<td> <td>

@ -20,7 +20,7 @@
$scope.searchTerm = ""; $scope.searchTerm = "";
$scope.hideColumns = false; $scope.hideColumns = false;
var ReadOnlyPermission = "Read Only User"; var ReadOnlyPermission = "Read Only User";
var open = false; var open = false;

@ -517,3 +517,11 @@ label {
background-color: #3e3e3e; background-color: #3e3e3e;
border: 1px solid transparent; } border: 1px solid transparent; }
.wizard-heading {
text-align: center; }
.wizard-img {
width: 300px;
display: block !important;
margin: 0 auto !important; }

File diff suppressed because one or more lines are too long

@ -641,4 +641,13 @@ $border-radius: 10px;
margin-bottom: -1px; margin-bottom: -1px;
background-color: #3e3e3e; background-color: #3e3e3e;
border: 1px solid transparent; border: 1px solid transparent;
}
.wizard-heading{
text-align: center;
}
.wizard-img{
width: 300px;
display: block $i;
margin: 0 auto $i;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@ -3,9 +3,42 @@
// Step 1 // Step 1
$('#firstNext') $('#firstNext')
.click(function () { .click(function () {
loadArea("plexAuthArea"); loadArea("mediaApplicationChoice");
}); });
// Plex click
$('#contentBody')
.on("click", "#plexImg", function(e) {
e.preventDefault();
return loadArea("plexAuthArea");
});
$('#contentBody')
.on("click", "#embyImg", function (e) {
e.preventDefault();
return loadArea("embyApiKey");
});
$('#contentBody').on('click', '#embyApiKeySave', function (e) {
e.preventDefault();
$('#spinner').attr("class", "fa fa-spinner fa-spin");
var $form = $("#embyAuthForm");
$.post($form.prop("action"), $form.serialize(), function (response) {
if (response.result === true) {
loadArea("authArea");
} else {
$('#spinner').attr("class", "fa fa-times");
generateNotify(response.message, "warning");
}
});
});
// Step 2 - Get the auth token // Step 2 - Get the auth token
$('#contentBody').on('click', '#requestToken', function (e) { $('#contentBody').on('click', '#requestToken', function (e) {
e.preventDefault(); e.preventDefault();

@ -72,9 +72,9 @@ namespace Ombi.UI.Helpers
return Security.IsLoggedIn(context); return Security.IsLoggedIn(context);
} }
public static bool IsPlexUser(this HtmlHelpers helper) public static bool IsExternalUser(this HtmlHelpers helper)
{ {
return Security.IsPlexUser(helper.CurrentUser); return Security.IsExternalUser(helper.CurrentUser);
} }
public static bool IsNormalUser(this HtmlHelpers helper) public static bool IsNormalUser(this HtmlHelpers helper)
{ {

@ -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,12 @@ 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(),
JobBuilder.Create<EmbyUserChecker>().WithIdentity("EmbyUserChecker", "Emby").Build(),
}; };
jobs.AddRange(jobList); jobs.AddRange(jobList);
@ -175,6 +178,22 @@ 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;
}
if (s.EmbyUserChecker == 0)
{
s.EmbyUserChecker = 24;
}
var triggers = new List<ITrigger>(); var triggers = new List<ITrigger>();
@ -280,6 +299,38 @@ 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();
var embyUserChecker =
TriggerBuilder.Create()
.WithIdentity("EmbyUserChecker", "Emby")
//.StartNow()
.StartAt(DateBuilder.FutureDate(1, IntervalUnit.Minute))
.WithSimpleSchedule(x => x.WithIntervalInHours(s.EmbyUserChecker).RepeatForever())
.Build();
triggers.Add(rencentlyAdded); triggers.Add(rencentlyAdded);
triggers.Add(plexAvailabilityChecker); triggers.Add(plexAvailabilityChecker);
triggers.Add(srCacher); triggers.Add(srCacher);
@ -294,6 +345,10 @@ 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);
triggers.Add(embyUserChecker);
return triggers; return triggers;
} }

@ -33,6 +33,8 @@ namespace Ombi.UI.Models
{ {
public class ScheduledJobsViewModel : ScheduledJobsSettings public class ScheduledJobsViewModel : ScheduledJobsSettings
{ {
public bool Emby { get; set; }
public bool Plex { get; set; }
public Dictionary<string,DateTime> JobRecorder { get; set; } public Dictionary<string,DateTime> JobRecorder { get; set; }
} }
} }

@ -97,6 +97,8 @@ namespace Ombi.UI.Modules.Admin
private IDiscordApi DiscordApi { get; } private IDiscordApi DiscordApi { get; }
private ISettingsService<RadarrSettings> RadarrSettings { get; } private ISettingsService<RadarrSettings> RadarrSettings { get; }
private IRadarrApi RadarrApi { get; } private IRadarrApi RadarrApi { get; }
private ISettingsService<EmbySettings> EmbySettings { get; }
private IEmbyApi EmbyApi { get; }
private static Logger Log = LogManager.GetCurrentClassLogger(); private static Logger Log = LogManager.GetCurrentClassLogger();
public AdminModule(ISettingsService<PlexRequestSettings> prService, public AdminModule(ISettingsService<PlexRequestSettings> prService,
@ -124,7 +126,8 @@ namespace Ombi.UI.Modules.Admin
ISettingsService<NotificationSettingsV2> notifyService, IRecentlyAdded recentlyAdded, ISettingsService<NotificationSettingsV2> notifyService, IRecentlyAdded recentlyAdded,
ISettingsService<WatcherSettings> watcherSettings , ISettingsService<WatcherSettings> watcherSettings ,
ISettingsService<DiscordNotificationSettings> discord, ISettingsService<DiscordNotificationSettings> discord,
IDiscordApi discordapi, ISettingsService<RadarrSettings> settings, IRadarrApi radarrApi IDiscordApi discordapi, ISettingsService<RadarrSettings> settings, IRadarrApi radarrApi,
ISettingsService<EmbySettings> embySettings, IEmbyApi emby
, ISecurityExtensions security) : base("admin", prService, security) , ISecurityExtensions security) : base("admin", prService, security)
{ {
PrService = prService; PrService = prService;
@ -160,7 +163,9 @@ namespace Ombi.UI.Modules.Admin
DiscordApi = discordapi; DiscordApi = discordapi;
RadarrSettings = settings; RadarrSettings = settings;
RadarrApi = radarrApi; RadarrApi = radarrApi;
EmbyApi = emby;
EmbySettings = embySettings;
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx); Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
Get["/"] = _ => Admin(); Get["/"] = _ => Admin();
@ -180,6 +185,10 @@ namespace Ombi.UI.Modules.Admin
Get["/plex"] = _ => Plex(); Get["/plex"] = _ => Plex();
Post["/plex", true] = async (x, ct) => await SavePlex(); Post["/plex", true] = async (x, ct) => await SavePlex();
Get["/emby", true] = async (x, ct) => await Emby();
Post["/emby", true] = async (x, ct) => await SaveEmby();
Get["/sonarr"] = _ => Sonarr(); Get["/sonarr"] = _ => Sonarr();
Post["/sonarr"] = _ => SaveSonarr(); Post["/sonarr"] = _ => SaveSonarr();
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles(); Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
@ -438,6 +447,21 @@ namespace Ombi.UI.Modules.Admin
return Response.AsJson(valid.SendJsonError()); return Response.AsJson(valid.SendJsonError());
} }
if (plexSettings.Enable)
{
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))
{ {
//Lookup identifier //Lookup identifier
@ -453,6 +477,49 @@ namespace Ombi.UI.Modules.Admin
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
} }
private async Task<Negotiator> Emby()
{
var settings = await EmbySettings.GetSettingsAsync();
return View["Emby", settings];
}
private async Task<Response> SaveEmby()
{
var emby = this.Bind<EmbySettings>();
var valid = this.Validate(emby);
if (!valid.IsValid)
{
return Response.AsJson(valid.SendJsonError());
}
if (emby.Enable)
{
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
var users = EmbyApi.GetUsers(emby.FullUri, emby.ApiKey);
// Find admin
var admin = users.FirstOrDefault(x => x.Policy.IsAdministrator);
emby.AdministratorId = admin?.Id;
var result = await EmbySettings.SaveSettingsAsync(emby);
return Response.AsJson(result
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Emby!" }
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
}
private Negotiator Sonarr() private Negotiator Sonarr()
{ {
var settings = SonarrService.GetSettings(); var settings = SonarrService.GetSettings();
@ -1063,6 +1130,8 @@ namespace Ombi.UI.Modules.Admin
{ {
var s = await ScheduledJobSettings.GetSettingsAsync(); var s = await ScheduledJobSettings.GetSettingsAsync();
var allJobs = await JobRecorder.GetJobsAsync(); var allJobs = await JobRecorder.GetJobsAsync();
var emby = await EmbySettings.GetSettingsAsync();
var plex = await PlexService.GetSettingsAsync();
var dict = new Dictionary<string, DateTime>(); var dict = new Dictionary<string, DateTime>();
@ -1083,6 +1152,8 @@ namespace Ombi.UI.Modules.Admin
var model = new ScheduledJobsViewModel var model = new ScheduledJobsViewModel
{ {
Emby = emby.Enable,
Plex = plex.Enable,
CouchPotatoCacher = s.CouchPotatoCacher, CouchPotatoCacher = s.CouchPotatoCacher,
PlexAvailabilityChecker = s.PlexAvailabilityChecker, PlexAvailabilityChecker = s.PlexAvailabilityChecker,
SickRageCacher = s.SickRageCacher, SickRageCacher = s.SickRageCacher,

@ -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, IEmbyUserChecker embyUser) : base("admin", settingsService, security)
{ {
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx); Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
@ -62,6 +64,10 @@ namespace Ombi.UI.Modules.Admin
RecentlyAdded = recentlyAdded; RecentlyAdded = recentlyAdded;
FaultQueueHandler = faultQueueHandler; FaultQueueHandler = faultQueueHandler;
PlexUserChecker = plexUserChecker; PlexUserChecker = plexUserChecker;
EmbyAvailabilityChecker = embyAvailabilityChecker;
EmbyContentCacher = embyContentCacher;
EmbyEpisodeCacher = embyEpisode;
EmbyUserChecker = embyUser;
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 +86,10 @@ 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 IEmbyUserChecker EmbyUserChecker { get; }
private async Task<Response> ScheduleRun(string key) private async Task<Response> ScheduleRun(string key)
@ -142,6 +152,22 @@ 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();
}
if (key.Equals(JobNames.EmbyUserChecker, StringComparison.CurrentCultureIgnoreCase))
{
EmbyUserChecker.Start();
}
return Response.AsJson(new JsonResponseModel { Result = true }); return Response.AsJson(new JsonResponseModel { Result = true });

@ -46,7 +46,7 @@ namespace Ombi.UI.Modules
public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi, public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi,
ISickRageApi srApi, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security, ISickRageApi srApi, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security,
IWatcherApi watcherApi, IRadarrApi radarrApi) : base("test", pr, security) IWatcherApi watcherApi, IRadarrApi radarrApi, IEmbyApi emby) : base("test", pr, security)
{ {
this.RequiresAuthentication(); this.RequiresAuthentication();
@ -57,6 +57,7 @@ namespace Ombi.UI.Modules
HeadphonesApi = hpApi; HeadphonesApi = hpApi;
WatcherApi = watcherApi; WatcherApi = watcherApi;
RadarrApi = radarrApi; RadarrApi = radarrApi;
Emby = emby;
Post["/cp"] = _ => CouchPotatoTest(); Post["/cp"] = _ => CouchPotatoTest();
Post["/sonarr"] = _ => SonarrTest(); Post["/sonarr"] = _ => SonarrTest();
@ -66,6 +67,7 @@ namespace Ombi.UI.Modules
Post["/headphones"] = _ => HeadphonesTest(); Post["/headphones"] = _ => HeadphonesTest();
Post["/plexdb"] = _ => TestPlexDb(); Post["/plexdb"] = _ => TestPlexDb();
Post["/watcher"] = _ => WatcherTest(); Post["/watcher"] = _ => WatcherTest();
Post["/emby"] = _ => EmbyTest();
} }
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); private static readonly Logger Log = LogManager.GetCurrentClassLogger();
@ -76,6 +78,7 @@ namespace Ombi.UI.Modules
private IHeadphonesApi HeadphonesApi { get; } private IHeadphonesApi HeadphonesApi { get; }
private IWatcherApi WatcherApi { get; } private IWatcherApi WatcherApi { get; }
private IRadarrApi RadarrApi { get; } private IRadarrApi RadarrApi { get; }
private IEmbyApi Emby { get; set; }
private Response CouchPotatoTest() private Response CouchPotatoTest()
{ {
@ -213,7 +216,7 @@ namespace Ombi.UI.Modules
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Plex, please check your settings." }); : Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Plex, please check your settings." });
} }
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them. catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
{ {
Log.Warn("Exception thrown when attempting to get Plex's status: "); Log.Warn("Exception thrown when attempting to get Plex's status: ");
Log.Warn(e); Log.Warn(e);
@ -225,6 +228,35 @@ namespace Ombi.UI.Modules
return Response.AsJson(new JsonResponseModel { Result = false, Message = message }); return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
} }
} }
private Response EmbyTest()
{
var emby = this.Bind<EmbySettings>();
var valid = this.Validate(emby);
if (!valid.IsValid)
{
return Response.AsJson(valid.SendJsonError());
}
try
{
var status = Emby.GetUsers(emby?.FullUri, emby?.ApiKey);
return status != null
? Response.AsJson(new JsonResponseModel { Result = true, Message = "Connected to Emby successfully!" })
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Emby, please check your settings." });
}
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
{
Log.Warn("Exception thrown when attempting to get Emby's users: ");
Log.Warn(e);
var message = $"Could not connect to Emby, please check your settings. <strong>Exception Message:</strong> {e.Message}";
if (e.InnerException != null)
{
message = $"Could not connect to Emby, please check your settings. <strong>Exception Message:</strong> {e.InnerException.Message}";
}
return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
}
}
private Response SickRageTest() private Response SickRageTest()
{ {

@ -65,7 +65,7 @@ namespace Ombi.UI.Modules
ISickRageApi sickRageApi, ISickRageApi sickRageApi,
ICacheProvider cache, ICacheProvider cache,
IAnalytics an, IAnalytics an,
INotificationEngine engine, IPlexNotificationEngine engine,
ISecurityExtensions security, ISecurityExtensions security,
ISettingsService<CustomizationSettings> customSettings) : base("requests", prSettings, security) ISettingsService<CustomizationSettings> customSettings) : base("requests", prSettings, security)
{ {
@ -438,8 +438,7 @@ namespace Ombi.UI.Modules
originalRequest.Available = available; originalRequest.Available = available;
var result = await Service.UpdateRequestAsync(originalRequest); var result = await Service.UpdateRequestAsync(originalRequest);
var plexService = await PlexSettings.GetSettingsAsync(); await NotificationEngine.NotifyUsers(originalRequest, available ? NotificationType.RequestAvailable : NotificationType.RequestDeclined);
await NotificationEngine.NotifyUsers(originalRequest, plexService.PlexAuthToken, available ? NotificationType.RequestAvailable : NotificationType.RequestDeclined);
return Response.AsJson(result return Response.AsJson(result
? new { Result = true, Available = available, Message = string.Empty } ? new { Result = true, Available = available, Message = string.Empty }
: new { Result = false, Available = false, Message = "Could not update the availability, please try again or check the logs" }); : new { Result = false, Available = false, Message = "Could not update the availability, please try again or check the logs" });

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save