< Summary - Jellyfin

Information
Class: Jellyfin.LiveTv.IO.DirectRecorder
Assembly: Jellyfin.LiveTv
File(s): /srv/git/jellyfin/src/Jellyfin.LiveTv/IO/DirectRecorder.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 9
Coverable lines: 9
Total lines: 118
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 2
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
GetOutputPath(...)100%210%
Record(...)0%620%
Dispose()100%210%

File(s)

/srv/git/jellyfin/src/Jellyfin.LiveTv/IO/DirectRecorder.cs

#LineLine coverage
 1#pragma warning disable CS1591
 2
 3using System;
 4using System.IO;
 5using System.Net.Http;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using MediaBrowser.Common.Net;
 9using MediaBrowser.Controller.Library;
 10using MediaBrowser.Controller.Streaming;
 11using MediaBrowser.Model.Dto;
 12using MediaBrowser.Model.IO;
 13using Microsoft.Extensions.Logging;
 14
 15namespace Jellyfin.LiveTv.IO
 16{
 17    public sealed class DirectRecorder : IRecorder
 18    {
 19        private readonly ILogger _logger;
 20        private readonly IHttpClientFactory _httpClientFactory;
 21        private readonly IStreamHelper _streamHelper;
 22
 23        public DirectRecorder(ILogger logger, IHttpClientFactory httpClientFactory, IStreamHelper streamHelper)
 24        {
 025            _logger = logger;
 026            _httpClientFactory = httpClientFactory;
 027            _streamHelper = streamHelper;
 028        }
 29
 30        public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
 31        {
 032            return targetFile;
 33        }
 34
 35        public Task Record(IDirectStreamProvider? directStreamProvider, MediaSourceInfo mediaSource, string targetFile, 
 36        {
 037            if (directStreamProvider is not null)
 38            {
 039                return RecordFromDirectStreamProvider(directStreamProvider, targetFile, duration, onStarted, cancellatio
 40            }
 41
 042            return RecordFromMediaSource(mediaSource, targetFile, duration, onStarted, cancellationToken);
 43        }
 44
 45        private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile,
 46        {
 47            Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a 
 48
 49            var output = new FileStream(
 50                targetFile,
 51                FileMode.CreateNew,
 52                FileAccess.Write,
 53                FileShare.Read,
 54                IODefaults.FileStreamBufferSize,
 55                FileOptions.Asynchronous);
 56
 57            await using (output.ConfigureAwait(false))
 58            {
 59                onStarted();
 60
 61                _logger.LogInformation("Copying recording to file {FilePath}", targetFile);
 62
 63                // The media source is infinite so we need to handle stopping ourselves
 64                using var durationToken = new CancellationTokenSource(duration);
 65                using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, d
 66                var linkedCancellationToken = cancellationTokenSource.Token;
 67                var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream());
 68                await using (fileStream.ConfigureAwait(false))
 69                {
 70                    await _streamHelper.CopyToAsync(
 71                        fileStream,
 72                        output,
 73                        IODefaults.CopyToBufferSize,
 74                        1000,
 75                        linkedCancellationToken).ConfigureAwait(false);
 76                }
 77            }
 78
 79            _logger.LogInformation("Recording completed: {FilePath}", targetFile);
 80        }
 81
 82        private async Task RecordFromMediaSource(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Acti
 83        {
 84            using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
 85                .GetAsync(mediaSource.Path, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(
 86
 87            _logger.LogInformation("Opened recording stream from tuner provider");
 88
 89            Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a 
 90
 91            var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.Cop
 92            await using (output.ConfigureAwait(false))
 93            {
 94                onStarted();
 95
 96                _logger.LogInformation("Copying recording stream to file {0}", targetFile);
 97
 98                // The media source if infinite so we need to handle stopping ourselves
 99                using var durationToken = new CancellationTokenSource(duration);
 100                using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, d
 101                cancellationToken = linkedCancellationToken.Token;
 102
 103                await _streamHelper.CopyUntilCancelled(
 104                    await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false),
 105                    output,
 106                    IODefaults.CopyToBufferSize,
 107                    cancellationToken).ConfigureAwait(false);
 108
 109                _logger.LogInformation("Recording completed to file {0}", targetFile);
 110            }
 111        }
 112
 113        /// <inheritdoc />
 114        public void Dispose()
 115        {
 0116        }
 117    }
 118}