Exemplo n.º 1
0
        internal static WebTVSeasonBasic TVSeasonBasic(IOwinContext context, MediaItem item, Guid?showId = null)
        {
            Guid?       user = ResourceAccessUtils.GetUser(context);
            ISet <Guid> necessaryMIATypespisodes = new HashSet <Guid>();

            necessaryMIATypespisodes.Add(MediaAspect.ASPECT_ID);
            necessaryMIATypespisodes.Add(EpisodeAspect.ASPECT_ID);

            IFilter unwatchedEpisodeFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And,
                                                                                     new RelationshipFilter(EpisodeAspect.ROLE_EPISODE, SeasonAspect.ROLE_SEASON, item.MediaItemId),
                                                                                     new RelationalUserDataFilter(user.Value, UserDataKeysKnown.KEY_PLAY_PERCENTAGE, RelationalOperator.LT, UserDataKeysKnown.GetSortablePlayPercentageString(100), true));

            int unwatchedCount = MediaLibraryAccess.CountMediaItems(context, necessaryMIATypespisodes, unwatchedEpisodeFilter);

            GetShowId(item, ref showId);

            var mediaAspect    = item.GetAspect(MediaAspect.Metadata);
            var seasonAspect   = item.GetAspect(SeasonAspect.Metadata);
            var importerAspect = item.GetAspect(ImporterAspect.Metadata);

            DateTime?firstAired = mediaAspect.GetAttributeValue <DateTime?>(MediaAspect.ATTR_RECORDINGTIME);

            return(new WebTVSeasonBasic
            {
                Title = mediaAspect.GetAttributeValue <string>(MediaAspect.ATTR_TITLE),
                Id = item.MediaItemId.ToString(),
                ShowId = showId.HasValue ? showId.Value.ToString() : null,
                SeasonNumber = seasonAspect.GetAttributeValue <int>(SeasonAspect.ATTR_SEASON),
                EpisodeCount = seasonAspect.GetAttributeValue <int>(SeasonAspect.ATTR_AVAILABLE_EPISODES),
                UnwatchedEpisodeCount = unwatchedCount,
                DateAdded = importerAspect.GetAttributeValue <DateTime>(ImporterAspect.ATTR_DATEADDED),
                Year = firstAired.HasValue ? firstAired.Value.Year : 0,
            });
        }
Exemplo n.º 2
0
        public static async Task <WebStringResult> ProcessAsync(IOwinContext context, string identifier, string profileName, long startPosition)
        {
            if (identifier == null)
            {
                throw new BadRequestException("InitStream: identifier is null");
            }
            if (profileName == null)
            {
                throw new BadRequestException("InitStream: profileName is null");
            }

            StreamItem streamItem = await StreamControl.GetStreamItemAsync(identifier);

            if (streamItem == null)
            {
                throw new BadRequestException(string.Format("StartStream: Unknown identifier: {0}", identifier));
            }

            // Prefer getting profile by name
            EndPointProfile profile = ProfileManager.Profiles.Values.FirstOrDefault(p => p.Name == profileName);

            // If no ptofile with the specified name, see if there's one with a matching id
            if (profile == null && !ProfileManager.Profiles.TryGetValue(profileName, out profile))
            {
                throw new BadRequestException(string.Format("StartStream: Unknown profile: {0}", profileName));
            }

            streamItem.Profile = profile;
            // Seeking is not supported in live streams
            streamItem.StartPosition = streamItem.RequestedMediaItem is LiveTvMediaItem ? 0 : startPosition;

            Guid?userId = ResourceAccessUtils.GetUser(context);

            streamItem.TranscoderObject = new ProfileMediaItem(identifier, profile, streamItem.IsLive);
            await streamItem.TranscoderObject.Initialize(userId, streamItem.RequestedMediaItem, null);

            if (streamItem.TranscoderObject.TranscodingParameter is VideoTranscoding vt)
            {
                vt.HlsBaseUrl = string.Format("RetrieveStream?identifier={0}&hls=", identifier);
            }

            await StreamControl.StartStreamingAsync(identifier, startPosition);

            string filePostFix = "&file=media.ts";

            if (profile.MediaTranscoding?.VideoTargets?.Any(t => t.Target.VideoContainerType == VideoContainer.Hls) ?? false)
            {
                filePostFix = "&file=manifest.m3u8"; //Must be added for some clients to work (Android mostly)
            }
            string url = GetBaseStreamUrl.GetBaseStreamURL(context) + "/MPExtended/StreamingService/stream/RetrieveStream?identifier=" + identifier + filePostFix;

            return(new WebStringResult {
                Result = url
            });
        }
