!wip started the searching process

pull/2478/head
TidusJar 7 years ago
parent 26d620cf01
commit 9156673f88

@ -22,7 +22,7 @@ namespace Ombi.Api.Lidarr
public Task<List<LidarrProfile>> GetProfiles(string apiKey, string baseUrl) public Task<List<LidarrProfile>> GetProfiles(string apiKey, string baseUrl)
{ {
var request = new Request($"{ApiVersion}/profile", baseUrl, HttpMethod.Get); var request = new Request($"{ApiVersion}/qualityprofile", baseUrl, HttpMethod.Get);
AddHeaders(request, apiKey); AddHeaders(request, apiKey);
return Api.Request<List<LidarrProfile>>(request); return Api.Request<List<LidarrProfile>>(request);

@ -2,12 +2,6 @@
namespace Ombi.Api.Lidarr.Models namespace Ombi.Api.Lidarr.Models
{ {
public class Cutoff
{
public int id { get; set; }
public string name { get; set; }
}
public class Quality public class Quality
{ {
public int id { get; set; } public int id { get; set; }
@ -23,9 +17,7 @@ namespace Ombi.Api.Lidarr.Models
public class LidarrProfile public class LidarrProfile
{ {
public string name { get; set; } public string name { get; set; }
public Cutoff cutoff { get; set; }
public List<Item> items { get; set; } public List<Item> items { get; set; }
public string language { get; set; }
public int id { get; set; } public int id { get; set; }
} }
} }

@ -7,6 +7,6 @@
public int trackCount { get; set; } public int trackCount { get; set; }
public int totalTrackCount { get; set; } public int totalTrackCount { get; set; }
public int sizeOnDisk { get; set; } public int sizeOnDisk { get; set; }
public int percentOfTracks { get; set; } public decimal percentOfTracks { get; set; }
} }
} }

@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Api.Lidarr.Models;
using Ombi.Core.Models.Search;
namespace Ombi.Core.Engine
{
public interface IMusicSearchEngine
{
Task<ArtistResult> GetAlbumArtist(string foreignArtistId);
Task<ArtistResult> GetArtist(int artistId);
Task<ArtistResult> GetArtistAlbums(string foreignArtistId);
Task<IEnumerable<AlbumLookup>> SearchAlbum(string search);
Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search);
}
}

