1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-23 17:14:46 -04:00

Compare commits

...

15 Commits

Author SHA1 Message Date
Leonardo Galli
5a8d944397 Fixed sorting in movie list view. Also added new downloaded quality column.
Fixes #128
2017-01-12 23:07:09 +01:00
Leonardo Galli
0b70a5c315 Should fix ordering of releases. Fixes #147 (hopefully) 2017-01-12 22:12:32 +01:00
Leonardo Galli
91cded3b71 Merge pull request #202 from Radarr/onedr0p-patch-1
Update UserAgentBuilder.cs
2017-01-12 21:48:16 +01:00
Leonardo Galli
84112dc85b Should fix queueService failed while processing
(#178)
2017-01-12 21:48:02 +01:00
Devin Buhl
b1b947ae7f Update UserAgentBuilder.cs
Make user-agent Radarr
2017-01-12 15:41:56 -05:00
Leonardo Galli
1b035f8657 Update Parser to support large array of Extended, Director, Collectors, ... Cut, Edition, etc.
Fixes #192
2017-01-12 19:21:09 +01:00
Devin Buhl
9d50f4d651 Merge pull request #199 from Radarr/patch/add-uhd-todefault-indexers
Add UHD to default movie categories for newsnab providers
2017-01-12 12:58:23 -05:00
Devin Buhl
c06a6dc988 Add UHD to default movie categories for newsnab providers 2017-01-12 12:53:09 -05:00
Devin Buhl
f198ca2b77 Merge pull request #177 from Radarr/patch/sort-title
Movies in list don't sort correctly #174
2017-01-12 01:08:32 -05:00
Devin Buhl
9cfc766889 Merge pull request #180 from wcomartin/Issue115
Changed Sonarr Branding to Radarr
2017-01-11 23:27:31 -05:00
William Comartin
5ef1e40403 Change Sonarr to Radarr in CLA.md and CONTRIBUTING.md 2017-01-11 22:02:54 -05:00
William Comartin
c9e6835d7b Change Sonarr to Radarr in Help Text, and in Notification Text
Change sonarr log files to radarr log files
2017-01-11 21:59:13 -05:00
William Comartin
604cea00f6 Replace Sonarr With Radarr in UI Directory 2017-01-11 21:42:47 -05:00
Tim Turner
b4782da1d1 Update sortValue when selecting movie for manual import 2017-01-11 19:29:22 -05:00
Devin Buhl
d5504043c5 Movies in list don't sort correctly #174 2017-01-11 19:06:08 -05:00
58 changed files with 262 additions and 99 deletions

4
CLA.md
View File

@@ -1,6 +1,6 @@
# Sonarr Individual Contributor License Agreement #
# Radarr Individual Contributor License Agreement #
Thank you for your interest in contributing to Sonarr ("We" or "Us").
Thank you for your interest in contributing to Radarr ("We" or "Us").
This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please complete the form below. This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us.
## 1. Definitions ##

View File

@@ -1,6 +1,6 @@
# How to Contribute #
We're always looking for people to help make Sonarr even better, there are a number of ways to contribute.
We're always looking for people to help make Radarr even better, there are a number of ways to contribute.
## Documentation ##
Setup guides, FAQ, the more information we have on the wiki the better.
@@ -15,7 +15,7 @@ Setup guides, FAQ, the more information we have on the wiki the better.
### Getting started ###
1. Fork Sonarr
1. Fork Radarr
2. Clone (develop branch) *you may need pull in submodules separately if you client doesn't clone them automatically (CurlSharp)*
3. Run `npm install`
4. Run `npm start` - Used to compile the UI components and copy them.
@@ -24,8 +24,8 @@ Setup guides, FAQ, the more information we have on the wiki the better.
5. Compile in Visual Studio
### Contributing Code ###
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Sonarr/Sonarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Sonarr's develop branch, don't merge
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Radarr/Radarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Radarr's develop branch, don't merge
- Make meaningful commits, or squash them
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
- Reach out to us on the forums or on IRC if you have any questions

View File

@@ -27,6 +27,7 @@ namespace NzbDrone.Api.Calendar
Get["/NzbDrone.ics"] = options => GetCalendarFeed();
Get["/Sonarr.ics"] = options => GetCalendarFeed();
Get["/Radarr.ics"] = options => GetCalendarFeed();
}
private Response GetCalendarFeed()

