Esempio n. 1
0
        private async Task <object> GetAsync(GetMasterManifest request, string method)
        {
            if (string.Equals(request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException("Audio codec copy is not allowed here.");
            }

            if (string.Equals(request.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException("Video codec copy is not allowed here.");
            }

            if (string.IsNullOrEmpty(request.MediaSourceId))
            {
                throw new ArgumentException("MediaSourceId is required");
            }

            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);

            var playlistText = string.Empty;

            if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase))
            {
                playlistText = GetManifestText(state);
            }

            return(ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.mpd"), new Dictionary <string, string>()));
        }
Esempio n. 2
0
        private string GetMimeType(ImageFormat format, string path)
        {
            if (format == ImageFormat.Bmp)
            {
                return(MimeTypes.GetMimeType("i.bmp"));
            }
            if (format == ImageFormat.Gif)
            {
                return(MimeTypes.GetMimeType("i.gif"));
            }
            if (format == ImageFormat.Jpg)
            {
                return(MimeTypes.GetMimeType("i.jpg"));
            }
            if (format == ImageFormat.Png)
            {
                return(MimeTypes.GetMimeType("i.png"));
            }
            if (format == ImageFormat.Webp)
            {
                return(MimeTypes.GetMimeType("i.webp"));
            }

            return(MimeTypes.GetMimeType(path));
        }
Esempio n. 3
0
        public Task <object> GetStaticFileResult(IRequest requestContext, StaticFileResultOptions options)
        {
            var path      = options.Path;
            var fileShare = options.FileShare;

            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentException("Path can't be empty.", nameof(options));
            }

            if (fileShare != FileShareMode.Read && fileShare != FileShareMode.ReadWrite)
            {
                throw new ArgumentException("FileShare must be either Read or ReadWrite");
            }

            if (string.IsNullOrEmpty(options.ContentType))
            {
                options.ContentType = MimeTypes.GetMimeType(path);
            }

            if (!options.DateLastModified.HasValue)
            {
                options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
            }

            options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));

            options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            return(GetStaticResult(requestContext, options));
        }
Esempio n. 4
0
        public async Task <object> Get(GetSubtitle request)
        {
            if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase))
            {
                request.Format = "json";
            }
            if (string.IsNullOrEmpty(request.Format))
            {
                var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));

                var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null)
                                  .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id));

                var subtitleStream = mediaSource.MediaStreams
                                     .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index);

                return(await ResultFactory.GetStaticFileResult(Request, subtitleStream.Path).ConfigureAwait(false));
            }

            using (var stream = await GetSubtitles(request).ConfigureAwait(false))
            {
                using (var reader = new StreamReader(stream))
                {
                    var text = reader.ReadToEnd();

                    if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap)
                    {
                        text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
                    }

                    return(ResultFactory.GetResult(text, MimeTypes.GetMimeType("file." + request.Format)));
                }
            }
        }
Esempio n. 5
0
        public Task <object> GetStaticFileResult(IRequest requestContext,
                                                 StaticFileResultOptions options)
        {
            var path      = options.Path;
            var fileShare = options.FileShare;

            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }

            if (fileShare != FileShare.Read && fileShare != FileShare.ReadWrite)
            {
                throw new ArgumentException("FileShare must be either Read or ReadWrite");
            }

            if (string.IsNullOrWhiteSpace(options.ContentType))
            {
                options.ContentType = MimeTypes.GetMimeType(path);
            }

            if (!options.DateLastModified.HasValue)
            {
                options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
            }

            var cacheKey = path + options.DateLastModified.Value.Ticks;

            options.CacheKey       = cacheKey.GetMD5();
            options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));

            return(GetStaticResult(requestContext, options));
        }
