More work around using the PlexDatabase

pull/591/head^2
Jamie.Rees 8 years ago
parent 67b124148c
commit dc92285cfa

@ -44,7 +44,8 @@ namespace PlexRequests.Core
if (!string.IsNullOrEmpty(settings.PlexDatabaseLocationOverride)) if (!string.IsNullOrEmpty(settings.PlexDatabaseLocationOverride))
{ {
Plex.DbLocation = settings.PlexDatabaseLocationOverride; //Overriden setting
Plex.DbLocation = Path.Combine(settings.PlexDatabaseLocationOverride, "Plug-in Support", "Databases", "com.plexapp.plugins.library.db");
} }
else if (Type.GetType("Mono.Runtime") != null) else if (Type.GetType("Mono.Runtime") != null)
{ {
@ -61,7 +62,11 @@ namespace PlexRequests.Core
public IEnumerable<MetadataItems> GetItemsAddedAfterDate(DateTime dateTime) public IEnumerable<MetadataItems> GetItemsAddedAfterDate(DateTime dateTime)
{ {
return Plex.QueryMetadataItems("select * from metadata_items where added_at > @AddedAt", // type 1 = Movie, type 4 = TV Episode
return Plex.QueryMetadataItems(@"SELECT * FROM metadata_items
WHERE added_at > @AddedAt
AND metadata_type in (1,4)
AND title <> ''",
new { AddedAt = dateTime }); new { AddedAt = dateTime });
} }
} }

@ -42,6 +42,7 @@ using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers; using PlexRequests.Helpers;
using PlexRequests.Services.Interfaces; using PlexRequests.Services.Interfaces;
using PlexRequests.Services.Jobs.Templates; using PlexRequests.Services.Jobs.Templates;
using PlexRequests.Store.Models.Plex;
using Quartz; using Quartz;
@ -52,7 +53,8 @@ namespace PlexRequests.Services.Jobs
public RecentlyAdded(IPlexApi api, ISettingsService<PlexSettings> plexSettings, public RecentlyAdded(IPlexApi api, ISettingsService<PlexSettings> plexSettings,
ISettingsService<EmailNotificationSettings> email, ISettingsService<EmailNotificationSettings> email,
ISettingsService<ScheduledJobsSettings> scheduledService, IJobRecord rec, ISettingsService<ScheduledJobsSettings> scheduledService, IJobRecord rec,
ISettingsService<PlexRequestSettings> plexRequest) ISettingsService<PlexRequestSettings> plexRequest,
IPlexReadOnlyDatabase db)
{ {
JobRecord = rec; JobRecord = rec;
Api = api; Api = api;
@ -60,6 +62,7 @@ namespace PlexRequests.Services.Jobs
EmailSettings = email; EmailSettings = email;
ScheduledJobsSettings = scheduledService; ScheduledJobsSettings = scheduledService;
PlexRequestSettings = plexRequest; PlexRequestSettings = plexRequest;
PlexDb = db;
} }
private IPlexApi Api { get; } private IPlexApi Api { get; }
@ -70,6 +73,7 @@ namespace PlexRequests.Services.Jobs
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; } private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
private ISettingsService<ScheduledJobsSettings> ScheduledJobsSettings { get; } private ISettingsService<ScheduledJobsSettings> ScheduledJobsSettings { get; }
private IJobRecord JobRecord { get; } private IJobRecord JobRecord { get; }
private IPlexReadOnlyDatabase PlexDb { get; }
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); private static readonly Logger Log = LogManager.GetCurrentClassLogger();
@ -108,7 +112,7 @@ namespace PlexRequests.Services.Jobs
public void Test() public void Test()
{ {
Start(true); StartDb(true);
} }
private void Start(bool testEmail = false) private void Start(bool testEmail = false)
@ -135,8 +139,26 @@ namespace PlexRequests.Services.Jobs
Send(html, plexSettings, testEmail); Send(html, plexSettings, testEmail);
} }
private void GenerateMovieHtml(IEnumerable<RecentlyAddedChild> movies, PlexSettings plexSettings, private void StartDb(bool testEmail = false)
ref StringBuilder sb) {
var sb = new StringBuilder();
var plexSettings = PlexSettings.GetSettings();
var recentlyAdded = PlexDb.GetItemsAddedAfterDate(DateTime.Now.AddDays(-7));
var movies = recentlyAdded.Where(x => x.MetadataType == 1);
var tv = recentlyAdded.Where(x => x.MetadataType == 4);
GenerateMovieHtmlDb(movies, ref sb);
GenerateTvHtml(tv, ref sb);
var template = new RecentlyAddedTemplate();
var html = template.LoadTemplate(sb.ToString());
Send(html, plexSettings, testEmail);
}
private void GenerateMovieHtml(IEnumerable<RecentlyAddedChild> movies, PlexSettings plexSettings,ref StringBuilder sb)
{ {
sb.Append("<h1>New Movies:</h1><br/><br/>"); sb.Append("<h1>New Movies:</h1><br/><br/>");
sb.Append( sb.Append(
@ -195,6 +217,65 @@ namespace PlexRequests.Services.Jobs
sb.Append("</table><br/><br/>"); sb.Append("</table><br/><br/>");
} }
private void GenerateMovieHtmlDb(IEnumerable<MetadataItems> movies, ref StringBuilder sb)
{
sb.Append("<h1>New Movies:</h1><br/><br/>");
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%\">");
foreach (var movie in movies)
{
var plexGUID = string.Empty;
try
{
plexGUID = movie.Guid;
var imdbId = PlexHelper.GetProviderIdFromPlexGuid(plexGUID);
var info = _movieApi.GetMovieInformation(imdbId).Result;
sb.Append("<tr>");
sb.Append("<td align=\"center\">");
sb.AppendFormat(
"<img src=\"https://image.tmdb.org/t/p/w500{0}\" width=\"400px\" text-align=\"center\" />",
info.BackdropPath);
sb.Append("</td>");
sb.Append("</tr>");
sb.Append("<tr>");
sb.Append(
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
sb.AppendFormat(
"<a href=\"https://www.imdb.com/title/{0}/\"><h3 style=\"font-family: sans-serif; font-weight: normal; margin: 0; Margin-bottom: 15px;\">{1} {2}</p></a>",
info.ImdbId, info.Title, info.ReleaseDate?.ToString("yyyy") ?? string.Empty);
if (info.Genres.Any())
{
sb.AppendFormat(
"<p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">Genre: {0}</p>",
string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray()));
}
sb.AppendFormat(
"<p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">{0}</p>",
info.Overview);
sb.Append("<td");
sb.Append("<hr>");
sb.Append("<br>");
sb.Append("<br>");
sb.Append("</tr>");
}
catch (Exception e)
{
Log.Error(e);
Log.Error("Exception when trying to process a Movie, either in getting the metadata from Plex OR getting the information from TheMovieDB, Plex GUID = {0}", plexGUID);
}
}
sb.Append("</table><br/><br/>");
}
private void GenerateTvHtml(IEnumerable<RecentlyAddedChild> tv, PlexSettings plexSettings, ref StringBuilder sb) private void GenerateTvHtml(IEnumerable<RecentlyAddedChild> tv, PlexSettings plexSettings, ref StringBuilder sb)
{ {
// TV // TV
@ -249,6 +330,65 @@ namespace PlexRequests.Services.Jobs
sb.Append("</table><br/><br/>"); sb.Append("</table><br/><br/>");
} }
private void GenerateTvHtml(IEnumerable<MetadataItems> tv, ref StringBuilder sb)
{
// TV
sb.Append("<h1>New Episodes:</h1><br/><br/>");
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%\">");
foreach (var t in tv)
{
var plexGUID = string.Empty;
try
{
plexGUID = t.Guid;
var seasonInfo = PlexHelper.GetSeasonsAndEpisodesFromPlexGuid(plexGUID);
var info = TvApi.ShowLookupByTheTvDbId(int.Parse(PlexHelper.GetProviderIdFromPlexGuid(plexGUID)));
var banner = info.image?.original;
if (!string.IsNullOrEmpty(banner))
{
banner = banner.Replace("http", "https"); // Always use the Https banners
}
sb.Append("<tr>");
sb.Append("<td align=\"center\">");
sb.AppendFormat("<img src=\"{0}\" width=\"400px\" text-align=\"center\" />", banner);
sb.Append("</td>");
sb.Append("</tr>");
sb.Append("<tr>");
sb.Append("<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
sb.AppendFormat("<a href=\"https://www.imdb.com/title/{0}/\"><h3 style=\"font-family: sans-serif; font-weight: normal; margin: 0; Margin-bottom: 15px;\">{1} {2}</p></a>",
info.externals.imdb, info.name, info.premiered.Substring(0, 4)); // Only the year
sb.AppendFormat("<p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">Season: {0}, Episode: {1}</p>", seasonInfo.SeasonNumber, seasonInfo.EpisodeNumber);
if (info.genres.Any())
{
sb.AppendFormat(
"<p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">Genre: {0}</p>",
string.Join(", ", info.genres.Select(x => x.ToString()).ToArray()));
}
sb.AppendFormat("<p style=\"font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;\">{0}</p>",
string.IsNullOrEmpty(t.Summary) ? info.summary : t.Summary); // Episode Summary
sb.Append("<td");
sb.Append("<hr>");
sb.Append("<br>");
sb.Append("<br>");
sb.Append("</tr>");
}
catch (Exception e)
{
Log.Error(e);
Log.Error("Exception when trying to process a TV Show, either in getting the metadata from Plex OR getting the information from TVMaze, Plex GUID = {0}", plexGUID);
}
}
sb.Append("</table><br/><br/>");
}
private void Send(string html, PlexSettings plexSettings, bool testEmail = false) private void Send(string html, PlexSettings plexSettings, bool testEmail = false)
{ {
var settings = EmailSettings.GetSettings(); var settings = EmailSettings.GetSettings();

@ -84,7 +84,7 @@ namespace PlexRequests.Store
{ {
using (var con = DbConnection()) using (var con = DbConnection())
{ {
return con.Query<MetadataItems>(query, param); return (IEnumerable<MetadataItems>)con.Query(query, param);
} }
} }
} }

@ -122,8 +122,8 @@ namespace PlexRequests.UI.Helpers
var sb = new StringBuilder(); var sb = new StringBuilder();
var startUrl = $"{content}/Content"; var startUrl = $"{content}/Content";
sb.AppendLine($"<link rel=\"stylesheet\" href=\"/{startUrl}/datepicker.min.css\" type=\"text/css\"/>"); sb.AppendLine($"<link rel=\"stylesheet\" href=\"{startUrl}/datepicker.min.css\" type=\"text/css\"/>");
sb.AppendLine($"<script src=\"/{startUrl}/bootstrap-datetimepicker.min.js\"></script>"); sb.AppendLine($"<script src=\"{startUrl}/bootstrap-datetimepicker.min.js\"></script>");
return helper.Raw(sb.ToString()); return helper.Raw(sb.ToString());
} }