Exemplo n.º 3
0
        protected static async Task SendAsync(IOwinContext context, Stream resourceStream, ProfileMediaItem item, EndPointProfile profile, bool onlyHeaders, bool partialResource, Range byteRange)
        {
            if (onlyHeaders)
            {
                return;
            }

            bool clientDisconnected = false;
            Guid streamID           = item.StartStreaming();

            if (streamID == Guid.Empty)
            {
                Logger.Error("BaseSendData: Unable to start stream");
                return;
            }
            try
            {
                if (context.Response.ContentLength == 0)
                {
                    //Not allowed to have a content length of zero
                    context.Response.ContentLength = null;
                }
                Logger.Debug("BaseSendData: Sending chunked: {0}", context.Response.ContentLength == null);
                string clientID   = context.Request.RemoteIpAddress;
                int    bufferSize = profile.Settings.Communication.DefaultBufferSize;
                if (bufferSize <= 0)
                {
                    bufferSize = 1500;
                }
                byte[] buffer = new byte[bufferSize];
                int    bytesRead;
                long   count       = 0;
                bool   isStream    = false;
                long   waitForSize = 0;
                if (byteRange.Length == 0 || (byteRange.Length > 0 && byteRange.Length >= profile.Settings.Communication.InitialBufferSize))
                {
                    waitForSize = profile.Settings.Communication.InitialBufferSize;
                }
                if (partialResource == false)
                {
                    if (waitForSize < byteRange.From)
                    {
                        waitForSize = byteRange.From;
                    }
                }
                if (await WaitForMinimumFileSizeAsync(resourceStream, waitForSize) == false)
                {
                    Logger.Error("BaseSendData: Unable to send stream because of invalid length: {0} ({1} required)", resourceStream.Length, waitForSize);
                    return;
                }

                long start = 0;
                if (partialResource == false)
                {
                    start = byteRange.From;
                }
                if (resourceStream.CanSeek)
                {
                    resourceStream.Seek(start, SeekOrigin.Begin);
                }
                long length = byteRange.Length;
                if (length <= 0 || item.IsLive || (item.IsSegmented == false && item.IsTranscoding == true))
                {
                    isStream = true;
                }
                int emptyCount = 0;
                while (item.IsStreamActive(streamID))
                {
                    if (isStream)
                    {
                        if (resourceStream.CanSeek)
                        {
                            length = resourceStream.Length - count;
                        }
                        else
                        {
                            length = bufferSize; //Keep stream alive
                        }
                    }
                    bytesRead = await resourceStream.ReadAsync(buffer, 0, length > bufferSize?bufferSize : (int)length);

                    count += bytesRead;

                    if (bytesRead > 0)
                    {
                        emptyCount = 0;
                        try
                        {
                            //Send fetched bytes
                            await context.Response.WriteAsync(buffer, 0, bytesRead, SendDataCancellation.Token);
                        }
                        catch (Exception)
                        {
                            // Client disconnected
                            Logger.Debug("BaseSendData: Connection lost after {0} bytes", count);
                            clientDisconnected = true;
                            break;
                        }
                        length -= bytesRead;

                        if (isStream == false && length <= 0)
                        {
                            //All bytes in the requested range sent
                            break;
                        }
                    }
                    else
                    {
                        emptyCount++;
                        if (emptyCount > 2)
                        {
                            Logger.Debug("BaseSendData: Buffer underrun delay");
                            await Task.Delay(100);
                        }
                        if (emptyCount > 10)
                        {
                            //Stream is not getting any bigger
                            break;
                        }
                    }

                    if (resourceStream.CanSeek)
                    {
                        if (item.IsTranscoding == false && resourceStream.Position == resourceStream.Length)
                        {
                            //No more data will be available
                            break;
                        }
                    }
                }
            }
            finally
            {
                item.StopStreaming(streamID);

                if (clientDisconnected || item.IsSegmented == false)
                {
                    if (clientDisconnected == false)
                    {
                        //Everything sent to client so presume watched
                        if (item.IsLive == false)
                        {
                            Guid?         userId  = ResourceAccessUtils.GetUser(context);
                            IMediaLibrary library = ServiceRegistration.Get <IMediaLibrary>();
                            if (library != null && userId.HasValue)
                            {
                                library.NotifyUserPlayback(userId.Value, item.MediaItemId, 100, true);
                            }
                        }
                    }
                }
                Logger.Debug("BaseSendData: Sending complete");
            }
        }
Exemplo n.º 4
0
        public static async Task <WebStringResult> ProcessAsync(IOwinContext context, string identifier, string profileName, long startPosition, int audioId = -1, int subtitleId = -1)
        {
            if (identifier == null)
            {
                throw new BadRequestException("StartStreamWithStreamSelection: identifier is null");
            }
            if (profileName == null)
            {
                throw new BadRequestException("StartStreamWithStreamSelection: profileName is null");
            }

            EndPointProfile        profile       = null;
            List <EndPointProfile> namedProfiles = ProfileManager.Profiles.Where(x => x.Value.Name == profileName).Select(namedProfile => namedProfile.Value).ToList();

            if (namedProfiles.Count > 0)
            {
                profile = namedProfiles[0];
            }
            else if (ProfileManager.Profiles.ContainsKey(profileName))
            {
                profile = ProfileManager.Profiles[profileName];
            }
            if (profile == null)
            {
                throw new BadRequestException(string.Format("StartStreamWithStreamSelection: unknown profile: {0}", profileName));
            }

            StreamItem streamItem = await StreamControl.GetStreamItemAsync(identifier);

            if (streamItem == null)
            {
                throw new BadRequestException(string.Format("StartStreamWithStreamSelection: unknown identifier: {0}", identifier));
            }

            streamItem.Profile       = profile;
            streamItem.StartPosition = startPosition;
            if (streamItem.RequestedMediaItem is LiveTvMediaItem)
            {
                streamItem.StartPosition = 0;
            }

            Guid?userId = ResourceAccessUtils.GetUser(context);

            streamItem.TranscoderObject = new ProfileMediaItem(identifier, profile, streamItem.IsLive);
            await streamItem.TranscoderObject.Initialize(userId, streamItem.RequestedMediaItem, audioId >= 0?audioId : (int?)null, subtitleId);

            if ((streamItem.TranscoderObject.TranscodingParameter is VideoTranscoding vt))
            {
                vt.HlsBaseUrl = string.Format("RetrieveStream?identifier={0}&hls=", identifier);
            }

            await StreamControl.StartStreamingAsync(identifier, startPosition);

            string filePostFix = "&file=media.ts";

            if (profile.MediaTranscoding != null && profile.MediaTranscoding.VideoTargets != null)
            {
                foreach (var target in profile.MediaTranscoding.VideoTargets)
                {
                    if (target.Target.VideoContainerType == VideoContainer.Hls)
                    {
                        filePostFix = "&file=manifest.m3u8"; //Must be added for some clients to work (Android mostly)
                        break;
                    }
                }
            }

            string url = GetBaseStreamUrl.GetBaseStreamURL(context) + "/MPExtended/StreamingService/stream/RetrieveStream?identifier=" + identifier + filePostFix;

            return(new WebStringResult {
                Result = url
            });
        }