public static string GetRecordingName(TimerInfo timer, ProgramInfo info)
 {
     if (info == null)
     {
         return (timer.ProgramId + ".ts");
     }
     var fancyName = info.Name;
     if (info.ProductionYear != null)
     {
         fancyName += "_(" + info.ProductionYear + ")";
     }
     if (info.IsSeries)
     {
         fancyName += "_" + info.EpisodeTitle.Replace("Season: ", "S").Replace(" Episode: ", "E");
     }
     if (info.IsHD ?? false)
     {
         fancyName += "_HD";
     }
     if (info.OriginalAirDate != null)
     {
         fancyName += "_" + info.OriginalAirDate.Value.ToString("yyyy-MM-dd");
     }
     return StringHelper.RemoveSpecialCharacters(fancyName) + ".ts";
 }
        public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service)
        {
            var dto = new TimerInfoDto
            {
                Id = GetInternalTimerId(service.Name, info.Id).ToString("N"),
                ChannelName = info.ChannelName,
                Overview = info.Overview,
                EndDate = info.EndDate,
                Name = info.Name,
                StartDate = info.StartDate,
                ExternalId = info.Id,
                ChannelId = GetInternalChannelId(service.Name, info.ChannelId, info.ChannelName).ToString("N"),
                Status = info.Status,
                SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"),
                PrePaddingSeconds = info.PrePaddingSeconds,
                PostPaddingSeconds = info.PostPaddingSeconds,
                IsPostPaddingRequired = info.IsPostPaddingRequired,
                IsPrePaddingRequired = info.IsPrePaddingRequired,
                ExternalChannelId = info.ChannelId,
                ExternalSeriesTimerId = info.SeriesTimerId,
                ServiceName = service.Name,
                ExternalProgramId = info.ProgramId,
                Priority = info.Priority
            };

            var duration = info.EndDate - info.StartDate;
            dto.DurationMs = Convert.ToInt32(duration.TotalMilliseconds);

            if (!string.IsNullOrEmpty(info.ProgramId))
            {
                dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
            }

            return dto;
        }
Exemple #3
0
        public static List<TimerInfo> GetTimers(Stream stream, IJsonSerializer json, ILogger logger)
        {
            List<TimerInfo> ret = new List<TimerInfo>();

            var root = ParseRecRules(stream, json);
            foreach (var item in root.RecRuleList.RecRules)
            {
                if (!item.Inactive && string.Compare(item.Type, "Not Recording", true) != 0)
                {
                    TimerInfo val = new TimerInfo()
                    {
                        Name = item.Title,
                        Overview = item.Description,
                        ChannelId = item.ChanId.ToString(),
                        EndDate = (DateTime)item.EndTime,
                        StartDate = (DateTime)item.StartTime,
                        Id = item.Id,
                        PrePaddingSeconds = item.StartOffset * 60,
                        PostPaddingSeconds = item.EndOffset * 60,
                        IsPostPaddingRequired = item.EndOffset != 0,
                        IsPrePaddingRequired = item.StartOffset != 0,
                        ProgramId = item.ProgramId
                    };

                    ret.Add(val);
                }
            }

            return ret;
        }
 public void CopyTimer(TimerInfo parent)
 {
     foreach (PropertyInfo prop in parent.GetType().GetProperties())
     {
         GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(parent, null), null);
     }
     this.Id = parent.ProgramId;
 }
 public static DateTime GetStartTime(TimerInfo timer)
 {
     if (timer.StartDate.AddSeconds(-timer.PrePaddingSeconds + 1) < DateTime.UtcNow)
     {
         return DateTime.UtcNow.AddSeconds(1);
     }
     return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds);
 }
        public async Task CreateTimer(TimerInfo info, CancellationToken cancellationToken)
        {
            try
            {

            }
            catch (Exception exception)
            {
                Logger.ErrorException("HTSP create timer failed", exception);
            }
        }
Exemple #7
0
        public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service, LiveTvProgram program, LiveTvChannel channel)
        {
            var dto = new TimerInfoDto
            {
                Id = GetInternalTimerId(service.Name, info.Id).ToString("N"),
                Overview = info.Overview,
                EndDate = info.EndDate,
                Name = info.Name,
                StartDate = info.StartDate,
                ExternalId = info.Id,
                ChannelId = GetInternalChannelId(service.Name, info.ChannelId).ToString("N"),
                Status = info.Status,
                SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"),
                PrePaddingSeconds = info.PrePaddingSeconds,
                PostPaddingSeconds = info.PostPaddingSeconds,
                IsPostPaddingRequired = info.IsPostPaddingRequired,
                IsPrePaddingRequired = info.IsPrePaddingRequired,
                KeepUntil = info.KeepUntil,
                ExternalChannelId = info.ChannelId,
                ExternalSeriesTimerId = info.SeriesTimerId,
                ServiceName = service.Name,
                ExternalProgramId = info.ProgramId,
                Priority = info.Priority,
                RunTimeTicks = (info.EndDate - info.StartDate).Ticks,
                ServerId = _appHost.SystemId
            };

            if (!string.IsNullOrEmpty(info.ProgramId))
            {
                dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
            }

            if (program != null)
            {
                dto.ProgramInfo = _dtoService.GetBaseItemDto(program, new DtoOptions());

                if (info.Status != RecordingStatus.Cancelled && info.Status != RecordingStatus.Error)
                {
                    dto.ProgramInfo.TimerId = dto.Id;
                    dto.ProgramInfo.Status = info.Status.ToString();
                }

                dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId;
            }

            if (channel != null)
            {
                dto.ChannelName = channel.Name;
            }

            return dto;
        }
Exemple #8
0
        public static string GetRecordingName(TimerInfo timer, ProgramInfo info)
        {
            if (info == null)
            {
                return timer.ProgramId;
            }

            var name = info.Name;

            if (info.IsSeries)
            {
                var addHyphen = true;

                if (info.SeasonNumber.HasValue && info.EpisodeNumber.HasValue)
                {
                    name += string.Format(" S{0}E{1}", info.SeasonNumber.Value.ToString("00", CultureInfo.InvariantCulture), info.EpisodeNumber.Value.ToString("00", CultureInfo.InvariantCulture));
                    addHyphen = false;
                }
                else if (info.OriginalAirDate.HasValue)
                {
                    name += " " + info.OriginalAirDate.Value.ToString("yyyy-MM-dd");
                }
                else
                {
                    name += " " + DateTime.Now.ToString("yyyy-MM-dd");
                }

                if (!string.IsNullOrWhiteSpace(info.EpisodeTitle))
                {
                    if (addHyphen)
                    {
                        name += " -";
                    }

                    name += " " + info.EpisodeTitle;
                }
            }

            else if (info.IsMovie && info.ProductionYear != null)
            {
                name += " (" + info.ProductionYear + ")";
            }
            else
            {
                name += " " + info.StartDate.ToString("yyyy-MM-dd") + " " + info.Id;
            }

            return name;
        }
        public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service, LiveTvProgram program, LiveTvChannel channel)
        {
            var dto = new TimerInfoDto
            {
                Id = GetInternalTimerId(service.Name, info.Id).ToString("N"),
                Overview = info.Overview,
                EndDate = info.EndDate,
                Name = info.Name,
                StartDate = info.StartDate,
                ExternalId = info.Id,
                ChannelId = GetInternalChannelId(service.Name, info.ChannelId).ToString("N"),
                Status = info.Status,
                SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"),
                PrePaddingSeconds = info.PrePaddingSeconds,
                PostPaddingSeconds = info.PostPaddingSeconds,
                IsPostPaddingRequired = info.IsPostPaddingRequired,
                IsPrePaddingRequired = info.IsPrePaddingRequired,
                ExternalChannelId = info.ChannelId,
                ExternalSeriesTimerId = info.SeriesTimerId,
                ServiceName = service.Name,
                ExternalProgramId = info.ProgramId,
                Priority = info.Priority,
                RunTimeTicks = (info.EndDate - info.StartDate).Ticks
            };

            if (!string.IsNullOrEmpty(info.ProgramId))
            {
                dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
            }

            if (program != null)
            {
                dto.ProgramInfo = GetProgramInfoDto(program, channel);

                dto.ProgramInfo.TimerId = dto.Id;
                dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId;
            }

            if (channel != null)
            {
                dto.ChannelName = channel.Name;
            }

            return dto;
        }
Exemple #10
0
        public static void CopyProgramInfoToTimerInfo(ProgramInfo programInfo, TimerInfo timerInfo)
        {
            timerInfo.SeasonNumber = programInfo.SeasonNumber;
            timerInfo.EpisodeNumber = programInfo.EpisodeNumber;
            timerInfo.IsMovie = programInfo.IsMovie;
            timerInfo.IsKids = programInfo.IsKids;
            timerInfo.IsNews = programInfo.IsNews;
            timerInfo.IsSports = programInfo.IsSports;
            timerInfo.ProductionYear = programInfo.ProductionYear;
            timerInfo.EpisodeTitle = programInfo.EpisodeTitle;
            timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
            timerInfo.IsProgramSeries = programInfo.IsSeries;

            timerInfo.HomePageUrl = programInfo.HomePageUrl;
            timerInfo.CommunityRating = programInfo.CommunityRating;
            timerInfo.ShortOverview = programInfo.ShortOverview;
            timerInfo.OfficialRating = programInfo.OfficialRating;
            timerInfo.IsRepeat = programInfo.IsRepeat;
        }
Exemple #11
0
        public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo series)
        {
            var timer = new TimerInfo();

            timer.ChannelId = parent.ChannelId;
            timer.Id = (series.Id + parent.Id).GetMD5().ToString("N");
            timer.StartDate = parent.StartDate;
            timer.EndDate = parent.EndDate;
            timer.ProgramId = parent.Id;
            timer.PrePaddingSeconds = series.PrePaddingSeconds;
            timer.PostPaddingSeconds = series.PostPaddingSeconds;
            timer.IsPostPaddingRequired = series.IsPostPaddingRequired;
            timer.IsPrePaddingRequired = series.IsPrePaddingRequired;
            timer.Priority = series.Priority;
            timer.Name = parent.Name;
            timer.Overview = parent.Overview;
            timer.SeriesTimerId = series.Id;

            return timer;
        }
        public async Task CreateTimer(TimerInfo info, CancellationToken cancellationToken)
        {
            try
            {
                var channel = new Channel().ById(info.ChannelId, cancellationToken).Result;

                var timer = "{\"channel\":\"" + channel.Uuid + 
                    "\",\"disp_title\":\"" + info.Name +
                    "\",\"disp_description\":\"" + info.Overview +
                    "\",\"start\":" + Helper.Converter.DatetimeToLinuxSeconds(info.StartDate) + 
                    ",\"stop\":" + Helper.Converter.DatetimeToLinuxSeconds(info.EndDate) + 
                    ",\"start_extra\":" + (info.PrePaddingSeconds / 60) +
                    ",\"stop_extra\":" + (info.PostPaddingSeconds / 60) +
                    "\"}";

                await Post(Url.Dvr.Create, timer, cancellationToken);
            }
            catch (Exception exception)
            {
                Logger.ErrorException("Creating timer DVR error, API call failed", exception);
            }
        }
        public void CreateSchedule(CancellationToken cancellationToken, TimerInfo timer)
        {
            var programData = GetProgram(cancellationToken, timer.ProgramId);
            if (programData == null)
            {
                throw ExceptionHelper.CreateArgumentException("timer.ProgramId", "The program id {0} could not be found", timer.ProgramId);
            }

            var builder = new StringBuilder("AddScheduleDetailed?");
            builder.AppendFormat("channelid={0}&", programData.ChannelId);
            builder.AppendFormat("title={0}&", programData.Title);
            builder.AppendFormat("starttime={0}&", programData.StartTime.ToLocalTime().ToUrlDate());
            builder.AppendFormat("endtime={0}&", programData.EndTime.ToLocalTime().ToUrlDate());
            builder.AppendFormat("scheduletype={0}&", (Int32)WebScheduleType.Once);

            if (timer.IsPrePaddingRequired & timer.PrePaddingSeconds > 0)
            {
                builder.AppendFormat("preRecordInterval={0}&", timer.PrePaddingSeconds / 60);
            }

            if (timer.IsPostPaddingRequired & timer.PostPaddingSeconds > 0)
            {
                builder.AppendFormat("postRecordInterval={0}&", timer.PostPaddingSeconds / 60);
            }

            builder.Remove(builder.Length - 1, 1);

            Plugin.Logger.Info("Creating scheule with StartTime: {0}, EndTime: {1}, ProgramData from MP: {2}",
                timer.StartDate, timer.EndDate, builder.ToString());

            var response = GetFromService<WebBoolResult>(cancellationToken, builder.ToString());
            if (!response.Result)
            {
                throw new LiveTvConflictException();
            }
        }
 public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
 {
     info.Id = Guid.NewGuid().ToString("N");
     _timerProvider.Add(info);
     return Task.FromResult(0);
 }
        private async Task RecordStream(TimerInfo timer, CancellationToken cancellationToken)
        {
            var mediaStreamInfo = await GetChannelStream(timer.ChannelId, "none", CancellationToken.None);
            var duration = (timer.EndDate - RecordingHelper.GetStartTime(timer)).TotalSeconds + timer.PrePaddingSeconds;

            HttpRequestOptions httpRequestOptions = new HttpRequestOptionsMod()
            {
                Url = mediaStreamInfo.Path + "?duration=" + duration
            };

            var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);
            var recordPath = RecordingPath;
            if (info.IsMovie)
            {
                recordPath = Path.Combine(recordPath, "Movies", StringHelper.RemoveSpecialCharacters(info.Name));
            }
            else
            {
                recordPath = Path.Combine(recordPath, "TV", StringHelper.RemoveSpecialCharacters(info.Name));
            }

            recordPath = Path.Combine(recordPath, RecordingHelper.GetRecordingName(timer, info));
            Directory.CreateDirectory(Path.GetDirectoryName(recordPath));

            var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, info.Id, StringComparison.OrdinalIgnoreCase));

            if (recording == null)
            {
                recording = new RecordingInfo()
                {
                    ChannelId = info.ChannelId,
                    Id = info.Id,
                    StartDate = info.StartDate,
                    EndDate = info.EndDate,
                    Genres = info.Genres ?? null,
                    IsKids = info.IsKids,
                    IsLive = info.IsLive,
                    IsMovie = info.IsMovie,
                    IsHD = info.IsHD,
                    IsNews = info.IsNews,
                    IsPremiere = info.IsPremiere,
                    IsSeries = info.IsSeries,
                    IsSports = info.IsSports,
                    IsRepeat = !info.IsPremiere,
                    Name = info.Name,
                    EpisodeTitle = info.EpisodeTitle ?? "",
                    ProgramId = info.Id,
                    HasImage = info.HasImage ?? false,
                    ImagePath = info.ImagePath ?? null,
                    ImageUrl = info.ImageUrl,
                    OriginalAirDate = info.OriginalAirDate,
                    Status = RecordingStatus.Scheduled,
                    Overview = info.Overview,
                    SeriesTimerId = info.Id.Substring(0, 10)
                };
                _recordingProvider.Add(recording);
            }

            recording.Path = recordPath;
            recording.Status = RecordingStatus.InProgress;
            _recordingProvider.Update(recording);

            try
            {
                httpRequestOptions.BufferContent = false;
                httpRequestOptions.CancellationToken = cancellationToken;
                _logger.Info("Writing file to path: " + recordPath);
                using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
                {
                    using (var output = File.Open(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
                    {
                        await response.Content.CopyToAsync(output, 4096, cancellationToken);
                    }
                }

                recording.Status = RecordingStatus.Completed;
            }
            catch (OperationCanceledException)
            {
                recording.Status = RecordingStatus.Cancelled;
            }
            catch
            {
                recording.Status = RecordingStatus.Error;
            }

            _recordingProvider.Update(recording);
            _timerProvider.Delete(timer);
            _logger.Info("Recording was a success");
        }
Exemple #16
0
        public async Task<TimerInfo> GetTimerInfo(TimerInfoDto dto, bool isNew, LiveTvManager liveTv, CancellationToken cancellationToken)
        {
            var info = new TimerInfo
            {
                Overview = dto.Overview,
                EndDate = dto.EndDate,
                Name = dto.Name,
                StartDate = dto.StartDate,
                Status = dto.Status,
                PrePaddingSeconds = dto.PrePaddingSeconds,
                PostPaddingSeconds = dto.PostPaddingSeconds,
                IsPostPaddingRequired = dto.IsPostPaddingRequired,
                IsPrePaddingRequired = dto.IsPrePaddingRequired,
                Priority = dto.Priority,
                SeriesTimerId = dto.ExternalSeriesTimerId,
                ProgramId = dto.ExternalProgramId,
                ChannelId = dto.ExternalChannelId,
                Id = dto.ExternalId
            };

            // Convert internal server id's to external tv provider id's
            if (!isNew && !string.IsNullOrEmpty(dto.Id) && string.IsNullOrEmpty(info.Id))
            {
                var timer = await liveTv.GetSeriesTimer(dto.Id, cancellationToken).ConfigureAwait(false);

                info.Id = timer.ExternalId;
            }

            if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId))
            {
                var channel = liveTv.GetInternalChannel(dto.ChannelId);

                if (channel != null)
                {
                    info.ChannelId = channel.ExternalId;
                }
            }

            if (!string.IsNullOrEmpty(dto.ProgramId) && string.IsNullOrEmpty(info.ProgramId))
            {
                var program = liveTv.GetInternalProgram(dto.ProgramId);

                if (program != null)
                {
                    info.ProgramId = program.ExternalId;
                }
            }

            if (!string.IsNullOrEmpty(dto.SeriesTimerId) && string.IsNullOrEmpty(info.SeriesTimerId))
            {
                var timer = await liveTv.GetSeriesTimer(dto.SeriesTimerId, cancellationToken).ConfigureAwait(false);

                if (timer != null)
                {
                    info.SeriesTimerId = timer.ExternalId;
                }
            }

            return info;
        }
        private TimerInfo GetTimerInfo(EpgEventJSONObject i)
        {
            var info = new TimerInfo();

            var recurr = i.recurr;
            if (recurr != null)
            {
                if (recurr.OID != 0)
                {
                    info.SeriesTimerId = recurr.OID.ToString(_usCulture);
                }

                info.Name = recurr.RecurringName;
            }

            var schd = i.schd;

            if (schd != null)
            {
                info.ChannelId = schd.ChannelOid.ToString(_usCulture);
                info.Id = schd.OID.ToString(_usCulture);
                info.Status = ParseStatus(schd.Status);
                info.StartDate = DateTime.Parse(schd.StartTime).ToUniversalTime();
                info.EndDate = DateTime.Parse(schd.EndTime).ToUniversalTime();

                info.PrePaddingSeconds = int.Parse(schd.PrePadding, _usCulture) * 60;
                info.PostPaddingSeconds = int.Parse(schd.PostPadding, _usCulture) * 60;

                info.Name = schd.Name;
            }

            var epg = i.epgEvent;

            if (epg != null)
            {
                //info.Audio = ListingsResponse.ParseAudio(epg.Audio);
                info.ProgramId = epg.OID.ToString(_usCulture);
                //info.OfficialRating = epg.Rating;
                //info.EpisodeTitle = epg.Subtitle;
                info.Name = epg.Title;
                info.Overview = epg.Desc;
                //info.Genres = epg.Genres;
                //info.IsRepeat = !epg.FirstRun;
                //info.CommunityRating = ListingsResponse.ParseCommunityRating(epg.StarRating);
                //info.IsHD = string.Equals(epg.Quality, "hdtv", StringComparison.OrdinalIgnoreCase);
            }

            return info;
        }
        /// <summary>
        /// Update a single Timer
        /// </summary>
        /// <param name="info">The program info</param>
        /// <param name="cancellationToken">The CancellationToken</param>
        /// <returns></returns>
        public async Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
        {
            _logger.Info(string.Format("[NextPvr] Start UpdateTimer Async for ChannelId: {0} & Name: {1}", info.ChannelId, info.Name));
            await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);

            var baseUrl = Plugin.Instance.Configuration.WebServiceUrl;

            var options = new HttpRequestOptions
            {
                CancellationToken = cancellationToken,
                Url = string.Format("{0}/public/ScheduleService/UpdateRec?sid={1}", baseUrl, Sid)
            };

            var timerSettings = await GetDefaultScheduleSettings(cancellationToken).ConfigureAwait(false);

            timerSettings.scheduleOID = int.Parse(info.Id);
            timerSettings.post_padding_min = info.PostPaddingSeconds / 60;
            timerSettings.pre_padding_min = info.PrePaddingSeconds / 60;

            var postContent = _jsonSerializer.SerializeToString(timerSettings);
            UtilsHelper.DebugInformation(_logger, string.Format("[NextPvr] TimerSettings UpdateTimer: {0} for ChannelId: {1} & Name: {2}", postContent, info.ChannelId, info.Name));

            options.RequestContent = postContent;
            options.RequestContentType = "application/json";

            try
            {
                await _httpClient.Post(options).ConfigureAwait((false));
            }
            catch (HttpException ex)
            {
                _logger.Error(string.Format("[NextPvr] UpdateTimer Async with exception: {0}", ex.Message));
                throw new LiveTvConflictException();
            }
        }
        public async Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
        {
            Logger.Debug("LiveTvService.UpdateTimerAsync");

            await Task.Run(() => true, cancellationToken);
        }
Exemple #20
0
        private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
        {
            if (timer == null)
            {
                throw new ArgumentNullException("timer");
            }

            ProgramInfo info = null;

            if (string.IsNullOrWhiteSpace(timer.ProgramId))
            {
                _logger.Info("Timer {0} has null programId", timer.Id);
            }
            else
            {
                info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);
            }

            if (info == null)
            {
                _logger.Info("Unable to find program with Id {0}. Will search using start date", timer.ProgramId);
                info = GetProgramInfoFromCache(timer.ChannelId, timer.StartDate);
            }

            if (info == null)
            {
                throw new InvalidOperationException(string.Format("Program with Id {0} not found", timer.ProgramId));
            }

            var recordPath = GetRecordingPath(timer, info);
            var recordingStatus = RecordingStatus.New;
            var isResourceOpen = false;
            SemaphoreSlim semaphore = null;

            try
            {
                var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None).ConfigureAwait(false);
                isResourceOpen = true;
                semaphore = result.Item3;
                var mediaStreamInfo = result.Item1;

                // HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
                //await Task.Delay(3000, cancellationToken).ConfigureAwait(false);

                var recorder = await GetRecorder().ConfigureAwait(false);

                recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
                recordPath = EnsureFileUnique(recordPath, timer.Id);

                _libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
                _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
                activeRecordingInfo.Path = recordPath;

                var duration = recordingEndDate - DateTime.UtcNow;

                _logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));

                _logger.Info("Writing file to path: " + recordPath);
                _logger.Info("Opening recording stream from tuner provider");

                Action onStarted = () =>
                {
                    timer.Status = RecordingStatus.InProgress;
                    _timerProvider.AddOrUpdate(timer, false);

                    result.Item3.Release();
                    isResourceOpen = false;
                };

                var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);

                // If it supports supplying duration via url
                if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase))
                {
                    mediaStreamInfo.Path = pathWithDuration;
                    mediaStreamInfo.RunTimeTicks = duration.Ticks;
                }

                await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);

                recordingStatus = RecordingStatus.Completed;
                _logger.Info("Recording completed: {0}", recordPath);
            }
            catch (OperationCanceledException)
            {
                _logger.Info("Recording stopped: {0}", recordPath);
                recordingStatus = RecordingStatus.Completed;
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Error recording to {0}", ex, recordPath);
                recordingStatus = RecordingStatus.Error;
            }
            finally
            {
                if (isResourceOpen && semaphore != null)
                {
                    semaphore.Release();
                }

                _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);

                ActiveRecordingInfo removed;
                _activeRecordings.TryRemove(timer.Id, out removed);
            }

            if (recordingStatus == RecordingStatus.Completed)
            {
                timer.Status = RecordingStatus.Completed;
                _timerProvider.Delete(timer);

                OnSuccessfulRecording(info.IsSeries, recordPath);
            }
            else if (DateTime.UtcNow < timer.EndDate)
            {
                const int retryIntervalSeconds = 60;
                _logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);

                timer.Status = RecordingStatus.New;
                timer.StartDate = DateTime.UtcNow.AddSeconds(retryIntervalSeconds);
                _timerProvider.AddOrUpdate(timer);
            }
            else
            {
                _timerProvider.Delete(timer);
            }
        }