@ -25,7 +25,8 @@
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System; using System;
using System.IO;
using Mono.Data.Sqlite;
using Nancy; using Nancy;
using Nancy.ModelBinding; using Nancy.ModelBinding;
using Nancy.Security; using Nancy.Security;
@ -35,6 +36,8 @@ using NLog;
using PlexRequests.Api.Interfaces; using PlexRequests.Api.Interfaces;
using PlexRequests.Core; using PlexRequests.Core;
using PlexRequests.Core.SettingModels; using PlexRequests.Core.SettingModels;
using PlexRequests.Store;
using PlexRequests.Store.Repository;
using PlexRequests.UI.Helpers; using PlexRequests.UI.Helpers;
using PlexRequests.UI.Models; using PlexRequests.UI.Models;
@ -59,7 +62,7 @@ namespace PlexRequests.UI.Modules
Post["/plex"] = _ => PlexTest(); Post["/plex"] = _ => PlexTest();
Post["/sickrage"] = _ => SickRageTest(); Post["/sickrage"] = _ => SickRageTest();
Post["/headphones"] = _ => HeadphonesTest(); Post["/headphones"] = _ => HeadphonesTest();
Post["/plexdb"] = _ => TestPlexDb();
} }
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); private static readonly Logger Log = LogManager.GetCurrentClassLogger();
@ -223,5 +226,65 @@ namespace PlexRequests.UI.Modules
return Response.AsJson(new JsonResponseModel { Result = false, Message = message }); ; return Response.AsJson(new JsonResponseModel { Result = false, Message = message }); ;
} }
} }
private Response TestPlexDb()
{
var settings = this.Bind<PlexSettings>();
var valid = this.Validate(settings);
if (!valid.IsValid)
{
return Response.AsJson(valid.SendJsonError());
}
try
{
var location = string.Empty;
if (string.IsNullOrEmpty(settings.PlexDatabaseLocationOverride))
{
if (Type.GetType("Mono.Runtime") != null)
{
// Mono
location = Path.Combine("/var/lib/plexmediaserver/Library/Application Support/",
"Plex Media Server", "Plug-in Support", "Databases", "com.plexapp.plugins.library.db");
}
else
{
// Default Windows
location = Path.Combine(Environment.ExpandEnvironmentVariables("%LOCALAPPDATA%"),
"Plex Media Server", "Plug-in Support", "Databases", "com.plexapp.plugins.library.db");
}
}
else
{
location = Path.Combine(settings.PlexDatabaseLocationOverride, "Plug-in Support", "Databases", "com.plexapp.plugins.library.db");
}
if (File.Exists(location))
{
return Response.AsJson(new JsonResponseModel
{
Result = true,
Message = "Found the database!"
});
}
return Response.AsJson(new JsonResponseModel
{
Result = false,
Message = $"Could not find the database at the following full location : {location}"
});
}
catch (Exception e)
{
Log.Warn("Exception thrown when attempting to find the plex database: ");
Log.Warn(e);
var message = $"Could not find Plex's DB, please check your settings. <strong>Exception Message:</strong> {e.Message}";
if (e.InnerException != null)
{
message = $"Could not find Plex's DB, please check your settings. <strong>Exception Message:</strong> {e.InnerException.Message}";
}
return Response.AsJson(new JsonResponseModel { Result = false, Message = message }); ;
}
}
} }
} }