View File

@@ -23,7 +23,7 @@ namespace NzbDrone.Common
Console.WriteLine(" Commands:");
Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
Console.WriteLine(" /{0} Don't open Sonarr in a browser", StartupContext.NO_BROWSER);
Console.WriteLine(" /{0} Don't open Radarr in a browser", StartupContext.NO_BROWSER);
Console.WriteLine(" <No Arguments> Run application in console mode.");
}

View File

@@ -9,12 +9,12 @@ namespace NzbDrone.Common.Http
static UserAgentBuilder()
{
UserAgent = string.Format("Sonarr/{0} ({1} {2})",
UserAgent = string.Format("Radarr/{0} ({1} {2})",
BuildInfo.Version,
OsInfo.Os, OsInfo.Version.ToString(2));
UserAgentSimplified = string.Format("Sonarr/{0}",
UserAgentSimplified = string.Format("Radarr/{0}",
BuildInfo.Version.ToString(2));
}
}
}
}

View File

@@ -103,9 +103,9 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterAppFile(IAppFolderInfo appFolderInfo)
{
RegisterAppFile(appFolderInfo, "appFileInfo", "sonarr.txt", 5, LogLevel.Info);
RegisterAppFile(appFolderInfo, "appFileDebug", "sonarr.debug.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileTrace", "sonarr.trace.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileInfo", "radarr.txt", 5, LogLevel.Info);
RegisterAppFile(appFolderInfo, "appFileDebug", "radarr.debug.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileTrace", "radarr.trace.txt", 50, LogLevel.Off);
}
private static LoggingRule RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)

View File

@@ -0,0 +1,45 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(115)]
public class update_movie_sorttitle : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
// Create.Column("SortTitle").OnTable("Series").AsString().Nullable();
Execute.WithConnection(SetSortTitles);
}
private void SetSortTitles(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Id, Title FROM Movies";
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var id = seriesReader.GetInt32(0);
var title = seriesReader.GetString(1);
var sortTitle = Parser.Parser.NormalizeTitle(title).ToLower();
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE Movies SET SortTitle = ? WHERE Id = ?";
updateCmd.AddParameter(sortTitle);
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

View File

@@ -24,8 +24,6 @@ namespace NzbDrone.Core.DecisionEngine
{
CompareQuality,
CompareProtocol,
CompareEpisodeCount,
CompareEpisodeNumber,
ComparePeersIfTorrent,
CompareAgeIfUsenet,
CompareSize
@@ -56,6 +54,12 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareQuality(DownloadDecision x, DownloadDecision y)
{
if (x.IsForMovie && y.IsForMovie)
{
return CompareAll(CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.Movie.Profile.Value.Items.FindIndex(v => v.Quality == remoteEpisode.ParsedMovieInfo.Quality.Quality)),
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.ParsedMovieInfo.Quality.Revision.Real),
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.ParsedMovieInfo.Quality.Revision.Version));
}
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.Profile.Value.Items.FindIndex(v => v.Quality == remoteEpisode.ParsedEpisodeInfo.Quality.Quality)),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Real),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version));
@@ -63,6 +67,7 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
{
var result = CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Series.Tags);
@@ -70,13 +75,22 @@ namespace NzbDrone.Core.DecisionEngine
return downloadProtocol == delayProfile.PreferredProtocol;
});
if (x.IsForMovie)
{
result = CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Movie.Tags);
var downloadProtocol = remoteEpisode.Release.DownloadProtocol;
return downloadProtocol == delayProfile.PreferredProtocol;
});
}
return result;
}
private int CompareEpisodeCount(DownloadDecision x, DownloadDecision y)
{
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.FullSeason),
CompareByReverse(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Episodes.Count));
return 0;
}
private int CompareEpisodeNumber(DownloadDecision x, DownloadDecision y)
@@ -88,20 +102,20 @@ namespace NzbDrone.Core.DecisionEngine
{
// Different protocols should get caught when checking the preferred protocol,
// since we're dealing with the same series in our comparisions
if (x.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Torrent ||
y.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Torrent)
if (x.RemoteMovie.Release.DownloadProtocol != DownloadProtocol.Torrent ||
y.RemoteMovie.Release.DownloadProtocol != DownloadProtocol.Torrent)
{
return 0;
}
return CompareAll(
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var seeders = TorrentInfo.GetSeeders(remoteEpisode.Release);
return seeders.HasValue && seeders.Value > 0 ? Math.Round(Math.Log10(seeders.Value)) : 0;
}),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var peers = TorrentInfo.GetPeers(remoteEpisode.Release);
@@ -117,7 +131,7 @@ namespace NzbDrone.Core.DecisionEngine
return 0;
}
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var ageHours = remoteEpisode.Release.AgeHours;
var age = remoteEpisode.Release.Age;
@@ -145,7 +159,7 @@ namespace NzbDrone.Core.DecisionEngine
{
// TODO: Is smaller better? Smaller for usenet could mean no par2 files.
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Release.Size.Round(200.Megabytes()));
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.Release.Size.Round(200.Megabytes()));
}
}
}

