Ejemplo n.º 1
0
        public async Task <Episode> Build(SonarrSharp.Models.Episode episode)
        {
            var mediaFileId = new MediaFileId
            {
                Provider = Providers.Sonarr,
                MediaId  = episode.SeriesId,
                FileId   = episode.EpisodeFileId,
            };
            var sessionRepo = await _sessionRepoFactory.GetRepo();

            var allSessionsForCurrentEpisode = (await sessionRepo.GetAll())
                                               .Where(session => session.MediaId == mediaFileId.ToString())
                                               .ToList();

            var lastSession = allSessionsForCurrentEpisode.OrderByDescending(session => session.EndUTC).FirstOrDefault();

            return(new Episode
            {
                Title = GrpcStringParser.Parse(episode.Title),
                Overview = GrpcStringParser.Parse(episode.Overview),
                SeriesId = episode.SeriesId,
                SeasonNumber = episode.SeasonNumber,
                EpisideNumber = episode.EpisodeNumber,
                EpisodeFileId = episode.EpisodeFileId,
                PlayableId = mediaFileId.ToString(),
                Progress = new Progress
                {
                    LastWatchedUtc = lastSession?.EndUTC ?? 0,
                    WatchedInSec = lastSession?.Duration.EndPostionInSec ?? 0,
                    Lenght = lastSession?.MediaLenghtInSec ?? 0
                },
            });
        }
Ejemplo n.º 2
0
        public MediaServer.Storage.ProtoGenerated.Session CreateNewSession
        (
            MediaFileId mediaFileId,
            TimeSpan mediaDuration,
            TimeSpan?startPosition = null
        )
        {
            var timeWatched = new Duration {
                EndPostionInSec = 0, StartPostionInSec = 0
            };

            if (startPosition.HasValue)
            {
                timeWatched.StartPostionInSec = startPosition.Value.TotalSeconds;
                timeWatched.EndPostionInSec   = startPosition.Value.TotalSeconds;
            }

            var session = new MediaServer.Storage.ProtoGenerated.Session
            {
                Id               = Guid.NewGuid().ToString("N"),
                MediaId          = mediaFileId.ToString(),
                Duration         = timeWatched,
                StartUTC         = _timeService.GetCurrentTimeAsUnixSeconds(),
                EndUTC           = _timeService.GetCurrentTimeAsUnixSeconds(),
                MediaLenghtInSec = mediaDuration.TotalSeconds,
            };

            return(session);
        }
Ejemplo n.º 3
0
        public async Task <ActionResult> DownloadFile(string mediaFileIdStr)
        {
            if (!MediaFileId.TryParse(mediaFileIdStr, out var mediaFileId))
            {
                return(BadRequest($"{nameof(mediaFileIdStr)} is invalid"));
            }

            await _fileDownloadService.DownloadFile(mediaFileId);

            return(StatusCode(202));
        }
Ejemplo n.º 4
0
        public async Task <ActionResult> PlayMedia(string mediaFileIdStr, double startPositionInSec)
        {
            if (!MediaFileId.TryParse(mediaFileIdStr, out var mediaFileId))
            {
                return(BadRequest($"{nameof(mediaFileIdStr)} is invalid"));
            }

            if (startPositionInSec < 0)
            {
                return(BadRequest($"{nameof(startPositionInSec)} must be > 0"));
            }

            var settings = _settingsService.Get();

            if (string.IsNullOrWhiteSpace(settings.System.MpvPath))
            {
                return(BadRequest("mpv path must be set in the settings tab"));
            }

            if (!_processManager.IsMpvRunning())
            {
                var arguments = new[] { $"--input-ipc-server={NamedPipeFactory.GetPipeNameForCurrentOs()}" };
                _processManager.StartProcess(settings.System.MpvPath, arguments);
            }

            if (!_processManager.IsSvpRunning() && !string.IsNullOrWhiteSpace(settings.System.SvpPath))
            {
                _processManager.StartProcess(settings.System.SvpPath);
            }

            var fileInfo = await _fileLookupProvider.GetFileInfoForId(mediaFileId.FileId);

            _queue.AddToQueue(new Item
            {
                Path          = fileInfo.Path,
                MediaFileId   = mediaFileId,
                StartPosition = TimeSpan.FromSeconds(startPositionInSec),
            });

            return(StatusCode(202));
        }