Exemple #21
0
        private string GetRecordingPath(TimerInfo timer, ProgramInfo info)
        {
            var recordPath = RecordingPath;
            var config = GetConfiguration();

            if (info.IsMovie)
            {
                var customRecordingPath = config.MovieRecordingPath;
                var allowSubfolder = true;
                if (!string.IsNullOrWhiteSpace(customRecordingPath))
                {
                    allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
                    recordPath = customRecordingPath;
                }

                if (allowSubfolder && config.EnableRecordingSubfolders)
                {
                    recordPath = Path.Combine(recordPath, "Movies");
                }

                var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
                if (info.ProductionYear.HasValue)
                {
                    folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
                }
                recordPath = Path.Combine(recordPath, folderName);
            }
            else if (info.IsSeries)
            {
                var customRecordingPath = config.SeriesRecordingPath;
                var allowSubfolder = true;
                if (!string.IsNullOrWhiteSpace(customRecordingPath))
                {
                    allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
                    recordPath = customRecordingPath;
                }

                if (allowSubfolder && config.EnableRecordingSubfolders)
                {
                    recordPath = Path.Combine(recordPath, "Series");
                }

                var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
                var folderNameWithYear = folderName;
                if (info.ProductionYear.HasValue)
                {
                    folderNameWithYear += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
                }

                if (Directory.Exists(Path.Combine(recordPath, folderName)))
                {
                    recordPath = Path.Combine(recordPath, folderName);
                }
                else
                {
                    recordPath = Path.Combine(recordPath, folderNameWithYear);
                }

                if (info.SeasonNumber.HasValue)
                {
                    folderName = string.Format("Season {0}", info.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture));
                    recordPath = Path.Combine(recordPath, folderName);
                }
            }
            else if (info.IsKids)
            {
                if (config.EnableRecordingSubfolders)
                {
                    recordPath = Path.Combine(recordPath, "Kids");
                }

                var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
                if (info.ProductionYear.HasValue)
                {
                    folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
                }
                recordPath = Path.Combine(recordPath, folderName);
            }
            else if (info.IsSports)
            {
                if (config.EnableRecordingSubfolders)
                {
                    recordPath = Path.Combine(recordPath, "Sports");
                }
                recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(info.Name).Trim());
            }
            else
            {
                if (config.EnableRecordingSubfolders)
                {
                    recordPath = Path.Combine(recordPath, "Other");
                }
                recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(info.Name).Trim());
            }

            var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts";

            return Path.Combine(recordPath, recordingFileName);
        }
Exemple #22
0
 public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
 {
     return CreateTimer(info, cancellationToken);
 }
        private List<ScheduleRule> UpdateRules(List<ScheduleRule> rules, TimerInfo timerInfo, SeriesTimerInfo seriesTimerInfo)
        {
            if (timerInfo != null)
            {
                //Single Recording    
                SchedulerHelper.AppendTitleRule(rules, 0, timerInfo.Name);
                SchedulerHelper.AppendChannelsRule(rules, false, new List<Guid> { Guid.Parse(timerInfo.ChannelId) });
                SchedulerHelper.AppendOnDateAndDaysOfWeekRule(rules, ScheduleDaysOfWeek.None, timerInfo.StartDate.ToLocalTime());
                SchedulerHelper.AppendAroundTimeRule(rules, timerInfo.StartDate.ToLocalTime());

            }
            else if (seriesTimerInfo != null)
            {
                //Serie Recording
                SchedulerHelper.AppendTitleRule(rules, 0, seriesTimerInfo.Name);
                SchedulerHelper.AppendOnDateAndDaysOfWeekRule(rules, SchedulerHelper.GetScheduleDaysOfWeek(seriesTimerInfo.Days), seriesTimerInfo.StartDate.ToLocalTime());
                SchedulerHelper.AppendNewEpisodesOnlyRule(rules, seriesTimerInfo.RecordNewOnly);

                if (!seriesTimerInfo.RecordAnyTime)
                {
                    SchedulerHelper.AppendAroundTimeRule(rules, seriesTimerInfo.StartDate.ToLocalTime());
                }

                if (!seriesTimerInfo.RecordAnyChannel)
                {
                    SchedulerHelper.AppendChannelsRule(rules, false, new List<Guid> { Guid.Parse(seriesTimerInfo.ChannelId) });
                }
            }

            return rules;
        }
        /// <summary>
        /// Create a new recording
        /// </summary>
        /// <param name="info">The TimerInfo</param>
        /// <param name="cancellationToken">The cancellationToken</param>
        /// <returns></returns>
        public async Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
        {
            _logger.Debug("[NextPvr] Start CreateTimer Async");
            await EnsureConnectionAsync(cancellationToken).ConfigureAwait(false);

            var baseUrl = Plugin.Instance.Configuration.WebServiceUrl;

            var options = new HttpRequestOptions
            {
                CancellationToken = cancellationToken,
                Url = string.Format("{0}/public/ScheduleService/Record?sid={1}", baseUrl,Sid)
            };

            var timerSettings = await GetDefaultScheduleSettings(cancellationToken).ConfigureAwait(false);

            timerSettings.allChannels = false;
            timerSettings.ChannelOID = int.Parse(info.ChannelId, _usCulture);

            if (!string.IsNullOrEmpty(info.ProgramId))
            {
                timerSettings.epgeventOID = int.Parse(info.ProgramId, _usCulture);
            }

            timerSettings.post_padding_min = info.PostPaddingSeconds / 60;
            timerSettings.pre_padding_min = info.PrePaddingSeconds / 60;

            var postContent = _jsonSerializer.SerializeToString(timerSettings);
            _logger.Debug("[NextPvr] TimerSettings for CreateTimer: {0}", postContent);

            options.RequestContent = postContent;
            options.RequestContentType = "application/json";

            try
            {
                await _httpClient.Post(options).ConfigureAwait((false));
            }
            catch (HttpException ex)
            {
                _logger.Debug("[NextPvr] " + ex.Message);
                throw new LiveTvConflictException();
            }
        }
 public Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
 {
     _timerProvider.Update(info);
     return Task.FromResult(true);
 }
        public Task<IEnumerable<TimerInfo>> buildPendingTimersInfos(CancellationToken cancellationToken)
        {
            return Task.Factory.StartNew<IEnumerable<TimerInfo>>(() =>
            {
                lock (_data)
                {
                    List<TimerInfo> result = new List<TimerInfo>();
                    foreach (KeyValuePair<string, HTSMessage> entry in _data)
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            _logger.Info("[TVHclient] DvrDataHelper.buildDvrInfos, call canceled - returning part list.");
                            return result;
                        }

                        HTSMessage m = entry.Value;
                        TimerInfo ti = new TimerInfo();

                        try
                        {
                            if (m.containsField("id"))
                            {
                                ti.Id = "" + m.getInt("id");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("channel"))
                            {
                                ti.ChannelId = "" + m.getInt("channel");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("start"))
                            {
                                long unixUtc = m.getLong("start");
                                ti.StartDate = _initialDateTimeUTC.AddSeconds(unixUtc).ToUniversalTime();
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("stop"))
                            {
                                long unixUtc = m.getLong("stop");
                                ti.EndDate = _initialDateTimeUTC.AddSeconds(unixUtc).ToUniversalTime();
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("title"))
                            {
                                ti.Name = m.getString("title");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("description"))
                            {
                                ti.Overview = m.getString("description");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("state"))
                            {
                                string state = m.getString("state");
                                switch (state)
                                {
                                    case "scheduled":
                                        ti.Status = RecordingStatus.Scheduled;
                                        break;
                                    default:
                                        // only scheduled timers need to be delivered
                                        continue;
                                }
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("startExtra"))
                            {

                                ti.PrePaddingSeconds = (int)m.getLong("startExtra") * 60;
                                ti.IsPrePaddingRequired = true;
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("stopExtra"))
                            {

                                ti.PostPaddingSeconds = (int)m.getLong("stopExtra") * 60;
                                ti.IsPostPaddingRequired = true;
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("priority"))
                            {
                                ti.Priority = m.getInt("priority");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("autorecId"))
                            {
                                ti.SeriesTimerId = m.getString("autorecId");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        try
                        {
                            if (m.containsField("eventId"))
                            {
                                ti.ProgramId = "" + m.getInt("eventId");
                            }
                        }
                        catch (InvalidCastException)
                        {
                        }

                        result.Add(ti);
                    }
                    return result;
                }
            });
        }
