New: iCal calendar feed.
This commit is contained in:
parent
cf1e0a4946
commit
794c09c17a
|
@ -23,7 +23,7 @@ namespace NzbDrone.Api.Calendar
|
||||||
|
|
||||||
private Response GetCalendarFeed()
|
private Response GetCalendarFeed()
|
||||||
{
|
{
|
||||||
var start = DateTime.Today.Subtract(TimeSpan.FromDays(7));
|
var start = DateTime.Today.AddDays(-7);
|
||||||
var end = DateTime.Today.AddDays(28);
|
var end = DateTime.Today.AddDays(28);
|
||||||
|
|
||||||
var queryStart = Request.Query.Start;
|
var queryStart = Request.Query.Start;
|
||||||
|
@ -35,28 +35,25 @@ namespace NzbDrone.Api.Calendar
|
||||||
var episodes = _episodeService.EpisodesBetweenDates(start, end);
|
var episodes = _episodeService.EpisodesBetweenDates(start, end);
|
||||||
var icalCalendar = new iCalendar();
|
var icalCalendar = new iCalendar();
|
||||||
|
|
||||||
foreach (var series in episodes.GroupBy(v => v.Series))
|
foreach (var episode in episodes.OrderBy(v => v.AirDateUtc.Value))
|
||||||
{
|
{
|
||||||
foreach (var episode in series)
|
var occurrence = icalCalendar.Create<Event>();
|
||||||
|
occurrence.UID = "NzbDrone_episode_" + episode.Id.ToString();
|
||||||
|
occurrence.Status = episode.HasFile ? EventStatus.Confirmed : EventStatus.Tentative;
|
||||||
|
occurrence.Start = new iCalDateTime(episode.AirDateUtc.Value);
|
||||||
|
occurrence.End = new iCalDateTime(episode.AirDateUtc.Value.AddMinutes(episode.Series.Runtime));
|
||||||
|
occurrence.Description = episode.Overview;
|
||||||
|
occurrence.Categories = new List<string>() { episode.Series.Network };
|
||||||
|
|
||||||
|
switch (episode.Series.SeriesType)
|
||||||
{
|
{
|
||||||
var occurrence = icalCalendar.Create<Event>();
|
case SeriesTypes.Daily:
|
||||||
occurrence.UID = "NzbDrone_episode_" + episode.Id.ToString();
|
occurrence.Summary = string.Format("{0} - {1}", episode.Series.Title, episode.Title);
|
||||||
occurrence.Status = episode.HasFile ? EventStatus.Confirmed : EventStatus.Tentative;
|
break;
|
||||||
occurrence.Start = new iCalDateTime(episode.AirDateUtc.Value);
|
|
||||||
occurrence.End = new iCalDateTime(episode.AirDateUtc.Value.AddMinutes(episode.Series.Runtime));
|
|
||||||
occurrence.Description = episode.Overview;
|
|
||||||
occurrence.Categories = new List<string>() { episode.Series.Network };
|
|
||||||
|
|
||||||
switch (episode.Series.SeriesType)
|
default:
|
||||||
{
|
occurrence.Summary = string.Format("{0} - {1}x{2:00} - {3}", episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber, episode.Title);
|
||||||
case SeriesTypes.Daily:
|
break;
|
||||||
occurrence.Summary = string.Format("{0} - {1}", episode.Series.Title, episode.Title);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
occurrence.Summary = string.Format("{0} - {1}x{2:00} - {3}", episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber, episode.Title);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,24 @@
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'marionette',
|
'marionette',
|
||||||
], function (Marionette) {
|
'System/StatusModel',
|
||||||
|
'Mixins/CopyToClipboard'
|
||||||
|
], function (Marionette, StatusModel) {
|
||||||
return Marionette.Layout.extend({
|
return Marionette.Layout.extend({
|
||||||
template: 'Calendar/CalendarFeedViewTemplate',
|
template: 'Calendar/CalendarFeedViewTemplate',
|
||||||
|
|
||||||
onRender: function() {
|
ui: {
|
||||||
// hackish way to determine the correct url, as using urlBase seems to only work for reverse proxies or so
|
icalUrl : '.x-ical-url',
|
||||||
var ics = '//' + window.location.host + '/feed/calendar/NzbDrone.ics';
|
icalCopy : '.x-ical-copy'
|
||||||
this.$('#ical-url').val(window.location.protocol + ics);
|
},
|
||||||
this.$('#ical-subscribe-button').attr('href', 'webcal:' + ics);
|
|
||||||
}
|
templateHelpers: {
|
||||||
|
icalHttpUrl : window.location.protocol + '//' + window.location.host + StatusModel.get('urlBase') + '/feed/calendar/NzbDrone.ics',
|
||||||
|
icalWebCalUrl : 'webcal://' + window.location.host + StatusModel.get('urlBase') + '/feed/calendar/NzbDrone.ics'
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow: function () {
|
||||||
|
this.ui.icalCopy.copyToClipboard(this.ui.icalUrl);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,14 +7,17 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="form-horizontal">
|
<div class="form-horizontal">
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label" for="ical-url">iCal feed</label>
|
<label class="control-label">iCal feed</label>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls ical-url">
|
||||||
<input type="text" id="ical-url" class="x-ical-url" value="/feed/calendar/NzbDrone.ics" name="ical-url">
|
<div class="input-append">
|
||||||
<span class="help-inline">
|
<input type="text" class="x-ical-url" value="{{icalHttpUrl}}" readonly="readonly" />
|
||||||
<i class="icon-nd-form-info" title="copy this url into your clients subscription form or use the subscribe now link if you have a webcal protocol handler installed"/>
|
<button class="btn btn-icon-only x-ical-copy" title="Copy to clipboard"><i class="icon-copy"></i></button>
|
||||||
</span>
|
<a class="btn btn-icon-only no-router" title="Subscribe" href="{{icalWebCalUrl}}" target="_blank"><i class="icon-calendar-empty"></i></a>
|
||||||
or <a href="webcal:///feed/calendar/NzbDrone.ics" id="ical-subscribe-button">subscribe now!</a>
|
</div>
|
||||||
|
<span class="help-inline">
|
||||||
|
<i class="icon-nd-form-info" title="Copy this url into your clients subscription form or use the subscribe button if your browser support webcal"/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<h4>
|
<h4>
|
||||||
<i class="icon-calendar-empty ical x-ical"></i>
|
<i class="icon-calendar-empty ical x-ical"></i>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div id="x-upcoming"/>
|
<div id="x-upcoming"/>
|
||||||
</div>
|
</div>
|
||||||
<div class=span9>
|
<div class=span9>
|
||||||
|
|
|
@ -162,9 +162,13 @@
|
||||||
.ical
|
.ical
|
||||||
{
|
{
|
||||||
color: @btnInverseBackground;
|
color: @btnInverseBackground;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ical-url
|
.ical-url {
|
||||||
{
|
|
||||||
width: 370px;
|
input {
|
||||||
}
|
width : 440px;
|
||||||
|
cursor : text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="/Content/Images/touch/144.png?v=2"/>
|
<link rel="apple-touch-icon" sizes="144x144" href="/Content/Images/touch/144.png?v=2"/>
|
||||||
<link rel="icon" type="image/ico" href="/Content/Images/favicon.ico?v=2"/>
|
<link rel="icon" type="image/ico" href="/Content/Images/favicon.ico?v=2"/>
|
||||||
|
|
||||||
<link rel="alternate" type="text/calendar" title="iCalendar feed for NzbDrone" href="/feed/calendar/NzbDrone.ics" />
|
<link rel="alternate" type="text/calendar" title="iCalendar feed for NzbDrone" href="/feed/calendar/NzbDrone.ics" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="nav-region"></div>
|
<div id="nav-region"></div>
|
||||||
|
|
|
@ -29,17 +29,21 @@ define(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
var href = event.target.getAttribute('href');
|
var href = event.target.getAttribute('href');
|
||||||
|
|
||||||
if (!href && $target.closest('a') && $target.closest('a')[0]) {
|
if (!href && $target.closest('a') && $target.closest('a')[0]) {
|
||||||
|
|
||||||
var linkElement = $target.closest('a')[0];
|
var linkElement = $target.closest('a')[0];
|
||||||
|
|
||||||
|
if ($(linkElement).hasClass('no-router')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
href = linkElement.getAttribute('href');
|
href = linkElement.getAttribute('href');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
if (!href) {
|
if (!href) {
|
||||||
throw 'couldn\'t find route target';
|
throw 'couldn\'t find route target';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue