mirror of
https://github.com/Radarr/Radarr
synced 2026-01-23 16:04:18 +01:00
feat(indexer): add multi-media type foundation
Add MediaType enum and indexer support for books/audiobooks: - MediaType enum (Movie, TV, Music, Book, Audiobook, Podcast, Comic) - NewznabStandardCategory constants for all media types - Database migration 243 for SupportedMediaTypes column - Updated IndexerDefinition, IIndexer, IndexerBase - Updated README with current project status
This commit is contained in:
parent
09b1d24ce8
commit
86faa9aef7
8 changed files with 203 additions and 9 deletions
46
README.md
46
README.md
|
|
@ -6,7 +6,7 @@ All-in-one media manager for movies, books, and audiobooks.
|
|||
|
||||
Aletheia (from Greek ἀλήθεια - "truth, disclosure") is a unified media management system forked from Radarr. It provides automated monitoring, downloading, and library management for multiple media types through a single interface.
|
||||
|
||||
**Current Status:** Early development. Movie functionality inherited from Radarr is working. Book and audiobook support is planned.
|
||||
**Current Status:** Active development. Movie functionality inherited from Radarr is working. Multi-media foundation being implemented.
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -15,20 +15,21 @@ Aletheia (from Greek ἀλήθεια - "truth, disclosure") is a unified media m
|
|||
- Metadata and artwork management
|
||||
- Integration with download clients and indexers
|
||||
|
||||
**Books (planned):**
|
||||
**Books (in development):**
|
||||
- EPUB, MOBI, PDF quality tracking
|
||||
- Author and series hierarchy
|
||||
- Goodreads/Hardcover metadata
|
||||
|
||||
**Audiobooks (planned):**
|
||||
**Audiobooks (in development):**
|
||||
- M4B, MP3, FLAC support
|
||||
- Narrator tracking and duration metadata
|
||||
- Audible metadata integration
|
||||
- Narrator tracking (competitive differentiator)
|
||||
- Duration metadata and Audible integration
|
||||
|
||||
**General:**
|
||||
- Usenet and BitTorrent support
|
||||
- SABnzbd, NZBGet, qBittorrent, Deluge, rTorrent, Transmission integration
|
||||
- Plex and Kodi integration
|
||||
- Built-in archive extraction (Unpackerr functionality)
|
||||
|
||||
## Privacy
|
||||
|
||||
|
|
@ -69,13 +70,40 @@ dotnet run --project src/Radarr
|
|||
|
||||
## Roadmap
|
||||
|
||||
1. **Foundation** - Generalize database schema, implement hierarchical monitoring (Author → Series → Item)
|
||||
2. **Multi-Media** - Add book and audiobook quality profiles, port metadata providers
|
||||
3. **Interface** - Unified dashboard with type filters, type-specific detail views
|
||||
See [ROADMAP.md](../ROADMAP.md) for detailed phase planning.
|
||||
|
||||
**Completed:**
|
||||
- Phase 0-1: Privacy & security fixes
|
||||
- Phase 2: Foundation (fork, CI/CD, branding)
|
||||
- Phase 2.5: Community standards, quality gates, Unpackerr absorption
|
||||
|
||||
**Current:**
|
||||
- Phase 3: Multi-media foundation (database generalization, indexer management)
|
||||
|
||||
**Planned:**
|
||||
- Phase 4: Books & audiobooks support
|
||||
- Phase 5: TV shows
|
||||
- Phase 6: Music (with fingerprinting and quality analysis)
|
||||
- Phase 7: Subtitles (Bazarr replacement), podcasts, comics
|
||||
|
||||
## Key Differences from Radarr
|
||||
|
||||
| Feature | Radarr | Aletheia |
|
||||
|---------|--------|----------|
|
||||
| Media types | Movies only | Movies, books, audiobooks (planned: TV, music, podcasts) |
|
||||
| Telemetry | Enabled by default | Disabled by default |
|
||||
| Indexer management | External (Prowlarr) | Built-in (planned) |
|
||||
| Archive extraction | External (Unpackerr) | Built-in |
|
||||
| Narrator tracking | N/A | Native support for audiobooks |
|
||||
|
||||
## Contributing
|
||||
|
||||
Early development phase. See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and code guidelines.
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code guidelines, and PR process.
|
||||
|
||||
**Development standards:**
|
||||
- Conventional commits (`feat:`, `fix:`, `docs:`, etc.)
|
||||
- Feature branches + PRs to `develop`
|
||||
- Pre-commit hooks for linting
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(243)]
|
||||
public class add_mediatype_to_indexers : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Indexers").AddColumn("SupportedMediaTypes").AsString().WithDefaultValue("[\"Movie\"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaTypes;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||
|
|
@ -202,6 +203,7 @@ private static void RegisterMappers()
|
|||
SqlMapper.AddTypeHandler(new DapperLanguageIntConverter());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<Language>>(new LanguageIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<string>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<MediaType>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ParsedMovieInfo>(new QualityIntConverter(), new LanguageIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ReleaseInfo>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<PendingReleaseAdditionalInfo>());
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaTypes;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ public interface IIndexer : IProvider
|
|||
bool SupportsRss { get; }
|
||||
bool SupportsSearch { get; }
|
||||
DownloadProtocol Protocol { get; }
|
||||
IEnumerable<MediaType> SupportedMediaTypes { get; }
|
||||
|
||||
Task<IList<ReleaseInfo>> FetchRecent();
|
||||
Task<IList<ReleaseInfo>> Fetch(MovieSearchCriteria searchCriteria);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaTypes;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
|
@ -29,6 +30,7 @@ public abstract class IndexerBase<TSettings> : IIndexer
|
|||
|
||||
public abstract bool SupportsRss { get; }
|
||||
public abstract bool SupportsSearch { get; }
|
||||
public virtual IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.Movie };
|
||||
|
||||
public IndexerBase(IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Equ;
|
||||
using NzbDrone.Core.MediaTypes;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
|
|
@ -13,6 +15,7 @@ public class IndexerDefinition : ProviderDefinition, IEquatable<IndexerDefinitio
|
|||
public IndexerDefinition()
|
||||
{
|
||||
Priority = DefaultPriority;
|
||||
SupportedMediaTypes = new List<MediaType> { MediaType.Movie };
|
||||
}
|
||||
|
||||
[MemberwiseEqualityIgnore]
|
||||
|
|
@ -29,6 +32,7 @@ public IndexerDefinition()
|
|||
public bool EnableInteractiveSearch { get; set; }
|
||||
public int DownloadClientId { get; set; }
|
||||
public int Priority { get; set; }
|
||||
public List<MediaType> SupportedMediaTypes { get; set; }
|
||||
|
||||
[MemberwiseEqualityIgnore]
|
||||
public override bool Enable => EnableRss || EnableAutomaticSearch || EnableInteractiveSearch;
|
||||
|
|
|
|||
128
src/NzbDrone.Core/Indexers/NewznabStandardCategory.cs
Normal file
128
src/NzbDrone.Core/Indexers/NewznabStandardCategory.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.MediaTypes;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
public static class NewznabStandardCategory
|
||||
{
|
||||
public static readonly int Console = 1000;
|
||||
public static readonly int ConsoleNDS = 1010;
|
||||
public static readonly int ConsolePSP = 1020;
|
||||
public static readonly int ConsoleWii = 1030;
|
||||
public static readonly int ConsoleXbox = 1040;
|
||||
public static readonly int ConsoleXbox360 = 1050;
|
||||
public static readonly int ConsoleWiiware = 1060;
|
||||
public static readonly int ConsoleXbox360DLC = 1070;
|
||||
public static readonly int ConsolePS3 = 1080;
|
||||
public static readonly int ConsoleOther = 1090;
|
||||
public static readonly int Console3DS = 1110;
|
||||
public static readonly int ConsolePSVita = 1120;
|
||||
public static readonly int ConsoleWiiU = 1130;
|
||||
public static readonly int ConsoleXboxOne = 1140;
|
||||
public static readonly int ConsolePS4 = 1180;
|
||||
|
||||
public static readonly int Movies = 2000;
|
||||
public static readonly int MoviesForeign = 2010;
|
||||
public static readonly int MoviesOther = 2020;
|
||||
public static readonly int MoviesSD = 2030;
|
||||
public static readonly int MoviesHD = 2040;
|
||||
public static readonly int MoviesUHD = 2045;
|
||||
public static readonly int MoviesBluRay = 2050;
|
||||
public static readonly int Movies3D = 2060;
|
||||
public static readonly int MoviesDVD = 2070;
|
||||
public static readonly int MoviesWEBDL = 2080;
|
||||
|
||||
public static readonly int Audio = 3000;
|
||||
public static readonly int AudioMP3 = 3010;
|
||||
public static readonly int AudioVideo = 3020;
|
||||
public static readonly int AudioAudiobook = 3030;
|
||||
public static readonly int AudioLossless = 3040;
|
||||
public static readonly int AudioOther = 3050;
|
||||
public static readonly int AudioForeign = 3060;
|
||||
|
||||
public static readonly int PC = 4000;
|
||||
public static readonly int PC0day = 4010;
|
||||
public static readonly int PCISO = 4020;
|
||||
public static readonly int PCMac = 4030;
|
||||
public static readonly int PCMobileOther = 4040;
|
||||
public static readonly int PCGames = 4050;
|
||||
public static readonly int PCMobileiOS = 4060;
|
||||
public static readonly int PCMobileAndroid = 4070;
|
||||
|
||||
public static readonly int TV = 5000;
|
||||
public static readonly int TVWEBDL = 5010;
|
||||
public static readonly int TVForeign = 5020;
|
||||
public static readonly int TVSD = 5030;
|
||||
public static readonly int TVHD = 5040;
|
||||
public static readonly int TVUHD = 5045;
|
||||
public static readonly int TVOther = 5050;
|
||||
public static readonly int TVSport = 5060;
|
||||
public static readonly int TVAnime = 5070;
|
||||
public static readonly int TVDocumentary = 5080;
|
||||
|
||||
public static readonly int XXX = 6000;
|
||||
public static readonly int XXXDVD = 6010;
|
||||
public static readonly int XXXWMV = 6020;
|
||||
public static readonly int XXXXviD = 6030;
|
||||
public static readonly int XXXx264 = 6040;
|
||||
public static readonly int XXXOther = 6050;
|
||||
public static readonly int XXXImageset = 6060;
|
||||
public static readonly int XXXPacks = 6070;
|
||||
|
||||
public static readonly int Books = 7000;
|
||||
public static readonly int BooksMags = 7010;
|
||||
public static readonly int BooksEBook = 7020;
|
||||
public static readonly int BooksComics = 7030;
|
||||
public static readonly int BooksTechnical = 7040;
|
||||
public static readonly int BooksOther = 7050;
|
||||
public static readonly int BooksForeign = 7060;
|
||||
|
||||
public static readonly int Other = 8000;
|
||||
public static readonly int OtherMisc = 8010;
|
||||
public static readonly int OtherHashed = 8020;
|
||||
|
||||
public static IReadOnlyList<int> GetCategoriesForMediaType(MediaType mediaType)
|
||||
{
|
||||
return mediaType switch
|
||||
{
|
||||
MediaType.Movie => new[]
|
||||
{
|
||||
Movies, MoviesForeign, MoviesOther, MoviesSD, MoviesHD,
|
||||
MoviesUHD, MoviesBluRay, Movies3D, MoviesDVD, MoviesWEBDL
|
||||
},
|
||||
MediaType.TV => new[]
|
||||
{
|
||||
TV, TVWEBDL, TVForeign, TVSD, TVHD, TVUHD,
|
||||
TVOther, TVSport, TVAnime, TVDocumentary
|
||||
},
|
||||
MediaType.Music => new[]
|
||||
{
|
||||
Audio, AudioMP3, AudioVideo, AudioLossless, AudioOther, AudioForeign
|
||||
},
|
||||
MediaType.Audiobook => new[] { AudioAudiobook, Audio },
|
||||
MediaType.Book => new[]
|
||||
{
|
||||
Books, BooksMags, BooksEBook, BooksTechnical, BooksOther, BooksForeign
|
||||
},
|
||||
MediaType.Comic => new[] { BooksComics, Books },
|
||||
MediaType.Podcast => new[] { Audio, AudioOther },
|
||||
_ => new[] { Movies }
|
||||
};
|
||||
}
|
||||
|
||||
public static IReadOnlyList<int> GetIgnoredCategoriesForMediaType(MediaType mediaType)
|
||||
{
|
||||
return mediaType switch
|
||||
{
|
||||
MediaType.Movie => new[] { Console, Audio, PC, XXX, Books },
|
||||
MediaType.TV => new[] { Console, Audio, PC, Movies, XXX, Books },
|
||||
MediaType.Music => new[] { Console, PC, Movies, XXX, Books, TV },
|
||||
MediaType.Audiobook => new[] { Console, PC, Movies, XXX, TV },
|
||||
MediaType.Book => new[] { Console, Audio, PC, Movies, XXX, TV },
|
||||
MediaType.Comic => new[] { Console, Audio, PC, Movies, XXX, TV },
|
||||
MediaType.Podcast => new[] { Console, PC, Movies, XXX, Books, TV },
|
||||
_ => new[] { Console, Audio, PC, XXX, Books }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/NzbDrone.Core/MediaTypes/MediaType.cs
Normal file
14
src/NzbDrone.Core/MediaTypes/MediaType.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace NzbDrone.Core.MediaTypes
|
||||
{
|
||||
public enum MediaType
|
||||
{
|
||||
Unknown = 0,
|
||||
Movie = 1,
|
||||
TV = 2,
|
||||
Music = 3,
|
||||
Book = 4,
|
||||
Audiobook = 5,
|
||||
Podcast = 6,
|
||||
Comic = 7
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue