Task <ICommentSession> CreateCommentSession(string contentId, DmcWatchData watchData)
        {
            var commentClient = new CommentClient(_niconicoSession, contentId);
            var dmcRes        = watchData.DmcWatchResponse;

            commentClient.CommentServerInfo = new CommentServerInfo()
            {
                ServerUrl         = dmcRes.Thread.ServerUrl,
                VideoId           = contentId,
                DefaultThreadId   = int.Parse(dmcRes.Thread.Ids.Default),
                ViewerUserId      = dmcRes.Viewer.Id,
                ThreadKeyRequired = dmcRes.Video.IsOfficial
            };

            // チャンネル動画ではOnwerはnullになる
            commentClient.VideoOwnerId = dmcRes.Owner?.Id;

            commentClient.DmcWatch = dmcRes;

            if (int.TryParse(dmcRes.Thread.Ids.Community, out var communityThreadId))
            {
                commentClient.CommentServerInfo.CommunityThreadId = communityThreadId;
                Debug.WriteLine("dmcRes.Video.DmcInfo.Thread.PostkeyAvailable: " + dmcRes.Video.DmcInfo?.Thread?.PostkeyAvailable);
            }

            return(Task.FromResult(new VideoCommentService(commentClient) as ICommentSession));
        }
        public PreparePlayVideoResult(string contentId, NiconicoSession niconicoSession, NicoVideoSessionOwnershipManager ownershipManager, DmcWatchData dmcWatchData)
            : this(contentId, niconicoSession)
        {
            _ownershipManager = ownershipManager;
            _dmcWatchData     = dmcWatchData;
            IsSuccess         = _dmcWatchData != null;
            if (_dmcWatchData?.DmcWatchResponse.Video.DmcInfo != null)
            {
                AvailableQualities = _dmcWatchData.DmcWatchResponse.Video.DmcInfo.Quality.Videos
                                     .Select(x => new NicoVideoQualityEntity(x.Available, QualityIdToNicoVideoQuality(x.Id), x.Id, x.Bitrate, x.Resolution?.Width, x.Resolution?.Height))
                                     .ToImmutableArray();
            }
            else if (_dmcWatchData.DmcWatchResponse.Video.SmileInfo != null)
            {
                var video     = _dmcWatchData.DmcWatchResponse.Video;
                var smileInfo = _dmcWatchData.DmcWatchResponse.Video.SmileInfo;
                var quality   = smileInfo.Url.EndsWith("low") ? NicoVideoQuality.Smile_Low : NicoVideoQuality.Smile_Original;

                AvailableQualities = new[]
                {
                    new NicoVideoQualityEntity(false, NicoVideoQuality.Smile_Low, "", null, video.Width, video.Height),
                    new NicoVideoQualityEntity(false, NicoVideoQuality.Smile_Original, "", null, video.Width, video.Height),
                }
                .ToImmutableArray();
            }
        }
        public DmcVideoStreamingSession(DmcWatchData res, NicoVideoQuality requestQuality, NiconicoContext context)
            : base(context)
        {
            RequestedQuality = requestQuality;
            _DmcWatchData    = res;
            DmcWatchResponse = res.DmcWatchResponse;

#if DEBUG
            Debug.WriteLine($"Id/Bitrate/Resolution/Available");
            foreach (var q in _DmcWatchData.DmcWatchResponse.Video.DmcInfo.Quality.Videos)
            {
                Debug.WriteLine($"{q.Id}/{q.Bitrate}/{q.Available}/{q.Resolution}");
            }
#endif

            VideoContent = ResetActualQuality();

            if (VideoContent == null || !VideoContent.Available)
            {
                VideoContent = DmcWatchResponse.Video.DmcInfo.Quality.Videos.FirstOrDefault(x => x.Available);
                _Quality     = NicoVideoVideoContentHelper.VideoContentToQuality(VideoContent);
            }
            else
            {
                _Quality = requestQuality;
            }

            if (VideoContent != null)
            {
                Debug.WriteLine($"quality={_Quality}");
                Debug.WriteLine($"{VideoContent.Id}/{VideoContent.Bitrate}/{VideoContent.Available}/w={VideoContent.Resolution.Width} h={VideoContent.Resolution.Height}");
            }
        }
        public static NicoVideoQuality ToNicoVideoQuality(this DmcWatchData dmcWatchData, string qualityId)
        {
            var dmcVideoContent = dmcWatchData?.DmcWatchResponse.Video.DmcInfo.Quality.Videos.FirstOrDefault(x => x.Id == qualityId);

            if (dmcVideoContent != null)
            {
                var qualities = dmcWatchData.DmcWatchResponse.Video.DmcInfo.Quality.Videos;

                var index = qualities.IndexOf(dmcVideoContent);

                // DmcInfo.Quality の要素数は動画によって1~5個まで様々である
                // また並びは常に先頭が最高画質、最後尾は最低画質(Mobile)となっている
                // Mobileは常に生成される
                // なのでDmcInfo.Quality[0] は動画ごとによって Dmc_SuperHigh だったり Dmc_Midium であったりまちまち
                // この差を吸収するため、
                // indexを Dmc_Mobile(6)~Dmc_SuperHigh(2) の空間に変換する
                // (qualities.Count - index - 1) によってDmc_Mobileの場合が 0 になる
                var nicoVideoQualityIndex = (int)NicoVideoQuality.Dmc_Mobile - (qualities.Count - index - 1);
                var quality = (NicoVideoQuality)nicoVideoQualityIndex;
                if (!quality.IsDmc())
                {
                    throw new NotSupportedException(qualityId);
                }

                return(quality);
            }
            else
            {
                if (Enum.TryParse <NicoVideoQuality>(qualityId, out var smileQuality) &&
                    smileQuality.IsLegacy()
                    )
                {
                    return(smileQuality);
                }
                else
                {
                    throw new NotSupportedException(qualityId);
                }
            }
        }
        public DmcVideoStreamingSession(string qualityId, DmcWatchData res, NiconicoSession niconicoSession, NicoVideoSessionOwnershipManager.VideoSessionOwnership videoSessionOwnership)
            : base(niconicoSession, videoSessionOwnership)
        {
            _DmcWatchData    = res;
            DmcWatchResponse = res.DmcWatchResponse;

            QualityId = qualityId;
            Quality   = res.ToNicoVideoQuality(qualityId);

#if DEBUG
            Debug.WriteLine($"Id/Bitrate/Resolution/Available");
            foreach (var q in _DmcWatchData.DmcWatchResponse.Video.DmcInfo.Quality.Videos)
            {
                Debug.WriteLine($"{q.Id}/{q.Bitrate}/{q.Available}/{q.Resolution}");
            }
#endif

            VideoContent = DmcWatchResponse.Video.DmcInfo.Quality.Videos.FirstOrDefault(x => x.Id == qualityId);

            if (VideoContent != null)
            {
                Debug.WriteLine($"{VideoContent.Id}/{VideoContent.Bitrate}/{VideoContent.Available}/w={VideoContent.Resolution.Width} h={VideoContent.Resolution.Height}");
            }
        }
 internal DmcVideoDetails(DmcWatchData dmcWatchData)
 {
     _dmcWatchRes = dmcWatchData.DmcWatchResponse;
     Tags         = _dmcWatchRes.Tags.Select(x => new NicoVideoTag(x.Name)).ToArray();
 }