From 01163a4f8759760c05173472764a2e6f565d2e1a Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Tue, 21 Jun 2011 18:12:20 -0700 Subject: [PATCH 1/2] Cleanup and tests around ImportFile --- Libraries/Migrator.NET/Migrator.Framework.dll | Bin 0 -> 27648 bytes Libraries/Migrator.NET/Migrator.Framework.pdb | Bin 0 -> 73216 bytes Libraries/Migrator.NET/Migrator.Framework.xml | 914 ++++++++++++++++++ Libraries/Migrator.NET/Migrator.Providers.dll | Bin 0 -> 77312 bytes Libraries/Migrator.NET/Migrator.Providers.pdb | Bin 0 -> 165376 bytes Libraries/Migrator.NET/Migrator.Providers.xml | 389 ++++++++ Libraries/Migrator.NET/Migrator.dll | Bin 0 -> 16384 bytes Libraries/Migrator.NET/Migrator.pdb | Bin 0 -> 52736 bytes NzbDrone.Core.Test/DiskScanProviderTest.cs | 268 ++--- NzbDrone.Core.Test/DownloadProviderTest.cs | 12 +- NzbDrone.Core.Test/EpisodeProviderTest.cs | 22 + ...deProviderTest_GetEpisodesByParseResult.cs | 190 ++++ NzbDrone.Core.Test/EpisodeSearchJobTest.cs | 12 +- .../InventoryProvider_IsMonitoredTest.cs | 114 ++- .../InventoryProvider_QualityNeededTest.cs | 37 +- NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 13 +- NzbDrone.Core.Test/SabProviderTest.cs | 8 +- NzbDrone.Core/Model/EpisodeParseResult.cs | 8 +- NzbDrone.Core/NzbDrone.Core.csproj | 26 +- NzbDrone.Core/Providers/Core/DiskProvider.cs | 2 +- NzbDrone.Core/Providers/DiskScanProvider.cs | 62 +- NzbDrone.Core/Providers/DownloadProvider.cs | 2 +- NzbDrone.Core/Providers/EpisodeProvider.cs | 59 +- NzbDrone.Core/Providers/IndexerProvider.cs | 5 +- NzbDrone.Core/Providers/InventoryProvider.cs | 36 +- .../Providers/Jobs/EpisodeSearchJob.cs | 8 +- .../Providers/Jobs/PostDownloadScanJob.cs | 2 +- .../Providers/Jobs/RenameEpisodeJob.cs | 2 +- NzbDrone.Core/Providers/MediaFileProvider.cs | 17 + NzbDrone.Core/Providers/SabProvider.cs | 2 +- 30 files changed, 1831 insertions(+), 379 deletions(-) create mode 100644 Libraries/Migrator.NET/Migrator.Framework.dll create mode 100644 Libraries/Migrator.NET/Migrator.Framework.pdb create mode 100644 Libraries/Migrator.NET/Migrator.Framework.xml create mode 100644 Libraries/Migrator.NET/Migrator.Providers.dll create mode 100644 Libraries/Migrator.NET/Migrator.Providers.pdb create mode 100644 Libraries/Migrator.NET/Migrator.Providers.xml create mode 100644 Libraries/Migrator.NET/Migrator.dll create mode 100644 Libraries/Migrator.NET/Migrator.pdb create mode 100644 NzbDrone.Core.Test/EpisodeProviderTest_GetEpisodesByParseResult.cs diff --git a/Libraries/Migrator.NET/Migrator.Framework.dll b/Libraries/Migrator.NET/Migrator.Framework.dll new file mode 100644 index 0000000000000000000000000000000000000000..97ceaeea3cc4f473fd4b6b754319d2f81462ae96 GIT binary patch literal 27648 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 G;Qs)sz~h1d literal 0 HcmV?d00001 diff --git a/Libraries/Migrator.NET/Migrator.Framework.pdb b/Libraries/Migrator.NET/Migrator.Framework.pdb new file mode 100644 index 0000000000000000000000000000000000000000..01826492f43412c59f59cab104fc53ab405e98b1 GIT binary patch literal 73216 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

XO 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 o& + + + Migrator.Framework + + + +