View File

@@ -26,10 +26,10 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
private static readonly TorrentBlackholeSettingsValidator Validator = new TorrentBlackholeSettingsValidator();
[FieldDefinition(0, Label = "Torrent Folder", Type = FieldType.Path, HelpText = "Folder in which Sonarr will store the .torrent file")]
[FieldDefinition(0, Label = "Torrent Folder", Type = FieldType.Path, HelpText = "Folder in which Radarr will store the .torrent file")]
public string TorrentFolder { get; set; }
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Sonarr should import completed downloads")]
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Radarr should import completed downloads")]
public string WatchFolder { get; set; }
[DefaultValue(false)]
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
[DefaultValue(false)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[FieldDefinition(3, Label = "Read Only", Type = FieldType.Checkbox, HelpText = "Instead of moving files this will instruct Sonarr to Copy or Hardlink (depending on settings/system configuration)")]
[FieldDefinition(3, Label = "Read Only", Type = FieldType.Checkbox, HelpText = "Instead of moving files this will instruct Radarr to Copy or Hardlink (depending on settings/system configuration)")]
public bool ReadOnly { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -19,10 +19,10 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
private static readonly UsenetBlackholeSettingsValidator Validator = new UsenetBlackholeSettingsValidator();
[FieldDefinition(0, Label = "Nzb Folder", Type = FieldType.Path, HelpText = "Folder in which Sonarr will store the .nzb file")]
[FieldDefinition(0, Label = "Nzb Folder", Type = FieldType.Path, HelpText = "Folder in which Radarr will store the .nzb file")]
public string NzbFolder { get; set; }
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Sonarr should import completed downloads")]
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Radarr should import completed downloads")]
public string WatchFolder { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -306,7 +306,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
{
return new NzbDroneValidationFailure("TvCategory", "Configuration of label failed")
{
DetailedDescription = "Sonarr as unable to add the label to Deluge."
DetailedDescription = "Radarr as unable to add the label to Deluge."
};
}
}

View File

@@ -43,7 +43,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
[FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox)]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Group", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(3, Label = "Group", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
[FieldDefinition(4, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbVortexPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

View File

@@ -337,7 +337,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 0")
{
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Sonarr from seeing completed downloads."
DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
};
}

View File

@@ -45,7 +45,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

View File

@@ -372,7 +372,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("Version", "Sabnzbd develop version, assuming version 1.1.0 or higher.")
{
IsWarning = true,
DetailedDescription = "Sonarr may not be able to support new features added to SABnzbd when running develop versions."
DetailedDescription = "Radarr may not be able to support new features added to SABnzbd when running develop versions."
};
}
@@ -431,7 +431,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("", "Disable 'Check before download' option in Sabnbzd")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port),
DetailedDescription = "Using Check before download affects Sonarr ability to track new downloads. Also Sabnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective."
DetailedDescription = "Using Check before download affects Radarr ability to track new downloads. Also Sabnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective."
};
}
@@ -450,7 +450,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "Enable Job folders")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
DetailedDescription = "Sonarr prefers each download to have a separate folder. With * appended to the Folder/Path Sabnzbd will not create these job folders. Go to Sabnzbd to fix it."
DetailedDescription = "Radarr prefers each download to have a separate folder. With * appended to the Folder/Path Sabnzbd will not create these job folders. Go to Sabnzbd to fix it."
};
}
}
@@ -475,7 +475,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "Disable TV Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd TV Sorting for the category Sonarr uses to prevent import issues. Go to Sabnzbd to fix it."
DetailedDescription = "You must disable Sabnzbd TV Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it."
};
}
}
@@ -489,7 +489,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "Disable Movie Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd Movie Sorting for the category Sonarr uses to prevent import issues. Go to Sabnzbd to fix it."
DetailedDescription = "You must disable Sabnzbd Movie Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it."
};
}
}
@@ -503,7 +503,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "Disable Date Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd Date Sorting for the category Sonarr uses to prevent import issues. Go to Sabnzbd to fix it."
DetailedDescription = "You must disable Sabnzbd Date Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it."
};
}
}