Esempio n. 6
0
        public async Task <object> Get(GetSubtitlePlaylist request)
        {
            var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));

            var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false);

            var runtime = mediaSource.RunTimeTicks ?? -1;

            if (runtime <= 0)
            {
                throw new ArgumentException("HLS Subtitles are not supported for this media.");
            }

            var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;

            if (segmentLengthTicks <= 0)
            {
                throw new ArgumentException("segmentLength was not given, or it was given incorrectly. (It should be bigger than 0)");
            }

            var builder = new StringBuilder();

            builder.AppendLine("#EXTM3U")
            .Append("#EXT-X-TARGETDURATION:")
            .AppendLine(request.SegmentLength.ToString(CultureInfo.InvariantCulture))
            .AppendLine("#EXT-X-VERSION:3")
            .AppendLine("#EXT-X-MEDIA-SEQUENCE:0")
            .AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");

            long positionTicks = 0;

            var accessToken = _authContext.GetAuthorizationInfo(Request).Token;

            while (positionTicks < runtime)
            {
                var remaining   = runtime - positionTicks;
                var lengthTicks = Math.Min(remaining, segmentLengthTicks);

                builder.Append("#EXTINF:")
                .Append(TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture))
                .AppendLine(",");

                var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);

                var url = string.Format("stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
                                        positionTicks.ToString(CultureInfo.InvariantCulture),
                                        endPositionTicks.ToString(CultureInfo.InvariantCulture),
                                        accessToken);

                builder.AppendLine(url);

                positionTicks += segmentLengthTicks;
            }

            builder.AppendLine("#EXT-X-ENDLIST");

            return(ResultFactory.GetResult(Request, builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>()));
        }
Esempio n. 7
0
        private async Task <object> GetVariantPlaylistInternal(StreamRequest request, bool isOutputVideo, string name)
        {
            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);

            var segmentLengths = GetSegmentLengths(state);

            var builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");
            builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
            builder.AppendLine("#EXT-X-VERSION:3");
            builder.Append("#EXT-X-TARGETDURATION:")
            .AppendLine(Math.Ceiling(segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength).ToString(CultureInfo.InvariantCulture));
            builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");

            var queryStringIndex = Request.RawUrl.IndexOf('?');
            var queryString      = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);

            // if ((Request.UserAgent ?? string.Empty).IndexOf("roku", StringComparison.OrdinalIgnoreCase) != -1)
            //{
            //    queryString = string.Empty;
            //}

            var index = 0;

            foreach (var length in segmentLengths)
            {
                builder.Append("#EXTINF:")
                .Append(length.ToString("0.0000", CultureInfo.InvariantCulture))
                .AppendLine(", nodesc");

                builder.AppendFormat(
                    CultureInfo.InvariantCulture,
                    "hls1/{0}/{1}{2}{3}",
                    name,
                    index.ToString(CultureInfo.InvariantCulture),
                    GetSegmentFileExtension(request),
                    queryString).AppendLine();

                index++;
            }

            builder.AppendLine("#EXT-X-ENDLIST");

            var playlistText = builder.ToString();

            return(ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>()));
        }
Esempio n. 8
0
        public object Get(GetSubtitlePlaylist request)
        {
            var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));

            var mediaSource = item.GetMediaSources(false)
                              .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id));

            var builder = new StringBuilder();

            var runtime = mediaSource.RunTimeTicks ?? -1;

            if (runtime <= 0)
            {
                throw new ArgumentException("HLS Subtitles are not supported for this media.");
            }

            builder.AppendLine("#EXTM3U");
            builder.AppendLine("#EXT-X-TARGETDURATION:" + request.SegmentLength.ToString(CultureInfo.InvariantCulture));
            builder.AppendLine("#EXT-X-VERSION:3");
            builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");

            long positionTicks      = 0;
            var  segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;

            while (positionTicks < runtime)
            {
                var remaining   = runtime - positionTicks;
                var lengthTicks = Math.Min(remaining, segmentLengthTicks);

                builder.AppendLine("#EXTINF:" + TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture));

                var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);

                var url = string.Format("stream.srt?StartPositionTicks={0}&EndPositionTicks={1}",
                                        positionTicks.ToString(CultureInfo.InvariantCulture),
                                        endPositionTicks.ToString(CultureInfo.InvariantCulture));

                builder.AppendLine(url);

                positionTicks += segmentLengthTicks;
            }

            builder.AppendLine("#EXT-X-ENDLIST");

            return(ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>()));
        }