+ A migration is a group of transformation applied to the database schema + (or sometimes data) to port the database from one version to another. + The Up() method must apply the modifications (eg.: create a table) + and the Down() method must revert, or rollback the modifications + (eg.: delete a table). + + Each migration must be decorated with the [Migration(0)] attribute. + Each migration number (0) must be unique, or else a + DuplicatedVersionException will be trown. + + + All migrations are executed inside a transaction. If an exception is + thrown, the transaction will be rolledback and transformations wont be + applied. + + + It is best to keep a limited number of transformation inside a migration + so you can easely move from one version of to another with fine grain + modifications. + You should give meaningful name to the migration class and prepend the + migration number to the filename so they keep ordered, eg.: + 002_CreateTableTest.cs. + + + Use the Database property to apply transformation and the + Logger property to output informations in the console (or other). + For more details on transformations see + ITransformationProvider. + + + + The following migration creates a new Customer table. + (File 003_AddCustomerTable.cs) + + [Migration(3)] + public class AddCustomerTable : Migration + { + public override void Up() + { + Database.AddTable("Customer", + new Column("Name", typeof(string), 50), + new Column("Address", typeof(string), 100) + ); + } + public override void Down() + { + Database.RemoveTable("Customer"); + } + } + + + + + + Defines tranformations to port the database to the current version. + + + + + This is run after the Up transaction has been committed + + + + + Defines transformations to revert things done in Up. + + + + + This is run after the Down transaction has been committed + + + + + This gets called once on the first migration object. + + + + + Represents the database. + . + + Migration.Framework.ITransformationProvider + + + + Defines tranformations to port the database to the current version. + + + + + This is run after the Up transaction has been committed + + + + + Defines transformations to revert things done in Up. + + + + + This is run after the Down transaction has been committed + + + + + This gets called once on the first migration object. + + + + + Represents the database. + . + + Migration.Framework.ITransformationProvider + + + + Log that we have started a migration + + Start list of versions + Final Version + + + + Log that we are migrating up + + Version we are migrating to + Migration name + + + + Log that we are migrating down + + Version we are migrating to + Migration name + + + + Inform that a migration corresponding to the number of + version is untraceable (not found?) and will be ignored. + + Version we couldnt find + + + + Log that we are rolling back to version + + + version + + + + + Log a Sql statement that changes the schema or content of the database as part of a migration + + + SELECT statements should not be logged using this method as they do not alter the data or schema of the + database. + + The Sql statement to log + + + + Log that we had an exception on a migration + + The version of the migration that caused the exception. + The name of the migration that caused the exception. + The exception itself + + + + Log that we had an exception on a migration + + An informative message to show to the user. + The exception itself + + + + Log that we have finished a migration + + List of versions with which we started + Final Version + + + + Log a message + + The format string ("{0}, blabla {1}"). + Parameters to apply to the format string. + + + + Log a Warning + + The format string ("{0}, blabla {1}"). + Parameters to apply to the format string. + + + + Log a Trace Message + + The format string ("{0}, blabla {1}"). + Parameters to apply to the format string. + + + + Base class for migration errors. + + + + + Return the plural of a word. + + The singular form + The plural form of + + + + Return the singular of a word. + + The plural form + The singular form of + + + + Capitalizes a word. + + The word to be capitalized. + capitalized. + + + + Convert a classname to something more readable. + ex.: CreateATable => Create a table + + + + + + + + + + + + + + + + Handles writing a message to the log medium (i.e. file, console) + + + + + Write this message + + + + + + + Write this message, as a line + + + + + + + Represents a table column properties. + + + + + Null is allowable + + + + + Null is not allowable + + + + + Identity column, autoinc + + + + + Unique Column + + + + + Indexed Column + + + + + Unsigned Column + + + + + Foreign Key + + + + + Primary Key + + + + + Primary key. Make the column a PrimaryKey and unsigned + + + + + A set of extension methods for the transformation provider to make it easier to + build many-to-many joining tables (takes care of adding the joining table and foreign + key constraints as necessary. + This functionality was useful when bootstrapping a number of projects a few years ago, but + now that most changes are brown-field I'm thinking of removing these methods as it's easier to maintain + code that creates the tables etc. directly within migration. + + + + + Describe a migration + + + + + Describe the migration + + The unique version of the migration. + + + + The version reflected by the migration + + + + + Set to true to ignore this migration. + + + + + The main interface to use in Migrations to make changes on a database schema. + + + + + Add a column to an existing table + + The name of the table that will get the new column + The name of the new column + The data type for the new columnd + The precision or size of the column + Properties that can be ORed together + The default value of the column if no value is given in a query + + + + Add a column to an existing table + + The name of the table that will get the new column + The name of the new column + The data type for the new columnd + + + + Add a column to an existing table + + The name of the table that will get the new column + The name of the new column + The data type for the new columnd + The precision or size of the column + + + + Add a column to an existing table + + The name of the table that will get the new column + The name of the new column + The data type for the new columnd + The precision or size of the column + Properties that can be ORed together + + + + Add a column to an existing table + + The name of the table that will get the new column + The name of the new column + The data type for the new columnd + Properties that can be ORed together + + + + Add a column to an existing table with the default column size. + + The name of the table that will get the new column + The name of the new column + The data type for the new columnd + The default value of the column if no value is given in a query + + + + Add a column to an existing table + + The name of the table that will get the new column + An instance of a Column with the specified properties + + + + Add a foreign key constraint + + The name of the foreign key. e.g. FK_TABLE_REF + The table that the foreign key will be created in (eg. Table.FK_id) + The columns that are the foreign keys (eg. FK_id) + The table that holds the primary keys (eg. Table.PK_id) + The columns that are the primary keys (eg. PK_id) + + + + Add a foreign key constraint + + The name of the foreign key. e.g. FK_TABLE_REF + The table that the foreign key will be created in (eg. Table.FK_id) + The columns that are the foreign keys (eg. FK_id) + The table that holds the primary keys (eg. Table.PK_id) + The columns that are the primary keys (eg. PK_id) + Constraint parameters + + + + Add a foreign key constraint + + + The name of the foreign key. e.g. FK_TABLE_REF + The table that the foreign key will be created in (eg. Table.FK_id) + The column that is the foreign key (eg. FK_id) + The table that holds the primary keys (eg. Table.PK_id) + The column that is the primary key (eg. PK_id) + + + + Add a foreign key constraint + + The name of the foreign key. e.g. FK_TABLE_REF + The table that the foreign key will be created in (eg. Table.FK_id) + The column that is the foreign key (eg. FK_id) + The table that holds the primary key (eg. Table.PK_id) + The column that is the primary key (eg. PK_id) + Constraint parameters + + + + Add a foreign key constraint when you don't care about the name of the constraint. + Warning: This will prevent you from dropping the constraint since you won't know the name. + + The table that the foreign key will be created in (eg. Table.FK_id) + The column that is the foreign key (eg. FK_id) + The table that holds the primary key (eg. Table.PK_id) + The column that is the primary key (eg. PK_id) + + + + Add a foreign key constraint when you don't care about the name of the constraint. + Warning: This will prevent you from dropping the constraint since you won't know the name. + + The table that the foreign key will be created in (eg. Table.FK_id) + The columns that are the foreign keys (eg. FK_id) + The table that holds the primary key (eg. Table.PK_id) + The column that is the primary key (eg. PK_id) + + + + Add a foreign key constraint when you don't care about the name of the constraint. + Warning: This will prevent you from dropping the constraint since you won't know the name. + + The table that the foreign key will be created in (eg. Table.FK_id) + The columns that are the foreign keys (eg. FK_id) + The table that holds the primary key (eg. Table.PK_id) + The columns that are the primary keys (eg. PK_id) + Constraint parameters + + + + Add a foreign key constraint when you don't care about the name of the constraint. + Warning: This will prevent you from dropping the constraint since you won't know the name. + + The table that the foreign key will be created in (eg. Table.FK_id) + The columns that are the foreign keys (eg. FK_id) + The table that holds the primary key (eg. Table.PK_id) + The column that is the primary key (eg. PK_id) + Constraint parameters + + + + Add a foreign key constraint when you don't care about the name of the constraint. + Warning: This will prevent you from dropping the constraint since you won't know the name. + + The current expectations are that there is a column named the same as the foreignTable present in + the table. This is subject to change because I think it's not a good convention. + + The table that the foreign key will be created in (eg. Table.FK_id) + The table that holds the primary key (eg. Table.PK_id) + + + + Add a foreign key constraint when you don't care about the name of the constraint. + Warning: This will prevent you from dropping the constraint since you won't know the name. + + The current expectations are that there is a column named the same as the foreignTable present in + the table. This is subject to change because I think it's not a good convention. + + The table that the foreign key will be created in (eg. Table.FK_id) + The table that holds the primary key (eg. Table.PK_id) + + + + + Add a primary key to a table + + The name of the primary key to add. + The name of the table that will get the primary key. + The name of the column or columns that are in the primary key. + + + + Add a constraint to a table + + The name of the constraint to add. + The name of the table that will get the constraint + The name of the column or columns that will get the constraint. + + + + Add a constraint to a table + + The name of the constraint to add. + The name of the table that will get the constraint + The check constraint definition. + + + + Add a table + + The name of the table to add. + The columns that are part of the table. + + + + Add a table + + The name of the table to add. + The name of the database engine to use. (MySQL) + The columns that are part of the table. + + + + Start a transction + + + + + Change the definition of an existing column. + + The name of the table that will get the new column + An instance of a Column with the specified properties and the name of an existing column + + + + Check to see if a column exists + + + + + + + + Commit the running transction + + + + + Check to see if a constraint exists + + The name of the constraint + The table that the constraint lives on. + + + + + Check to see if a primary key constraint exists on the table + + The name of the primary key + The table that the constraint lives on. + + + + + Execute an arbitrary SQL query + + The SQL to execute. + + + + + Execute an arbitrary SQL query + + The SQL to execute. + + + + + Execute an arbitrary SQL query + + The SQL to execute. + A single value that is returned. + + + + Get the information about the columns in a table + + The table name that you want the columns for. + + + + + Get information about a single column in a table + + The table name that you want the columns for. + The column name for which you want information. + + + + + Get the names of all of the tables + + The names of all the tables. + + + + Insert data into a table + + The table that will get the new data + The names of the columns + The values in the same order as the columns + + + + + Delete data from a table + + The table that will have the data deleted + The names of the columns used in a where clause + The values in the same order as the columns + + + + + Delete data from a table + + The table that will have the data deleted + The name of the column used in a where clause + The value for the where clause + + + + + Marks a Migration version number as having been applied + + The version number of the migration that was applied + + + + Marks a Migration version number as having been rolled back from the database + + The version number of the migration that was removed + + + + Remove an existing column from a table + + The name of the table to remove the column from + The column to remove + + + + Remove an existing foreign key constraint + + The table that contains the foreign key. + The name of the foreign key to remove + + + + Remove an existing constraint + + The table that contains the foreign key. + The name of the constraint to remove + + + + Remove an existing table + + The name of the table + + + + Rename an existing table + + The old name of the table + The new name of the table + + + + Rename an existing table + + The name of the table + The old name of the column + The new name of the column + + + + Rollback the currently running transaction. + + + + + Get values from a table + + The columns to select + The table to select from + The where clause to limit the selection + + + + + Get values from a table + + The columns to select + The table to select from + + + + + Get a single value from a table + + The columns to select + The table to select from + + + + + + Get a single value from a table + + The columns to select + The table to select from + + + + + Check if a table already exists + + The name of the table that you want to check on. + + + + + Update the values in a table + + The name of the table to update + The names of the columns. + The values for the columns in the same order as the names. + + + + + Update the values in a table + + The name of the table to update + The names of the columns. + The values for the columns in the same order as the names. + A where clause to limit the update + + + + + Get a command instance + + + + + + Execute a schema builder + + + + + + Quote a multiple column names, if required + + + + + + + Quaote column if required + + + + + + + Quote table name if required + + + + + + + Encodes a guid value as a string, suitable for inclusion in sql statement + + + + + + + Get this provider or a NoOp provider if you are not running in the context of 'provider'. + + + + + The list of Migrations currently applied to the database. + + + + + Logger used to log details of operations performed during migration + + + + + ILogger interface. + Implicit in this interface is that the logger will delegate actual + logging to the (s) that have been attached + + + + + Attach an + + + + + + Detach an + + + + + + Represents a table column. + + + + + Adds a Table to be created to the Schema + + Table name to be created + SchemaBuilder for chaining + + + + Reference an existing table. + + Table to reference + SchemaBuilder for chaining + + + + Reference an existing table. + + Table to reference + SchemaBuilder for chaining + + + + Adds a Column to be created + + Column name to be added + IColumnOptions to restrict chaining + + + + Text logger for the migration mediator + + + + diff --git a/Libraries/Migrator.NET/Migrator.Providers.dll b/Libraries/Migrator.NET/Migrator.Providers.dll new file mode 100644 index 0000000000000000000000000000000000000000..85fe26cef22b1fd078bb9da5d6c83fa3e7894722 GIT binary patch literal 77312 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⁢^rKM8-voVu>qnpmpkIdm0s2_* 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 + + + Migrator.Providers + + + + + Summary description for SQLiteTransformationProvider. + + + + + Base class for every transformation providers. + A 'tranformation' is an operation that modifies the database. + + + + + Add a new table + + Table name + Columns + + Adds the Test table with two columns: + + Database.AddTable("Test", + new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + new Column("Title", typeof(string), 100) + ); + + + + + + Add a new table + + Table name + Columns + the database storage engine to use + + Adds the Test table with two columns: + + Database.AddTable("Test", "INNODB", + new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + new Column("Title", typeof(string), 100) + ); + + + + + + Add a new column to an existing table. + + Table to which to add the column + Column name + Date type of the column + Max length of the column + Properties of the column, see ColumnProperty, + Default value + + + + + AddColumn(string, string, Type, int, ColumnProperty, object) + + + + + + + AddColumn(string, string, Type, int, ColumnProperty, object) + + + + + + + AddColumn(string, string, Type, int, ColumnProperty, object) + + + + + + + AddColumn(string, string, Type, int, ColumnProperty, object) + + + + + + Append a primary key to a table. + + Constraint name + Table name + Primary column names + + + + Guesses the name of the foreign key and add it + + + + + Guesses the name of the foreign key and add it + + + + + Guesses the name of the foreign key and add it + + + + + Guesses the name of the foreign key and add it + + + + + Append a foreign key (relation) between two tables. + tables. + + Constraint name + Table name containing the primary key + Primary key column name + Foreign table name + Foreign column name + + + + + AddForeignKey(string, string, string, string, string) + + + + + + Determines if a constraint exists. + + Constraint name + Table owning the constraint + true if the constraint exists. + + + + Execute an SQL query returning results. + + The SQL command. + A data iterator, IDataReader. + + + + Starts a transaction. Called by the migration mediator. + + + + + Rollback the current migration. Called by the migration mediator. + + + + + Commit the current transaction. Called by the migrations mediator. + + + + + Marks a Migration version number as having been applied + + The version number of the migration that was applied + + + + Marks a Migration version number as having been rolled back from the database + + The version number of the migration that was removed + + + + Returns the event logger + + + + + The list of Migrations currently applied to the database. + + + + + Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' + + + + + Name is the first value before the space. + + + + + + + No Op (Null Object Pattern) implementation of the ITransformationProvider + + + + + Defines the implementations specific details for a particular database. + + + + + Subclasses register a typename for the given type code and maximum + column length. $l in the type name will be replaced by the column + length (if appropriate) + + The typecode + Maximum length of database type + The database type name + + + + Suclasses register a typename for the given type code. $l in the + typename will be replaced by the column length (if appropriate). + + The typecode + The database type name + + + + Get the name of the database type associated with the given + + The DbType + The database type name used by ddl. + + + + Get the name of the database type associated with the given + + The DbType + The database type name used by ddl. + + + + + Get the name of the database type associated with the given + + The DbType + The database type name used by ddl. + + + + + + + Subclasses register which DbTypes are unsigned-compatible (ie, available in signed and unsigned variants) + + + + + + Determine if a particular database type has an unsigned variant + + The DbType + True if the database type has an unsigned variant, otherwise false + + + + Migration transformations provider for Microsoft SQL Server. + + + + + Migration transformations provider for Microsoft SQL Server. + + + + + Migration transformations provider for PostgreSql (using NPGSql .Net driver) + + + + + This is basically a just a helper base class + per-database implementors may want to override ColumnSql + + + + The SQL type + + + The name of the column + + + + the type of the column + + + + + Sql if This column is Indexed + + + + + Sql if this column has a default value + + + + + The sql for this column, override in database-specific implementation classes + + + + + This class maps a DbType to names. + + + Associations may be marked with a capacity. Calling the Get() + method with a type and actual size n will return the associated + name with smallest capacity >= n, if available and an unmarked + default type otherwise. + Eg, setting + + Names.Put(DbType, "TEXT" ); + Names.Put(DbType, 255, "VARCHAR($l)" ); + Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); + + will give you back the following: + + Names.Get(DbType) // --> "TEXT" (default) + Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) + Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) + Names.Get(DbType,100000) // --> "TEXT" (default) + + On the other hand, simply putting + + Names.Put(DbType, "VARCHAR($l)" ); + + would result in + + Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) + Names.Get(DbType,100) // --> "VARCHAR(100)" + Names.Get(DbType,1000) // --> "VARCHAR(1000)" + Names.Get(DbType,10000) // --> "VARCHAR(10000)" + + + + + + Get default type name for specified type + + the type key + the default type name associated with the specified key + + + + Get the type name specified type and size + + the type key + the SQL length + the SQL scale + the SQL precision + + The associated name with smallest capacity >= size if available and the + default type name otherwise + + + + + Set a type name for specified type key and capacity + + the type key + the (maximum) type size/length + The associated name + + + + + + + + + + + Summary description for MySqlTransformationProvider. + + + + diff --git a/Libraries/Migrator.NET/Migrator.dll b/Libraries/Migrator.NET/Migrator.dll new file mode 100644 index 0000000000000000000000000000000000000000..fbcf23e2a6d04db3e71451fa7a18b57156783e5b GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/Libraries/Migrator.NET/Migrator.pdb b/Libraries/Migrator.NET/Migrator.pdb new file mode 100644 index 0000000000000000000000000000000000000000..832d105b165893162ebdfd5a61acb8de35d0ffdf GIT binary patch literal 52736 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.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew() - .With(c => c.SeriesId = fakeSeries.SeriesId) - .With(c => c.SeasonNumber = seasonNumber) - .Build(); + var fakeEpisode = Builder.CreateNew().Build(); //Mocks var mocker = new AutoMoqer(); mocker.GetMock() - .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); - - var database = mocker.GetMock(MockBehavior.Strict); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1).Verifiable(); + .Setup(e => e.GetSize(newFile)).Returns(12345).Verifiable(); + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); mocker.GetMock() - .Setup(e => e.GetEpisode(fakeSeries.SeriesId, seasonNumber, episodeNumner)).Returns(fakeEpisode); + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(new List { fakeEpisode }); //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, newFile); //Assert - Assert.IsNotNull(result); - mocker.GetMock().Verify(r => r.Insert(result), Times.Once()); - mocker.VerifyAllMocks(); + VerifyFileImport(result, mocker, fakeEpisode, 12345); - result.SeasonNumber.Should().Be(fakeEpisode.SeasonNumber); - - Assert.AreEqual(fakeEpisode.SeriesId, result.SeriesId); - Assert.AreEqual(QualityTypes.DVD, result.Quality); - Assert.AreEqual(Parser.NormalizePath(fileName), result.Path); - Assert.AreEqual(size, result.Size); - Assert.AreEqual(false, result.Proper); - Assert.AreNotEqual(new DateTime(), result.DateAdded); } - [TestCase(QualityTypes.SDTV, true)] + [TestCase(QualityTypes.SDTV, false)] [TestCase(QualityTypes.DVD, true)] [TestCase(QualityTypes.HDTV, false)] - public void import_new_file_with_better_same_quality(QualityTypes currentFileQuality, bool currentFileProper) + public void import_new_file_with_better_same_quality_should_succeed(QualityTypes currentFileQuality, bool currentFileProper) { - const string newFile = @"WEEDS.S03E01.DUAL.1080p.-HELLYWOOD.mkv"; - const int seasonNumber = 3; - const int episodeNumner = 1; + const string newFile = @"WEEDS.S03E01.DUAL.1080p.HELLYWOOD.mkv"; const int size = 12345; //Fakes var fakeSeries = Builder.CreateNew().Build(); var fakeEpisode = Builder.CreateNew() - .With(c => c.SeriesId = fakeSeries.SeriesId) - .With(c => c.SeasonNumber = seasonNumber) .With(e => e.EpisodeFile = Builder.CreateNew() .With(g => g.Quality = (QualityTypes)currentFileQuality) .And(g => g.Proper = currentFileProper).Build() - ) - .Build(); + ).Build(); - //Mocks var mocker = new AutoMoqer(); mocker.GetMock() .Setup(e => e.GetSize(newFile)).Returns(12345).Verifiable(); - var database = mocker.GetMock(MockBehavior.Strict); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1).Verifiable(); mocker.GetMock() - .Setup(e => e.GetEpisode(fakeSeries.SeriesId, seasonNumber, episodeNumner)).Returns(fakeEpisode); + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(new List { fakeEpisode }); //Act var result = mocker.Resolve().ImportFile(fakeSeries, newFile); //Assert - Assert.IsNotNull(result); - mocker.GetMock().Verify(r => r.Insert(result), Times.Once()); - mocker.VerifyAllMocks(); + VerifyFileImport(result, mocker, fakeEpisode, size); + } - result.SeasonNumber.Should().Be(fakeEpisode.SeasonNumber); - Assert.AreEqual(fakeEpisode.SeriesId, result.SeriesId); - Assert.AreEqual(QualityTypes.HDTV, result.Quality); - Assert.AreEqual(Parser.NormalizePath(newFile), result.Path); - Assert.AreEqual(size, result.Size); - Assert.AreEqual(false, result.Proper); - Assert.AreNotEqual(new DateTime(), result.DateAdded); - } [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] [TestCase("WEEDS.S03E01.DUAL.SDTV.XviD.AC3.-HELLYWOOD.avi")] - public void import_new_file_skip_if_episode_has_same_or_better_quality(string fileName) + public void import_new_file_episode_has_same_or_better_quality_should_skip(string fileName) { - const int seasonNumber = 3; - const int episodeNumner = 1; //Fakes var fakeSeries = Builder.CreateNew().Build(); var fakeEpisode = Builder.CreateNew() - .With(c => c.SeriesId = fakeSeries.SeriesId) - .With(c => c.SeasonNumber = seasonNumber) .With(c => c.EpisodeFile = Builder.CreateNew() .With(e => e.Quality = QualityTypes.Bluray720p).Build() ) @@ -145,116 +102,34 @@ namespace NzbDrone.Core.Test mocker.GetMock() .Setup(e => e.GetSize(fileName)).Returns(12345).Verifiable(); - var database = mocker.GetMock(MockBehavior.Strict); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); mocker.GetMock() - .Setup(e => e.GetEpisode(fakeSeries.SeriesId, seasonNumber, episodeNumner)).Returns(fakeEpisode); + .Setup(e => e.GetEpisodesByParseResult(It.IsAny(), false)).Returns(new List { fakeEpisode }); //Act var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert - result.Should().BeNull(); - mocker.GetMock().Verify(r => r.Insert(result), Times.Never()); - mocker.VerifyAllMocks(); + VerifySkipImport(result, mocker); } [Test] - public void import_new_daily_file() - { - //Arrange - ///////////////////////////////////////// - - //Constants - const string fileName = @"2011.01.10 - Denis Leary - HD TV.mkv"; - var airDate = new DateTime(2011, 01, 10); - const int size = 12345; - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew().With(c => c.SeriesId = fakeSeries.SeriesId).Build(); - - //Mocks - var mocker = new AutoMoqer(); - - var database = mocker.GetMock(MockBehavior.Strict); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1).Verifiable(); - - mocker.GetMock() - .Setup(e => e.GetEpisode(fakeSeries.SeriesId, airDate)).Returns(fakeEpisode). - Verifiable(); - - mocker.GetMock() - .Setup(e => e.GetSize(fileName)).Returns(size).Verifiable(); - - //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); - - //Assert - Assert.IsNotNull(result); - mocker.GetMock().VerifyAll(); - mocker.GetMock().Verify(r => r.Insert(result), Times.Once()); - mocker.GetMock().VerifyAll(); - mocker.GetMock().VerifyAll(); - - //Currently can't verify this since the list of episodes are loaded - //Dynamically by SubSonic - //Assert.AreEqual(fakeEpisode, result.EpisodeNumbers[0]); - - Assert.AreEqual(fakeEpisode.SeriesId, result.SeriesId); - Assert.AreEqual(QualityTypes.HDTV, result.Quality); - Assert.AreEqual(Parser.NormalizePath(fileName), result.Path); - Assert.AreEqual(size, result.Size); - Assert.AreEqual(false, result.Proper); - Assert.AreNotEqual(new DateTime(), result.DateAdded); - } - - [Test] - public void import_existing_season_file_should_skip() + public void import_unparsable_file_should_skip() { - //Arrange - ///////////////////////////////////////// - - //Constants - const string fileName = @"WEEDS.S03E01.DUAL.BDRip.XviD.AC3.-HELLYWOOD.avi"; - - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - - //Mocks - var mocker = new AutoMoqer(); - - mocker.GetMock(MockBehavior.Strict) - .Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(true).Verifiable(); - - //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); - - //Assert - mocker.VerifyAllMocks(); - result.Should().BeNull(); - } - - [Test] - public void import_unparsable_file() - { - //Arrange - ///////////////////////////////////////// - - //Constants const string fileName = @"WEEDS.avi"; const int size = 12345; - //Fakes var fakeSeries = Builder.CreateNew().Build(); - //Mocks + var mocker = new AutoMoqer(); - mocker.GetMock(MockBehavior.Strict) - .Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())).Returns(false); mocker.GetMock() .Setup(e => e.GetSize(fileName)).Returns(size).Verifiable(); @@ -263,103 +138,81 @@ namespace NzbDrone.Core.Test var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert - mocker.VerifyAllMocks(); - Assert.IsNull(result); + VerifySkipImport(result, mocker); ExceptionVerification.ExcpectedWarns(1); } [Test] - public void import_sample_file() + public void import_sample_file_should_skip() { - //Arrange - ///////////////////////////////////////// - - //Constants const string fileName = @"2011.01.10 - Denis Leary - sample - HD TV.mkv"; - var airDate = new DateTime(2011, 01, 10); const int size = 12345; //Fakes var fakeSeries = Builder.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew().With(c => c.SeriesId = fakeSeries.SeriesId).Build(); //Mocks var mocker = new AutoMoqer(); - mocker.GetMock() - .Setup(r => r.Exists(It.IsAny())).Returns(false).Verifiable(); - mocker.GetMock() - .Setup(r => r.Insert(It.IsAny())).Returns(0).Verifiable(); - - mocker.GetMock() - .Setup(e => e.GetEpisode(fakeSeries.SeriesId, airDate)).Returns(fakeEpisode). - Verifiable(); + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())).Returns(false); mocker.GetMock() .Setup(e => e.GetSize(fileName)).Returns(size).Verifiable(); - //Act var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert - Assert.IsNull(result); + VerifySkipImport(result, mocker); } [Test] - public void import_existing_file() + public void import_existing_file_should_skip() { const string fileName = "WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD.avi"; var fakeSeries = Builder.CreateNew().Build(); - var mocker = new AutoMoqer(); - mocker.GetMock(MockBehavior.Strict) - .Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(true).Verifiable(); - - mocker.GetMock(MockBehavior.Strict); + var mocker = new AutoMoqer(MockBehavior.Strict); + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(true); //Act var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert - result.Should().BeNull(); - mocker.GetMock().Verify(r => r.Insert(result), Times.Never()); - mocker.VerifyAllMocks(); + VerifySkipImport(result, mocker); } [Test] - public void import_file_with_no_episode_in_db_should_return_null() + public void import_file_with_no_episode_in_db_should_skip() { - //Constants const string fileName = "WEEDS.S03E01.DUAL.BDRip.XviD.AC3.-HELLYWOOD.avi"; - const int seasonNumber = 3; - const int episodeNumner = 01; //Fakes var fakeSeries = Builder.CreateNew().Build(); //Mocks var mocker = new AutoMoqer(); - mocker.GetMock(MockBehavior.Strict) - .Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - - mocker.GetMock(MockBehavior.Strict) - .Setup(e => e.GetEpisode(fakeSeries.SeriesId, seasonNumber, episodeNumner)).Returns(null). - Verifiable(); + mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); mocker.GetMock(MockBehavior.Strict) .Setup(e => e.GetSize(fileName)).Returns(90000000000); + mocker.GetMock() + .Setup(c => c.GetEpisodesByParseResult(It.IsAny(), false)) + .Returns(new List()); + //Act var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert - mocker.VerifyAllMocks(); - result.Should().BeNull(); - mocker.GetMock().Verify(r => r.Insert(result), Times.Never()); - ExceptionVerification.ExcpectedWarns(1); + VerifySkipImport(result, mocker); } [Test] @@ -384,5 +237,30 @@ namespace NzbDrone.Core.Test mocker.VerifyAllMocks(); } + + + + private static void VerifyFileImport(EpisodeFile result, AutoMoqer mocker, Episode fakeEpisode, int size) + { + mocker.VerifyAllMocks(); + result.Should().NotBeNull(); + result.SeriesId.Should().Be(fakeEpisode.SeriesId); + result.Size.Should().Be(size); + result.DateAdded.Should().HaveDay(DateTime.Now.Day); + mocker.GetMock().Verify(p => p.Add(It.IsAny()), Times.Once()); + + //Get the count of episodes linked + var count = mocker.GetMock().Object.GetEpisodesByParseResult(null, false).Count; + + mocker.GetMock().Verify(p => p.UpdateEpisode(It.Is(e => e.EpisodeFileId == result.EpisodeFileId)), Times.Exactly(count)); + } + + private static void VerifySkipImport(EpisodeFile result, AutoMoqer mocker) + { + mocker.VerifyAllMocks(); + result.Should().BeNull(); + mocker.GetMock().Verify(p => p.Add(It.IsAny()), Times.Never()); + mocker.GetMock().Verify(p => p.UpdateEpisode(It.IsAny()), Times.Never()); + } } } diff --git a/NzbDrone.Core.Test/DownloadProviderTest.cs b/NzbDrone.Core.Test/DownloadProviderTest.cs index 9c24890ff..552c2f7c3 100644 --- a/NzbDrone.Core.Test/DownloadProviderTest.cs +++ b/NzbDrone.Core.Test/DownloadProviderTest.cs @@ -21,12 +21,13 @@ namespace NzbDrone.Core.Test { var mocker = new AutoMoqer(MockBehavior.Strict); var parseResult = Builder.CreateNew() - .With(e => e.Episodes = Builder.CreateListOfSize(2) + .With(c => c.Quality = new Quality(QualityTypes.DVD, false)) + .Build(); + var episodes = Builder.CreateListOfSize(2) .WhereTheFirst(1).Has(s => s.EpisodeId = 12) .AndTheNext(1).Has(s => s.EpisodeId = 99) - .Build()) - .With(c => c.Quality = new Quality(QualityTypes.DVD, false)) - .Build(); + .Build(); + const string sabTitle = "My fake sab title"; mocker.GetMock() @@ -46,6 +47,9 @@ namespace NzbDrone.Core.Test mocker.GetMock() .Setup(s => s.Add(It.Is(h => h.EpisodeId == 99))); + mocker.GetMock() + .Setup(c => c.GetEpisodesByParseResult(It.IsAny(), false)).Returns(episodes); + mocker.Resolve().DownloadReport(parseResult); diff --git a/NzbDrone.Core.Test/EpisodeProviderTest.cs b/NzbDrone.Core.Test/EpisodeProviderTest.cs index 02c40742c..2dea94e39 100644 --- a/NzbDrone.Core.Test/EpisodeProviderTest.cs +++ b/NzbDrone.Core.Test/EpisodeProviderTest.cs @@ -588,6 +588,22 @@ namespace NzbDrone.Core.Test episodes.Should().NotBeEmpty(); } + [Test] + public void GetEpisode_by_Season_Episode_none_existing() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + + //Act + var episode = mocker.Resolve().GetEpisode(1, 1, 1); + + //Assert + episode.Should().BeNull(); + } + + [Test] public void GetEpisode_by_Season_Episode_with_EpisodeFile() { @@ -644,6 +660,9 @@ namespace NzbDrone.Core.Test episode.EpisodeFile.Should().BeNull(); } + + + [Test] public void GetEpisode_by_AirDate_with_EpisodeFile() { @@ -697,5 +716,8 @@ namespace NzbDrone.Core.Test episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); episode.EpisodeFile.Should().BeNull(); } + + + } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/EpisodeProviderTest_GetEpisodesByParseResult.cs b/NzbDrone.Core.Test/EpisodeProviderTest_GetEpisodesByParseResult.cs new file mode 100644 index 000000000..1338bc061 --- /dev/null +++ b/NzbDrone.Core.Test/EpisodeProviderTest_GetEpisodesByParseResult.cs @@ -0,0 +1,190 @@ +// ReSharper disable RedundantUsingDirective +using System; +using System.Collections.Generic; +using System.Linq; +using AutoMoq; +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Model; +using NzbDrone.Core.Providers; +using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Repository; +using NzbDrone.Core.Repository.Quality; +using NzbDrone.Core.Test.Framework; +using PetaPoco; +using TvdbLib.Data; + +namespace NzbDrone.Core.Test +{ + [TestFixture] + // ReSharper disable InconsistentNaming + public class EpisodeProviderTest_GetEpisodesByParseResult : TestBase + { + + [Test] + public void Single_GetSeason_Episode_Exists() + { + var db = MockLib.GetEmptyDatabase(); + var mocker = new AutoMoqer(); + mocker.SetConstant(db); + + var fakeEpisode = Builder.CreateNew() + .With(e => e.SeriesId = 1) + .With(e => e.SeasonNumber = 2) + .With(e => e.EpisodeNumber = 10) + .Build(); + + var fakeSeries = Builder.CreateNew().Build(); + + db.Insert(fakeEpisode); + db.Insert(fakeSeries); + + var parseResult = new EpisodeParseResult + { + Series = fakeSeries, + SeasonNumber = 2, + EpisodeNumbers = new List { 10 } + }; + + var ep = mocker.Resolve().GetEpisodesByParseResult(parseResult); + + ep.Should().HaveCount(1); + ep.First().ShouldHave().AllPropertiesBut(e => e.Series); + } + + [Test] + public void Single_GetSeason_Episode_Doesnt_exists_should_not_add() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + + + var parseResult = new EpisodeParseResult + { + Series = fakeSeries, + SeasonNumber = 2, + EpisodeNumbers = new List { 10 } + }; + + var ep = mocker.Resolve().GetEpisodesByParseResult(parseResult); + + ep.Should().BeEmpty(); + db.Fetch().Should().HaveCount(0); + } + + [Test] + public void Single_GetSeason_Episode_Doesnt_exists_should_add() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + + + var parseResult = new EpisodeParseResult + { + Series = fakeSeries, + SeasonNumber = 2, + EpisodeNumbers = new List { 10 } + }; + + var ep = mocker.Resolve().GetEpisodesByParseResult(parseResult, true); + + ep.Should().HaveCount(1); + db.Fetch().Should().HaveCount(1); + } + + + [Test] + public void Multi_GetSeason_Episode_Exists() + { + var db = MockLib.GetEmptyDatabase(); + var mocker = new AutoMoqer(); + mocker.SetConstant(db); + + var fakeEpisode = Builder.CreateNew() + .With(e => e.SeriesId = 1) + .With(e => e.SeasonNumber = 2) + .With(e => e.EpisodeNumber = 10) + .Build(); + + var fakeEpisode2 = Builder.CreateNew() + .With(e => e.SeriesId = 1) + .With(e => e.SeasonNumber = 2) + .With(e => e.EpisodeNumber = 11) + .Build(); + + var fakeSeries = Builder.CreateNew().Build(); + + db.Insert(fakeEpisode); + db.Insert(fakeEpisode2); + db.Insert(fakeSeries); + + var parseResult = new EpisodeParseResult + { + Series = fakeSeries, + SeasonNumber = 2, + EpisodeNumbers = new List { 10, 11 } + }; + + var ep = mocker.Resolve().GetEpisodesByParseResult(parseResult); + + ep.Should().HaveCount(2); + db.Fetch().Should().HaveCount(2); + ep.First().ShouldHave().AllPropertiesBut(e => e.Series); + } + + [Test] + public void Multi_GetSeason_Episode_Doesnt_exists_should_not_add() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + + + var parseResult = new EpisodeParseResult + { + Series = fakeSeries, + SeasonNumber = 2, + EpisodeNumbers = new List { 10, 11 } + }; + + var ep = mocker.Resolve().GetEpisodesByParseResult(parseResult); + + ep.Should().BeEmpty(); + db.Fetch().Should().HaveCount(0); + } + + [Test] + public void Multi_GetSeason_Episode_Doesnt_exists_should_add() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + + + var parseResult = new EpisodeParseResult + { + Series = fakeSeries, + SeasonNumber = 2, + EpisodeNumbers = new List { 10, 11 } + }; + + var ep = mocker.Resolve().GetEpisodesByParseResult(parseResult, true); + + ep.Should().HaveCount(2); + db.Fetch().Should().HaveCount(2); + } + + } +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/EpisodeSearchJobTest.cs b/NzbDrone.Core.Test/EpisodeSearchJobTest.cs index 26ea4c501..0e34f0a64 100644 --- a/NzbDrone.Core.Test/EpisodeSearchJobTest.cs +++ b/NzbDrone.Core.Test/EpisodeSearchJobTest.cs @@ -199,7 +199,7 @@ namespace NzbDrone.Core.Test } - + [TestCase(0)] [TestCase(-1)] [TestCase(-100)] @@ -245,7 +245,7 @@ namespace NzbDrone.Core.Test .Returns(indexers); mocker.GetMock() - .Setup(c => c.IsQualityNeeded(It.Is(d => d.Series != null && d.Episodes.Count != 0))).Returns(false); + .Setup(c => c.IsQualityNeeded(It.IsAny())).Returns(false); mocker.GetMock() .Setup(s => s.GetSceneName(It.IsAny())).Returns(""); @@ -296,7 +296,7 @@ namespace NzbDrone.Core.Test .Returns(indexers); mocker.GetMock() - .Setup(c => c.IsQualityNeeded(It.Is(d => d.Series != null && d.Episodes.Count != 0))).Returns(false); + .Setup(c => c.IsQualityNeeded(It.IsAny())).Returns(false); mocker.GetMock() .Setup(s => s.GetSceneName(71256)).Returns("The Daily Show"); @@ -326,7 +326,7 @@ namespace NzbDrone.Core.Test .With(c => c.SeasonNumber = 12) .Build(); - var mocker = new AutoMoqer(MockBehavior.Strict); + var mocker = new AutoMoqer(); mocker.GetMock() .Setup(c => c.GetEpisode(episode.EpisodeId)) @@ -342,7 +342,7 @@ namespace NzbDrone.Core.Test .Throws(new Exception()).Verifiable(); var indexer3 = new Mock(); - indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) + indexer3.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) .Returns(parseResults).Verifiable(); @@ -353,7 +353,7 @@ namespace NzbDrone.Core.Test .Returns(indexers); mocker.GetMock() - .Setup(c => c.IsQualityNeeded(It.Is(d => d.Series != null && d.Episodes.Count != 0))).Returns(false);; + .Setup(c => c.IsQualityNeeded(It.IsAny())).Returns(false); mocker.GetMock() .Setup(s => s.GetSceneName(It.IsAny())).Returns(""); diff --git a/NzbDrone.Core.Test/InventoryProvider_IsMonitoredTest.cs b/NzbDrone.Core.Test/InventoryProvider_IsMonitoredTest.cs index 0197d94f6..589cf808f 100644 --- a/NzbDrone.Core.Test/InventoryProvider_IsMonitoredTest.cs +++ b/NzbDrone.Core.Test/InventoryProvider_IsMonitoredTest.cs @@ -110,9 +110,9 @@ namespace NzbDrone.Core.Test mocker.VerifyAllMocks(); } - + [Test] - public void IsMonitored_dailyshow_should_do_daily_lookup() + public void IsMonitored_should_return_true() { var mocker = new AutoMoqer(MockBehavior.Strict); @@ -121,23 +121,47 @@ namespace NzbDrone.Core.Test .Returns(series); mocker.GetMock() - .Setup(p => p.GetEpisode(episode.SeriesId, episode.SeasonNumber, episode.EpisodeNumber)) - .Returns(null); + .Setup(p => p.GetEpisodesByParseResult(It.IsAny(), true)) + .Returns(new List { episode }); + + parseResultSingle.Series.Should().BeNull(); + + var result = mocker.Resolve().IsMonitored(parseResultSingle); + + //Assert + result.Should().BeTrue(); + parseResultSingle.Series.Should().Be(series); + mocker.VerifyAllMocks(); + } + + + [Test] + public void IsMonitored_ignored_single_episode_should_return_false() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + + mocker.GetMock() + .Setup(p => p.FindSeries(It.IsAny())) + .Returns(series); mocker.GetMock() - .Setup(p => p.GetEpisode(episode.SeriesId, episode.AirDate)) - .Returns(episode); + .Setup(p => p.GetEpisodesByParseResult(It.IsAny(), true)) + .Returns(new List { episode }); + + episode.Ignored = true; + + parseResultSingle.Series.Should().BeNull(); var result = mocker.Resolve().IsMonitored(parseResultSingle); //Assert - Assert.IsTrue(result); - Assert.AreSame(series, parseResultSingle.Series); + result.Should().BeFalse(); + parseResultSingle.Series.Should().Be(series); mocker.VerifyAllMocks(); } [Test] - public void none_db_episode_should_be_added() + public void IsMonitored_multi_some_episodes_ignored_should_return_true() { var mocker = new AutoMoqer(MockBehavior.Strict); @@ -146,25 +170,75 @@ namespace NzbDrone.Core.Test .Returns(series); mocker.GetMock() - .Setup(p => p.GetEpisode(episode.SeriesId, episode.SeasonNumber, episode.EpisodeNumber)) - .Returns(null); + .Setup(p => p.GetEpisodesByParseResult(It.IsAny(), true)) + .Returns(new List { episode, episode2 }); + + episode.Ignored = true; + episode2.Ignored = false; + + parseResultMulti.Series.Should().BeNull(); + + var result = mocker.Resolve().IsMonitored(parseResultMulti); + + //Assert + result.Should().BeTrue(); + parseResultMulti.Series.Should().Be(series); + mocker.VerifyAllMocks(); + } + + [Test] + public void IsMonitored_multi_all_episodes_ignored_should_return_false() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + + mocker.GetMock() + .Setup(p => p.FindSeries(It.IsAny())) + .Returns(series); mocker.GetMock() - .Setup(p => p.GetEpisode(episode.SeriesId, episode.AirDate)) - .Returns(null); + .Setup(p => p.GetEpisodesByParseResult(It.IsAny(), true)) + .Returns(new List { episode, episode2 }); + + episode.Ignored = true; + episode2.Ignored = true; + + parseResultSingle.Series.Should().BeNull(); + + var result = mocker.Resolve().IsMonitored(parseResultMulti); + + //Assert + result.Should().BeFalse(); + parseResultMulti.Series.Should().Be(series); + mocker.VerifyAllMocks(); + } + + + [Test] + public void IsMonitored_multi_no_episodes_ignored_should_return_true() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + + mocker.GetMock() + .Setup(p => p.FindSeries(It.IsAny())) + .Returns(series); mocker.GetMock() - .Setup(p => p.AddEpisode(It.IsAny())); + .Setup(p => p.GetEpisodesByParseResult(It.IsAny(), true)) + .Returns(new List { episode, episode2 }); - //Act - var result = mocker.Resolve().IsMonitored(parseResultSingle); + episode.Ignored = false; + episode2.Ignored = false; + + parseResultSingle.Series.Should().BeNull(); + + var result = mocker.Resolve().IsMonitored(parseResultMulti); //Assert - Assert.IsTrue(result); - Assert.AreSame(series, parseResultSingle.Series); - parseResultSingle.Episodes.Should().HaveCount(1); - Assert.AreEqual("TBD", parseResultSingle.Episodes[0].Title); + result.Should().BeTrue(); + parseResultMulti.Series.Should().Be(series); mocker.VerifyAllMocks(); } + + } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/InventoryProvider_QualityNeededTest.cs b/NzbDrone.Core.Test/InventoryProvider_QualityNeededTest.cs index ca03ab27c..3bf61ff62 100644 --- a/NzbDrone.Core.Test/InventoryProvider_QualityNeededTest.cs +++ b/NzbDrone.Core.Test/InventoryProvider_QualityNeededTest.cs @@ -37,7 +37,6 @@ namespace NzbDrone.Core.Test EpisodeNumbers = new List { 3, 4 }, SeasonNumber = 12, AirDate = DateTime.Now.AddDays(-12).Date, - Episodes = new List() }; parseResultSingle = new EpisodeParseResult @@ -48,7 +47,6 @@ namespace NzbDrone.Core.Test EpisodeNumbers = new List { 3 }, SeasonNumber = 12, AirDate = DateTime.Now.AddDays(-12).Date, - Episodes = new List() }; episodeFile = Builder.CreateNew().With(c => c.Quality = QualityTypes.DVD).Build(); @@ -99,9 +97,9 @@ namespace NzbDrone.Core.Test parseResultMulti.Series = series; parseResultSingle.Series = series; - parseResultSingle.Episodes.Add(episode); - parseResultMulti.Episodes.Add(episode); - parseResultMulti.Episodes.Add(episode2); + /* parseResultSingle.Episodes.Add(episode); + parseResultMulti.Episodes.Add(episode); + parseResultMulti.Episodes.Add(episode2);*/ base.Setup(); @@ -129,9 +127,15 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); parseResultMulti.Series.QualityProfile = hdProfile; - parseResultMulti.Episodes[0].EpisodeFile.Quality = QualityTypes.Bluray720p; + parseResultMulti.Quality = new Quality(QualityTypes.HDTV, true); + mocker.GetMock() + .Setup(p => p.GetEpisodesByParseResult(parseResultMulti, true)) + .Returns(new List { episode, episode2 }); + + episode.EpisodeFile.Quality = QualityTypes.Bluray720p; + //Act bool result = mocker.Resolve().IsQualityNeeded(parseResultMulti); @@ -147,13 +151,18 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); parseResultSingle.Series.QualityProfile = sdProfile; - parseResultSingle.Episodes[0].EpisodeFile.Quality = QualityTypes.SDTV; parseResultSingle.Quality.QualityType = QualityTypes.DVD; mocker.GetMock() .Setup(p => p.GetBestQualityInHistory(episode.EpisodeId)) .Returns(new Quality(QualityTypes.DVD, true)); + mocker.GetMock() + .Setup(p => p.GetEpisodesByParseResult(parseResultSingle, true)) + .Returns(new List { episode }); + + episode.EpisodeFile.Quality = QualityTypes.SDTV; + //Act bool result = mocker.Resolve().IsQualityNeeded(parseResultSingle); @@ -168,13 +177,18 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); parseResultSingle.Series.QualityProfile = sdProfile; - parseResultSingle.Episodes[0].EpisodeFile.Quality = QualityTypes.SDTV; parseResultSingle.Quality.QualityType = QualityTypes.DVD; mocker.GetMock() .Setup(p => p.GetBestQualityInHistory(episode.EpisodeId)) .Returns(new Quality(QualityTypes.SDTV, true)); + mocker.GetMock() + .Setup(p => p.GetEpisodesByParseResult(parseResultSingle, true)) + .Returns(new List { episode }); + + episode.EpisodeFile.Quality = QualityTypes.SDTV; + //Act bool result = mocker.Resolve().IsQualityNeeded(parseResultSingle); @@ -189,13 +203,18 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); parseResultSingle.Series.QualityProfile = sdProfile; - parseResultSingle.Episodes[0].EpisodeFile.Quality = QualityTypes.SDTV; parseResultSingle.Quality.QualityType = QualityTypes.DVD; mocker.GetMock() .Setup(p => p.GetBestQualityInHistory(episode.EpisodeId)) .Returns(null); + + mocker.GetMock() + .Setup(p => p.GetEpisodesByParseResult(parseResultSingle, true)) + .Returns(new List { episode }); + + episode.EpisodeFile.Quality = QualityTypes.SDTV; //Act bool result = mocker.Resolve().IsQualityNeeded(parseResultSingle); diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index ed54b6fe2..bfed0f28a 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -85,6 +85,7 @@ + @@ -128,18 +129,6 @@ - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework - - - {D58C68E4-D789-40F7-9078-C9F587D4363C} - Migrator.Providers - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator - {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205} NzbDrone.Core diff --git a/NzbDrone.Core.Test/SabProviderTest.cs b/NzbDrone.Core.Test/SabProviderTest.cs index ced522f06..92d8c3c90 100644 --- a/NzbDrone.Core.Test/SabProviderTest.cs +++ b/NzbDrone.Core.Test/SabProviderTest.cs @@ -259,7 +259,7 @@ namespace NzbDrone.Core.Test mocker.Resolve().IsInQueue(String.Empty); } - + [Test] [TestCase(1, new[] { 2 }, "My Episode Title", QualityTypes.DVD, false, "My Series Name - 1x2 - My Episode Title [DVD]")] [TestCase(1, new[] { 2 }, "My Episode Title", QualityTypes.DVD, true, "My Series Name - 1x2 - My Episode Title [DVD] [Proper]")] [TestCase(1, new[] { 2 }, "", QualityTypes.DVD, true, "My Series Name - 1x2 - [DVD] [Proper]")] @@ -274,10 +274,6 @@ namespace NzbDrone.Core.Test .With(c => c.Path = @"d:\tv shows\My Series Name") .Build(); - var episode = Builder.CreateNew() - .With(e => e.Title = title) - .Build(); - var parsResult = new EpisodeParseResult() { AirDate = DateTime.Now, @@ -285,7 +281,7 @@ namespace NzbDrone.Core.Test Quality = new Quality(quality, proper), SeasonNumber = seasons, Series = series, - Episodes = new List() { episode } + EpisodeTitle = title }; //Act diff --git a/NzbDrone.Core/Model/EpisodeParseResult.cs b/NzbDrone.Core/Model/EpisodeParseResult.cs index de566a5e6..9c9818d82 100644 --- a/NzbDrone.Core/Model/EpisodeParseResult.cs +++ b/NzbDrone.Core/Model/EpisodeParseResult.cs @@ -7,13 +7,15 @@ namespace NzbDrone.Core.Model public class EpisodeParseResult { internal string CleanTitle { get; set; } + + public string EpisodeTitle { get; set; } internal int SeasonNumber { get; set; } internal List EpisodeNumbers { get; set; } internal DateTime AirDate { get; set; } - + public Quality Quality { get; set; } public LanguageType Language { get; set; } @@ -24,8 +26,6 @@ namespace NzbDrone.Core.Model public Series Series { get; set; } - public IList Episodes { get; set; } - public String Indexer { get; set; } public override string ToString() @@ -34,7 +34,7 @@ namespace NzbDrone.Core.Model return string.Format("{0} - {1} {2}", CleanTitle, AirDate.ToShortDateString(), Quality); return string.Format("{0} - S{1:00}E{2} {3}", CleanTitle, SeasonNumber, - String.Join("-", EpisodeNumbers),Quality); + String.Join("-", EpisodeNumbers), Quality); } } diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 648df1730..1fd72ff8f 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -126,6 +126,18 @@ ..\Libraries\Exceptioneer.WindowsFormsClient.dll + + False + ..\Libraries\Migrator.NET\Migrator.dll + + + False + ..\Libraries\Migrator.NET\Migrator.Framework.dll + + + False + ..\Libraries\Migrator.NET\Migrator.Providers.dll + False ..\packages\MiniProfiler.1.3\lib\MvcMiniProfiler.dll @@ -279,20 +291,6 @@ - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework - - - {D58C68E4-D789-40F7-9078-C9F587D4363C} - Migrator.Providers - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator - - diff --git a/NzbDrone.Core/Providers/Core/DiskProvider.cs b/NzbDrone.Core/Providers/Core/DiskProvider.cs index a8574c5cb..8e8ae2cb0 100644 --- a/NzbDrone.Core/Providers/Core/DiskProvider.cs +++ b/NzbDrone.Core/Providers/Core/DiskProvider.cs @@ -43,7 +43,7 @@ namespace NzbDrone.Core.Providers.Core File.Delete(path); } - public virtual void RenameFile(string sourcePath, string destinationPath) + public virtual void MoveFile(string sourcePath, string destinationPath) { File.Move(sourcePath, destinationPath); } diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index 7783c376b..8e38bd616 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -14,7 +14,6 @@ namespace NzbDrone.Core.Providers { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly string[] MediaExtentions = new[] { ".mkv", ".avi", ".wmv", ".mp4" }; - private readonly IDatabase _database; private readonly DiskProvider _diskProvider; private readonly EpisodeProvider _episodeProvider; private readonly MediaFileProvider _mediaFileProvider; @@ -22,14 +21,12 @@ namespace NzbDrone.Core.Providers [Inject] public DiskScanProvider(DiskProvider diskProvider, EpisodeProvider episodeProvider, - SeriesProvider seriesProvider, MediaFileProvider mediaFileProvider, - IDatabase database) + SeriesProvider seriesProvider, MediaFileProvider mediaFileProvider) { _diskProvider = diskProvider; _episodeProvider = episodeProvider; _seriesProvider = seriesProvider; _mediaFileProvider = mediaFileProvider; - _database = database; } @@ -86,7 +83,7 @@ namespace NzbDrone.Core.Providers { Logger.Trace("Importing file to database [{0}]", filePath); - if (_database.Exists("WHERE Path =@0", Parser.NormalizePath(filePath))) + if (_mediaFileProvider.Exists(filePath)) { Logger.Trace("[{0}] already exists in the database. skipping.", filePath); return null; @@ -107,46 +104,15 @@ namespace NzbDrone.Core.Providers return null; parseResult.CleanTitle = series.Title; //replaces the nasty path as title to help with logging + parseResult.Series = series; - //Stores the list of episodes to add to the EpisodeFile - var episodes = new List(); + var episodes = _episodeProvider.GetEpisodesByParseResult(parseResult); - //Check for daily shows - if (parseResult.EpisodeNumbers == null) - { - var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.AirDate.Date); - - if (episode != null) - { - episodes.Add(episode); - } - else - { - Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); - } - } - else - { - foreach (var episodeNumber in parseResult.EpisodeNumbers) - { - var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, - episodeNumber); - - if (episode != null) - { - episodes.Add(episode); - } - else - { - Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); - } - } - } - - //Return null if no Episodes exist in the DB for the parsed episodes from file if (episodes.Count <= 0) + { + Logger.Debug("Can't find any matching episodes in the database. skipping"); return null; - + } if (episodes.Any(e => e.EpisodeFile != null && e.EpisodeFile.QualityWrapper > parseResult.Quality)) { @@ -162,18 +128,16 @@ namespace NzbDrone.Core.Providers episodeFile.Quality = parseResult.Quality.QualityType; episodeFile.Proper = parseResult.Quality.Proper; episodeFile.SeasonNumber = parseResult.SeasonNumber; - int fileId = Convert.ToInt32(_database.Insert(episodeFile)); + var fileId = _mediaFileProvider.Add(episodeFile); - //This is for logging + updating the episodes that are linked to this EpisodeFile - string episodeList = String.Empty; + //Link file to all episodes foreach (var ep in episodes) { ep.EpisodeFileId = fileId; _episodeProvider.UpdateEpisode(ep); - episodeList += String.Format(", {0}", ep.EpisodeId).Trim(' ', ','); + Logger.Trace("Linking file {0} to {1}", filePath, ep); } - Logger.Trace("File {0}:{1} attached to episode(s): '{2}'", episodeFile.EpisodeFileId, filePath, - episodeList); + return episodeFile; } @@ -191,7 +155,7 @@ namespace NzbDrone.Core.Providers //Do the rename Logger.Trace("Attempting to rename {0} to {1}", episodeFile.Path, newFile.FullName); - _diskProvider.RenameFile(episodeFile.Path, newFile.FullName); + _diskProvider.MoveFile(episodeFile.Path, newFile.FullName); //Update the filename in the DB episodeFile.Path = newFile.FullName; @@ -221,7 +185,7 @@ namespace NzbDrone.Core.Providers } //Delete it from the DB - _database.Delete(episodeFile.EpisodeFileId); + _mediaFileProvider.Delete(episodeFile.EpisodeFileId); } } } diff --git a/NzbDrone.Core/Providers/DownloadProvider.cs b/NzbDrone.Core/Providers/DownloadProvider.cs index e98813a28..be9fe20be 100644 --- a/NzbDrone.Core/Providers/DownloadProvider.cs +++ b/NzbDrone.Core/Providers/DownloadProvider.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Providers if (addSuccess) { - foreach (var episode in parseResult.Episodes) + foreach (var episode in _episodeProvider.GetEpisodesByParseResult(parseResult)) { var history = new History(); history.Date = DateTime.Now; diff --git a/NzbDrone.Core/Providers/EpisodeProvider.cs b/NzbDrone.Core/Providers/EpisodeProvider.cs index edc435c2b..be0ac12e4 100644 --- a/NzbDrone.Core/Providers/EpisodeProvider.cs +++ b/NzbDrone.Core/Providers/EpisodeProvider.cs @@ -35,7 +35,7 @@ namespace NzbDrone.Core.Providers public virtual Episode GetEpisode(long id) { - var episode = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes + var episode = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId WHERE EpisodeId = @0", id).Single()); @@ -86,7 +86,7 @@ namespace NzbDrone.Core.Providers if (episode.EpisodeFileId == 0) episode.EpisodeFile = null; } - + return episodes; } @@ -105,33 +105,46 @@ namespace NzbDrone.Core.Providers return episodes; } - public virtual List GetEpisodes(EpisodeParseResult parseResult) - { - if (parseResult.Series == null) - { - Logger.Debug("Episode Parse Result is Invalid, skipping"); - return new List(); - } - var episodes = new List(); + public virtual IList GetEpisodesByParseResult(EpisodeParseResult parseResult, Boolean autoAddNew = false) + { + var result = new List(); - foreach (var ep in parseResult.EpisodeNumbers) + foreach (var episodeNumber in parseResult.EpisodeNumbers) { - var episode = GetEpisode(parseResult.Series.SeriesId, parseResult.SeasonNumber, ep); - - if (episode == null) - return new List(); - - episodes.Add(episode); - } + var episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.SeasonNumber, episodeNumber); + if (episodeInfo == null) + { + episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.AirDate); + } + //if still null we should add the temp episode + if (episodeInfo == null && autoAddNew) + { + Logger.Debug("Episode {0} doesn't exist in db. adding it now.", parseResult); + episodeInfo = new Episode + { + SeriesId = parseResult.Series.SeriesId, + AirDate = DateTime.Now.Date, + EpisodeNumber = episodeNumber, + SeasonNumber = parseResult.SeasonNumber, + Title = "TBD", + Overview = String.Empty, + }; + + AddEpisode(episodeInfo); + } - foreach (var episode in episodes) - { - if (episode.EpisodeFileId == 0) - episode.EpisodeFile = null; + if (episodeInfo != null) + { + result.Add(episodeInfo); + } + else + { + Logger.Debug("Unable to file {0}-S{1:00}E{2:00}", parseResult.Series.Title, parseResult.SeasonNumber, episodeNumber); + } } - return episodes; + return result; } public virtual IList EpisodesWithoutFiles(bool includeSpecials) diff --git a/NzbDrone.Core/Providers/IndexerProvider.cs b/NzbDrone.Core/Providers/IndexerProvider.cs index 48ad40431..6bb8a83b9 100644 --- a/NzbDrone.Core/Providers/IndexerProvider.cs +++ b/NzbDrone.Core/Providers/IndexerProvider.cs @@ -14,12 +14,13 @@ namespace NzbDrone.Core.Providers private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly IDatabase _database; - private IList _indexers = new List(); + private IEnumerable _indexers; [Inject] - public IndexerProvider(IDatabase database) + public IndexerProvider(IDatabase database, IEnumerable indexers) { _database = database; + _indexers = indexers; } public IndexerProvider() diff --git a/NzbDrone.Core/Providers/InventoryProvider.cs b/NzbDrone.Core/Providers/InventoryProvider.cs index ffe3931ca..202f0a9c7 100644 --- a/NzbDrone.Core/Providers/InventoryProvider.cs +++ b/NzbDrone.Core/Providers/InventoryProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Ninject; using NLog; using NzbDrone.Core.Model; @@ -41,7 +42,6 @@ namespace NzbDrone.Core.Providers } parseResult.Series = series; - parseResult.Episodes = new List(); if (!series.Monitored) { @@ -49,34 +49,16 @@ namespace NzbDrone.Core.Providers return false; } - foreach (var episodeNumber in parseResult.EpisodeNumbers) - { - var episodeInfo = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, episodeNumber); - if (episodeInfo == null) - { - episodeInfo = _episodeProvider.GetEpisode(series.SeriesId, parseResult.AirDate); - } - //if still null we should add the temp episode - if (episodeInfo == null) - { - Logger.Debug("Episode {0} doesn't exist in db. adding it now.", parseResult); - episodeInfo = new Episode - { - SeriesId = series.SeriesId, - AirDate = DateTime.Now.Date, - EpisodeNumber = episodeNumber, - SeasonNumber = parseResult.SeasonNumber, - Title = "TBD", - Overview = String.Empty, - }; - - _episodeProvider.AddEpisode(episodeInfo); - } + var episodes = _episodeProvider.GetEpisodesByParseResult(parseResult, true); - parseResult.Episodes.Add(episodeInfo); + //return monitored if any of the episodes are monitored + if (episodes.Any(episode => !episode.Ignored)) + { + return true; } - return true; + Logger.Debug("All episodes are ignored. skipping."); + return false; } /// @@ -97,7 +79,7 @@ namespace NzbDrone.Core.Providers var cutoff = parsedReport.Series.QualityProfile.Cutoff; - foreach (var episode in parsedReport.Episodes) + foreach (var episode in _episodeProvider.GetEpisodesByParseResult(parsedReport, true)) { //Checking File var file = episode.EpisodeFile; diff --git a/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs b/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs index 97f5e3f24..45330756a 100644 --- a/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs +++ b/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs @@ -68,11 +68,11 @@ namespace NzbDrone.Core.Providers.Jobs { try { - notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name); + //notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name); //TODO:Add support for daily episodes, maybe search using both date and season/episode? var indexerResults = indexer.FetchEpisode(title, episode.SeasonNumber, episode.EpisodeNumber); - + reports.AddRange(indexerResults); } catch (Exception e) @@ -84,10 +84,12 @@ namespace NzbDrone.Core.Providers.Jobs Logger.Debug("Finished searching all indexers. Total {0}", reports.Count); notification.CurrentMessage = "Processing search results"; + + //TODO:fix this so when search returns more than one episode + //TODO:-its populated with more than the original episode. reports.ForEach(c => { c.Series = series; - c.Episodes = new List { episode }; }); ProcessResults(notification, episode, reports); diff --git a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs index e48119aa0..f1564425c 100644 --- a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs +++ b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs @@ -83,7 +83,7 @@ namespace NzbDrone.Core.Providers.Jobs } var importedFiles = _diskScanProvider.Scan(series, subfolder); - importedFiles.ForEach(file => _diskScanProvider.RenameEpisodeFile(file)); + importedFiles.ForEach(file => _diskScanProvider.MoveEpisodeFile(file)); } Logger.Debug("New Download Scan Job completed successfully"); diff --git a/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs b/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs index cc39c455a..9e7920767 100644 --- a/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs +++ b/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Providers.Jobs public void Start(ProgressNotification notification, int targetId) { var episode = _mediaFileProvider.GetEpisodeFile(targetId); - _diskScanProvider.RenameEpisodeFile(episode); + _diskScanProvider.MoveEpisodeFile(episode); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/MediaFileProvider.cs b/NzbDrone.Core/Providers/MediaFileProvider.cs index d9e4271ec..d734bb988 100644 --- a/NzbDrone.Core/Providers/MediaFileProvider.cs +++ b/NzbDrone.Core/Providers/MediaFileProvider.cs @@ -31,11 +31,28 @@ namespace NzbDrone.Core.Providers { } + + + public virtual int Add(EpisodeFile episodeFile) + { + return Convert.ToInt32(_database.Insert(episodeFile)); + } + public virtual void Update(EpisodeFile episodeFile) { _database.Update(episodeFile); } + public virtual void Delete(int episodeFileId) + { + _database.Delete(episodeFileId); + } + + public virtual bool Exists(string path) + { + return _database.Exists("WHERE Path =@0", Parser.NormalizePath(path)); + } + public virtual EpisodeFile GetEpisodeFile(int episodeFileId) { return _database.Single(episodeFileId); diff --git a/NzbDrone.Core/Providers/SabProvider.cs b/NzbDrone.Core/Providers/SabProvider.cs index db8e59b79..734f04026 100644 --- a/NzbDrone.Core/Providers/SabProvider.cs +++ b/NzbDrone.Core/Providers/SabProvider.cs @@ -126,7 +126,7 @@ namespace NzbDrone.Core.Providers var epNumberString = String.Join("-", episodeString); - var result = String.Format("{0} - {1} - {2} [{3}]", new DirectoryInfo(parseResult.Series.Path).Name, epNumberString, parseResult.Episodes.FirstOrDefault().Title, parseResult.Quality.QualityType); + var result = String.Format("{0} - {1} - {2} [{3}]", new DirectoryInfo(parseResult.Series.Path).Name, epNumberString, parseResult.EpisodeTitle, parseResult.Quality.QualityType); if (parseResult.Quality.Proper) { From f6ccb5e17c8a0a4e888e7003f89d745a27b15ec3 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Tue, 21 Jun 2011 18:22:52 -0700 Subject: [PATCH 2/2] Fixed broken build --- NzbDrone.Core/Providers/DiskScanProvider.cs | 2 +- NzbDrone.Core/Providers/SeriesProvider.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index 8e38bd616..be123a816 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -143,7 +143,7 @@ namespace NzbDrone.Core.Providers } - public virtual bool RenameEpisodeFile(EpisodeFile episodeFile) + public virtual bool MoveEpisodeFile(EpisodeFile episodeFile) { if (episodeFile == null) throw new ArgumentNullException("episodeFile"); diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index 0271e8ab7..896f09a02 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -135,10 +135,11 @@ namespace NzbDrone.Core.Providers return series; } - //This will catch InvalidOperationExceptions that may be thrown for GetSeries due to the series being in SceneMapping, but not in the users Database - catch (InvalidOperationException ex) + + catch (InvalidOperationException) { - Logger.DebugException(ex.Message, ex); + //This will catch InvalidOperationExceptions(Sequence contains no element) + //that may be thrown for GetSeries due to the series being in SceneMapping, but not in the users Database return null; } }