View File

@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

View File

@@ -232,7 +232,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
_logger.Error(ex, ex.Message);
return new NzbDroneValidationFailure("Username", "Authentication failure")
{
DetailedDescription = string.Format("Please verify your username and password. Also verify if the host running Sonarr isn't blocked from accessing {0} by WhiteList limitations in the {0} configuration.", Name)
DetailedDescription = string.Format("Please verify your username and password. Also verify if the host running Radarr isn't blocked from accessing {0} by WhiteList limitations in the {0} configuration.", Name)
};
}
catch (WebException ex)

View File

@@ -50,7 +50,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")]
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")]
public string TvCategory { get; set; }
[FieldDefinition(6, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default Transmission location")]

View File

@@ -49,7 +49,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
[FieldDefinition(5, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional.")]
[FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional.")]
public string TvCategory { get; set; }
[FieldDefinition(7, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default rTorrent location")]

View File

@@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

View File

@@ -109,7 +109,11 @@ namespace NzbDrone.Core.Download
if (movie == null)
{
movie = _movieService.GetMovie(historyItem.MovieId);
if (historyItem != null)
{
movie = _movieService.GetMovie(historyItem.MovieId);
}
if (movie == null)
{

View File

@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Download
if (grabbedItems.Empty())
{
trackedDownload.Warn("Download wasn't grabbed by sonarr, skipping");
trackedDownload.Warn("Download wasn't grabbed by Radarr, skipping");
return;
}

View File

@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Newznab
public NewznabSettings()
{
Categories = new[] { 2030, 2035, 2040, 2050 };
Categories = new[] { 2030, 2035, 2040, 2045, 2050 };
AnimeCategories = Enumerable.Empty<int>();
}

View File

@@ -327,7 +327,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
imdbMovie.TmdbId = result.id;
try
{
imdbMovie.SortTitle = result.title;
imdbMovie.SortTitle = Parser.Parser.NormalizeTitle(result.title);
imdbMovie.Title = result.title;
string titleSlug = result.title;
imdbMovie.TitleSlug = titleSlug.ToLower().Replace(" ", "-");

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.Email
public override void OnGrab(GrabMessage grabMessage)
{
const string subject = "Sonarr [TV] - Grabbed";
const string subject = "Radarr [TV] - Grabbed";
var body = string.Format("{0} sent to queue.", grabMessage.Message);
_emailService.SendEmail(Settings, subject, body);
@@ -26,7 +26,7 @@ namespace NzbDrone.Core.Notifications.Email
public override void OnDownload(DownloadMessage message)
{
const string subject = "Sonarr [TV] - Downloaded";
const string subject = "Radarr [TV] - Downloaded";
var body = string.Format("{0} Downloaded and sorted.", message.Message);
_emailService.SendEmail(Settings, subject, body);

View File

@@ -64,7 +64,7 @@ namespace NzbDrone.Core.Notifications.Email
try
{
SendEmail(settings, "Sonarr - Test Notification", body);
SendEmail(settings, "Radarr - Test Notification", body);
}
catch (Exception ex)
{

View File

@@ -18,14 +18,14 @@ namespace NzbDrone.Core.Notifications.Join
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Episode Grabbed";
const string title = "Radarr - Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Episode Downloaded";
const string title = "Radarr - Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Grabbed";
const string title = "Radarr - Grabbed";
if (Settings.Notify)
{
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Downloaded";
const string title = "Radarr - Downloaded";
if (Settings.Notify)
{

View File

@@ -18,13 +18,13 @@ namespace NzbDrone.Core.Notifications.Plex
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr [TV] - Grabbed";
const string header = "Radarr [TV] - Grabbed";
_plexClientService.Notify(Settings, header, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr [TV] - Downloaded";
const string header = "Radarr [TV] - Downloaded";
_plexClientService.Notify(Settings, header, message.Message);
}

View File

@@ -23,14 +23,14 @@ namespace NzbDrone.Core.Notifications.Plex
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr - Grabbed";
const string header = "Radarr - Grabbed";
Notify(Settings, header, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr - Downloaded";
const string header = "Radarr - Downloaded";
Notify(Settings, header, message.Message);
}

View File

@@ -98,7 +98,7 @@ namespace NzbDrone.Core.Notifications.Plex
{
if (version >= new Version(1, 3, 0) && version < new Version(1, 3, 1))
{
throw new PlexVersionException("Found version {0}, upgrade to PMS 1.3.1 to fix library updating and then restart Sonarr", version);
throw new PlexVersionException("Found version {0}, upgrade to PMS 1.3.1 to fix library updating and then restart Radarr", version);
}
}

View File

@@ -18,14 +18,14 @@ namespace NzbDrone.Core.Notifications.PushBullet
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Episode Grabbed";
const string title = "Radarr - Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Episode Downloaded";
const string title = "Radarr - Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}

View File

@@ -92,7 +92,7 @@ namespace NzbDrone.Core.Notifications.PushBullet
{
try
{
const string title = "Sonarr - Test Notification";
const string title = "Radarr - Test Notification";
const string body = "This is a test message from Radarr";
SendNotification(title, body, settings);

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.Pushalot
[FieldDefinition(1, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(PushalotPriority))]
public int Priority { get; set; }
[FieldDefinition(2, Label = "Image", Type = FieldType.Checkbox, HelpText = "Include Sonarr logo with notifications")]
[FieldDefinition(2, Label = "Image", Type = FieldType.Checkbox, HelpText = "Include Radarr logo with notifications")]
public bool Image { get; set; }
public bool IsValid => !string.IsNullOrWhiteSpace(AuthToken);

View File

@@ -101,7 +101,7 @@ namespace NzbDrone.Core.Notifications.Slack
{
try
{
var message = $"Test message from Sonarr posted at {DateTime.Now}";
var message = $"Test message from Radarr posted at {DateTime.Now}";
var payload = new SlackPayload
{
IconEmoji = Settings.Icon,

View File

@@ -125,7 +125,7 @@ namespace NzbDrone.Core.Notifications.Twitter
{
try
{
var body = "Sonarr: Test Message @ " + DateTime.Now;
var body = "Radarr: Test Message @ " + DateTime.Now;
SendNotification(body, settings);
}

View File

@@ -23,14 +23,14 @@ namespace NzbDrone.Core.Notifications.Xbmc
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr - Grabbed";
const string header = "Radarr - Grabbed";
Notify(Settings, header, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr - Downloaded";
const string header = "Radarr - Downloaded";
Notify(Settings, header, message.Message);
UpdateAndClean(message.Series, message.OldFiles.Any());

View File

@@ -183,6 +183,7 @@
<Compile Include="Datastore\Migration\002_remove_tvrage_imdb_unique_constraint.cs" />
<Compile Include="Datastore\Migration\003_remove_clean_title_from_scene_mapping.cs" />
<Compile Include="Datastore\Migration\004_updated_history.cs" />
<Compile Include="Datastore\Migration\115_update_movie_sorttitle.cs" />
<Compile Include="Datastore\Migration\111_remove_bitmetv.cs" />
<Compile Include="Datastore\Migration\112_remove_torrentleech.cs" />
<Compile Include="Datastore\Migration\114_remove_fanzub.cs" />

View File

@@ -18,16 +18,10 @@ namespace NzbDrone.Core.Parser
private static readonly Regex[] ReportMovieTitleRegex = new[]
{
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\w+\.?edition))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\.?((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX)))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily!
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}edition))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Cut Movies, e.g: Mission.Impossible.3.Directors.Cut.2011
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\w+\.?cut))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Cut Movies, e.g: Mission.Impossible.3.2011.Directors.Cut
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}cut))",
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Normal movie format, e.g: Mission.Impossible.3.2011

View File

@@ -24,7 +24,7 @@ namespace Radarr.Host
SecurityProtocolPolicy.Register();
X509CertificateValidationPolicy.Register();
Logger.Info("Starting Sonarr - {0} - Version {1}", Assembly.GetCallingAssembly().Location, Assembly.GetExecutingAssembly().GetName().Version);
Logger.Info("Starting Radarr - {0} - Version {1}", Assembly.GetCallingAssembly().Location, Assembly.GetExecutingAssembly().GetName().Version);
if (!PlatformValidation.IsValidate(userAlert))
{

View File

@@ -91,7 +91,7 @@
{{/if_eq}}
{{#if_eq reason compare="MissingFromDisk"}}
Sonarr was unable to find the file on disk so it was removed
Radarr was unable to find the file on disk so it was removed
{{/if_eq}}
{{#if_eq reason compare="Upgrade"}}

View File

@@ -1,7 +1,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Sonarr Calendar feed</h3>
<h3>Radarr Calendar feed</h3>
</div>
<div class="modal-body edit-series-modal">
<div class="form-horizontal">

View File

@@ -0,0 +1,34 @@
var Backgrid = require('backgrid');
var ProfileCollection = require('../Profile/ProfileCollection');
var _ = require('underscore');
module.exports = Backgrid.Cell.extend({
className : 'profile-cell',
_originalInit : Backgrid.Cell.prototype.initialize,
initialize : function () {
this._originalInit.apply(this, arguments);
this.listenTo(ProfileCollection, 'sync', this.render);
},
render : function() {
this.$el.empty();
if (this.model.get("movieFile")) {
var profileId = this.model.get("movieFile").quality.quality.id;
var profile = _.findWhere(ProfileCollection.models, { id : profileId });
if (profile) {
this.$el.html(profile.get('name'));
} else {
this.$el.html(this.model.get("movieFile").quality.quality.name);
}
}
return this;
}
});

View File

@@ -3,4 +3,8 @@ var TemplatedCell = require('./TemplatedCell');
module.exports = TemplatedCell.extend({
className : 'movie-title-cell',
template : 'Cells/MovieDownloadStatusTemplate',
sortKey : function(model) {
debugger;
return 0;
}
});

View File

@@ -21,7 +21,7 @@ module.exports = Marionette.Layout.extend({
name : 'title',
label : 'Title',
cell : 'String',
sortValue : 'sortTitle'
sortValue : 'title'
}
],

View File

@@ -13,6 +13,7 @@ var MovieLinksCell = require('../../Cells/MovieLinksCell');
var MovieActionCell = require('../../Cells/MovieActionCell');
var MovieStatusCell = require('../../Cells/MovieStatusCell');
var MovieDownloadStatusCell = require('../../Cells/MovieDownloadStatusCell');
var DownloadedQualityCell = require('../../Cells/DownloadedQualityCell');
var FooterView = require('./FooterView');
var FooterModel = require('./FooterModel');
var ToolbarLayout = require('../../Shared/Toolbar/ToolbarLayout');
@@ -40,6 +41,11 @@ module.exports = Marionette.Layout.extend({
cell : MovieTitleCell,
cellValue : 'this',
},
{
name : "downloadedQuality",
label : "Downloaded",
cell : DownloadedQualityCell,
},
{
name : 'profileId',
label : 'Profile',
@@ -54,12 +60,19 @@ module.exports = Marionette.Layout.extend({
name : 'this',
label : 'Links',
cell : MovieLinksCell,
className : "movie-links-cell"
className : "movie-links-cell",
sortable : false,
},
{
name : "this",
label : "Status",
cell : MovieDownloadStatusCell,
sortValue : function(m, k) {
if (m.get("downloaded")) {
return -1;
}
return 0;
}
},
{
name : 'this',

View File

@@ -9,5 +9,31 @@ module.exports = Backbone.Model.extend({
episodeCount : 0,
isExisting : false,
status : 0
},
getStatus : function() {
var monitored = this.get("monitored");
var status = this.get("status");
var inCinemas = this.get("inCinemas");
var date = new Date(inCinemas);
var timeSince = new Date().getTime() - date.getTime();
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
if (status === "announced") {
return "announced"
}
if (numOfMonths < 3 && numOfMonths > 0) {
return "inCinemas";
}
if (status === 'released') {
return "released";
}
if (numOfMonths > 3) {
return "released";//TODO: Update for PreDB.me
}
}
});

View File

@@ -15,10 +15,10 @@ var Collection = PageableCollection.extend({
tableName : 'movie',
state : {
sortKey : 'title',
sortKey : 'sortTitle',
order : 1,
pageSize : 100000,
secondarySortKey : 'title',
secondarySortKey : 'sortTitle',
secondarySortOrder : -1
},
@@ -73,9 +73,28 @@ var Collection = PageableCollection.extend({
sortMappings : {
title : {
sortKey : 'title'
sortKey : 'sortTitle'
},
statusWeight : {
sortValue : function(model, attr) {
if (model.getStatus() == "released") {
return 1;
}
if (model.getStatus() == "inCinemas") {
return 0;
}
return -1;
}
},
downloadedQuality : {
sortValue : function(model, attr) {
if (model.get("movieFile")) {
return 1000-model.get("movieFile").quality.quality.id;
}
return -1;
}
},
nextAiring : {
sortValue : function(model, attr, order) {
var nextAiring = model.get(attr);
@@ -91,7 +110,15 @@ var Collection = PageableCollection.extend({
return Number.MAX_VALUE;
}
},
status: {
sortValue : function(model, attr) {
debugger;
if (model.get("downloaded")) {
return -1;
}
return 0;
}
},
percentOfEpisodes : {
sortValue : function(model, attr) {
var percentOfEpisodes = model.get(attr);

View File

@@ -7,12 +7,12 @@
<span class="icon-sonarr-navbar-collapsed fa-lg"></span>
</button>
<a class="navbar-brand" href="{{UrlBase}}/">
<!--<img src="{{UrlBase}}/Content/Images/logo.png?v=2" alt="Sonarr">-->
<!--<img src="{{UrlBase}}/Content/Images/logo.png?v=2" alt="Radarr">-->
<img src="{{UrlBase}}/Content/Images/logos/128.png" class="visible-lg"/>
<img src="{{UrlBase}}/Content/Images/logos/64.png" class="visible-md visible-sm"/>
<span class="visible-xs">
<img src="{{UrlBase}}/Content/Images/logos/32.png"/>
<span class="logo-text">sonarr</span>
<span class="logo-text">Radarr</span>
</span>
</a>

View File

@@ -27,7 +27,7 @@
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Should Sonarr download episodes for this series?"/>
<i class="icon-sonarr-form-info" title="Should Radarr download episodes for this series?"/>
</span>
</div>
</div>

View File

@@ -10,7 +10,7 @@
<div class="modal-body remotepath-mapping-modal">
<div class="form-horizontal">
<div>
<p>Use this feature if you have a remotely running Download Client. Sonarr will use the information provided to translate the paths provided by the Download Client API to something Sonarr can access and import.</p>
<p>Use this feature if you have a remotely running Download Client. Radarr will use the information provided to translate the paths provided by the Download Client API to something Radarr can access and import.</p>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Host</label>
@@ -40,7 +40,7 @@
<label class="col-sm-3 control-label">Local Path</label>
<div class="col-sm-1 col-sm-push-5 help-inline">
<i class="icon-sonarr-form-info" title="Path that Sonarr should use to access the same directory remotely." />
<i class="icon-sonarr-form-info" title="Path that Radarr should use to access the same directory remotely." />
</div>
<div class="col-sm-5 col-sm-pull-1">

View File

@@ -100,7 +100,7 @@
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Open a web browser and navigate to Sonarr homepage on app start. Has no effect if installed as a windows service"/>
<i class="icon-sonarr-form-info" title="Open a web browser and navigate to Radarr homepage on app start. Has no effect if installed as a windows service"/>
</span>
</div>
</div>
@@ -114,7 +114,7 @@
<div class="col-sm-1 col-sm-push-4 help-inline">
<i class="icon-sonarr-form-warning" title="Requires restart to take effect"/>
<i class="icon-sonarr-form-info" title="Require Username and Password to access Sonarr"/>
<i class="icon-sonarr-form-info" title="Require Username and Password to access Radarr"/>
</div>
<div class="col-sm-4 col-sm-pull-1">
@@ -308,7 +308,7 @@
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Send anonymous information about your browser and which parts of the web interface you use to Sonarr servers. We use this information to prioritize features and browser support. We will NEVER include any personal information or any information that could identify you."/>
<i class="icon-sonarr-form-info" title="Send anonymous information about your browser and which parts of the web interface you use to Radarr servers. We use this information to prioritize features and browser support. We will NEVER include any personal information or any information that could identify you."/>
<i class="icon-sonarr-form-warning" title="Requires restart to take effect"/>
</span>
</div>

View File

@@ -5,7 +5,7 @@
</div>
<div class="modal-body">
<div class="alert alert-info">
Sonarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.<br/>
Radarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.<br/>
For more information on the individual indexers, click on the info buttons.
</div>
<div class="add-indexer add-thingies">

View File

@@ -61,7 +61,7 @@
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Extract video information such as resolution, runtime and codec information from files. This requires Sonarr to read parts of the file which may cause high disk or network activity during scans."/>
<i class="icon-sonarr-form-info" title="Extract video information such as resolution, runtime and codec information from files. This requires Radarr to read parts of the file which may cause high disk or network activity during scans."/>
</span>
</div>
</div>

View File

@@ -28,7 +28,7 @@
<label class="col-sm-3 control-label">File chmod mask</label>
<div class="col-sm-1 col-sm-push-4 help-inline">
<i class="icon-sonarr-form-info" title="Octal, applied to media files when imported/renamed by Sonarr"/>
<i class="icon-sonarr-form-info" title="Octal, applied to media files when imported/renamed by Radarr"/>
</div>
<div class="col-sm-4 col-sm-pull-1">
@@ -40,7 +40,7 @@
<label class="col-sm-3 control-label">Folder chmod mask</label>
<div class="col-sm-1 col-sm-push-4 help-inline">
<i class="icon-sonarr-form-info" title="Octal, applied to series/season folders created by Sonarr"/>
<i class="icon-sonarr-form-info" title="Octal, applied to series/season folders created by Radarr"/>
</div>
<div class="col-sm-4 col-sm-pull-1">

View File

@@ -40,6 +40,6 @@
</div>
<div class="col-sm-1 help-inline">
<i class="icon-sonarr-form-info" title="Once this quality is reached Sonarr will no longer download episodes"/>
<i class="icon-sonarr-form-info" title="Once this quality is reached Radarr will no longer download episodes"/>
</div>
</div>

View File

@@ -40,7 +40,7 @@
<link rel="mask-icon" href="/Content/Images/safari/logo.svg" color="#35c5f4">
<link rel="icon" type="image/ico" href="/Content/Images/favicon.ico"/>
<link rel="alternate" type="text/calendar" title="iCalendar feed for Sonarr" href="/feed/calendar/NzbDrone.ics"/>
<link rel="alternate" type="text/calendar" title="iCalendar feed for Radarr" href="/feed/calendar/NzbDrone.ics"/>
</head>
<body>
<div class="container">

View File

@@ -27,7 +27,7 @@
<div class="container-fluid main-region" id="main-region">
<div class="col-md-2 col-md-offset-5">
<form name="login" id="login" class="login" method="POST">
<h2><img src="/Content/Images/logos/32.png" alt=""/> Sonarr</h2>
<h2><img src="/Content/Images/logos/32.png" alt=""/> Radarr</h2>
<div class="form-group">
<label for="username" class="sr-only">Email address</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>