Exemple #27
0
        private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, CancellationToken cancellationToken)
        {
            if (timer == null)
            {
                throw new ArgumentNullException("timer");
            }

            if (string.IsNullOrWhiteSpace(timer.ProgramId))
            {
                throw new InvalidOperationException("timer.ProgramId is null. Cannot record.");
            }

            var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);

            if (info == null)
            {
                throw new InvalidOperationException(string.Format("Program with Id {0} not found", timer.ProgramId));
            }

            var recordPath = RecordingPath;

            if (info.IsMovie)
            {
                recordPath = Path.Combine(recordPath, "Movies", _fileSystem.GetValidFilename(info.Name).Trim());
            }
            else if (info.IsSeries)
            {
                recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name).Trim());
            }
            else if (info.IsKids)
            {
                recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name).Trim());
            }
            else if (info.IsSports)
            {
                recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name).Trim());
            }
            else
            {
                recordPath = Path.Combine(recordPath, "Other", _fileSystem.GetValidFilename(info.Name).Trim());
            }

            var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts";

            recordPath = Path.Combine(recordPath, recordingFileName);
            _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));

            var recordingId = info.Id.GetMD5().ToString("N");
            var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, recordingId, StringComparison.OrdinalIgnoreCase));

            if (recording == null)
            {
                recording = new RecordingInfo
                {
                    ChannelId = info.ChannelId,
                    Id = recordingId,
                    StartDate = info.StartDate,
                    EndDate = info.EndDate,
                    Genres = info.Genres,
                    IsKids = info.IsKids,
                    IsLive = info.IsLive,
                    IsMovie = info.IsMovie,
                    IsHD = info.IsHD,
                    IsNews = info.IsNews,
                    IsPremiere = info.IsPremiere,
                    IsSeries = info.IsSeries,
                    IsSports = info.IsSports,
                    IsRepeat = !info.IsPremiere,
                    Name = info.Name,
                    EpisodeTitle = info.EpisodeTitle,
                    ProgramId = info.Id,
                    ImagePath = info.ImagePath,
                    ImageUrl = info.ImageUrl,
                    OriginalAirDate = info.OriginalAirDate,
                    Status = RecordingStatus.Scheduled,
                    Overview = info.Overview,
                    SeriesTimerId = timer.SeriesTimerId,
                    TimerId = timer.Id,
                    ShowId = info.ShowId
                };
                _recordingProvider.Add(recording);
            }

            try
            {
                var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None);
                var mediaStreamInfo = result.Item1;
                var isResourceOpen = true;

                // Unfortunately due to the semaphore we have to have a nested try/finally
                try
                {
                    // HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
                    await Task.Delay(3000, cancellationToken).ConfigureAwait(false);

                    var duration = recordingEndDate - DateTime.UtcNow;

                    HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
                    {
                        Url = mediaStreamInfo.Path
                    };

                    recording.Path = recordPath;
                    recording.Status = RecordingStatus.InProgress;
                    recording.DateLastUpdated = DateTime.UtcNow;
                    _recordingProvider.Update(recording);

                    _logger.Info("Beginning recording.");

                    httpRequestOptions.BufferContent = false;
                    var durationToken = new CancellationTokenSource(duration);
                    var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
                    httpRequestOptions.CancellationToken = linkedToken;
                    _logger.Info("Writing file to path: " + recordPath);
                    using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
                    {
                        using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
                        {
                            result.Item2.Release();
                            isResourceOpen = false;

                            await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
                        }
                    }

                    recording.Status = RecordingStatus.Completed;
                    _logger.Info("Recording completed");
                }
                finally
                {
                    if (isResourceOpen)
                    {
                        result.Item2.Release();
                    }
                }
            }
            catch (OperationCanceledException)
            {
                _logger.Info("Recording stopped");
                recording.Status = RecordingStatus.Completed;
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Error recording", ex);
                recording.Status = RecordingStatus.Error;
            }
            finally
            {
                CancellationTokenSource removed;
                _activeRecordings.TryRemove(timer.Id, out removed);
            }

            recording.DateLastUpdated = DateTime.UtcNow;
            _recordingProvider.Update(recording);

            if (recording.Status == RecordingStatus.Completed)
            {
                OnSuccessfulRecording(recording);
                _timerProvider.Delete(timer);
            }
            else if (DateTime.UtcNow < timer.EndDate)
            {
                const int retryIntervalSeconds = 60;
                _logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);

                _timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
            }
            else
            {
                _timerProvider.Delete(timer);
                _recordingProvider.Delete(recording);
            }
        }
        public async Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
        {
            Logger.Debug("LiveTvService.CreateTimerAsync");

            await (new Htsp.Dvr()).CreateTimer(info, cancellationToken).ConfigureAwait(false);
        }