Ejemplo n.º 5
0
        public override async Task Download
        (
            DownloadFileRequest request,
            IServerStreamWriter <ResponseDownloadFile> responseStream,
            ServerCallContext context
        )
        {
            if (!MediaFileId.TryParse(request.MediaFileId, out var mediaFileId))
            {
                throw new Exception("Invalid mediaFileId");
            }

            var info = await _episodeFileLookupProvider.GetFileInfoForId(mediaFileId.FileId);


            var backSlashIndex = info.Path.LastIndexOf("\\", StringComparison.CurrentCultureIgnoreCase);
            var index          = backSlashIndex > -1 ? backSlashIndex : info.Path.LastIndexOf("/", StringComparison.CurrentCultureIgnoreCase);

            var fileName = info.Path.Substring(index + 1);

            var chunkSize = 2048;

            using (Stream source = File.OpenRead(info.Path))
            {
                byte[] buffer = new byte[chunkSize];
                int    bytesRead;

                await responseStream.WriteAsync(new ResponseDownloadFile
                {
                    Started = new Started
                    {
                        FileName     = fileName,
                        Lenght       = source.Length,
                        SizePerChunk = chunkSize,
                    }
                });


                while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
                {
                    await responseStream.WriteAsync(new ResponseDownloadFile
                    {
                        Progress = new Chunk
                        {
                            Content = ByteString.CopyFrom(buffer, 0, bytesRead)
                        }
                    });
                }

                source.Seek(0, SeekOrigin.Begin);

                string hash;
                using (var md5 = MD5.Create())
                {
                    var byteHash = md5.ComputeHash(source);
                    hash = BitConverter.ToString(byteHash).Replace("-", "").ToLowerInvariant();
                }

                await responseStream.WriteAsync(new ResponseDownloadFile
                {
                    Done = new Done
                    {
                        Hash = hash
                    }
                });
            }
        }
Ejemplo n.º 6
0
        public async Task DownloadFile(MediaFileId id)
        {
            var streamingCall = _client.Download(new DownloadFileRequest
            {
                MediaFileId = id.ToString(),
            });

            var settings = _settingsService.Get();


            double nrOfChunks = 0;

            var currentChunk         = 0;
            var currentTempFileIndex = 0;

            FileStream fileStream = null;

            const int tempFileSize = 1024 * 10 * 10;

            var fileName = "";

            _logger.LogInformation($"Starting to download file");

            var stopwatch = Stopwatch.StartNew();

            while (await streamingCall.ResponseStream.MoveNext(CancellationToken.None))
            {
                var res = streamingCall.ResponseStream.Current;

                switch (res.TypeCase)
                {
                case ResponseDownloadFile.TypeOneofCase.Started:
                    fileName   = res.Started.FileName;
                    nrOfChunks = (int)Math.Ceiling(res.Started.Lenght / res.Started.SizePerChunk);
                    _logger.LogTrace($"Length is {res.Started.Lenght}");
                    _logger.LogTrace($"ChunkSize is {res.Started.SizePerChunk}");
                    _logger.LogTrace($"Nr of chunks should be {nrOfChunks}");
                    break;

                case ResponseDownloadFile.TypeOneofCase.Progress:
                    if (currentChunk % tempFileSize == 0)
                    {
                        if (fileStream != null)
                        {
                            fileStream.Close();
                            fileStream.Dispose();
                        }

                        fileStream = File.Create(settings.System.TempFileDir + $"{fileName}.{currentTempFileIndex}.temp");

                        currentTempFileIndex++;
                    }

                    var byteArray = res.Progress.Content.ToByteArray();
                    await fileStream.WriteAsync(byteArray, 0, byteArray.Length);

                    if (currentChunk % 1000 == 0)
                    {
                        _logger.LogTrace($"Progress {currentChunk / nrOfChunks:P}");
                    }

                    currentChunk++;
                    break;

                case ResponseDownloadFile.TypeOneofCase.Done:
                    _logger.LogDebug($"Downloaded chunks in {stopwatch.Elapsed:g}");

                    fileStream.Close();
                    fileStream.Dispose();

                    var sw          = Stopwatch.StartNew();
                    var filePattern = $"{fileName}.*.temp";
                    await _fileService.CombineMultipleFilesIntoSingleFile(settings.System.TempFileDir, filePattern, settings.System.FileDir + fileName);

                    string hash;
                    using (Stream source = File.OpenRead(settings.System.FileDir + fileName))
                        using (var md5 = MD5.Create())
                        {
                            var byteHash = md5.ComputeHash(source);
                            hash = BitConverter.ToString(byteHash).Replace("-", "").ToLowerInvariant();
                        }

                    // TODO
                    //This needs to be the zip:ed file, else there will be a missmatch.
//                        if (hash != res.Done.Hash)
//                        {
//                            throw new HashMismatchException(res.Done.Hash, hash);
//                        }

                    _logger.LogDebug($"Combined files in {sw.Elapsed:g}");
                    sw.Stop();
                    break;

                case ResponseDownloadFile.TypeOneofCase.None:
                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            stopwatch.Stop();

            _logger.LogInformation($"It took {stopwatch.Elapsed:g}");
        }