mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-06 13:31:28 -05:00
Compare commits
28 Commits
v0.2.0.134
...
v0.2.0.152
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d665aeb21 | ||
|
|
967d3fd5c0 | ||
|
|
199d9c93ed | ||
|
|
30d2b41fbb | ||
|
|
75bb2533a3 | ||
|
|
9b3b4eb55b | ||
|
|
42f84b830c | ||
|
|
eb0f825cfc | ||
|
|
56a5b6ec89 | ||
|
|
af478d3799 | ||
|
|
c2d40051d4 | ||
|
|
281e516495 | ||
|
|
f63c3091f4 | ||
|
|
50f49863b7 | ||
|
|
941b3bd701 | ||
|
|
f60b8cefca | ||
|
|
7c5f2ca54e | ||
|
|
401a650273 | ||
|
|
105af5cf11 | ||
|
|
637c2e43eb | ||
|
|
53373e6f4a | ||
|
|
ad147ed425 | ||
|
|
ed35e2f194 | ||
|
|
674919dbf5 | ||
|
|
15b77e303f | ||
|
|
757ca1d72c | ||
|
|
8c8c7a99e3 | ||
|
|
b3dfb960b5 |
26
.gitignore
vendored
26
.gitignore
vendored
@@ -101,16 +101,21 @@ App_Data/*.ldf
|
||||
_NCrunch_*
|
||||
_TeamCity*
|
||||
|
||||
# Sonarr
|
||||
config.xml
|
||||
nzbdrone.log*txt
|
||||
# Radarr
|
||||
Backups/
|
||||
logs/
|
||||
MediaCover/
|
||||
UpdateLogs/
|
||||
xdg/
|
||||
config.xml
|
||||
logs.db*
|
||||
nzbdrone.db*
|
||||
nzbdrone.pid
|
||||
*workspace.xml
|
||||
*.test-cache
|
||||
*.userprefs
|
||||
*/test-results/*
|
||||
src/UI/.idea/*
|
||||
*log.txt
|
||||
node_modules/
|
||||
_output*
|
||||
_rawPackage/
|
||||
@@ -122,23 +127,26 @@ setup/Output/
|
||||
|
||||
UI.Phantom/
|
||||
|
||||
#VS outout folders
|
||||
# VS outout folders
|
||||
bin
|
||||
obj
|
||||
output/*
|
||||
|
||||
#Packages
|
||||
# Packages
|
||||
Radarr_*/
|
||||
Radarr_*.zip
|
||||
Radarr_*.gz
|
||||
|
||||
#OS X metadata files
|
||||
# macOS metadata files
|
||||
._*
|
||||
.DS_Store
|
||||
|
||||
_start
|
||||
_temp_*/**/*
|
||||
|
||||
#AppVeyor
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
|
||||
# AppVeyor
|
||||
/tools-cake/
|
||||
/_artifacts/
|
||||
/_artifacts/
|
||||
|
||||
10
.travis.yml
10
.travis.yml
@@ -1,12 +1,14 @@
|
||||
language: csharp
|
||||
solution: src/NzbDrone.sln
|
||||
script: # the following commands are just examples, use whatever your build process requires
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- nodejs
|
||||
- npm
|
||||
script:
|
||||
- ./build.sh
|
||||
- chmod +x test.sh
|
||||
# - ./test.sh Linux Unit Takes far too long, maybe even crashes travis :/
|
||||
install:
|
||||
- sudo apt-get install nodejs
|
||||
- sudo apt-get install npm
|
||||
after_success:
|
||||
- chmod +x package.sh
|
||||
- ./package.sh
|
||||
|
||||
BIN
Logo/Thumbs.db
BIN
Logo/Thumbs.db
Binary file not shown.
94
README.md
Normal file
94
README.md
Normal file
@@ -0,0 +1,94 @@
|
||||
## Status
|
||||
|
||||
[](https://github.com/Radarr/Radarr/issues)
|
||||
[](https://github.com/Radarr/Radarr/pulls)
|
||||
[](http://www.gnu.org/licenses/gpl.html)
|
||||
[](https://github.com/Radarr/Radarr)
|
||||
[](https://github.com/Radar/Radarr/releases/latest)
|
||||
[](https://hub.docker.com/r/linuxserver/radarr/)
|
||||
|
||||
| Service | Master | Develop |
|
||||
|----------|:---------------------------:|:----------------------------:|
|
||||
| AppVeyor | [](https://ci.appveyor.com/project/galli-leo/Radarr) | [](https://ci.appveyor.com/project/galli-leo/Radarr-usby1) |
|
||||
| Travis | [](https://travis-ci.org/Radarr/Radarr) | [](https://travis-ci.org/Radarr/Radarr) |
|
||||
|
||||
This fork of Sonarr aims to turn it into something like CouchPotato.
|
||||
|
||||
## Downloads
|
||||
|
||||
[](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
[](https://ci.appveyor.com/project/galli-leo/radarr-usby1/build/artifacts)
|
||||
|
||||
[](https://store.docker.com/community/images/linuxserver/radarr)
|
||||
[](https://store.docker.com/community/images/lsioarmhf/radarr)
|
||||
[](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
|
||||
|
||||
To connect to the UI, fire up your browser and open <http://localhost:7878> or <http://your-ip:7878>.
|
||||
|
||||
## Support
|
||||
|
||||
[](https://discord.gg/AD3UP37)
|
||||
[](https://www.reddit.com/r/radarr)
|
||||
[](https://github.com/Radarr/Radarr/issues)
|
||||
|
||||
## Features
|
||||
|
||||
### Currently Working
|
||||
|
||||
* Adding new movies
|
||||
* Manually searching for releases of movies
|
||||
* Automatically searching for releases
|
||||
* Automatically importing downloaded movies
|
||||
* Recognizing Special Editions, Director's Cut, etc.
|
||||
* Identifying releases with hardcoded subs
|
||||
* Rarbg.to, Torznab and Newznab Indexer
|
||||
* QBittorrent and Deluge download client (Other clients are coming)
|
||||
* New TorrentPotato Indexer (Works well with [Jackett](https://github.com/Jackett/Jackett))
|
||||
|
||||
### Planned Features
|
||||
|
||||
* Scanning PreDB to know when a new release is available
|
||||
* Fixing the other Indexers and download clients
|
||||
* Importing of Sonarr config
|
||||
|
||||
### Major Features
|
||||
|
||||
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
||||
* Can watch for better quality of the movies you have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
|
||||
* Automatic failed download handling will try another release if one fails
|
||||
* Manual search so you can pick any release or to see why a release was not downloaded automatically
|
||||
* Full integration with SABnzbd and NZBGet
|
||||
* Full integration with Kodi, Plex (notification, library update, metadata)
|
||||
* And a beautiful UI
|
||||
|
||||
## Configuring Development Environment
|
||||
|
||||
### Requirements
|
||||
|
||||
* [Visual Studio Community](https://www.visualstudio.com/vs/community/) or [MonoDevelop](http://www.monodevelop.com)
|
||||
* [Git](https://git-scm.com/downloads)
|
||||
* [Node.js](https://nodejs.org/en/download/)
|
||||
|
||||
### Setup
|
||||
|
||||
* Make sure all the required software mentioned above are installed
|
||||
* Clone the repository into your development machine ([*info*](https://help.github.com/desktop/guides/contributing/working-with-your-remote-repository-on-github-or-github-enterprise))
|
||||
* Grab the submodules `git submodule init && git submodule update`
|
||||
* Install the required Node Packages `npm install`
|
||||
* Start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
|
||||
|
||||
> **Notice**
|
||||
> Gulp must be running at all times while you are working with Radarr client source files.
|
||||
|
||||
### Development
|
||||
|
||||
* Open `NzbDrone.sln` in Visual Studio or run the build.sh script, if Mono is installed
|
||||
* Make sure `NzbDrone.Console` is set as the startup project
|
||||
|
||||
## Sponsors
|
||||
|
||||
[JetBrains](http://www.jetbrains.com) for providing us with free licenses to their great tools:
|
||||
* [ReSharper](http://www.jetbrains.com/resharper)
|
||||
* [WebStorm](http://www.jetbrains.com/webstorm)
|
||||
* [TeamCity](http://www.jetbrains.com/teamcity)
|
||||
83
readme.md
83
readme.md
@@ -1,83 +0,0 @@
|
||||
# Radarr
|
||||
|
||||
| Service | Master | Develop |
|
||||
|----------|:---------------------------:|:----------------------------:|
|
||||
| AppVeyor | [](https://ci.appveyor.com/project/galli-leo/Radarr) | [](https://ci.appveyor.com/project/galli-leo/Radarr-usby1) |
|
||||
| Travis | [](https://travis-ci.org/galli-leo/Radarr) | [](https://travis-ci.org/galli-leo/Radarr) |
|
||||
|
||||
This fork of Sonarr aims to turn it into something like Couchpotato.
|
||||
|
||||
## Currently working:
|
||||
* Adding new movies
|
||||
* Manually searching for releases of movies.
|
||||
* Automatically searching for releases.
|
||||
* Automatically importing downloaded movies.
|
||||
* Recognizing Special Editions, Director's Cut, etc.
|
||||
* Identifying releases with hardcoded subs.
|
||||
* Rarbg.to, Torznab and Newznab Indexer.
|
||||
* QBittorrent and Deluge download client (Other clients are coming)
|
||||
* New TorrentPotato Indexer (Works well with [Jackett](https://github.com/Jackett/Jackett))
|
||||
|
||||
## Planned Features:
|
||||
* Scanning PreDB to know when a new release is available.
|
||||
* Fixing the other Indexers and download clients.
|
||||
* Importing of Sonarr config.
|
||||
|
||||
## Download
|
||||
The latest precompiled binary versions can be found here: https://github.com/galli-leo/Radarr/releases.
|
||||
|
||||
To connect to the UI, fire up your browser and open localhost:7878 or your-ip:7878.
|
||||
|
||||
Docker containers from [linuxserver.io](https://linuxserver.io) can be found here.
|
||||
* [Radarr (x64)](https://hub.docker.com/r/linuxserver/radarr/)
|
||||
* [Radarr (armhf)](https://hub.docker.com/r/lsioarmhf/radarr/)
|
||||
* [Radarr (aarch64)](https://hub.docker.com/r/lsioarmhf/radarr-aarch64/)
|
||||
|
||||
For more up to date versions (but also sometimes broken), daily builds can be found here:
|
||||
* [OSX](https://leonardogalli.ch/radarr/builds/latest.php?os=osx)
|
||||
* [Windows](https://leonardogalli.ch/radarr/builds/latest.php?os=windows)
|
||||
* [Linux](https://leonardogalli.ch/radarr/builds/latest.php?os=mono)
|
||||
|
||||
## Major Features Include: ##
|
||||
|
||||
* Support for major platforms: Windows, Linux, OSX, Raspberry Pi, etc.
|
||||
* Can watch for better quality of the movies you have and do an upgrade.
|
||||
* Automatic failed download handling will try another release if one fails
|
||||
* Manual search so you can pick any release or to see why a release was not downloaded automatically.
|
||||
* Full integration with SABNzbd and NzbGet.
|
||||
* Full integration with XBMC, Plex (notification, library update, metadata).
|
||||
* And a beautiful UI
|
||||
|
||||
## Configuring Development Environment: ##
|
||||
|
||||
### Requirements ###
|
||||
- Visual Studio 2015 [Free Community Edition](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) or Mono
|
||||
- [Git](http://git-scm.com/downloads)
|
||||
- [NodeJS](http://nodejs.org/download/)
|
||||
|
||||
### Setup ###
|
||||
|
||||
- Make sure all the required software mentioned above are installed.
|
||||
- Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
|
||||
- Grab the submodules `git submodule init && git submodule update`
|
||||
- install the required Node Packages `npm install`
|
||||
- start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
|
||||
|
||||
*Please note gulp must be running at all times while you are working with Sonarr client source files.*
|
||||
|
||||
|
||||
### Development ###
|
||||
- Open `NzbDrone.sln` in Visual Studio or run the build.sh script, if Mono is installed.
|
||||
- Make sure `NzbDrone.Console` is set as the startup project
|
||||
|
||||
|
||||
### License ###
|
||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||
Copyright 2010-2016
|
||||
|
||||
|
||||
### Sponsors ###
|
||||
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
|
||||
- [ReSharper](http://www.jetbrains.com/resharper/)
|
||||
- [WebStorm](http://www.jetbrains.com/webstorm/)
|
||||
- [TeamCity](http://www.jetbrains.com/teamcity/)
|
||||
@@ -2,24 +2,38 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Movie;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.MovieStats;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.Validation;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
|
||||
namespace NzbDrone.Api.Calendar
|
||||
{
|
||||
public class CalendarModule : EpisodeModuleWithSignalR
|
||||
public class CalendarModule : MovieModule
|
||||
{
|
||||
public CalendarModule(IEpisodeService episodeService,
|
||||
ISeriesService seriesService,
|
||||
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "calendar")
|
||||
public CalendarModule(IBroadcastSignalRMessage signalR,
|
||||
IMovieService moviesService,
|
||||
IMovieStatisticsService moviesStatisticsService,
|
||||
ISceneMappingService sceneMappingService,
|
||||
IMapCoversToLocal coverMapper)
|
||||
: base(signalR, moviesService, moviesStatisticsService, sceneMappingService, coverMapper, "calendar")
|
||||
{
|
||||
|
||||
GetResourceAll = GetCalendar;
|
||||
}
|
||||
|
||||
private List<EpisodeResource> GetCalendar()
|
||||
private List<MovieResource> GetCalendar()
|
||||
{
|
||||
var start = DateTime.Today;
|
||||
var end = DateTime.Today.AddDays(2);
|
||||
@@ -33,9 +47,9 @@ namespace NzbDrone.Api.Calendar
|
||||
if (queryEnd.HasValue) end = DateTime.Parse(queryEnd.Value);
|
||||
if (queryIncludeUnmonitored.HasValue) includeUnmonitored = Convert.ToBoolean(queryIncludeUnmonitored.Value);
|
||||
|
||||
var resources = MapToResource(_episodeService.EpisodesBetweenDates(start, end, includeUnmonitored), true, true);
|
||||
var resources = _moviesService.GetMoviesBetweenDates(start, end, includeUnmonitored).Select(MapToResource);
|
||||
|
||||
return resources.OrderBy(e => e.AirDateUtc).ToList();
|
||||
return resources.OrderBy(e => e.InCinemas).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Api.Movie
|
||||
IHandle<MediaCoversUpdatedEvent>
|
||||
|
||||
{
|
||||
private readonly IMovieService _moviesService;
|
||||
protected readonly IMovieService _moviesService;
|
||||
private readonly IMovieStatisticsService _moviesStatisticsService;
|
||||
private readonly IMapCoversToLocal _coverMapper;
|
||||
|
||||
@@ -78,13 +78,33 @@ namespace NzbDrone.Api.Movie
|
||||
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
||||
}
|
||||
|
||||
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IMovieService moviesService,
|
||||
IMovieStatisticsService moviesStatisticsService,
|
||||
ISceneMappingService sceneMappingService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_moviesService = moviesService;
|
||||
_moviesStatisticsService = moviesStatisticsService;
|
||||
|
||||
_coverMapper = coverMapper;
|
||||
|
||||
GetResourceAll = AllMovie;
|
||||
GetResourceById = GetMovie;
|
||||
CreateResource = AddMovie;
|
||||
UpdateResource = UpdateMovie;
|
||||
DeleteResource = DeleteMovie;
|
||||
}
|
||||
|
||||
private MovieResource GetMovie(int id)
|
||||
{
|
||||
var movies = _moviesService.GetMovie(id);
|
||||
return MapToResource(movies);
|
||||
}
|
||||
|
||||
private MovieResource MapToResource(Core.Tv.Movie movies)
|
||||
protected MovieResource MapToResource(Core.Tv.Movie movies)
|
||||
{
|
||||
if (movies == null) return null;
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace NzbDrone.Api.Movie
|
||||
public string RemotePoster { get; set; }
|
||||
public int Year { get; set; }
|
||||
public bool HasFile { get; set; }
|
||||
public string YouTubeTrailerId { get; set; }
|
||||
public string Studio { get; set; }
|
||||
|
||||
//View & Edit
|
||||
public string Path { get; set; }
|
||||
@@ -144,7 +146,9 @@ namespace NzbDrone.Api.Movie
|
||||
AddOptions = model.AddOptions,
|
||||
AlternativeTitles = model.AlternativeTitles,
|
||||
Ratings = model.Ratings,
|
||||
MovieFile = movieFile
|
||||
MovieFile = movieFile,
|
||||
YouTubeTrailerId = model.YouTubeTrailerId,
|
||||
Studio = model.Studio
|
||||
};
|
||||
}
|
||||
|
||||
@@ -191,7 +195,9 @@ namespace NzbDrone.Api.Movie
|
||||
Added = resource.Added,
|
||||
AddOptions = resource.AddOptions,
|
||||
AlternativeTitles = resource.AlternativeTitles,
|
||||
Ratings = resource.Ratings
|
||||
Ratings = resource.Ratings,
|
||||
YouTubeTrailerId = resource.YouTubeTrailerId,
|
||||
Studio = resource.Studio
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(119)]
|
||||
public class add_youtube_trailer_id : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Movies").AddColumn("YouTubeTrailerId").AsString().Nullable();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(120)]
|
||||
public class add_studio : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Movies").AddColumn("Studio").AsString().Nullable();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
if (parsedEpisodeInfo.Quality.HardcodedSubs.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
remoteEpisode.DownloadAllowed = false;
|
||||
remoteEpisode.DownloadAllowed = true;
|
||||
decision = new DownloadDecision(remoteEpisode, new Rejection("Hardcoded subs found: " + parsedEpisodeInfo.Quality.HardcodedSubs));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
{
|
||||
//Let's try anyways with q parameter, worst case nothing found.
|
||||
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search",
|
||||
string.Format("&q={0}", searchCriteria.Movie.Title)));
|
||||
string.Format("&q={0}", Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title))));
|
||||
}
|
||||
|
||||
return pageableRequests;
|
||||
|
||||
@@ -36,12 +36,11 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||
torrentInfo.Size = (long)torrent.size*1000*1000;
|
||||
torrentInfo.DownloadUrl = torrent.download_url;
|
||||
torrentInfo.InfoUrl = torrent.details_url;
|
||||
torrentInfo.PublishDate = new System.DateTime();
|
||||
torrentInfo.PublishDate = torrent.publishdate.ToUniversalTime();
|
||||
torrentInfo.Seeders = torrent.seeders;
|
||||
torrentInfo.Peers = torrent.leechers + torrent.seeders;
|
||||
torrentInfo.Freeleech = torrent.freeleech;
|
||||
torrentInfo.PublishDate = torrent.publishdate.ToUniversalTime();
|
||||
|
||||
|
||||
results.Add(torrentInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
||||
public int vote_count { get; set; }
|
||||
public AlternativeTitles alternative_titles { get; set; }
|
||||
public ReleaseDatesResource release_dates { get; set; }
|
||||
public VideosResource videos { get; set; }
|
||||
}
|
||||
|
||||
public class ReleaseDatesResource
|
||||
@@ -130,4 +131,21 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
||||
public string iso_3166_1 { get; set; }
|
||||
public string title { get; set; }
|
||||
}
|
||||
|
||||
public class VideosResource
|
||||
{
|
||||
public List<Video> results { get; set; }
|
||||
}
|
||||
|
||||
public class Video
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string iso_639_1 { get; set; }
|
||||
public string iso_3166_1 { get; set; }
|
||||
public string key { get; set; }
|
||||
public string name { get; set; }
|
||||
public string site { get; set; }
|
||||
public string size { get; set; }
|
||||
public string type { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||
.SetSegment("route", "movie")
|
||||
.SetSegment("id", TmdbId.ToString())
|
||||
.SetSegment("secondaryRoute", "")
|
||||
.AddQueryParam("append_to_response", "alternative_titles,release_dates")
|
||||
.AddQueryParam("append_to_response", "alternative_titles,release_dates,videos")
|
||||
.AddQueryParam("country", "US")
|
||||
.Build();
|
||||
|
||||
@@ -149,6 +149,23 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||
{
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
}
|
||||
|
||||
if (resource.videos != null)
|
||||
{
|
||||
foreach(Video video in resource.videos.results)
|
||||
{
|
||||
if(video.type == "Trailer" && video.site == "YouTube")
|
||||
{
|
||||
movie.YouTubeTrailerId = video.key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resource.production_companies != null && resource.production_companies.Count() > 0)
|
||||
{
|
||||
movie.Studio = resource.production_companies[0].name;
|
||||
}
|
||||
|
||||
return movie;
|
||||
}
|
||||
|
||||
@@ -183,6 +183,8 @@
|
||||
<Compile Include="Datastore\Migration\002_remove_tvrage_imdb_unique_constraint.cs" />
|
||||
<Compile Include="Datastore\Migration\003_remove_clean_title_from_scene_mapping.cs" />
|
||||
<Compile Include="Datastore\Migration\004_updated_history.cs" />
|
||||
<Compile Include="Datastore\Migration\120_add_studio_to_table.cs" />
|
||||
<Compile Include="Datastore\Migration\119_add_youtube_trailer_id_table .cs" />
|
||||
<Compile Include="Datastore\Migration\118_update_movie_slug.cs" />
|
||||
<Compile Include="Datastore\Migration\117_update_movie_file.cs" />
|
||||
<Compile Include="Datastore\Migration\116_update_movie_sorttitle_again.cs" />
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Organizer
|
||||
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{(?:Movie)(?<separator>[- ._])(Clean)?Title\})",
|
||||
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?Title)\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
|
||||
@@ -163,6 +163,7 @@ namespace NzbDrone.Core.Organizer
|
||||
AddReleaseDateTokens(tokenHandlers, movie.Year); //In case we want to separate the year
|
||||
AddQualityTokens(tokenHandlers, movie, movieFile);
|
||||
AddMediaInfoTokens(tokenHandlers, movieFile);
|
||||
AddMovieFileTokens(tokenHandlers, movieFile);
|
||||
|
||||
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
|
||||
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
|
||||
@@ -503,6 +504,13 @@ namespace NzbDrone.Core.Organizer
|
||||
tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr");
|
||||
}
|
||||
|
||||
private void AddMovieFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile episodeFile)
|
||||
{
|
||||
tokenHandlers["{Original Title}"] = m => GetOriginalTitle(episodeFile);
|
||||
tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(episodeFile);
|
||||
tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr");
|
||||
}
|
||||
|
||||
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Series series, EpisodeFile episodeFile)
|
||||
{
|
||||
var qualityTitle = _qualityDefinitionService.Get(episodeFile.Quality.Quality).Title;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Parser
|
||||
)\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b(?<hcsub>(\w+SUB))|(?<hc>(HC))\b", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b(?<hcsub>(\w+SUB)\b)|(?<hc>(HC))\b", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
private static readonly Regex RawHDRegex = new Regex(@"\b(?<rawhd>RawHD|1080i[-_. ]HDTV|Raw[-_. ]HD|MPEG[-_. ]?2)\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace NzbDrone.Core.Tv
|
||||
public LazyLoaded<MovieFile> MovieFile { get; set; }
|
||||
public int MovieFileId { get; set; }
|
||||
public List<string> AlternativeTitles { get; set; }
|
||||
public string YouTubeTrailerId{ get; set; }
|
||||
public string Studio { get; set; }
|
||||
|
||||
public bool HasFile => MovieFileId > 0;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace NzbDrone.Core.Tv
|
||||
Movie FindByTitle(string cleanTitle, int year);
|
||||
Movie FindByImdbId(string imdbid);
|
||||
Movie FindByTitleSlug(string slug);
|
||||
List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
|
||||
List<Movie> GetMoviesByFileId(int fileId);
|
||||
void SetFileId(int fileId, int movieId);
|
||||
}
|
||||
@@ -119,5 +120,17 @@ namespace NzbDrone.Core.Tv
|
||||
{
|
||||
return Query.Where(m => m.TitleSlug == slug).FirstOrDefault();
|
||||
}
|
||||
|
||||
public List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
|
||||
{
|
||||
var query = Query.Where(m => m.InCinemas >= start && m.InCinemas <= end).OrWhere(m => m.PhysicalRelease >= start && m.PhysicalRelease <= end);
|
||||
|
||||
if (!includeUnmonitored)
|
||||
{
|
||||
query.AndWhere(e => e.Monitored);
|
||||
}
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ namespace NzbDrone.Core.Tv
|
||||
Movie FindByTitleInexact(string title);
|
||||
Movie FindByTitleSlug(string slug);
|
||||
Movie GetMovieByFileId(int fileId);
|
||||
List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
|
||||
void DeleteMovie(int movieId, bool deleteFiles);
|
||||
List<Movie> GetAllMovies();
|
||||
Movie UpdateMovie(Movie movie);
|
||||
@@ -224,5 +225,12 @@ namespace NzbDrone.Core.Tv
|
||||
{
|
||||
return _movieRepository.FindByTitleSlug(slug);
|
||||
}
|
||||
|
||||
public List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
|
||||
{
|
||||
var episodes = _movieRepository.MoviesBetweenDates(start.ToUniversalTime(), end.ToUniversalTime(), includeUnmonitored);
|
||||
|
||||
return episodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ namespace NzbDrone.Core.Tv
|
||||
movie.AlternativeTitles = movieInfo.AlternativeTitles;
|
||||
movie.Year = movieInfo.Year;
|
||||
movie.PhysicalRelease = movieInfo.PhysicalRelease;
|
||||
movie.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
|
||||
movie.Studio = movieInfo.Studio;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
Binary file not shown.
BIN
src/Thumbs.db
BIN
src/Thumbs.db
Binary file not shown.
@@ -26,6 +26,12 @@ var QueueCollection = PageableCollection.extend({
|
||||
});
|
||||
},
|
||||
|
||||
findMovie : function(movieId) {
|
||||
return _.find(this.fullCollection.models, function(queueModel) {
|
||||
return queueModel.get('movie').id === movieId;
|
||||
});
|
||||
},
|
||||
|
||||
sortMappings : {
|
||||
series : {
|
||||
sortValue : function(model, attr) {
|
||||
|
||||
@@ -17,7 +17,8 @@ module.exports = Marionette.Layout.extend({
|
||||
|
||||
events : {
|
||||
'click .x-import' : '_importMovies',
|
||||
'click .x-add-new' : '_addMovies'
|
||||
'click .x-add-new' : '_addMovies',
|
||||
'click .x-show-existing' : '_toggleExisting'
|
||||
},
|
||||
|
||||
attributes : {
|
||||
@@ -31,13 +32,20 @@ module.exports = Marionette.Layout.extend({
|
||||
});
|
||||
},
|
||||
|
||||
_toggleExisting : function(e) {
|
||||
var showExisting = e.target.checked;
|
||||
|
||||
vent.trigger(vent.Commands.ShowExistingCommand, {
|
||||
showExisting: showExisting
|
||||
});
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this.workspace.show(new AddMoviesView());
|
||||
},
|
||||
|
||||
_folderSelected : function(options) {
|
||||
vent.trigger(vent.Commands.CloseModalCommand);
|
||||
//TODO: Fix this shit.
|
||||
this.workspace.show(new ExistingMoviesCollectionView({ model : options.model }));
|
||||
},
|
||||
|
||||
|
||||
@@ -9,6 +9,33 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-horizontal" style="margin-top: 15px;">
|
||||
<div class="form-group" style="margin-bottom: 0px;">
|
||||
<label class="col-sm-3 control-label">Display Existing Movies</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input class="x-show-existing" type="checkbox" checked="checked" name="showExisting"/>
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Should Radarr display movies already in your collection?"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="add-movies-workspace"></div>
|
||||
|
||||
@@ -27,6 +27,7 @@ module.exports = Marionette.Layout.extend({
|
||||
|
||||
initialize : function(options) {
|
||||
console.log(options);
|
||||
|
||||
this.isExisting = options.isExisting;
|
||||
this.collection = new AddMoviesCollection();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var Marionette = require('marionette');
|
||||
var AddMoviesView = require('../AddMoviesView');
|
||||
var UnmappedFolderCollection = require('./UnmappedFolderCollection');
|
||||
var vent = require('vent');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
itemView : AddMoviesView,
|
||||
|
||||
@@ -48,7 +48,7 @@ var Layout = Marionette.Layout.extend({
|
||||
var self = this;
|
||||
|
||||
var newDir = new RootFolderModel({
|
||||
Path : this.ui.pathInput.val()
|
||||
Path : this.ui.pathInput.val(),
|
||||
});
|
||||
|
||||
this.bindToModelValidation(newDir);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
|
||||
<button class="btn" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
var Marionette = require('marionette');
|
||||
var SearchResultView = require('./SearchResultView');
|
||||
var MoviesCollection = require('../Movies/MoviesCollection');
|
||||
var vent = require('vent');
|
||||
|
||||
module.exports = Marionette.CollectionView.extend({
|
||||
itemView : SearchResultView,
|
||||
|
||||
initialize : function(options) {
|
||||
this.showExisting = true;
|
||||
this.isExisting = options.isExisting;
|
||||
this.showing = 1;
|
||||
vent.on(vent.Commands.ShowExistingCommand, this._onExistingToggle.bind(this));
|
||||
},
|
||||
|
||||
_onExistingToggle : function(data) {
|
||||
this.showExisting = data.showExisting;
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
showAll : function() {
|
||||
@@ -34,8 +44,19 @@ module.exports = Marionette.CollectionView.extend({
|
||||
},
|
||||
|
||||
appendHtml : function(collectionView, itemView, index) {
|
||||
if (!this.isExisting || index < this.showing || index === 0) {
|
||||
collectionView.$el.append(itemView.el);
|
||||
var tmdbId = itemView.model.get('tmdbId');
|
||||
var existingMovies = MoviesCollection.where({ tmdbId: tmdbId });
|
||||
if(existingMovies.length > 0) {
|
||||
if(this.showExisting) {
|
||||
if (index < this.showing || index === 0) {
|
||||
collectionView.$el.append(itemView.el);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (index < this.showing || index === 0) {
|
||||
collectionView.$el.append(itemView.el);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ var view = Marionette.ItemView.extend({
|
||||
throw 'model is required';
|
||||
}
|
||||
|
||||
console.log(this.route);
|
||||
//console.log(this.route);
|
||||
|
||||
this.templateHelpers = {};
|
||||
this._configureTemplateHelpers();
|
||||
@@ -92,14 +92,12 @@ var view = Marionette.ItemView.extend({
|
||||
|
||||
_configureTemplateHelpers : function() {
|
||||
var existingMovies = MoviesCollection.where({ tmdbId : this.model.get('tmdbId') });
|
||||
console.log(existingMovies);
|
||||
if (existingMovies.length > 0) {
|
||||
this.templateHelpers.existing = existingMovies[0].toJSON();
|
||||
}
|
||||
|
||||
this.templateHelpers.profiles = Profiles.toJSON();
|
||||
console.log(this.model);
|
||||
console.log(this.templateHelpers.existing);
|
||||
//console.log(this.templateHelpers.isExisting);
|
||||
if (!this.model.get('isExisting')) {
|
||||
this.templateHelpers.rootFolders = RootFolders.toJSON();
|
||||
}
|
||||
@@ -185,8 +183,8 @@ var view = Marionette.ItemView.extend({
|
||||
var self = this;
|
||||
var promise = this.model.save();
|
||||
|
||||
console.log(this.model.save);
|
||||
console.log(promise);
|
||||
//console.log(this.model.save);
|
||||
//console.log(promise);
|
||||
|
||||
if (searchForMovie) {
|
||||
this.ui.addSearchButton.spinForPromise(promise);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var Backbone = require('backbone');
|
||||
var EpisodeModel = require('../Series/EpisodeModel');
|
||||
var EpisodeModel = require('../Movies/MovieModel');
|
||||
|
||||
module.exports = Backbone.Collection.extend({
|
||||
url : window.NzbDrone.ApiRoot + '/calendar',
|
||||
@@ -7,8 +7,8 @@ module.exports = Backbone.Collection.extend({
|
||||
tableName : 'calendar',
|
||||
|
||||
comparator : function(model) {
|
||||
var date = new Date(model.get('airDateUtc'));
|
||||
var date = new Date(model.get('inCinemas'));
|
||||
var time = date.getTime();
|
||||
return time;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,75 +1,57 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Radarr Calendar feed</h3>
|
||||
</div>
|
||||
<div class="modal-body edit-series-modal">
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Include Unmonitored</label>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Radarr Calendar feed</h3>
|
||||
</div>
|
||||
<div class="modal-body edit-series-modal">
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Include Unmonitored</label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" name="includeUnmonitored" class="form-control x-includeUnmonitored"/>
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" name="includeUnmonitored" class="form-control x-includeUnmonitored"/>
|
||||
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Season Premiers Only</label>
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Tags</label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<label class="checkbox toggle well">
|
||||
<input type="checkbox" name="premiersOnly" class="form-control x-premiersOnly"/>
|
||||
<div class="col-sm-1 col-sm-push-5 help-inline">
|
||||
<i class="icon-sonarr-form-info" title="One or more tags only show matching series" />
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<span>Yes</span>
|
||||
<span>No</span>
|
||||
</p>
|
||||
|
||||
<div class="btn btn-primary slide-button"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Tags</label>
|
||||
|
||||
<div class="col-sm-1 col-sm-push-5 help-inline">
|
||||
<i class="icon-sonarr-form-info" title="One or more tags only show matching series" />
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5 col-sm-pull-1">
|
||||
<input type="text" class="form-control x-tags">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">iCal feed</label>
|
||||
<div class="col-sm-1 col-sm-push-8 help-inline">
|
||||
<i class="icon-sonarr-form-info" title="Copy this url into your clients subscription form or use the subscribe button if your browser support webcal" />
|
||||
</div>
|
||||
<div class="col-sm-8 col-sm-pull-1">
|
||||
<div class="input-group ical-url">
|
||||
<input type="text" class="form-control x-ical-url" readonly="readonly" />
|
||||
<div class="input-group-btn">
|
||||
<button class="btn btn-icon-only x-ical-copy"><i class="icon-sonarr-copy"></i></button>
|
||||
<button class="btn btn-icon-only no-router x-ical-webcal" title="Subscribe" target="_blank"><i class="icon-sonarr-calendar-o"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
<div class="col-sm-5 col-sm-pull-1">
|
||||
<input type="text" class="form-control x-tags">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">iCal feed</label>
|
||||
<div class="col-sm-1 col-sm-push-8 help-inline">
|
||||
<i class="icon-sonarr-form-info" title="Copy this url into your clients subscription form or use the subscribe button if your browser support webcal" />
|
||||
</div>
|
||||
<div class="col-sm-8 col-sm-pull-1">
|
||||
<div class="input-group ical-url">
|
||||
<input type="text" class="form-control x-ical-url" readonly="readonly" />
|
||||
<div class="input-group-btn">
|
||||
<button class="btn btn-icon-only x-ical-copy"><i class="icon-sonarr-copy"></i></button>
|
||||
<button class="btn btn-icon-only no-router x-ical-webcal" title="Subscribe" target="_blank"><i class="icon-sonarr-calendar-o"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
<div id="x-calendar" class="calendar"/>
|
||||
<div class="legend calendar">
|
||||
<ul class='legend-labels'>
|
||||
<li class="legend-label"><span class="premiere" title="Premiere episode hasn't aired yet"></span>Unaired Premiere</li>
|
||||
<li class="legend-label"><span class="primary" title="Episode hasn't aired yet"></span>Unaired</li>
|
||||
<li class="legend-label"><span class="warning" title="Episode is currently airing"></span>On Air</li>
|
||||
<li class="legend-label"><span class="purple" title="Episode is currently downloading"></span>Downloading</li>
|
||||
<li class="legend-label"><span class="danger" title="Episode file has not been found"></span>Missing</li>
|
||||
<li class="legend-label"><span class="success" title="Episode was downloaded and sorted"></span>Downloaded</li>
|
||||
<li class="legend-label"><span class="unmonitored" title="Episode is unmonitored"></span>Unmonitored</li>
|
||||
<li class="legend-label"><span class="premiere" title="This Movie is still in cinemas and hasn't been released yet. Only poor qualities will be available"></span>In Cinemas</li>
|
||||
<li class="legend-label"><span class="primary" title="This movie has only been announced yet."></span>Announced</li>
|
||||
<!--<li class="legend-label"><span class="warning" title="Episode is currently airing"></span>On Air</li>-->
|
||||
<li class="legend-label"><span class="purple" title="Movie is currently downloading"></span>Downloading</li>
|
||||
<li class="legend-label"><span class="danger" title="Movie file has not been found"></span>Missing</li>
|
||||
<li class="legend-label"><span class="success" title="Movie was downloaded and sorted"></span>Downloaded</li>
|
||||
<li class="legend-label"><span class="unmonitored" title="Movie is unmonitored"></span>Unmonitored</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,273 +12,274 @@ require('fullcalendar');
|
||||
require('jquery.easypiechart');
|
||||
|
||||
module.exports = Marionette.ItemView.extend({
|
||||
storageKey : 'calendar.view',
|
||||
storageKey : 'calendar.view',
|
||||
|
||||
initialize : function() {
|
||||
this.showUnmonitored = Config.getValue('calendar.show', 'monitored') === 'all';
|
||||
this.collection = new CalendarCollection().bindSignalR({ updateOnly : true });
|
||||
this.listenTo(this.collection, 'change', this._reloadCalendarEvents);
|
||||
this.listenTo(QueueCollection, 'sync', this._reloadCalendarEvents);
|
||||
},
|
||||
initialize : function() {
|
||||
this.showUnmonitored = Config.getValue('calendar.show', 'monitored') === 'all';
|
||||
this.collection = new CalendarCollection().bindSignalR({ updateOnly : true });
|
||||
this.listenTo(this.collection, 'change', this._reloadCalendarEvents);
|
||||
this.listenTo(QueueCollection, 'sync', this._reloadCalendarEvents);
|
||||
},
|
||||
|
||||
render : function() {
|
||||
this.$el.empty().fullCalendar(this._getOptions());
|
||||
},
|
||||
render : function() {
|
||||
this.$el.empty().fullCalendar(this._getOptions());
|
||||
},
|
||||
|
||||
onShow : function() {
|
||||
this.$('.fc-today-button').click();
|
||||
},
|
||||
onShow : function() {
|
||||
this.$('.fc-today-button').click();
|
||||
},
|
||||
|
||||
setShowUnmonitored : function (showUnmonitored) {
|
||||
if (this.showUnmonitored !== showUnmonitored) {
|
||||
this.showUnmonitored = showUnmonitored;
|
||||
this._getEvents(this.$el.fullCalendar('getView'));
|
||||
}
|
||||
},
|
||||
setShowUnmonitored : function (showUnmonitored) {
|
||||
if (this.showUnmonitored !== showUnmonitored) {
|
||||
this.showUnmonitored = showUnmonitored;
|
||||
this._getEvents(this.$el.fullCalendar('getView'));
|
||||
}
|
||||
},
|
||||
|
||||
_viewRender : function(view, element) {
|
||||
if (Config.getValue(this.storageKey) !== view.name) {
|
||||
Config.setValue(this.storageKey, view.name);
|
||||
}
|
||||
_viewRender : function(view, element) {
|
||||
if (Config.getValue(this.storageKey) !== view.name) {
|
||||
Config.setValue(this.storageKey, view.name);
|
||||
}
|
||||
|
||||
this._getEvents(view);
|
||||
element.find('.fc-day-grid-container').css('height', '');
|
||||
},
|
||||
this._getEvents(view);
|
||||
element.find('.fc-day-grid-container').css('height', '');
|
||||
},
|
||||
|
||||
_eventRender : function(event, element) {
|
||||
element.addClass(event.statusLevel);
|
||||
element.children('.fc-content').addClass(event.statusLevel);
|
||||
_eventRender : function(event, element) {
|
||||
element.addClass(event.statusLevel);
|
||||
element.children('.fc-content').addClass(event.statusLevel);
|
||||
|
||||
if (event.downloading) {
|
||||
var progress = 100 - event.downloading.get('sizeleft') / event.downloading.get('size') * 100;
|
||||
var releaseTitle = event.downloading.get('title');
|
||||
var estimatedCompletionTime = moment(event.downloading.get('estimatedCompletionTime')).fromNow();
|
||||
var status = event.downloading.get('status').toLocaleLowerCase();
|
||||
var errorMessage = event.downloading.get('errorMessage');
|
||||
if (event.downloading) {
|
||||
var progress = 100 - event.downloading.get('sizeleft') / event.downloading.get('size') * 100;
|
||||
var releaseTitle = event.downloading.get('title');
|
||||
var estimatedCompletionTime = moment(event.downloading.get('estimatedCompletionTime')).fromNow();
|
||||
var status = event.downloading.get('status').toLocaleLowerCase();
|
||||
var errorMessage = event.downloading.get('errorMessage');
|
||||
|
||||
if (status === 'pending') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-pending', 'Release will be processed {0}'.format(estimatedCompletionTime));
|
||||
}
|
||||
if (status === 'pending') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-pending', 'Release will be processed {0}'.format(estimatedCompletionTime));
|
||||
}
|
||||
|
||||
else if (errorMessage) {
|
||||
if (status === 'completed') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-import-failed', 'Import failed: {0}'.format(errorMessage));
|
||||
} else {
|
||||
this._addStatusIcon(element, 'icon-sonarr-download-failed', 'Download failed: {0}'.format(errorMessage));
|
||||
}
|
||||
}
|
||||
else if (errorMessage) {
|
||||
if (status === 'completed') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-import-failed', 'Import failed: {0}'.format(errorMessage));
|
||||
} else {
|
||||
this._addStatusIcon(element, 'icon-sonarr-download-failed', 'Download failed: {0}'.format(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
else if (status === 'failed') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-download-failed', 'Download failed: check download client for more details');
|
||||
}
|
||||
else if (status === 'failed') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-download-failed', 'Download failed: check download client for more details');
|
||||
}
|
||||
|
||||
else if (status === 'warning') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-download-warning', 'Download warning: check download client for more details');
|
||||
}
|
||||
else if (status === 'warning') {
|
||||
this._addStatusIcon(element, 'icon-sonarr-download-warning', 'Download warning: check download client for more details');
|
||||
}
|
||||
|
||||
else {
|
||||
element.find('.fc-time').after('<span class="chart pull-right" data-percent="{0}"></span>'.format(progress));
|
||||
else {
|
||||
element.find('.fc-time').after('<span class="chart pull-right" data-percent="{0}"></span>'.format(progress));
|
||||
|
||||
element.find('.chart').easyPieChart({
|
||||
barColor : '#ffffff',
|
||||
trackColor : false,
|
||||
scaleColor : false,
|
||||
lineWidth : 2,
|
||||
size : 14,
|
||||
animate : false
|
||||
});
|
||||
element.find('.chart').easyPieChart({
|
||||
barColor : '#ffffff',
|
||||
trackColor : false,
|
||||
scaleColor : false,
|
||||
lineWidth : 2,
|
||||
size : 14,
|
||||
animate : false
|
||||
});
|
||||
|
||||
element.find('.chart').tooltip({
|
||||
title : 'Episode is downloading - {0}% {1}'.format(progress.toFixed(1), releaseTitle),
|
||||
container : '.fc'
|
||||
});
|
||||
}
|
||||
}
|
||||
element.find('.chart').tooltip({
|
||||
title : 'Episode is downloading - {0}% {1}'.format(progress.toFixed(1), releaseTitle),
|
||||
container : '.fc'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
else if (event.model.get('unverifiedSceneNumbering')) {
|
||||
this._addStatusIcon(element, 'icon-sonarr-form-warning', 'Scene number hasn\'t been verified yet.');
|
||||
}
|
||||
else if (event.model.get('unverifiedSceneNumbering')) {
|
||||
this._addStatusIcon(element, 'icon-sonarr-form-warning', 'Scene number hasn\'t been verified yet.');
|
||||
}
|
||||
},
|
||||
|
||||
else if (event.model.get('series').seriesType === 'anime' && event.model.get('seasonNumber') > 0 && !event.model.has('absoluteEpisodeNumber')) {
|
||||
this._addStatusIcon(element, 'icon-sonarr-form-warning', 'Episode does not have an absolute episode number');
|
||||
}
|
||||
},
|
||||
_eventAfterAllRender : function () {
|
||||
if ($(window).width() < 768) {
|
||||
this.$('.fc-center').show();
|
||||
this.$('.calendar-title').remove();
|
||||
|
||||
_eventAfterAllRender : function () {
|
||||
if ($(window).width() < 768) {
|
||||
this.$('.fc-center').show();
|
||||
this.$('.calendar-title').remove();
|
||||
var title = this.$('.fc-center').html();
|
||||
var titleDiv = '<div class="calendar-title">{0}</div>'.format(title);
|
||||
|
||||
var title = this.$('.fc-center').html();
|
||||
var titleDiv = '<div class="calendar-title">{0}</div>'.format(title);
|
||||
this.$('.fc-toolbar').before(titleDiv);
|
||||
this.$('.fc-center').hide();
|
||||
}
|
||||
|
||||
this.$('.fc-toolbar').before(titleDiv);
|
||||
this.$('.fc-center').hide();
|
||||
}
|
||||
this._clearScrollBar();
|
||||
},
|
||||
|
||||
this._clearScrollBar();
|
||||
},
|
||||
_windowResize : function () {
|
||||
this._clearScrollBar();
|
||||
},
|
||||
|
||||
_windowResize : function () {
|
||||
this._clearScrollBar();
|
||||
},
|
||||
_getEvents : function(view) {
|
||||
var start = moment(view.start.toISOString()).toISOString();
|
||||
var end = moment(view.end.toISOString()).toISOString();
|
||||
|
||||
_getEvents : function(view) {
|
||||
var start = moment(view.start.toISOString()).toISOString();
|
||||
var end = moment(view.end.toISOString()).toISOString();
|
||||
this.$el.fullCalendar('removeEvents');
|
||||
|
||||
this.$el.fullCalendar('removeEvents');
|
||||
this.collection.fetch({
|
||||
data : {
|
||||
start : start,
|
||||
end : end,
|
||||
unmonitored : this.showUnmonitored
|
||||
},
|
||||
success : this._setEventData.bind(this, new Date(start), new Date(end))
|
||||
});
|
||||
},
|
||||
|
||||
this.collection.fetch({
|
||||
data : {
|
||||
start : start,
|
||||
end : end,
|
||||
unmonitored : this.showUnmonitored
|
||||
},
|
||||
success : this._setEventData.bind(this)
|
||||
});
|
||||
},
|
||||
_setEventData : function(startD, endD, collection) {
|
||||
if (collection.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_setEventData : function(collection) {
|
||||
if (collection.length === 0) {
|
||||
return;
|
||||
}
|
||||
var events = [];
|
||||
var self = this;
|
||||
|
||||
var events = [];
|
||||
var self = this;
|
||||
collection.each(function(model) {
|
||||
var seriesTitle = model.get('title');
|
||||
var start = model.get('inCinemas');
|
||||
var startDate = new Date(start);
|
||||
if (!(startD <= startDate && startDate <= endD)) {
|
||||
start = model.get("physicalRelease");
|
||||
}
|
||||
var runtime = model.get('runtime');
|
||||
var end = moment(start).add('minutes', runtime).toISOString();
|
||||
|
||||
collection.each(function(model) {
|
||||
var seriesTitle = model.get('series').title;
|
||||
var start = model.get('airDateUtc');
|
||||
var runtime = model.get('series').runtime;
|
||||
var end = moment(start).add('minutes', runtime).toISOString();
|
||||
var event = {
|
||||
title : seriesTitle,
|
||||
start : moment(start),
|
||||
end : moment(end),
|
||||
allDay : true,
|
||||
statusLevel : self._getStatusLevel(model, end),
|
||||
downloading : QueueCollection.findMovie(model.get('id')),
|
||||
model : model,
|
||||
sortOrder : 0
|
||||
};
|
||||
|
||||
var event = {
|
||||
title : seriesTitle,
|
||||
start : moment(start),
|
||||
end : moment(end),
|
||||
allDay : false,
|
||||
statusLevel : self._getStatusLevel(model, end),
|
||||
downloading : QueueCollection.findEpisode(model.get('id')),
|
||||
model : model,
|
||||
sortOrder : (model.get('seasonNumber') === 0 ? 1000000 : model.get('seasonNumber') * 10000) + model.get('episodeNumber')
|
||||
};
|
||||
events.push(event);
|
||||
});
|
||||
|
||||
events.push(event);
|
||||
});
|
||||
this.$el.fullCalendar('addEventSource', events);
|
||||
},
|
||||
|
||||
this.$el.fullCalendar('addEventSource', events);
|
||||
},
|
||||
_getStatusLevel : function(element, endTime) {
|
||||
var hasFile = element.get('hasFile');
|
||||
var downloading = QueueCollection.findMovie(element.get('id')) || element.get('grabbed');
|
||||
var currentTime = moment();
|
||||
var start = moment(element.get('inCinemas'));
|
||||
var status = element.getStatus();
|
||||
var end = moment(endTime);
|
||||
var monitored = element.get('monitored');
|
||||
|
||||
_getStatusLevel : function(element, endTime) {
|
||||
var hasFile = element.get('hasFile');
|
||||
var downloading = QueueCollection.findEpisode(element.get('id')) || element.get('grabbed');
|
||||
var currentTime = moment();
|
||||
var start = moment(element.get('airDateUtc'));
|
||||
var end = moment(endTime);
|
||||
var monitored = element.get('series').monitored && element.get('monitored');
|
||||
var statusLevel = 'primary';
|
||||
|
||||
var statusLevel = 'primary';
|
||||
if (hasFile) {
|
||||
statusLevel = 'success';
|
||||
}
|
||||
|
||||
if (hasFile) {
|
||||
statusLevel = 'success';
|
||||
}
|
||||
else if (downloading) {
|
||||
statusLevel = 'purple';
|
||||
}
|
||||
|
||||
else if (downloading) {
|
||||
statusLevel = 'purple';
|
||||
}
|
||||
else if (!monitored) {
|
||||
statusLevel = 'unmonitored';
|
||||
}
|
||||
|
||||
else if (!monitored) {
|
||||
statusLevel = 'unmonitored';
|
||||
}
|
||||
else if (status == "inCinemas") {
|
||||
statusLevel = 'premiere';
|
||||
}
|
||||
|
||||
else if (currentTime.isAfter(start) && currentTime.isBefore(end)) {
|
||||
statusLevel = 'warning';
|
||||
}
|
||||
else if (status == "released") {
|
||||
statusLevel = 'danger';
|
||||
}
|
||||
|
||||
else if (start.isBefore(currentTime) && !hasFile) {
|
||||
statusLevel = 'danger';
|
||||
}
|
||||
else if (status == "announced") {
|
||||
statusLevel = 'primary';
|
||||
}
|
||||
|
||||
else if (element.get('episodeNumber') === 1) {
|
||||
statusLevel = 'premiere';
|
||||
}
|
||||
if (end.isBefore(currentTime.startOf('day'))) {
|
||||
statusLevel += ' past';
|
||||
}
|
||||
|
||||
if (end.isBefore(currentTime.startOf('day'))) {
|
||||
statusLevel += ' past';
|
||||
}
|
||||
return statusLevel;
|
||||
},
|
||||
|
||||
return statusLevel;
|
||||
},
|
||||
_reloadCalendarEvents : function() {
|
||||
this.$el.fullCalendar('removeEvents');
|
||||
var view = this.$el.fullCalendar('getView');
|
||||
var start = moment(view.start.toISOString()).toISOString();
|
||||
var end = moment(view.end.toISOString()).toISOString();
|
||||
this._setEventData(new Date(start), new Date(end), this.collection);
|
||||
},
|
||||
|
||||
_reloadCalendarEvents : function() {
|
||||
this.$el.fullCalendar('removeEvents');
|
||||
this._setEventData(this.collection);
|
||||
},
|
||||
_getOptions : function() {
|
||||
var options = {
|
||||
allDayDefault : true,
|
||||
weekMode : 'variable',
|
||||
firstDay : UiSettings.get('firstDayOfWeek'),
|
||||
timeFormat : 'h(:mm)t',
|
||||
viewRender : this._viewRender.bind(this),
|
||||
eventRender : this._eventRender.bind(this),
|
||||
eventAfterAllRender : this._eventAfterAllRender.bind(this),
|
||||
windowResize : this._windowResize.bind(this),
|
||||
eventClick : function(event) {
|
||||
//vent.trigger(vent.Commands.ShowMovieDetails, { movie : event.model });
|
||||
window.location.href = "movies/"+event.model.get("titleSlug");
|
||||
}
|
||||
};
|
||||
|
||||
_getOptions : function() {
|
||||
var options = {
|
||||
allDayDefault : false,
|
||||
weekMode : 'variable',
|
||||
firstDay : UiSettings.get('firstDayOfWeek'),
|
||||
timeFormat : 'h(:mm)t',
|
||||
viewRender : this._viewRender.bind(this),
|
||||
eventRender : this._eventRender.bind(this),
|
||||
eventAfterAllRender : this._eventAfterAllRender.bind(this),
|
||||
windowResize : this._windowResize.bind(this),
|
||||
eventClick : function(event) {
|
||||
vent.trigger(vent.Commands.ShowEpisodeDetails, { episode : event.model });
|
||||
}
|
||||
};
|
||||
if ($(window).width() < 768) {
|
||||
options.defaultView = Config.getValue(this.storageKey, 'listYear');
|
||||
|
||||
if ($(window).width() < 768) {
|
||||
options.defaultView = Config.getValue(this.storageKey, 'basicDay');
|
||||
options.header = {
|
||||
left : 'prev,next today',
|
||||
center : 'title',
|
||||
right : 'listYear'
|
||||
};
|
||||
}
|
||||
|
||||
options.header = {
|
||||
left : 'prev,next today',
|
||||
center : 'title',
|
||||
right : 'basicWeek,basicDay'
|
||||
};
|
||||
}
|
||||
else {
|
||||
options.defaultView = Config.getValue(this.storageKey, 'month');
|
||||
|
||||
else {
|
||||
options.defaultView = Config.getValue(this.storageKey, 'basicWeek');
|
||||
options.header = {
|
||||
left : 'prev,next today',
|
||||
center : 'title',
|
||||
right : 'month,listYear'
|
||||
};
|
||||
}
|
||||
|
||||
options.header = {
|
||||
left : 'prev,next today',
|
||||
center : 'title',
|
||||
right : 'month,basicWeek,basicDay'
|
||||
};
|
||||
}
|
||||
options.titleFormat = "L";
|
||||
|
||||
options.titleFormat = {
|
||||
month : 'MMMM YYYY',
|
||||
week : UiSettings.get('shortDateFormat'),
|
||||
day : UiSettings.get('longDateFormat')
|
||||
};
|
||||
options.columnFormat = "L"/*{
|
||||
month : 'ddd',
|
||||
week : UiSettings.get('calendarWeekColumnHeader'),
|
||||
day : 'dddd'
|
||||
};*///For now ignore settings. TODO update that.
|
||||
|
||||
options.columnFormat = {
|
||||
month : 'ddd',
|
||||
week : UiSettings.get('calendarWeekColumnHeader'),
|
||||
day : 'dddd'
|
||||
};
|
||||
options.timeFormat = UiSettings.get('timeFormat');
|
||||
|
||||
options.timeFormat = UiSettings.get('timeFormat');
|
||||
return options;
|
||||
},
|
||||
|
||||
return options;
|
||||
},
|
||||
_addStatusIcon : function(element, icon, tooltip) {
|
||||
element.find('.fc-time').after('<span class="status pull-right"><i class="{0}"></i></span>'.format(icon));
|
||||
element.find('.status').tooltip({
|
||||
title : tooltip,
|
||||
container : '.fc'
|
||||
});
|
||||
},
|
||||
|
||||
_addStatusIcon : function(element, icon, tooltip) {
|
||||
element.find('.fc-time').after('<span class="status pull-right"><i class="{0}"></i></span>'.format(icon));
|
||||
element.find('.status').tooltip({
|
||||
title : tooltip,
|
||||
container : '.fc'
|
||||
});
|
||||
},
|
||||
|
||||
_clearScrollBar : function () {
|
||||
// Remove height from calendar so we don't have another scroll bar
|
||||
this.$('.fc-day-grid-container').css('height', '');
|
||||
this.$('.fc-row.fc-widget-header').attr('style', '');
|
||||
}
|
||||
});
|
||||
_clearScrollBar : function () {
|
||||
// Remove height from calendar so we don't have another scroll bar
|
||||
this.$('.fc-day-grid-container').css('height', '');
|
||||
this.$('.fc-row.fc-widget-header').attr('style', '');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
var Backbone = require('backbone');
|
||||
var moment = require('moment');
|
||||
var EpisodeModel = require('../Series/EpisodeModel');
|
||||
var EpisodeModel = require('../Movies/MovieModel');
|
||||
|
||||
module.exports = Backbone.Collection.extend({
|
||||
url : window.NzbDrone.ApiRoot + '/calendar',
|
||||
model : EpisodeModel,
|
||||
|
||||
comparator : function(model1, model2) {
|
||||
var airDate1 = model1.get('airDateUtc');
|
||||
var airDate1 = model1.get('inCinemas');
|
||||
var date1 = moment(airDate1);
|
||||
var time1 = date1.unix();
|
||||
|
||||
var airDate2 = model2.get('airDateUtc');
|
||||
var airDate2 = model2.get('inCinemas');
|
||||
var date2 = moment(airDate2);
|
||||
var time2 = date2.unix();
|
||||
|
||||
@@ -25,4 +25,4 @@ module.exports = Backbone.Collection.extend({
|
||||
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,8 +11,8 @@ module.exports = Marionette.ItemView.extend({
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
var start = this.model.get('airDateUtc');
|
||||
var runtime = this.model.get('series').runtime;
|
||||
var start = this.model.get('inCinemas');
|
||||
var runtime = this.model.get('runtime');
|
||||
var end = moment(start).add('minutes', runtime);
|
||||
|
||||
this.model.set({
|
||||
@@ -25,4 +25,4 @@ module.exports = Marionette.ItemView.extend({
|
||||
_showEpisodeDetails : function() {
|
||||
vent.trigger(vent.Commands.ShowEpisodeDetails, { episode : this.model });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,248 +7,259 @@
|
||||
@import "../Content/Overrides/bootstrap";
|
||||
|
||||
.calendar {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
|
||||
th, td {
|
||||
border-color : #eeeeee;
|
||||
}
|
||||
th, td {
|
||||
border-color : #eeeeee;
|
||||
}
|
||||
|
||||
.fc-event-skin {
|
||||
background-color : #007ccd;
|
||||
border : 1px solid #007ccd;
|
||||
border-radius : 4px;
|
||||
text-align : center;
|
||||
}
|
||||
.fc-event-skin {
|
||||
background-color : #007ccd;
|
||||
border : 1px solid #007ccd;
|
||||
border-radius : 4px;
|
||||
text-align : center;
|
||||
}
|
||||
|
||||
.fc-event {
|
||||
.clickable;
|
||||
.fc-event {
|
||||
.clickable;
|
||||
|
||||
.status {
|
||||
margin-right : 4px;
|
||||
}
|
||||
}
|
||||
.status {
|
||||
margin-right : 4px;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
background-color : #eeeeee;
|
||||
}
|
||||
th {
|
||||
background-color : #eeeeee;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size : 17.5px;
|
||||
}
|
||||
h2 {
|
||||
font-size : 17.5px;
|
||||
}
|
||||
|
||||
.fc-state-highlight {
|
||||
background : #dbdbdb;
|
||||
}
|
||||
.fc-state-highlight {
|
||||
background : #dbdbdb;
|
||||
}
|
||||
|
||||
.past {
|
||||
opacity : 0.8;
|
||||
}
|
||||
.past {
|
||||
opacity : 0.8;
|
||||
}
|
||||
|
||||
.fc-title {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.fc-list-table {
|
||||
.past {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.event {
|
||||
display : inline-block;
|
||||
width : 100%;
|
||||
margin-bottom : 10px;
|
||||
border-top : 1px solid #eeeeee;
|
||||
padding-top : 10px;
|
||||
display : inline-block;
|
||||
width : 100%;
|
||||
margin-bottom : 10px;
|
||||
border-top : 1px solid #eeeeee;
|
||||
padding-top : 10px;
|
||||
|
||||
h4 {
|
||||
font-weight : 500;
|
||||
color : #008dcd;
|
||||
margin : 5px 0px;
|
||||
}
|
||||
h4 {
|
||||
font-weight : 500;
|
||||
color : #008dcd;
|
||||
margin : 5px 0px;
|
||||
}
|
||||
|
||||
p {
|
||||
color : #999999;
|
||||
margin : 0px;
|
||||
}
|
||||
p {
|
||||
color : #999999;
|
||||
margin : 0px;
|
||||
}
|
||||
|
||||
.date {
|
||||
text-align : center;
|
||||
display : inline-block;
|
||||
border-left : 4px solid #eeeeee;
|
||||
padding-left : 16px;
|
||||
float : left;
|
||||
margin-right : 20px;
|
||||
.date {
|
||||
text-align : center;
|
||||
display : inline-block;
|
||||
border-left : 4px solid #eeeeee;
|
||||
padding-left : 16px;
|
||||
float : left;
|
||||
margin-right : 20px;
|
||||
|
||||
h4 {
|
||||
line-height : 1em;
|
||||
color : #555555;
|
||||
font-weight : 300;
|
||||
text-transform : uppercase;
|
||||
}
|
||||
h4 {
|
||||
line-height : 1em;
|
||||
color : #555555;
|
||||
font-weight : 300;
|
||||
text-transform : uppercase;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight : 500;
|
||||
line-height : 0.8em;
|
||||
}
|
||||
}
|
||||
h1 {
|
||||
font-weight : 500;
|
||||
line-height : 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.primary {
|
||||
border-color : @btn-primary-bg;
|
||||
}
|
||||
.primary {
|
||||
border-color : @btn-primary-bg;
|
||||
}
|
||||
|
||||
.info {
|
||||
border-color : @btn-info-bg;
|
||||
}
|
||||
.info {
|
||||
border-color : @btn-info-bg;
|
||||
}
|
||||
|
||||
.inverse {
|
||||
border-color : @btn-link-disabled-color;
|
||||
}
|
||||
.inverse {
|
||||
border-color : @btn-link-disabled-color;
|
||||
}
|
||||
|
||||
.warning {
|
||||
border-color : @btn-warning-bg;
|
||||
}
|
||||
.warning {
|
||||
border-color : @btn-warning-bg;
|
||||
}
|
||||
|
||||
.danger {
|
||||
border-color : @btn-danger-bg;
|
||||
}
|
||||
.danger {
|
||||
border-color : @btn-danger-bg;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.success {
|
||||
border-color : @btn-success-bg;
|
||||
}
|
||||
.success {
|
||||
border-color : @btn-success-bg;
|
||||
}
|
||||
|
||||
.purple {
|
||||
border-color : @nzbdronePurple;
|
||||
}
|
||||
.purple {
|
||||
border-color : @nzbdronePurple;
|
||||
}
|
||||
|
||||
.pink {
|
||||
border-color : @nzbdronePink;
|
||||
}
|
||||
.pink {
|
||||
border-color : @nzbdronePink;
|
||||
}
|
||||
|
||||
.premiere {
|
||||
border-color : @droneTeal;
|
||||
}
|
||||
.premiere {
|
||||
border-color : @droneTeal;
|
||||
}
|
||||
|
||||
.unmonitored {
|
||||
border-color : grey;
|
||||
}
|
||||
.unmonitored {
|
||||
border-color : grey;
|
||||
}
|
||||
|
||||
.episode-title {
|
||||
.btn-link;
|
||||
.text-overflow;
|
||||
color : @link-color;
|
||||
margin-top : 1px;
|
||||
display : inline-block;
|
||||
.episode-title {
|
||||
.btn-link;
|
||||
.text-overflow;
|
||||
color : @link-color;
|
||||
margin-top : 1px;
|
||||
display : inline-block;
|
||||
|
||||
@media (max-width: @screen-xs-min) {
|
||||
width : 140px;
|
||||
}
|
||||
@media (max-width: @screen-xs-min) {
|
||||
width : 140px;
|
||||
}
|
||||
|
||||
@media (min-width: @screen-md-min) {
|
||||
width : 135px;
|
||||
}
|
||||
}
|
||||
@media (min-width: @screen-md-min) {
|
||||
width : 135px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar {
|
||||
|
||||
// background-position : -160px -128px;
|
||||
|
||||
.primary {
|
||||
border-color : @btn-primary-bg;
|
||||
background-color : @btn-primary-bg;
|
||||
.primary {
|
||||
border-color : @btn-primary-bg;
|
||||
background-color : @btn-primary-bg;
|
||||
|
||||
.color-impaired-background-gradient(90deg, @btn-primary-bg);
|
||||
}
|
||||
.color-impaired-background-gradient(90deg, @btn-primary-bg);
|
||||
}
|
||||
|
||||
.info {
|
||||
border-color : @btn-info-bg;
|
||||
background-color : @btn-info-bg;
|
||||
}
|
||||
.info {
|
||||
border-color : @btn-info-bg;
|
||||
background-color : @btn-info-bg;
|
||||
}
|
||||
|
||||
.inverse {
|
||||
border-color : @btn-link-disabled-color;
|
||||
background-color : @btn-link-disabled-color;
|
||||
}
|
||||
.inverse {
|
||||
border-color : @btn-link-disabled-color;
|
||||
background-color : @btn-link-disabled-color;
|
||||
}
|
||||
|
||||
.warning {
|
||||
border-color : @btn-warning-bg;
|
||||
background-color : @btn-warning-bg;
|
||||
.warning {
|
||||
border-color : @btn-warning-bg;
|
||||
background-color : @btn-warning-bg;
|
||||
|
||||
.color-impaired-background-gradient(90deg, @btn-warning-bg);
|
||||
}
|
||||
.color-impaired-background-gradient(90deg, @btn-warning-bg);
|
||||
}
|
||||
|
||||
.danger {
|
||||
border-color : @btn-danger-bg;
|
||||
background-color : @btn-danger-bg;
|
||||
.danger {
|
||||
border-color : @btn-danger-bg;
|
||||
background-color : @btn-danger-bg;
|
||||
color: white;
|
||||
.color-impaired-background-gradient(90deg, @btn-danger-bg);
|
||||
}
|
||||
|
||||
.color-impaired-background-gradient(90deg, @btn-danger-bg);
|
||||
}
|
||||
.success {
|
||||
border-color : @btn-success-bg;
|
||||
background-color : @btn-success-bg;
|
||||
}
|
||||
|
||||
.success {
|
||||
border-color : @btn-success-bg;
|
||||
background-color : @btn-success-bg;
|
||||
}
|
||||
.purple {
|
||||
border-color : @nzbdronePurple;
|
||||
background-color : @nzbdronePurple;
|
||||
}
|
||||
|
||||
.purple {
|
||||
border-color : @nzbdronePurple;
|
||||
background-color : @nzbdronePurple;
|
||||
}
|
||||
.pink {
|
||||
border-color : @nzbdronePink;
|
||||
background-color : @nzbdronePink;
|
||||
}
|
||||
|
||||
.pink {
|
||||
border-color : @nzbdronePink;
|
||||
background-color : @nzbdronePink;
|
||||
}
|
||||
.premiere {
|
||||
border-color : @droneTeal;
|
||||
background-color : @droneTeal;
|
||||
|
||||
.premiere {
|
||||
border-color : @droneTeal;
|
||||
background-color : @droneTeal;
|
||||
.color-impaired-background-gradient(90deg, @droneTeal);
|
||||
}
|
||||
|
||||
.color-impaired-background-gradient(90deg, @droneTeal);
|
||||
}
|
||||
.unmonitored {
|
||||
border-color : grey;
|
||||
background-color : grey;
|
||||
|
||||
.unmonitored {
|
||||
border-color : grey;
|
||||
background-color : grey;
|
||||
.color-impaired-background-gradient(45deg, grey);
|
||||
}
|
||||
|
||||
.color-impaired-background-gradient(45deg, grey);
|
||||
}
|
||||
.chart {
|
||||
margin-top : 2px;
|
||||
margin-right : 2px;
|
||||
line-height : 12px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
margin-top : 2px;
|
||||
margin-right : 2px;
|
||||
line-height : 12px;
|
||||
}
|
||||
.legend-labels {
|
||||
max-width : 100%;
|
||||
width : 500px;
|
||||
|
||||
.legend-labels {
|
||||
max-width : 100%;
|
||||
width : 500px;
|
||||
@media (max-width: @screen-xs-min) {
|
||||
width : 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs-min) {
|
||||
width : 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.legend-label {
|
||||
display : inline-block;
|
||||
width : 150px;
|
||||
}
|
||||
.legend-label {
|
||||
display : inline-block;
|
||||
width : 150px;
|
||||
}
|
||||
}
|
||||
|
||||
.ical {
|
||||
color: @btn-link-disabled-color;
|
||||
cursor: pointer;
|
||||
color: @btn-link-disabled-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ical-url {
|
||||
|
||||
input, input[readonly] {
|
||||
cursor : text;
|
||||
}
|
||||
input, input[readonly] {
|
||||
cursor : text;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-title {
|
||||
text-align : center;
|
||||
text-align : center;
|
||||
|
||||
h2 {
|
||||
margin-top : 0px;
|
||||
margin-bottom : 5px;
|
||||
}
|
||||
h2 {
|
||||
margin-top : 0px;
|
||||
margin-bottom : 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-toolbar {
|
||||
.page-toolbar {
|
||||
margin-bottom : 10px;
|
||||
}
|
||||
.page-toolbar {
|
||||
margin-bottom : 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,9 @@
|
||||
{{#if imdbId}}
|
||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if youTubeTrailerId}}
|
||||
<a href="{{youTubeTrailerUrl}}" class="label label-info">Trailer</a>
|
||||
{{/if}}
|
||||
|
||||
</span>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* FullCalendar v2.3.2 Stylesheet
|
||||
* FullCalendar v3.1.0 Stylesheet
|
||||
* Docs & License: http://fullcalendar.io/
|
||||
* (c) 2015 Adam Shaw
|
||||
* (c) 2016 Adam Shaw
|
||||
*/
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ body .fc { /* extra precedence to overcome jqui */
|
||||
.fc-unthemed tbody,
|
||||
.fc-unthemed .fc-divider,
|
||||
.fc-unthemed .fc-row,
|
||||
.fc-unthemed .fc-popover {
|
||||
.fc-unthemed .fc-content, /* for gutter border */
|
||||
.fc-unthemed .fc-popover,
|
||||
.fc-unthemed .fc-list-view,
|
||||
.fc-unthemed .fc-list-heading td {
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
@@ -37,7 +40,8 @@ body .fc { /* extra precedence to overcome jqui */
|
||||
}
|
||||
|
||||
.fc-unthemed .fc-divider,
|
||||
.fc-unthemed .fc-popover .fc-header {
|
||||
.fc-unthemed .fc-popover .fc-header,
|
||||
.fc-unthemed .fc-list-heading td {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
@@ -45,20 +49,18 @@ body .fc { /* extra precedence to overcome jqui */
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.fc-unthemed .fc-today {
|
||||
.fc-unthemed td.fc-today {
|
||||
background: #fcf8e3;
|
||||
}
|
||||
|
||||
.fc-highlight { /* when user is selecting cells */
|
||||
background: #bce8f1;
|
||||
opacity: .3;
|
||||
filter: alpha(opacity=30); /* for IE */
|
||||
}
|
||||
|
||||
.fc-bgevent { /* default look for background events */
|
||||
background: rgb(143, 223, 130);
|
||||
opacity: .3;
|
||||
filter: alpha(opacity=30); /* for IE */
|
||||
}
|
||||
|
||||
.fc-nonbusiness { /* default look for non-business-hours areas */
|
||||
@@ -72,7 +74,6 @@ body .fc { /* extra precedence to overcome jqui */
|
||||
|
||||
.fc-icon {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
font-size: 1em;
|
||||
@@ -99,7 +100,6 @@ NOTE: use percentage font sizes or else old IE chokes
|
||||
|
||||
.fc-icon:after {
|
||||
position: relative;
|
||||
margin: 0 -1em; /* ensures character will be centered, regardless of width */
|
||||
}
|
||||
|
||||
.fc-icon-left-single-arrow:after {
|
||||
@@ -107,7 +107,6 @@ NOTE: use percentage font sizes or else old IE chokes
|
||||
font-weight: bold;
|
||||
font-size: 200%;
|
||||
top: -7%;
|
||||
left: 3%;
|
||||
}
|
||||
|
||||
.fc-icon-right-single-arrow:after {
|
||||
@@ -115,7 +114,6 @@ NOTE: use percentage font sizes or else old IE chokes
|
||||
font-weight: bold;
|
||||
font-size: 200%;
|
||||
top: -7%;
|
||||
left: -3%;
|
||||
}
|
||||
|
||||
.fc-icon-left-double-arrow:after {
|
||||
@@ -134,14 +132,12 @@ NOTE: use percentage font sizes or else old IE chokes
|
||||
content: "\25C4";
|
||||
font-size: 125%;
|
||||
top: 3%;
|
||||
left: -2%;
|
||||
}
|
||||
|
||||
.fc-icon-right-triangle:after {
|
||||
content: "\25BA";
|
||||
font-size: 125%;
|
||||
top: 3%;
|
||||
left: 2%;
|
||||
}
|
||||
|
||||
.fc-icon-down-triangle:after {
|
||||
@@ -252,7 +248,6 @@ NOTE: use percentage font sizes or else old IE chokes
|
||||
cursor: default;
|
||||
background-image: none;
|
||||
opacity: 0.65;
|
||||
filter: alpha(opacity=65);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@@ -372,6 +367,7 @@ hr.fc-divider {
|
||||
|
||||
.fc table {
|
||||
width: 100%;
|
||||
box-sizing: border-box; /* fix scrollbar issue in firefox */
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
@@ -395,6 +391,18 @@ hr.fc-divider {
|
||||
}
|
||||
|
||||
|
||||
/* Internal Nav Links
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
a[data-goto] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a[data-goto]:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* Fake Table Rows
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
@@ -491,15 +499,15 @@ temporary rendered events).
|
||||
/* Scrolling Container
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-scroller { /* this class goes on elements for guaranteed vertical scrollbars */
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
.fc-scroller {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.fc-scroller > * { /* we expect an immediate inner element */
|
||||
/* TODO: move to agenda/basic */
|
||||
.fc-scroller > .fc-day-grid,
|
||||
.fc-scroller > .fc-time-grid {
|
||||
position: relative; /* re-scope all positions */
|
||||
width: 100%; /* hack to force re-sizing this inner element when scrollbars appear/disappear */
|
||||
overflow: hidden; /* don't let negative margins or absolute positioning create further scroll */
|
||||
}
|
||||
|
||||
|
||||
@@ -513,10 +521,14 @@ temporary rendered events).
|
||||
line-height: 1.3;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #3a87ad; /* default BORDER color */
|
||||
background-color: #3a87ad; /* default BACKGROUND color */
|
||||
font-weight: normal; /* undo jqui's ui-widget-header bold */
|
||||
}
|
||||
|
||||
.fc-event,
|
||||
.fc-event-dot {
|
||||
background-color: #3a87ad; /* default BACKGROUND color */
|
||||
}
|
||||
|
||||
/* overpower some of bootstrap's and jqui's styles on <a> tags */
|
||||
.fc-event,
|
||||
.fc-event:hover,
|
||||
@@ -539,7 +551,6 @@ temporary rendered events).
|
||||
z-index: 1;
|
||||
background: #fff;
|
||||
opacity: .25;
|
||||
filter: alpha(opacity=25); /* for IE */
|
||||
}
|
||||
|
||||
.fc-event .fc-content {
|
||||
@@ -547,15 +558,68 @@ temporary rendered events).
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* resizer (cursor AND touch devices) */
|
||||
|
||||
.fc-event .fc-resizer {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
/* resizer (touch devices) */
|
||||
|
||||
.fc-event .fc-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fc-event.fc-allow-mouse-resize .fc-resizer,
|
||||
.fc-event.fc-selected .fc-resizer {
|
||||
/* only show when hovering or selected (with touch) */
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* hit area */
|
||||
|
||||
.fc-event.fc-selected .fc-resizer:before {
|
||||
/* 40x40 touch area */
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 9999; /* user of this util can scope within a lower z-index */
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: -20px;
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
|
||||
/* Event Selection (only for touch devices)
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-event.fc-selected {
|
||||
z-index: 9999 !important; /* overcomes inline z-index */
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.fc-event.fc-selected.fc-dragging {
|
||||
box-shadow: 0 2px 7px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
|
||||
/* Horizontal Events
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* bigger touch area when selected */
|
||||
.fc-h-event.fc-selected:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 3; /* below resizers */
|
||||
top: -10px;
|
||||
bottom: -10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* events that are continuing to/from another week. kill rounded corners and butt up against edge */
|
||||
|
||||
.fc-ltr .fc-h-event.fc-not-start,
|
||||
@@ -576,36 +640,56 @@ temporary rendered events).
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
/* resizer */
|
||||
|
||||
.fc-h-event .fc-resizer { /* positioned it to overcome the event's borders */
|
||||
top: -1px;
|
||||
bottom: -1px;
|
||||
left: -1px;
|
||||
right: -1px;
|
||||
width: 5px;
|
||||
}
|
||||
/* resizer (cursor AND touch devices) */
|
||||
|
||||
/* left resizer */
|
||||
.fc-ltr .fc-h-event .fc-start-resizer,
|
||||
.fc-ltr .fc-h-event .fc-start-resizer:before,
|
||||
.fc-ltr .fc-h-event .fc-start-resizer:after,
|
||||
.fc-rtl .fc-h-event .fc-end-resizer,
|
||||
.fc-rtl .fc-h-event .fc-end-resizer:before,
|
||||
.fc-rtl .fc-h-event .fc-end-resizer:after {
|
||||
right: auto; /* ignore the right and only use the left */
|
||||
.fc-rtl .fc-h-event .fc-end-resizer {
|
||||
cursor: w-resize;
|
||||
left: -1px; /* overcome border */
|
||||
}
|
||||
|
||||
/* right resizer */
|
||||
.fc-ltr .fc-h-event .fc-end-resizer,
|
||||
.fc-ltr .fc-h-event .fc-end-resizer:before,
|
||||
.fc-ltr .fc-h-event .fc-end-resizer:after,
|
||||
.fc-rtl .fc-h-event .fc-start-resizer,
|
||||
.fc-rtl .fc-h-event .fc-start-resizer:before,
|
||||
.fc-rtl .fc-h-event .fc-start-resizer:after {
|
||||
left: auto; /* ignore the left and only use the right */
|
||||
.fc-rtl .fc-h-event .fc-start-resizer {
|
||||
cursor: e-resize;
|
||||
right: -1px; /* overcome border */
|
||||
}
|
||||
|
||||
/* resizer (mouse devices) */
|
||||
|
||||
.fc-h-event.fc-allow-mouse-resize .fc-resizer {
|
||||
width: 7px;
|
||||
top: -1px; /* overcome top border */
|
||||
bottom: -1px; /* overcome bottom border */
|
||||
}
|
||||
|
||||
/* resizer (touch devices) */
|
||||
|
||||
.fc-h-event.fc-selected .fc-resizer {
|
||||
/* 8x8 little dot */
|
||||
border-radius: 4px;
|
||||
border-width: 1px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-style: solid;
|
||||
border-color: inherit;
|
||||
background: #fff;
|
||||
/* vertically center */
|
||||
top: 50%;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
/* left resizer */
|
||||
.fc-ltr .fc-h-event.fc-selected .fc-start-resizer,
|
||||
.fc-rtl .fc-h-event.fc-selected .fc-end-resizer {
|
||||
margin-left: -4px; /* centers the 8x8 dot on the left edge */
|
||||
}
|
||||
|
||||
/* right resizer */
|
||||
.fc-ltr .fc-h-event.fc-selected .fc-end-resizer,
|
||||
.fc-rtl .fc-h-event.fc-selected .fc-start-resizer {
|
||||
margin-right: -4px; /* centers the 8x8 dot on the right edge */
|
||||
}
|
||||
|
||||
|
||||
@@ -620,6 +704,23 @@ be a descendant of the grid when it is being dragged.
|
||||
padding: 0 1px;
|
||||
}
|
||||
|
||||
tr:first-child > td > .fc-day-grid-event {
|
||||
margin-top: 2px; /* a little bit more space before the first event */
|
||||
}
|
||||
|
||||
.fc-day-grid-event.fc-selected:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 1; /* same z-index as fc-bg, behind text */
|
||||
/* overcome the borders */
|
||||
top: -1px;
|
||||
right: -1px;
|
||||
bottom: -1px;
|
||||
left: -1px;
|
||||
/* darkening effect */
|
||||
background: #000;
|
||||
opacity: .25;
|
||||
}
|
||||
|
||||
.fc-day-grid-event .fc-content { /* force events to be one-line tall */
|
||||
white-space: nowrap;
|
||||
@@ -630,10 +731,18 @@ be a descendant of the grid when it is being dragged.
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fc-day-grid-event .fc-resizer { /* enlarge the default hit area */
|
||||
left: -3px;
|
||||
right: -3px;
|
||||
width: 7px;
|
||||
/* resizer (cursor devices) */
|
||||
|
||||
/* left resizer */
|
||||
.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer,
|
||||
.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer {
|
||||
margin-left: -2px; /* to the day cell's edge */
|
||||
}
|
||||
|
||||
/* right resizer */
|
||||
.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer,
|
||||
.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer {
|
||||
margin-right: -2px; /* to the day cell's edge */
|
||||
}
|
||||
|
||||
|
||||
@@ -672,14 +781,46 @@ a.fc-more:hover {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* Now Indicator
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-now-indicator {
|
||||
position: absolute;
|
||||
border: 0 solid red;
|
||||
}
|
||||
|
||||
|
||||
/* Utilities
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-unselectable {
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Toolbar
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-toolbar {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fc-toolbar.fc-header-toolbar {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.fc-toolbar.fc-footer-toolbar {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.fc-toolbar .fc-left {
|
||||
float: left;
|
||||
}
|
||||
@@ -753,6 +894,8 @@ a.fc-more:hover {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* BasicView
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
@@ -760,8 +903,7 @@ a.fc-more:hover {
|
||||
|
||||
.fc-basicWeek-view .fc-content-skeleton,
|
||||
.fc-basicDay-view .fc-content-skeleton {
|
||||
/* we are sure there are no day numbers in these views, so... */
|
||||
padding-top: 1px; /* add a pixel to make sure there are 2px padding above events */
|
||||
/* there may be week numbers in these views, so no padding-top */
|
||||
padding-bottom: 1em; /* ensure a space at bottom of cell for user selecting/clicking */
|
||||
}
|
||||
|
||||
@@ -784,42 +926,45 @@ a.fc-more:hover {
|
||||
|
||||
/* week and day number styling */
|
||||
|
||||
.fc-day-top.fc-other-month {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.fc-basic-view .fc-week-number,
|
||||
.fc-basic-view .fc-day-number {
|
||||
padding: 0 2px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.fc-basic-view td.fc-week-number span,
|
||||
.fc-basic-view td.fc-day-number {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
.fc-basic-view th.fc-week-number,
|
||||
.fc-basic-view th.fc-day-number {
|
||||
padding: 0 2px; /* column headers can't have as much v space */
|
||||
}
|
||||
|
||||
.fc-basic-view .fc-week-number {
|
||||
.fc-ltr .fc-basic-view .fc-day-top .fc-day-number { float: right; }
|
||||
.fc-rtl .fc-basic-view .fc-day-top .fc-day-number { float: left; }
|
||||
|
||||
.fc-ltr .fc-basic-view .fc-day-top .fc-week-number { float: left; border-radius: 0 0 3px 0; }
|
||||
.fc-rtl .fc-basic-view .fc-day-top .fc-week-number { float: right; border-radius: 0 0 0 3px; }
|
||||
|
||||
.fc-basic-view .fc-day-top .fc-week-number {
|
||||
min-width: 1.5em;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
/* when week/day number have own column */
|
||||
|
||||
.fc-basic-view td.fc-week-number {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fc-basic-view .fc-week-number span {
|
||||
.fc-basic-view td.fc-week-number > * {
|
||||
/* work around the way we do column resizing and ensure a minimum width */
|
||||
display: inline-block;
|
||||
min-width: 1.25em;
|
||||
}
|
||||
|
||||
.fc-ltr .fc-basic-view .fc-day-number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.fc-rtl .fc-basic-view .fc-day-number {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fc-day-number.fc-other-month {
|
||||
opacity: 0.3;
|
||||
filter: alpha(opacity=30); /* for IE */
|
||||
/* opacity with small font can sometimes look too faded
|
||||
might want to set the 'color' property instead
|
||||
making day-numbers bold also fixes the problem */
|
||||
}
|
||||
|
||||
/* AgendaView all-day area
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
@@ -834,7 +979,6 @@ a.fc-more:hover {
|
||||
}
|
||||
|
||||
.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton {
|
||||
padding-top: 1px; /* add a pixel to make sure there are 2px padding above events */
|
||||
padding-bottom: 1em; /* give space underneath events for clicking/selecting days */
|
||||
}
|
||||
|
||||
@@ -888,27 +1032,46 @@ a.fc-more:hover {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-bgevent-skeleton,
|
||||
.fc-time-grid .fc-content-col {
|
||||
position: relative; /* because now-indicator lives directly inside */
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-content-skeleton {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-bgevent-skeleton {
|
||||
/* divs within a cell within the fc-content-skeleton */
|
||||
|
||||
.fc-time-grid .fc-business-container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-bgevent-container {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-highlight-container {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-highlight-skeleton {
|
||||
.fc-time-grid .fc-event-container {
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-content-skeleton {
|
||||
.fc-time-grid .fc-now-indicator-line {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.fc-time-grid .fc-helper-skeleton {
|
||||
.fc-time-grid .fc-helper-container { /* also is fc-event-container */
|
||||
position: relative;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
@@ -948,11 +1111,6 @@ a.fc-more:hover {
|
||||
/* TimeGrid Event Containment
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-time-grid .fc-event-container, /* a div within a cell within the fc-content-skeleton */
|
||||
.fc-time-grid .fc-bgevent-container { /* a div within a cell within the fc-bgevent-skeleton */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fc-ltr .fc-time-grid .fc-event-container { /* space on the sides of events for LTR (default) */
|
||||
margin: 0 2.5% 0 2px;
|
||||
}
|
||||
@@ -1008,6 +1166,20 @@ be a descendant of the grid when it is being dragged.
|
||||
overflow: hidden; /* don't let the bg flow over rounded corners */
|
||||
}
|
||||
|
||||
.fc-time-grid-event.fc-selected {
|
||||
/* need to allow touch resizers to extend outside event's bounding box */
|
||||
/* common fc-selected styles hide the fc-bg, so don't need this anyway */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.fc-time-grid-event.fc-selected .fc-bg {
|
||||
display: none; /* hide semi-white background, to appear darker */
|
||||
}
|
||||
|
||||
.fc-time-grid-event .fc-content {
|
||||
overflow: hidden; /* for when .fc-selected */
|
||||
}
|
||||
|
||||
.fc-time-grid-event .fc-time,
|
||||
.fc-time-grid-event .fc-title {
|
||||
padding: 0 1px;
|
||||
@@ -1049,9 +1221,9 @@ be a descendant of the grid when it is being dragged.
|
||||
padding: 0; /* undo padding from above */
|
||||
}
|
||||
|
||||
/* resizer */
|
||||
/* resizer (cursor device) */
|
||||
|
||||
.fc-time-grid-event .fc-resizer {
|
||||
.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
@@ -1064,6 +1236,169 @@ be a descendant of the grid when it is being dragged.
|
||||
cursor: s-resize;
|
||||
}
|
||||
|
||||
.fc-time-grid-event .fc-resizer:after {
|
||||
.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after {
|
||||
content: "=";
|
||||
}
|
||||
|
||||
/* resizer (touch device) */
|
||||
|
||||
.fc-time-grid-event.fc-selected .fc-resizer {
|
||||
/* 10x10 dot */
|
||||
border-radius: 5px;
|
||||
border-width: 1px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-style: solid;
|
||||
border-color: inherit;
|
||||
background: #fff;
|
||||
/* horizontally center */
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
/* center on the bottom edge */
|
||||
bottom: -5px;
|
||||
}
|
||||
|
||||
|
||||
/* Now Indicator
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-time-grid .fc-now-indicator-line {
|
||||
border-top-width: 1px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* arrow on axis */
|
||||
|
||||
.fc-time-grid .fc-now-indicator-arrow {
|
||||
margin-top: -5px; /* vertically center on top coordinate */
|
||||
}
|
||||
|
||||
.fc-ltr .fc-time-grid .fc-now-indicator-arrow {
|
||||
left: 0;
|
||||
/* triangle pointing right... */
|
||||
border-width: 5px 0 5px 6px;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
.fc-rtl .fc-time-grid .fc-now-indicator-arrow {
|
||||
right: 0;
|
||||
/* triangle pointing left... */
|
||||
border-width: 5px 6px 5px 0;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* List View
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* possibly reusable */
|
||||
|
||||
.fc-event-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* view wrapper */
|
||||
|
||||
.fc-rtl .fc-list-view {
|
||||
direction: rtl; /* unlike core views, leverage browser RTL */
|
||||
}
|
||||
|
||||
.fc-list-view {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
/* table resets */
|
||||
|
||||
.fc .fc-list-table {
|
||||
table-layout: auto; /* for shrinkwrapping cell content */
|
||||
}
|
||||
|
||||
.fc-list-table td {
|
||||
border-width: 1px 0 0;
|
||||
padding: 8px 14px;
|
||||
}
|
||||
|
||||
.fc-list-table tr:first-child td {
|
||||
border-top-width: 0;
|
||||
}
|
||||
|
||||
/* day headings with the list */
|
||||
|
||||
.fc-list-heading {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.fc-list-heading td {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fc-ltr .fc-list-heading-main { float: left; }
|
||||
.fc-ltr .fc-list-heading-alt { float: right; }
|
||||
|
||||
.fc-rtl .fc-list-heading-main { float: right; }
|
||||
.fc-rtl .fc-list-heading-alt { float: left; }
|
||||
|
||||
/* event list items */
|
||||
|
||||
.fc-list-item.fc-has-url {
|
||||
cursor: pointer; /* whole row will be clickable */
|
||||
}
|
||||
|
||||
.fc-list-item:hover td {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.fc-list-item-marker,
|
||||
.fc-list-item-time {
|
||||
white-space: nowrap;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
/* make the dot closer to the event title */
|
||||
.fc-ltr .fc-list-item-marker { padding-right: 0; }
|
||||
.fc-rtl .fc-list-item-marker { padding-left: 0; }
|
||||
|
||||
.fc-list-item-title a {
|
||||
/* every event title cell has an <a> tag */
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.fc-list-item-title a[href]:hover {
|
||||
/* hover effect only on titles with hrefs */
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* message when no events */
|
||||
|
||||
.fc-list-empty-wrap2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.fc-list-empty-wrap1 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.fc-list-empty {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fc-unthemed .fc-list-empty { /* theme will provide own background */
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ Handlebars.registerHelper('StatusLevel', function() {
|
||||
var start = moment(this.airDateUtc);
|
||||
var end = moment(this.end);
|
||||
var monitored = this.series.monitored && this.monitored;
|
||||
|
||||
debugger;
|
||||
if (hasFile) {
|
||||
return 'success';
|
||||
}
|
||||
@@ -63,4 +63,4 @@ Handlebars.registerHelper('EpisodeProgressClass', function() {
|
||||
}
|
||||
|
||||
return 'progress-bar-warning';
|
||||
});
|
||||
});
|
||||
|
||||
@@ -51,6 +51,10 @@ Handlebars.registerHelper('tmdbUrl', function() {
|
||||
return 'https://www.themoviedb.org/movie/' + this.tmdbId;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('youTubeTrailerUrl', function() {
|
||||
return 'https://www.youtube.com/watch?v=' + this.youTubeTrailerId;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('homepage', function() {
|
||||
return this.website;
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,9 @@
|
||||
<span class="label label-info">{{network}}</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if studio}}
|
||||
<span class="label label-info">{{studio}}</span>
|
||||
{{/if}}
|
||||
<span class="label label-info">{{runtime}} minutes</span>
|
||||
<span class="label label-info">{{path}}</span>
|
||||
|
||||
@@ -33,6 +36,10 @@
|
||||
{{#if imdbId}}
|
||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if youTubeTrailerId}}
|
||||
<a href="{{youTubeTrailerUrl}}" class="label label-info">Trailer</a>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,6 +54,10 @@
|
||||
{{#if imdbId}}
|
||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if youTubeTrailerId}}
|
||||
<a href="{{youTubeTrailerUrl}}" class="label label-info">Trailer</a>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
{{#if imdbId}}
|
||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if youTubeTrailerId}}
|
||||
<a href="{{youTubeTrailerUrl}}" class="label label-info">Trailer</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,33 +6,33 @@ var MoviesDetailsLayout = require('./Details/MoviesDetailsLayout');
|
||||
var SeriesDetailsLayout = require('../Series/Details/SeriesDetailsLayout');
|
||||
|
||||
module.exports = NzbDroneController.extend({
|
||||
_originalInit : NzbDroneController.prototype.initialize,
|
||||
_originalInit : NzbDroneController.prototype.initialize,
|
||||
|
||||
initialize : function() {
|
||||
this.route('', this.series);
|
||||
this.route('movies', this.series);
|
||||
this.route('movies/:query', this.seriesDetails);
|
||||
initialize : function() {
|
||||
this.route('', this.series);
|
||||
this.route('movies', this.series);
|
||||
this.route('movies/:query', this.seriesDetails);
|
||||
|
||||
this._originalInit.apply(this, arguments);
|
||||
},
|
||||
this._originalInit.apply(this, arguments);
|
||||
},
|
||||
|
||||
series : function() {
|
||||
this.setTitle('Movies');
|
||||
this.showMainRegion(new MoviesIndexLayout());
|
||||
},
|
||||
series : function() {
|
||||
this.setTitle('Movies');
|
||||
this.showMainRegion(new MoviesIndexLayout());
|
||||
},
|
||||
|
||||
seriesDetails : function(query) {
|
||||
var series = MoviesCollection.where({ titleSlug : query });
|
||||
if (series.length !== 0) {
|
||||
var targetMovie = series[0];
|
||||
console.log(AppLayout.mainRegion);
|
||||
seriesDetails : function(query) {
|
||||
var series = MoviesCollection.where({ titleSlug : query });
|
||||
if (series.length !== 0) {
|
||||
var targetMovie = series[0];
|
||||
console.log(AppLayout.mainRegion);
|
||||
|
||||
this.setTitle(targetMovie.get('title'));
|
||||
//this.showNotFound();
|
||||
//this.showMainRegion(new SeriesDetailsLayout({model : targetMovie}));
|
||||
this.showMainRegion(new MoviesDetailsLayout({ model : targetMovie }));
|
||||
} else {
|
||||
this.showNotFound();
|
||||
}
|
||||
}
|
||||
this.setTitle(targetMovie.get('title'));
|
||||
//this.showNotFound();
|
||||
//this.showMainRegion(new SeriesDetailsLayout({model : targetMovie}));
|
||||
this.showMainRegion(new MoviesDetailsLayout({ model : targetMovie }));
|
||||
} else {
|
||||
this.showNotFound();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
.card;
|
||||
.clickable;
|
||||
margin-bottom : 20px;
|
||||
height : 324px;
|
||||
height : 344px;
|
||||
|
||||
.center {
|
||||
display : block;
|
||||
@@ -166,7 +166,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs-max) {
|
||||
height : 235px;
|
||||
height : 268px;
|
||||
margin : 5px;
|
||||
padding : 6px 5px;
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ vent.Commands = {
|
||||
ShowFileBrowser : 'showFileBrowser',
|
||||
CloseFileBrowser : 'closeFileBrowser',
|
||||
OpenControlPanelCommand : 'OpenControlPanelCommand',
|
||||
CloseControlPanelCommand : 'CloseControlPanelCommand'
|
||||
CloseControlPanelCommand : 'CloseControlPanelCommand',
|
||||
ShowExistingCommand : 'ShowExistingCommand'
|
||||
};
|
||||
|
||||
vent.Hotkeys = {
|
||||
|
||||
Reference in New Issue
Block a user