public async void RecordPlaybackPositionAsync(NicoNicoWatchApiData apiData, double pos) { try { var form = new Dictionary <string, string> { ["watch_id"] = apiData.Video.Id, ["playback_position"] = pos.ToString(), ["csrf_token"] = apiData.Context.CsrfToken }; var request = new HttpRequestMessage(HttpMethod.Post, RecordPositionApi) { Content = new FormUrlEncodedContent(form) }; var a = await App.ViewModelRoot.CurrentUser.Session.GetAsync(request); var json = DynamicJson.Parse(a); if (json.status == "ok") { //再生位置を記録出来た、と //Owner.Status = "再生位置を保存しました。"; } else { //Owner.Status = "再生位置の保存に失敗しました"; } } catch (RequestFailed) { Owner.Status = "再生位置の保存に失敗しました"; } }
public async Task <bool> ToggleFollowOwnerAsync(NicoNicoWatchApiData apiData) { try { if (apiData.IsChannelVideo) { GetRequestQuery query = null; if (apiData.IsUploaderFollowed) { query = new GetRequestQuery(ChannelUnFollowApi); } else { query = new GetRequestQuery(ChannelFollowApi); } query.AddQuery("channel_id", apiData.Channel.Id); query.AddQuery("return_json", 1); query.AddQuery("time", apiData.Channel.FavoriteTokenTime); query.AddQuery("key", apiData.Channel.FavoriteToken); var a = await App.ViewModelRoot.CurrentUser.Session.GetAsync(query.TargetUrl); var json = DynamicJson.Parse(a); if (json.status == "succeed") { if (apiData.IsUploaderFollowed) { Owner.Status = "フォローを解除しました"; } else { Owner.Status = "フォローしました"; } return(true); } } else { if (apiData.IsUploaderFollowed) { var request = new HttpRequestMessage(HttpMethod.Delete, string.Format(UploaderInfoApi, apiData.Owner.Id)) { Content = new FormUrlEncodedContent(new Dictionary <string, string>()) }; request.Headers.Add("x-request-with", Owner.VideoUrl); var a = await App.ViewModelRoot.CurrentUser.Session.GetAsync(request); var json = DynamicJson.Parse(a); if (json.meta.status == 200D) { Owner.Status = "フォローを解除しました"; return(true); } else { Owner.Status = "フォロー解除に失敗しました"; return(false); } } else { var request = new HttpRequestMessage(HttpMethod.Post, string.Format(UploaderInfoApi, apiData.Owner.Id)) { Content = new FormUrlEncodedContent(new Dictionary <string, string>()) }; request.Headers.Add("x-request-with", Owner.VideoUrl); var a = await App.ViewModelRoot.CurrentUser.Session.GetAsync(request); var json = DynamicJson.Parse(a); if (json.meta.status == 200D) { Owner.Status = "フォローしました"; return(true); } else { Owner.Status = "フォローに失敗しました"; return(false); } } } return(false); } catch (RequestFailed) { return(false); } }
public async Task <NicoNicoWatchApiData> GetWatchApiDataAsync() { try { var res = await App.ViewModelRoot.CurrentUser.Session.GetResponseAsync(Owner.VideoUrl); //チャンネル動画などでリダイレクトされるURLの可能性があるのでリダイレクトされた場合はリダイレクト先を読み込む if (res.StatusCode == HttpStatusCode.MovedPermanently) { res = await App.ViewModelRoot.CurrentUser.Session.GetResponseAsync(res.Headers.Location.OriginalString); } //削除された動画は404を律儀に返してくる if (res.StatusCode == HttpStatusCode.NotFound) { Owner.Status = "動画が削除されている可能性があります"; return(null); } //鯖落ちかな? if (res.StatusCode == HttpStatusCode.ServiceUnavailable) { Owner.Status = "サーバーが混み合っているようです"; return(null); } //Cookieを取得してWebBrowserの方に反映させる //これがないと動画を取得しようとしても403が返ってくる IEnumerable <string> cookie; if (res.Headers.TryGetValues("Set-Cookie", out cookie)) { foreach (string s in cookie) { foreach (string ss in s.Split(';')) { App.SetCookie(new Uri("http://nicovideo.jp/"), ss); } } } //html var a = await res.Content.ReadAsStringAsync(); //Responsehはもう必要ない res.Dispose(); var doc = new HtmlDocument(); doc.LoadHtml(a); var container = doc.DocumentNode.SelectSingleNode("//div[@id='js-initial-watch-data']"); if (container == null) { container = doc.DocumentNode.SelectSingleNode("//div[@id='watchAPIDataContainer']"); //html5版ページで視聴できなかった場合 if (container != null) { var json = DynamicJson.Parse(HttpUtility.HtmlDecode(container.InnerText)); var flash = json.flashvars; var flv = HttpUtility.UrlDecode(HttpUtility.UrlDecode(flash.flvInfo)); var getFlv = HttpUtility.ParseQueryString(flv); var videoDetail = json.videoDetail; var ret = new NicoNicoWatchApiData(); //動画情報 ret.Video = new NicoNicoVideo() { Id = videoDetail.id, SmileInfo = new NicoNicoVideo.NicoNicoSmileInfo() { Url = getFlv["url"] }, Title = videoDetail.title, OriginalTitle = videoDetail.title_original, Description = videoDetail.description, OriginalDescription = videoDetail.description_original, ThumbNailUrl = videoDetail.thumbnail, PostedDateTime = DateTime.Parse(videoDetail.postedAt), OriginalPostedDateTime = DateTime.MinValue, Duration = (int)videoDetail.length, ViewCount = (int)videoDetail.viewCount, MylistCount = (int)videoDetail.mylistCount }; ret.Thread = new NicoNicoThread() { CommentCount = (int)videoDetail.commentCount, HasOwnerThread = videoDetail.has_owner_thread, ServerUrl = getFlv["ms"].Replace("api", "api.json"), SubServerurl = getFlv["ms_sub"], ThreadIds = new NicoNicoThreadIds() { Default = getFlv["thread_id"], Nicos = getFlv["thread_id"], Community = getFlv["thread_id"] } }; ret.Tags = new List <NicoNicoVideoTag>(); foreach (var tag in videoDetail.tagList) { var entry = new NicoNicoVideoTag() { Id = tag.id, Tag = HttpUtility.HtmlDecode(tag.tag), Dic = tag.dic(), Lck = tag.lck == "1" ? true : false, Cat = tag.cat() }; entry.Url = "http://dic.nicovideo.jp/a/" + entry.Tag; ret.Tags.Add(entry); } if (json.uploaderInfo()) { var owner = json.uploaderInfo; ret.Owner = new NicoNicoVideoOwner() { Id = owner.id, UserUrl = "http://www.nicovideo.jp/user/" + owner.id, Nickname = owner.nickname, IconUrl = owner.icon_url, IsUserVideoPublic = owner.is_uservideo_public, IsUserMyVideoPublic = owner.is_user_myvideo_public, IsUserOpenListPublic = owner.is_user_openlist_public }; //投稿者をお気に入り登録しているか調べる var follow = await App.ViewModelRoot.CurrentUser.Session.GetAsync(string.Format(UploaderInfoApi, ret.Owner.Id)); ret.IsUploaderFollowed = DynamicJson.Parse(follow).data.following; } if (json.channelInfo()) { var channel = json.channelInfo; ret.Channel = new NicoNicoVideoChannel() { Id = channel.id, Name = channel.name, IconUrl = channel.icon_url, FavoriteToken = channel.favorite_token, FavoriteTokenTime = (long)channel.favorite_token_time, IsFavorited = channel.is_favorited == 1D }; ret.Channel.ChannelUrl = "http://ch.nicovideo.jp/ch" + ret.Channel.Id; ret.IsChannelVideo = true; ret.IsUploaderFollowed = ret.Channel.IsFavorited; } var viewer = json.viewerInfo; ret.Viewer = new NicoNicoVideoViewer() { Id = Convert.ToString(viewer.id), Nickname = viewer.nickname, IsPremium = viewer.isPremium, IsPrivileged = viewer.isPrivileged, }; ret.Context = new NicoNicoVideoContext() { HighestRank = videoDetail.highest_rank != null?int.Parse(videoDetail.highest_rank) : null, YesterdayRank = videoDetail.yesterday_rank != null?int.Parse(videoDetail.yesterday_rank) : null, CsrfToken = flash.csrfToken, UserKey = getFlv["userkey"] }; ret.FmsToken = getFlv["fmst"]; return(ret); } Owner.Status = "動画の読み込みに失敗しました"; return(null); } else { //htmlから取得したJsonをhtmlデコードしてdynamic型に変える var json = DynamicJson.Parse(HttpUtility.HtmlDecode(container.Attributes["data-api-data"].Value.Trim())); var ret = new NicoNicoWatchApiData(); //動画情報 var video = json.video; ret.Video = new NicoNicoVideo() { Id = video.id, SmileInfo = new NicoNicoVideo.NicoNicoSmileInfo() { Url = video.smileInfo.url, IsSlowLine = video.smileInfo.isSlowLine, CurrentQualityId = video.smileInfo.currentQualityId }, Title = HttpUtility.HtmlDecode(video.title), OriginalTitle = video.originalTitle, Description = HyperLinkReplacer.Replace(video.description), OriginalDescription = video.originalDescription, ThumbNailUrl = video.thumbnailURL, PostedDateTime = DateTime.Parse(video.postedDateTime), OriginalPostedDateTime = video.originalPostedDateTime() && video.originalPostedDateTime != null?DateTime.Parse(video.originalPostedDateTime) : DateTime.MinValue, Width = (int?)video.width, Height = (int?)video.height, Duration = (int)video.duration, ViewCount = (int)video.viewCount, MylistCount = (int)video.mylistCount, Translation = video.translation, Translator = video.translator, MovieType = video.movieType, Badges = video.badges, IntroducedNicoliveDJInfo = video.introducedNicoliveDJInfo, DmcInfo = video.dmcInfo != null ? new NicoNicoDmc() { Time = (long)video.dmcInfo.time, TimeMs = (long)video.dmcInfo.time_ms, VideoId = video.dmcInfo.video.video_id, LengthSeconds = (int)video.dmcInfo.video.length_seconds, Deleted = (int)video.dmcInfo.video.deleted, ServerUrl = video.dmcInfo.thread.server_url, SubServerUrl = video.dmcInfo.thread.sub_server_url, ThreadId = Convert.ToString(video.dmcInfo.thread.thread_id), NicosThreadId = Convert.ToString(video.dmcInfo.thread.nicos_thread_id), OptionalThreadId = Convert.ToString(video.dmcInfo.thread.optional_thread_id), ThreadKeyRequired = video.dmcInfo.thread.thread_key_required, ChannelNGWords = video.dmcInfo.thread.channel_ng_words, OwnerNGWords = video.dmcInfo.thread.owner_ng_words, MaintenancesNg = video.dmcInfo.thread.maintenances_ng, PostkeyAvailable = video.dmcInfo.thread.postkey_available, NgRevision = (int?)video.dmcInfo.thread.ng_revision, ApiUrls = video.dmcInfo.session_api.api_urls, RecipeId = video.dmcInfo.session_api.recipe_id, PlayerId = video.dmcInfo.session_api.player_id, Videos = video.dmcInfo.session_api.videos, Audios = video.dmcInfo.session_api.audios, Movies = video.dmcInfo.session_api.movies, Protocols = video.dmcInfo.session_api.protocols, AuthType = video.dmcInfo.session_api.auth_types.http, ServiceUserId = video.dmcInfo.session_api.service_user_id, Token = video.dmcInfo.session_api.token, Signature = video.dmcInfo.session_api.signature, ContentId = video.dmcInfo.session_api.content_id, HeartbeatLifeTime = (int)video.dmcInfo.session_api.heartbeat_lifetime, ContentKeyTimeout = (int)video.dmcInfo.session_api.content_key_timeout, Priority = video.dmcInfo.session_api.priority } : null, BackCommentType = video.backCommentType, IsCommentExpired = video.isCommentExpired, IsWide = video.isWide, IsOfficialAnime = (int?)video.isOfficialAnime, IsNoBanner = video.isNoBanner, IsDeleted = video.isDeleted, IsTranslated = video.isTranslated, IsR18 = video.isR18, IsAdult = video.isAdult, IsNicowari = video.isNicowari, IsPublic = video.isPublic, IsPublishedNicoscript = video.isPublishedNicoscript, IsNoNGS = video.isNoNGS, IsCommunityMemberOnly = video.isCommunityMemberOnly, IsCommonsTreeExists = video.isCommonsTreeExists, IsNoIchiba = video.isNoIchiba, IsOfficial = video.isOfficial, IsMonetized = video.isMonetized }; var thread = json.thread; ret.Thread = new NicoNicoThread() { CommentCount = (int)thread.commentCount, HasOwnerThread = thread.hasOwnerThread, MymemoryLanguage = thread.mymemoryLanguage, ServerUrl = thread.serverUrl.Replace("api", "api.json"), SubServerurl = thread.subServerUrl, ThreadIds = new NicoNicoThreadIds() { Default = thread.ids.@default, Nicos = thread.ids.nicos, Community = thread.ids.community } }; //タグを走査 ret.Tags = new List <NicoNicoVideoTag>(); foreach (var tag in json.tags) { var entry = new NicoNicoVideoTag() { Id = tag.id, Tag = HttpUtility.HtmlDecode(tag.name), Dic = tag.isDictionaryExists, Lck = tag.isLocked, Cat = tag.isCategory }; entry.Url = "http://dic.nicovideo.jp/a/" + entry.Tag; ret.Tags.Add(entry); } var owner = json.owner; if (owner != null) { ret.Owner = new NicoNicoVideoOwner() { Id = owner.id, UserUrl = "http://www.nicovideo.jp/user/" + owner.id, Nickname = owner.nickname, IconUrl = owner.iconURL, NicoliveInfo = owner.nicoliveInfo, ChannelInfo = owner.channelInfo, IsUserVideoPublic = owner.isUserVideoPublic, IsUserMyVideoPublic = owner.isUserMyVideoPublic, IsUserOpenListPublic = owner.isUserOpenListPublic }; //投稿者をお気に入り登録しているか調べる var follow = await App.ViewModelRoot.CurrentUser.Session.GetAsync(string.Format(UploaderInfoApi, ret.Owner.Id)); ret.IsUploaderFollowed = DynamicJson.Parse(follow).data.following; } var channel = json.channel; if (channel != null) { ret.Channel = new NicoNicoVideoChannel() { Id = channel.id, Name = channel.name, IconUrl = channel.iconURL, FavoriteToken = channel.favoriteToken, FavoriteTokenTime = (long)channel.favoriteTokenTime, IsFavorited = channel.isFavorited, NGFilters = new List <NicoNicoVideoNGFilter>(), ThreadType = channel.threadType, GlobalId = channel.globalId }; ret.Channel.ChannelUrl = "http://ch.nicovideo.jp/" + ret.Channel.GlobalId; foreach (var filter in channel.ngList) { ret.Channel.NGFilters.Add(new NicoNicoVideoNGFilter() { Source = filter.source, Destination = filter.destination }); } ret.IsChannelVideo = true; ret.IsUploaderFollowed = ret.Channel.IsFavorited; } var viewer = json.viewer; ret.Viewer = new NicoNicoVideoViewer() { Id = Convert.ToString(viewer.id), Nickname = viewer.nickname, Prefecture = (int)viewer.prefecture, Sex = (int)viewer.sex, Age = (int)viewer.age, IsPremium = viewer.isPremium, IsPrivileged = viewer.isPrivileged, IsPostLocked = viewer.isPostLocked, IsHtrzm = viewer.isHtrzm, IsTwitterConnection = viewer.isTwitterConnection }; var context = json.context; ret.Context = new NicoNicoVideoContext() { PlayFrom = context.playFrom, InitialPlaybackPosition = (int?)context.initialPlaybackPosition, InitialPlaybackType = context.initialPlaybackType, PlayLength = context.playLength, ReturnId = context.returnId, ReturnTo = context.returnTo, ReturnMsg = context.returnMsg, WatchId = context.watchId, IsNoMovie = context.isNoMovie, IsNoRelatedVideo = context.isNoRelatedVideo, IsDownloadCompleteWait = context.isDownloadCompleteWait, IsNoNicotic = context.isNoNicotic, IsNeedPayment = context.isNeedPayment, IsAdultRatingNG = context.isAdultRatingNG, IsPlayable = context.isPlayable, IsTranslatable = context.isTranslatable, IsTagUneditable = context.isTagUneditable, IsVideoOwner = context.isVideoOwner, IsThreadOwner = context.isThreadOwner, IsOwnerThreadEditable = context.isOwnerThreadEditable, UseChecklistCache = context.useChecklistCache, IsDisabledMarquee = context.isDisabledMarquee, IsDictionaryDisplayable = context.isDictionaryDisplayable, IsDefaultCommentInvisible = context.isDefaultCommentInvisible, AccessFrom = context.accessFrom, CsrfToken = context.csrfToken, TranslationVersionJsonUpdateTime = (long)context.translationVersionJsonUpdateTime, UserKey = context.userkey, WatchAuthKey = context.watchAuthKey, WatchTrackId = context.watchTrackId, WatchPageServerTime = (long)context.watchPageServerTime, IsAuthenticationRequired = context.isAuthenticationRequired, IsPeakTime = context.isPeakTime, NgRevision = (int)context.ngRevision, CategoryName = context.categoryName, CategoryKey = context.categoryKey, CategoryGroupName = context.categoryGroupName, CategoryGroupKey = context.categoryGroupKey, YesterdayRank = (int?)context.yesterdayRank, HighestRank = (int?)context.highestRank, IsMyMemory = context.isMyMemory, OwnerNGFilters = new List <NicoNicoVideoNGFilter>() }; //垢消しうp主 if (ret.Channel == null && ret.Owner == null) { ret.IsOwnerDeleted = true; } if (!Settings.Instance.UseResumePlay) { ret.Context.InitialPlaybackPosition = 0; } foreach (var filter in context.ownerNGList) { ret.Context.OwnerNGFilters.Add(new NicoNicoVideoNGFilter() { Source = filter.source, Destination = filter.destination }); } return(ret); } } catch (RequestFailed) { Owner.Status = "動画情報の取得に失敗しました"; return(null); } }