Exemple #29
0
 public static DateTime GetStartTime(TimerInfo timer)
 {
     return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds);
 }
Exemple #30
0
        private async Task RecordStream(TimerInfo timer, CancellationToken cancellationToken)
        {
            if (timer == null)
            {
                throw new ArgumentNullException("timer");
            }

            var mediaStreamInfo = await GetChannelStream(timer.ChannelId, null, CancellationToken.None);
            var duration = (timer.EndDate - DateTime.UtcNow).Add(TimeSpan.FromSeconds(timer.PostPaddingSeconds));

            HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
            {
                Url = mediaStreamInfo.Path
            };

            var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);
            var recordPath = RecordingPath;

            if (info.IsMovie)
            {
                recordPath = Path.Combine(recordPath, "Movies", _fileSystem.GetValidFilename(info.Name));
            }
            else if (info.IsSeries)
            {
                recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name));
            }
            else if (info.IsKids)
            {
                recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name));
            }
            else if (info.IsSports)
            {
                recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name));
            }
            else
            {
                recordPath = Path.Combine(recordPath, "Other", _fileSystem.GetValidFilename(info.Name));
            }

            var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)) + ".ts";

            recordPath = Path.Combine(recordPath, recordingFileName);
            Directory.CreateDirectory(Path.GetDirectoryName(recordPath));

            var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase));

            if (recording == null)
            {
                recording = new RecordingInfo
                {
                    ChannelId = info.ChannelId,
                    Id = Guid.NewGuid().ToString("N"),
                    StartDate = info.StartDate,
                    EndDate = info.EndDate,
                    Genres = info.Genres,
                    IsKids = info.IsKids,
                    IsLive = info.IsLive,
                    IsMovie = info.IsMovie,
                    IsHD = info.IsHD,
                    IsNews = info.IsNews,
                    IsPremiere = info.IsPremiere,
                    IsSeries = info.IsSeries,
                    IsSports = info.IsSports,
                    IsRepeat = !info.IsPremiere,
                    Name = info.Name,
                    EpisodeTitle = info.EpisodeTitle,
                    ProgramId = info.Id,
                    HasImage = info.HasImage,
                    ImagePath = info.ImagePath,
                    ImageUrl = info.ImageUrl,
                    OriginalAirDate = info.OriginalAirDate,
                    Status = RecordingStatus.Scheduled,
                    Overview = info.Overview,
                    SeriesTimerId = timer.SeriesTimerId,
                    TimerId = timer.Id,
                    ShowId = info.ShowId
                };
                _recordingProvider.Add(recording);
            }

            recording.Path = recordPath;
            recording.Status = RecordingStatus.InProgress;
            recording.DateLastUpdated = DateTime.UtcNow;
            _recordingProvider.Update(recording);

            _logger.Info("Beginning recording.");
            
            try
            {
                httpRequestOptions.BufferContent = false;
                var durationToken = new CancellationTokenSource(duration);
                var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
                httpRequestOptions.CancellationToken = linkedToken;
                _logger.Info("Writing file to path: " + recordPath);
                using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
                {
                    using (var output = File.Open(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
                    {
                        await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
                    }
                }

                recording.Status = RecordingStatus.Completed;
                _logger.Info("Recording completed");
            }
            catch (OperationCanceledException)
            {
                _logger.Info("Recording stopped");
                recording.Status = RecordingStatus.Completed;
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Error recording", ex);
                recording.Status = RecordingStatus.Error;
            }

            recording.DateLastUpdated = DateTime.UtcNow;
            _recordingProvider.Update(recording);
            _timerProvider.Delete(timer);
            _logger.Info("Recording was a success");

            if (recording.Status == RecordingStatus.Completed)
            {
                OnSuccessfulRecording(recording);
            }
        }