@ -46,6 +46,7 @@ namespace PlexRequests.UI.NinjectModules
Bind<ICacheProvider>().To<MemoryCacheProvider>().InSingletonScope(); Bind<ICacheProvider>().To<MemoryCacheProvider>().InSingletonScope();
Bind<ISqliteConfiguration>().To<DbConfiguration>().WithConstructorArgument("provider", new SqliteFactory()); Bind<ISqliteConfiguration>().To<DbConfiguration>().WithConstructorArgument("provider", new SqliteFactory());
Bind<IPlexDatabase>().To<PlexDatabase>().WithConstructorArgument("provider", new SqliteFactory()); Bind<IPlexDatabase>().To<PlexDatabase>().WithConstructorArgument("provider", new SqliteFactory());
Bind<IPlexReadOnlyDatabase>().To<PlexReadOnlyDatabase>();
Bind<IUserMapper>().To<UserMapper>(); Bind<IUserMapper>().To<UserMapper>();

@ -121,6 +121,8 @@
}); });
$('#save').click(function (e) { $('#save').click(function (e) {
e.preventDefault();
var start = ''; var start = '';
var end = ''; var end = '';
if ($startDate.data("DateTimePicker").date()) { if ($startDate.data("DateTimePicker").date()) {
@ -130,8 +132,6 @@
end = $endDate.data("DateTimePicker").date().toISOString(); end = $endDate.data("DateTimePicker").date().toISOString();
} }
e.preventDefault();
var $form = $("#mainForm"); var $form = $("#mainForm");
var data = $form.serialize(); var data = $form.serialize();

@ -91,7 +91,15 @@
<div class="form-group"> <div class="form-group">
<label for="PlexDatabaseLocationOverride" class="control-label">Plex Database Override</label> <label for="PlexDatabaseLocationOverride" class="control-label">Plex Database Override</label>
<div> <div>
<input type="text" class="form-control form-control-custom " id="PlexDatabaseLocationOverride" name="PlexDatabaseLocationOverride" value="@Model.PlexDatabaseLocationOverride"> <input type="text" class="form-control form-control-custom " id="PlexDatabaseLocationOverride" name="PlexDatabaseLocationOverride" placeholder="%LOCALAPPDATA%\Plex Media Server\" value="@Model.PlexDatabaseLocationOverride">
</div>
<small>
This is your Plex data directory location, if we cannot manually find it then you need to specify the location! See <a href="https://support.plex.tv/hc/en-us/articles/202915258-Where-is-the-Plex-Media-Server-data-directory-located-">Here</a>.
</small>
</div>
<div class="form-group">
<div class="">
<button id="dbTest" class="btn btn-primary-outline">Test Database Directory <i class="fa fa-database"></i> <div id="dbSpinner"></div></button>
</div> </div>
</div> </div>
@ -102,6 +110,8 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label">Username and Password</label> <label for="username" class="control-label">Username and Password</label>
<div> <div>
@ -173,6 +183,38 @@
}); });
}); });
$('#dbTest').click(function (e) {
e.preventDefault();
var url = createBaseUrl(base, '/test/plexdb');
var $form = $("#mainForm");
$('#dbSpinner').attr("class", "fa fa-spinner fa-spin");
$.ajax({
type: $form.prop("method"),
url: url,
data: $form.serialize(),
dataType: "json",
success: function (response) {
$('#dbSpinner').attr("class", "");
console.log(response);
if (response.result === true) {
generateNotify(response.message, "success");
$('#dbSpinner').attr("class", "fa fa-check");
} else {
generateNotify(response.message, "warning");
$('#dbSpinner').attr("class", "fa fa-times");
}
},
error: function (e) {
$('#spinner').attr("class", "fa fa-times");
console.log(e);
generateNotify("Something went wrong!", "danger");
}
});
});
$('#requestToken').click(function (e) { $('#requestToken').click(function (e) {
e.preventDefault(); e.preventDefault();
var $form = $("#mainForm"); var $form = $("#mainForm");

Loading…
Cancel
Save