@ -24,7 +24,7 @@ using Ombi.Store.Repository;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MusicSearchEngine : BaseMediaEngine public class MusicSearchEngine : BaseMediaEngine, IMusicSearchEngine
{ {
public MusicSearchEngine(IPrincipal identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper, public MusicSearchEngine(IPrincipal identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper,
ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
@ -60,12 +60,42 @@ namespace Ombi.Core.Engine
/// </summary> /// </summary>
/// <param name="search">The search.</param> /// <param name="search">The search.</param>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<ArtistLookup>> SearchArtist(string search) public async Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search)
{ {
var settings = await GetSettings(); var settings = await GetSettings();
var result = await _lidarrApi.ArtistLookup(search, settings.ApiKey, settings.FullUri); var result = await _lidarrApi.ArtistLookup(search, settings.ApiKey, settings.FullUri);
return result; var vm = new List<SearchArtistViewModel>();
foreach (var r in result)
{
vm.Add(MapIntoArtistVm(r));
}
return vm;
}
private SearchArtistViewModel MapIntoArtistVm(ArtistLookup a)
{
var vm = new SearchArtistViewModel
{
ArtistName = a.artistName,
ArtistType = a.artistType,
Banner = a.images?.FirstOrDefault(x => x.coverType.Equals("banner"))?.url,
Logo = a.images?.FirstOrDefault(x => x.coverType.Equals("logo"))?.url,
CleanName = a.cleanName,
Disambiguation = a.disambiguation,
ForignArtistId = a.foreignArtistId,
Links = a.links,
Overview = a.overview,
};
var poster = a.images?.FirstOrDefault(x => x.coverType.Equals("poaster"));
if (poster == null)
{
vm.Poster = a.remotePoster;
}
return vm;
} }
/// <summary> /// <summary>
@ -73,7 +103,7 @@ namespace Ombi.Core.Engine
/// </summary> /// </summary>
/// <param name="artistId"></param> /// <param name="artistId"></param>
/// <returns></returns> /// <returns></returns>
public async Task GetArtistAlbums(string foreignArtistId) public async Task<ArtistResult> GetArtistAlbums(string foreignArtistId)
{ {
var settings = await GetSettings(); var settings = await GetSettings();
return await _lidarrApi.GetArtistByForignId(foreignArtistId, settings.ApiKey, settings.FullUri); return await _lidarrApi.GetArtistByForignId(foreignArtistId, settings.ApiKey, settings.FullUri);
@ -82,11 +112,12 @@ namespace Ombi.Core.Engine
/// <summary> /// <summary>
/// Returns the artist that produced the album /// Returns the artist that produced the album
/// </summary> /// </summary>
/// <param name="albumId"></param> /// <param name="foreignArtistId"></param>
/// <returns></returns> /// <returns></returns>
public async Task GetAlbumArtist(string foreignArtistId) public async Task<ArtistResult> GetAlbumArtist(string foreignArtistId)
{ {
throw new NotImplementedException(); var settings = await GetSettings();
return await _lidarrApi.GetArtistByForignId(foreignArtistId, settings.ApiKey, settings.FullUri);
} }
public async Task<ArtistResult> GetArtist(int artistId) public async Task<ArtistResult> GetArtist(int artistId)

@ -0,0 +1,21 @@
using Ombi.Api.Lidarr.Models;
namespace Ombi.Core.Models.Search
{
public class SearchArtistViewModel
{
public string ArtistName { get; set; }
public string ForignArtistId { get; set; }
public string Overview { get; set; }
public string Disambiguation { get; set; }
public string Banner { get; set; }
public string Poster { get; set; }
public string Logo { get; set; }
public bool Monitored { get; set; }
public bool Available { get; set; }
public bool Requested { get; set; }
public string ArtistType { get; set; }
public string CleanName { get; set; }
public Link[] Links { get; set; } // Couldn't be bothered to map it
}
}

@ -83,6 +83,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<IUserStatsEngine, UserStatsEngine>(); services.AddTransient<IUserStatsEngine, UserStatsEngine>();
services.AddTransient<IMovieSender, MovieSender>(); services.AddTransient<IMovieSender, MovieSender>();
services.AddTransient<IRecentlyAddedEngine, RecentlyAddedEngine>(); services.AddTransient<IRecentlyAddedEngine, RecentlyAddedEngine>();
services.AddTransient<IMusicSearchEngine, MusicSearchEngine>();
services.AddTransient<ITvSender, TvSender>(); services.AddTransient<ITvSender, TvSender>();
services.AddTransient<IMassEmailSender, MassEmailSender>(); services.AddTransient<IMassEmailSender, MassEmailSender>();
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>(); services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();

@ -83,7 +83,7 @@
<ng-template #notRequestedBtn> <ng-template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"> <button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i> <i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i>{{ 'Common.Request' | translate }}</button> <i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i> {{ 'Common.Request' | translate }}</button>
</ng-template> </ng-template>
</div> </div>
<button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button> <button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button>

@ -4,13 +4,13 @@ import { TranslateService } from "@ngx-translate/core";
import { Subject } from "rxjs"; import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators"; import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service"; import { AuthService } from "../../auth/auth.service";
import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../interfaces"; import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../../interfaces";
import { NotificationService, RequestService, SearchService } from "../services"; import { NotificationService, RequestService, SearchService } from "../../services";
@Component({ @Component({
selector: "music-search", selector: "music-search",
templateUrl: "./music.component.html", templateUrl: "./musicsearch.component.html",
}) })
export class MusicSearchComponent implements OnInit { export class MusicSearchComponent implements OnInit {
@ -19,6 +19,7 @@ export class MusicSearchComponent implements OnInit {
public movieResults: ISearchMovieResult[]; public movieResults: ISearchMovieResult[];
public result: IRequestEngineResult; public result: IRequestEngineResult;
public searchApplied = false; public searchApplied = false;
public searchArtist: boolean;
@Input() public issueCategories: IIssueCategory[]; @Input() public issueCategories: IIssueCategory[];
@Input() public issuesEnabled: boolean; @Input() public issuesEnabled: boolean;
@ -44,11 +45,20 @@ export class MusicSearchComponent implements OnInit {
this.clearResults(); this.clearResults();
return; return;
} }
this.searchService.searchMusic(this.searchText) if(this.searchArtist) {
this.searchService.searchArtist(this.searchText)
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.searchApplied = true; this.searchApplied = true;
}); });
} else {
this.searchService.searchAlbum(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
});
}
}); });
this.defaultPoster = "../../../images/default_movie_poster.png"; this.defaultPoster = "../../../images/default_movie_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM(); const base = this.platformLocation.getBaseHrefFromDOM();
@ -65,7 +75,6 @@ export class MusicSearchComponent implements OnInit {
result: false, result: false,
errorMessage: "", errorMessage: "",
}; };
this.popularMovies();
} }
public search(text: any) { public search(text: any) {
@ -111,77 +120,6 @@ export class MusicSearchComponent implements OnInit {
} }
} }
public popularMovies() {
this.clearResults();
this.searchService.popularMovies()
.subscribe(x => {
this.movieResults = x;
});
}
public nowPlayingMovies() {
this.clearResults();
this.searchService.nowPlayingMovies()
.subscribe(x => {
this.movieResults = x;
});
}
public topRatedMovies() {
this.clearResults();
this.searchService.topRatedMovies()
.subscribe(x => {
this.movieResults = x;
});
}
public upcomingMovies() {
this.clearResults();
this.searchService.upcomingMovies()
.subscribe(x => {
this.movieResults = x;
});
}
public reportIssue(catId: IIssueCategory, req: ISearchMovieResult) {
this.issueRequestId = req.id;
this.issueRequestTitle = req.title + `(${req.releaseDate.getFullYear})`;
this.issueCategorySelected = catId;
this.issuesBarVisible = true;
this.issueProviderId = req.id.toString();
}
public similarMovies(theMovieDbId: number) {
this.clearResults();
this.searchService.similarMovies(theMovieDbId)
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public subscribe(r: ISearchMovieResult) {
r.subscribed = true;
this.requestService.subscribeToMovie(r.requestId)
.subscribe(x => {
this.notificationService.success("Subscribed To Movie!");
});
}
public unSubscribe(r: ISearchMovieResult) {
r.subscribed = false;
this.requestService.unSubscribeToMovie(r.requestId)
.subscribe(x => {
this.notificationService.success("Unsubscribed Movie!");
});
}
private updateItem(key: ISearchMovieResult, updated: ISearchMovieResult) {
const index = this.movieResults.indexOf(key, 0);
if (index > -1) {
const copy = { ...this.movieResults[index] };
this.movieResults[index] = updated;
this.movieResults[index].background = copy.background;
this.movieResults[index].posterPath = copy.posterPath;
}
}
private clearResults() { private clearResults() {
this.movieResults = []; this.movieResults = [];
this.searchApplied = false; this.searchApplied = false;

@ -13,6 +13,9 @@
<li role="presentation"> <li role="presentation">
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTvTab()"><i class="fa fa-television"></i> {{ 'Search.TvTab' | translate }}</a> <a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTvTab()"><i class="fa fa-television"></i> {{ 'Search.TvTab' | translate }}</a>
</li> </li>
<li role="presentation" *ngIf="musicEnabled">
<a id="tvTabButton" href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectMusicTab()"><i class="fa fa-music"></i> {{ 'Search.MusicTab' | translate }}</a>
</li>
</ul> </ul>
<!-- Tab panes --> <!-- Tab panes -->
@ -25,6 +28,9 @@
<div [hidden]="!showTv"> <div [hidden]="!showTv">
<tv-search [issueCategories]="issueCategories" [issuesEnabled]="issuesEnabled"></tv-search> <tv-search [issueCategories]="issueCategories" [issuesEnabled]="issuesEnabled"></tv-search>
</div> </div>
<div [hidden]="!showMusic">
<music-search></music-search>
</div>
</div> </div>

@ -9,8 +9,10 @@ import { IssuesService, SettingsService } from "../services";
export class SearchComponent implements OnInit { export class SearchComponent implements OnInit {
public showTv: boolean; public showTv: boolean;
public showMovie: boolean; public showMovie: boolean;
public showMusic: boolean;
public issueCategories: IIssueCategory[]; public issueCategories: IIssueCategory[];
public issuesEnabled = false; public issuesEnabled = false;
public musicEnabled: boolean;
constructor(private issuesService: IssuesService, constructor(private issuesService: IssuesService,
private settingsService: SettingsService) { private settingsService: SettingsService) {
@ -18,8 +20,10 @@ export class SearchComponent implements OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.settingsService.getLidarr().subscribe(x => this.musicEnabled = x.enabled);
this.showMovie = true; this.showMovie = true;
this.showTv = false; this.showTv = false;
this.showMusic = false;
this.issuesService.getCategories().subscribe(x => this.issueCategories = x); this.issuesService.getCategories().subscribe(x => this.issueCategories = x);
this.settingsService.getIssueSettings().subscribe(x => this.issuesEnabled = x.enabled); this.settingsService.getIssueSettings().subscribe(x => this.issuesEnabled = x.enabled);
} }
@ -27,10 +31,17 @@ export class SearchComponent implements OnInit {
public selectMovieTab() { public selectMovieTab() {
this.showMovie = true; this.showMovie = true;
this.showTv = false; this.showTv = false;
this.showMusic = false;
} }
public selectTvTab() { public selectTvTab() {
this.showMovie = false; this.showMovie = false;
this.showTv = true; this.showTv = true;
this.showMusic = false;
}
public selectMusicTab() {
this.showMovie = false;
this.showTv = false;
this.showMusic = true;
} }
} }

@ -7,6 +7,7 @@ import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { MovieSearchComponent } from "./moviesearch.component"; import { MovieSearchComponent } from "./moviesearch.component";
import { MovieSearchGridComponent } from "./moviesearchgrid.component"; import { MovieSearchGridComponent } from "./moviesearchgrid.component";
import { MusicSearchComponent } from "./music/musicsearch.component";
import { SearchComponent } from "./search.component"; import { SearchComponent } from "./search.component";
import { SeriesInformationComponent } from "./seriesinformation.component"; import { SeriesInformationComponent } from "./seriesinformation.component";
import { TvSearchComponent } from "./tvsearch.component"; import { TvSearchComponent } from "./tvsearch.component";
@ -41,6 +42,7 @@ const routes: Routes = [
TvSearchComponent, TvSearchComponent,
SeriesInformationComponent, SeriesInformationComponent,
MovieSearchGridComponent, MovieSearchGridComponent,
MusicSearchComponent,
], ],
exports: [ exports: [
RouterModule, RouterModule,

@ -69,7 +69,10 @@ export class SearchService extends ServiceHelpers {
return this.http.get<ISearchTvResult[]>(`${this.url}/Tv/trending`, {headers: this.headers}); return this.http.get<ISearchTvResult[]>(`${this.url}/Tv/trending`, {headers: this.headers});
} }
// Music // Music
public searchMusic(searchTerm: string): Observable<ISearchMovieResult[]> { public searchArtist(searchTerm: string): Observable<any> {
return this.http.get<ISearchMovieResult[]>(`${this.url}/Music/` + searchTerm); return this.http.get<any>(`${this.url}/Music/Artist/` + searchTerm);
}
public searchAlbum(searchTerm: string): Observable<any> {
return this.http.get<any>(`${this.url}/Music/Album/` + searchTerm);
} }
} }

@ -3,8 +3,7 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { ILidarrSettings, IMinimumAvailability, IRadarrProfile, IRadarrRootFolder } from "../../interfaces"; import { ILidarrSettings, IMinimumAvailability, IRadarrProfile, IRadarrRootFolder } from "../../interfaces";
import { IRadarrSettings } from "../../interfaces"; import { IRadarrSettings } from "../../interfaces";
import { RadarrService } from "../../services"; import { LidarrService, TesterService } from "../../services";
import { TesterService } from "../../services";
import { NotificationService } from "../../services"; import { NotificationService } from "../../services";
import { SettingsService } from "../../services"; import { SettingsService } from "../../services";
@ -22,7 +21,7 @@ export class LidarrComponent implements OnInit {
public form: FormGroup; public form: FormGroup;
constructor(private settingsService: SettingsService, constructor(private settingsService: SettingsService,
private radarrService: RadarrService, private lidarrService: LidarrService,
private notificationService: NotificationService, private notificationService: NotificationService,
private fb: FormBuilder, private fb: FormBuilder,
private testerService: TesterService) { } private testerService: TesterService) { }
@ -59,7 +58,7 @@ export class LidarrComponent implements OnInit {
public getProfiles(form: FormGroup) { public getProfiles(form: FormGroup) {
this.profilesRunning = true; this.profilesRunning = true;
this.radarrService.getQualityProfiles(form.value).subscribe(x => { this.lidarrService.getQualityProfiles(form.value).subscribe(x => {
this.qualities = x; this.qualities = x;
this.qualities.unshift({ name: "Please Select", id: -1 }); this.qualities.unshift({ name: "Please Select", id: -1 });
@ -70,7 +69,7 @@ export class LidarrComponent implements OnInit {
public getRootFolders(form: FormGroup) { public getRootFolders(form: FormGroup) {
this.rootFoldersRunning = true; this.rootFoldersRunning = true;
this.radarrService.getRootFolders(form.value).subscribe(x => { this.lidarrService.getRootFolders(form.value).subscribe(x => {
this.rootFolders = x; this.rootFolders = x;
this.rootFolders.unshift({ path: "Please Select", id: -1 }); this.rootFolders.unshift({ path: "Please Select", id: -1 });

@ -50,7 +50,7 @@
<li class="dropdown" [routerLinkActive]="['active']"> <li class="dropdown" [routerLinkActive]="['active']">
<a href="ignore($event)" class="dropdown-toggle" data-toggle="dropdown"> <a href="ignore($event)" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-film" aria-hidden="true"></i> Music <span class="caret"></span> <i class="fa fa-music" aria-hidden="true"></i> Music <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Lidarr']">Lidarr</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Lidarr']">Lidarr</a></li>

@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr.Models;
using Ombi.Core; using Ombi.Core;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
@ -18,16 +18,18 @@ namespace Ombi.Controllers
[Produces("application/json")] [Produces("application/json")]
public class SearchController : Controller public class SearchController : Controller
{ {
public SearchController(IMovieEngine movie, ITvSearchEngine tvEngine, ILogger<SearchController> logger) public SearchController(IMovieEngine movie, ITvSearchEngine tvEngine, ILogger<SearchController> logger, IMusicSearchEngine music)
{ {
MovieEngine = movie; MovieEngine = movie;
TvEngine = tvEngine; TvEngine = tvEngine;
Logger = logger; Logger = logger;
MusicEngine = music;
} }
private ILogger<SearchController> Logger { get; } private ILogger<SearchController> Logger { get; }
private IMovieEngine MovieEngine { get; } private IMovieEngine MovieEngine { get; }
private ITvSearchEngine TvEngine { get; } private ITvSearchEngine TvEngine { get; }
private IMusicSearchEngine MusicEngine { get; }
/// <summary> /// <summary>
/// Searches for a movie. /// Searches for a movie.
@ -182,5 +184,27 @@ namespace Ombi.Controllers
{ {
return await TvEngine.Trending(); return await TvEngine.Trending();
} }
/// <summary>
/// Returns the artist information we searched for
/// </summary>
/// <remarks>We use Lidarr as the Provider</remarks>
/// <returns></returns>
[HttpGet("music/artist/{searchTerm}")]
public async Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string searchTerm)
{
return await MusicEngine.SearchArtist(searchTerm);
}
/// <summary>
/// Returns the album information we searched for
/// </summary>
/// <remarks>We use Lidarr as the Provider</remarks>
/// <returns></returns>
[HttpGet("music/album/{searchTerm}")]
public async Task<IEnumerable<AlbumLookup>> SearchAlbum(string searchTerm)
{
return await MusicEngine.SearchAlbum(searchTerm);
}
} }
} }

@ -333,7 +333,7 @@ namespace Ombi.Controllers
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("sonarr")] [HttpPost("lidarr")]
public async Task<bool> LidarrSettings([FromBody]LidarrSettings settings) public async Task<bool> LidarrSettings([FromBody]LidarrSettings settings)
{ {
return await Save(settings); return await Save(settings);

@ -78,6 +78,7 @@
"Want to watch something that is not currently available? No problem, just search for it below and request it!", "Want to watch something that is not currently available? No problem, just search for it below and request it!",
"MoviesTab": "Movies", "MoviesTab": "Movies",
"TvTab": "TV Shows", "TvTab": "TV Shows",
"MusicTab":"Music",
"Suggestions": "Suggestions", "Suggestions": "Suggestions",
"NoResults": "Sorry, we didn't find any results!", "NoResults": "Sorry, we didn't find any results!",
"DigitalDate": "Digital Release: {{date}}", "DigitalDate": "Digital Release: {{date}}",

Loading…
Cancel
Save