Esempio n. 9
0
        public Task <object> GetStaticFileResult(IRequest requestContext,
                                                 StaticFileResultOptions options)
        {
            var path      = options.Path;
            var fileShare = options.FileShare;

            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }

            if (fileShare != FileShareMode.Read && fileShare != FileShareMode.ReadWrite)
            {
                throw new ArgumentException("FileShare must be either Read or ReadWrite");
            }

            if (string.IsNullOrWhiteSpace(options.ContentType))
            {
                options.ContentType = MimeTypes.GetMimeType(path);
            }

            if (!options.DateLastModified.HasValue)
            {
                options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
            }

            var cacheKey = path + options.DateLastModified.Value.Ticks;

            options.CacheKey       = cacheKey.GetMD5();
            options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));

            options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            if (!options.ResponseHeaders.ContainsKey("Content-Disposition"))
            {
                // Quotes are valid in linux. They'll possibly cause issues here
                var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
                if (!string.IsNullOrWhiteSpace(filename))
                {
                    options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\"";
                }
            }

            return(GetStaticResult(requestContext, options));
        }
Esempio n. 10
0
        private async Task <object> GetPlaylistAsync(VideoStreamRequest request, string name)
        {
            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);

            var builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");
            builder.AppendLine("#EXT-X-VERSION:3");
            builder.AppendLine("#EXT-X-TARGETDURATION:" + state.SegmentLength.ToString(UsCulture));
            builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
            builder.AppendLine("#EXT-X-ALLOW-CACHE:NO");

            var queryStringIndex = Request.RawUrl.IndexOf('?');
            var queryString      = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);

            var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;

            var index = 0;

            while (seconds > 0)
            {
                var length = seconds >= state.SegmentLength ? state.SegmentLength : seconds;

                builder.AppendLine("#EXTINF:" + length.ToString(UsCulture) + ",");

                builder.AppendLine(string.Format("hlsdynamic/{0}/{1}.ts{2}",

                                                 name,
                                                 index.ToString(UsCulture),
                                                 queryString));

                seconds -= state.SegmentLength;
                index++;
            }

            builder.AppendLine("#EXT-X-ENDLIST");

            var playlistText = builder.ToString();

            return(ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>()));
        }
Esempio n. 11
0
        private async Task <object> GetMasterPlaylistInternal(StreamRequest request, string method)
        {
            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);

            if (string.IsNullOrEmpty(request.MediaSourceId))
            {
                throw new ArgumentException("MediaSourceId is required");
            }

            var playlistText = string.Empty;

            if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase))
            {
                var audioBitrate = state.OutputAudioBitrate ?? 0;
                var videoBitrate = state.OutputVideoBitrate ?? 0;

                playlistText = GetMasterPlaylistFileText(state, videoBitrate + audioBitrate);
            }

            return(ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>()));
        }
Esempio n. 12
0
        private async Task <object> GetVariantPlaylistInternal(StreamRequest request, bool isOutputVideo, string name)
        {
            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);

            var segmentLengths = GetSegmentLengths(state);

            var builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");
            builder.AppendLine("#EXT-X-VERSION:3");
            builder.AppendLine("#EXT-X-TARGETDURATION:" + Math.Ceiling((segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength)).ToString(UsCulture));
            builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");

            var queryStringIndex = Request.RawUrl.IndexOf('?');
            var queryString      = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);

            var index = 0;

            foreach (var length in segmentLengths)
            {
                builder.AppendLine("#EXTINF:" + length.ToString("0.000000", UsCulture) + ",");

                builder.AppendLine(string.Format("hlsdynamic/{0}/{1}{2}{3}",

                                                 name,
                                                 index.ToString(UsCulture),
                                                 GetSegmentFileExtension(isOutputVideo),
                                                 queryString));

                index++;
            }

            builder.AppendLine("#EXT-X-ENDLIST");

            var playlistText = builder.ToString();

            return(ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>()));
        }
Esempio n. 13
0
        public object Get(GetSubtitle request)
        {
            if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase))
            {
                request.Format = "json";
            }
            if (string.IsNullOrEmpty(request.Format))
            {
                var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));

                var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null)
                                  .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id));

                var subtitleStream = mediaSource.MediaStreams
                                     .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index);

                return(ToStaticFileResult(subtitleStream.Path));
            }

            var stream = GetSubtitles(request).Result;

            return(ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format)));
        }
Esempio n. 14
0
        public async Task <object> Get(GetRemoteSubtitles request)
        {
            var result = await _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).ConfigureAwait(false);

            return(ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format)));
        }
Esempio n. 15
0
        public object Get(GetRemoteSubtitles request)
        {
            var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result;

            return(ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format)));
        }