コード例 #1
0
        public async Task DownloadAsync(IProgress <ProgressReport> progress, CancellationToken cancellationToken)
        {
            using (WebClient client = new WebClient())
            {
                client.Encoding = Encoding.UTF8;
                client.Headers.Add("Accept", "application/vnd.twitchtv.v5+json; charset=UTF-8");
                client.Headers.Add("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");

                DownloadType downloadType = downloadOptions.Id.All(x => Char.IsDigit(x)) ? DownloadType.Video : DownloadType.Clip;
                string       videoId      = "";

                List <Comment> comments = new List <Comment>();
                ChatRoot       chatRoot = new ChatRoot()
                {
                    streamer = new Streamer(), video = new VideoTime(), comments = comments
                };

                double videoStart    = 0.0;
                double videoEnd      = 0.0;
                double videoDuration = 0.0;
                int    errorCount    = 0;

                if (downloadType == DownloadType.Video)
                {
                    videoId = downloadOptions.Id;
                    GqlVideoResponse taskInfo = await TwitchHelper.GetVideoInfo(Int32.Parse(videoId));

                    chatRoot.streamer.name = taskInfo.data.video.owner.displayName;
                    chatRoot.streamer.id   = int.Parse(taskInfo.data.video.owner.id);
                    videoStart             = downloadOptions.CropBeginning ? downloadOptions.CropBeginningTime : 0.0;
                    videoEnd = downloadOptions.CropEnding ? downloadOptions.CropEndingTime : taskInfo.data.video.lengthSeconds;
                }
                else
                {
                    GqlClipResponse taskInfo = await TwitchHelper.GetClipInfo(downloadOptions.Id);

                    if (taskInfo.data.clip.video == null || taskInfo.data.clip.videoOffsetSeconds == null)
                    {
                        throw new Exception("Invalid VOD for clip, deleted/expired VOD possibly?");
                    }

                    videoId = taskInfo.data.clip.video.id;
                    downloadOptions.CropBeginning     = true;
                    downloadOptions.CropBeginningTime = (int)taskInfo.data.clip.videoOffsetSeconds;
                    downloadOptions.CropEnding        = true;
                    downloadOptions.CropEndingTime    = downloadOptions.CropBeginningTime + taskInfo.data.clip.durationSeconds;
                    chatRoot.streamer.name            = taskInfo.data.clip.broadcaster.displayName;
                    chatRoot.streamer.id = int.Parse(taskInfo.data.clip.broadcaster.id);
                    videoStart           = (int)taskInfo.data.clip.videoOffsetSeconds;
                    videoEnd             = (int)taskInfo.data.clip.videoOffsetSeconds + taskInfo.data.clip.durationSeconds;
                }

                chatRoot.video.start = videoStart;
                chatRoot.video.end   = videoEnd;
                videoDuration        = videoEnd - videoStart;

                double latestMessage = videoStart - 1;
                bool   isFirst       = true;
                string cursor        = "";

                while (latestMessage < videoEnd)
                {
                    string response;

                    try
                    {
                        if (isFirst)
                        {
                            response = await client.DownloadStringTaskAsync(String.Format("https://api.twitch.tv/v5/videos/{0}/comments?content_offset_seconds={1}", videoId, videoStart));
                        }
                        else
                        {
                            response = await client.DownloadStringTaskAsync(String.Format("https://api.twitch.tv/v5/videos/{0}/comments?cursor={1}", videoId, cursor));
                        }
                        errorCount = 0;
                    }
                    catch (WebException ex)
                    {
                        await Task.Delay(1000 *errorCount);

                        errorCount++;

                        if (errorCount >= 10)
                        {
                            throw ex;
                        }

                        continue;
                    }

                    CommentResponse commentResponse = JsonConvert.DeserializeObject <CommentResponse>(response);

                    foreach (var comment in commentResponse.comments)
                    {
                        if (latestMessage < videoEnd && comment.content_offset_seconds > videoStart)
                        {
                            comments.Add(comment);
                        }

                        latestMessage = comment.content_offset_seconds;
                    }
                    if (commentResponse._next == null)
                    {
                        break;
                    }
                    else
                    {
                        cursor = commentResponse._next;
                    }

                    int percent = (int)Math.Floor((latestMessage - videoStart) / videoDuration * 100);
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Percent, data = percent
                    });
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.MessageInfo, data = $"Downloading {percent}%"
                    });

                    cancellationToken.ThrowIfCancellationRequested();

                    if (isFirst)
                    {
                        isFirst = false;
                    }
                }

                if (downloadOptions.EmbedEmotes && downloadOptions.IsJson)
                {
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Message, data = "Downloading + Embedding Emotes"
                    });
                    chatRoot.emotes = new Emotes();
                    List <FirstPartyEmoteData> firstParty = new List <FirstPartyEmoteData>();
                    List <ThirdPartyEmoteData> thirdParty = new List <ThirdPartyEmoteData>();

                    string             cacheFolder      = Path.Combine(Path.GetTempPath(), "TwitchDownloader", "cache");
                    List <TwitchEmote> thirdPartyEmotes = new List <TwitchEmote>();
                    List <TwitchEmote> firstPartyEmotes = new List <TwitchEmote>();

                    await Task.Run(() => {
                        thirdPartyEmotes = TwitchHelper.GetThirdPartyEmotes(chatRoot.streamer.id, cacheFolder);
                        firstPartyEmotes = TwitchHelper.GetEmotes(comments, cacheFolder).ToList();
                    });

                    foreach (TwitchEmote emote in thirdPartyEmotes)
                    {
                        ThirdPartyEmoteData newEmote = new ThirdPartyEmoteData();
                        newEmote.id         = emote.id;
                        newEmote.imageScale = emote.imageScale;
                        newEmote.data       = emote.imageData;
                        newEmote.name       = emote.name;
                        thirdParty.Add(newEmote);
                    }
                    foreach (TwitchEmote emote in firstPartyEmotes)
                    {
                        FirstPartyEmoteData newEmote = new FirstPartyEmoteData();
                        newEmote.id         = emote.id;
                        newEmote.imageScale = 1;
                        newEmote.data       = emote.imageData;
                        firstParty.Add(newEmote);
                    }

                    chatRoot.emotes.thirdParty = thirdParty;
                    chatRoot.emotes.firstParty = firstParty;
                }

                if (downloadOptions.IsJson)
                {
                    using (TextWriter writer = File.CreateText(downloadOptions.Filename))
                    {
                        var serializer = new JsonSerializer();
                        serializer.Serialize(writer, chatRoot);
                    }
                }
                else
                {
                    using (StreamWriter sw = new StreamWriter(downloadOptions.Filename))
                    {
                        foreach (var comment in chatRoot.comments)
                        {
                            string username = comment.commenter.display_name;
                            string message  = comment.message.body;
                            if (downloadOptions.TimeFormat == TimestampFormat.Utc)
                            {
                                string timestamp = comment.created_at.ToString("u").Replace("Z", " UTC");
                                sw.WriteLine(String.Format("[{0}] {1}: {2}", timestamp, username, message));
                            }
                            else if (downloadOptions.TimeFormat == TimestampFormat.Relative)
                            {
                                TimeSpan time      = new TimeSpan(0, 0, (int)comment.content_offset_seconds);
                                string   timestamp = time.ToString(@"h\:mm\:ss");
                                sw.WriteLine(String.Format("[{0}] {1}: {2}", timestamp, username, message));
                            }
                            else if (downloadOptions.TimeFormat == TimestampFormat.None)
                            {
                                sw.WriteLine(String.Format("{0}: {1}", username, message));
                            }
                        }

                        sw.Flush();
                        sw.Close();
                    }
                }

                chatRoot = null;
                GC.Collect();
            }
        }
コード例 #2
0
        public async Task DownloadAsync(IProgress <ProgressReport> progress, CancellationToken cancellationToken)
        {
            using (WebClient client = new WebClient())
            {
                client.Encoding = Encoding.UTF8;
                client.Headers.Add("Accept", "application/vnd.twitchtv.v5+json; charset=UTF-8");
                client.Headers.Add("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");

                DownloadType downloadType = downloadOptions.Id.All(x => Char.IsDigit(x)) ? DownloadType.Video : DownloadType.Clip;
                string       videoId      = "";

                JObject result   = new JObject();
                JObject video    = new JObject();
                JObject streamer = new JObject();
                JArray  comments = new JArray();

                double videoStart    = 0.0;
                double videoEnd      = 0.0;
                double videoDuration = 0.0;

                if (downloadType == DownloadType.Video)
                {
                    videoId = downloadOptions.Id;
                    JObject taskInfo = await TwitchHelper.GetVideoInfo(Int32.Parse(videoId));

                    streamer["name"] = taskInfo["channel"]["display_name"];
                    streamer["id"]   = taskInfo["channel"]["_id"];
                    videoStart       = downloadOptions.CropBeginning ? downloadOptions.CropBeginningTime : 0.0;
                    videoEnd         = downloadOptions.CropEnding ? downloadOptions.CropEndingTime : taskInfo["length"].ToObject <double>();
                }
                else
                {
                    JObject taskInfo = await TwitchHelper.GetClipInfo(downloadOptions.Id);

                    videoId = taskInfo["vod"]["id"].ToString();
                    downloadOptions.CropBeginning     = true;
                    downloadOptions.CropBeginningTime = taskInfo["vod"]["offset"].ToObject <int>();
                    downloadOptions.CropEnding        = true;
                    downloadOptions.CropEndingTime    = downloadOptions.CropBeginningTime + taskInfo["duration"].ToObject <double>();
                    streamer["name"] = taskInfo["broadcaster"]["display_name"];
                    streamer["id"]   = taskInfo["broadcaster"]["id"];
                    videoStart       = taskInfo["vod"]["offset"].ToObject <double>();
                    videoEnd         = taskInfo["vod"]["offset"].ToObject <double>() + taskInfo["duration"].ToObject <double>();
                }

                video["start"] = videoStart;
                video["end"]   = videoEnd;
                videoDuration  = videoEnd - videoStart;

                double latestMessage = videoStart - 1;
                bool   isFirst       = true;
                string cursor        = "";

                while (latestMessage < videoEnd)
                {
                    string response;
                    if (isFirst)
                    {
                        response = await client.DownloadStringTaskAsync(String.Format("https://api.twitch.tv/v5/videos/{0}/comments?content_offset_seconds={1}", videoId, videoStart));
                    }
                    else
                    {
                        response = await client.DownloadStringTaskAsync(String.Format("https://api.twitch.tv/v5/videos/{0}/comments?cursor={1}", videoId, cursor));
                    }

                    JObject res = JObject.Parse(response);

                    foreach (var comment in res["comments"])
                    {
                        if (latestMessage < videoEnd && comment["content_offset_seconds"].ToObject <double>() > videoStart)
                        {
                            comments.Add(comment);
                        }

                        latestMessage = comment["content_offset_seconds"].ToObject <double>();
                    }
                    if (res["_next"] == null)
                    {
                        break;
                    }
                    else
                    {
                        cursor = res["_next"].ToString();
                    }

                    int percent = (int)Math.Floor((latestMessage - videoStart) / videoDuration * 100);
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Percent, data = percent
                    });
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Message, data = $"Downloading {percent}%"
                    });

                    cancellationToken.ThrowIfCancellationRequested();

                    if (isFirst)
                    {
                        isFirst = false;
                    }
                }

                result["streamer"] = streamer;
                result["comments"] = comments;
                result["video"]    = video;

                if (downloadOptions.EmbedEmotes && downloadOptions.IsJson)
                {
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Message, data = "Downloading + Embedding Emotes"
                    });
                    result["emotes"] = new JObject();
                    JArray firstParty = new JArray();
                    JArray thirdParty = new JArray();

                    string cacheFolder = Path.Combine(Path.GetTempPath(), "TwitchDownloader", "cache");
                    List <ThirdPartyEmote> thirdPartyEmotes = new List <ThirdPartyEmote>();
                    List <KeyValuePair <string, SKBitmap> > firstPartyEmotes = new List <KeyValuePair <string, SKBitmap> >();

                    await Task.Run(() => {
                        thirdPartyEmotes = TwitchHelper.GetThirdPartyEmotes(streamer["id"].ToObject <int>(), cacheFolder);
                        firstPartyEmotes = TwitchHelper.GetEmotes(result["comments"].ToObject <List <Comment> >(), cacheFolder).ToList();
                    });

                    foreach (ThirdPartyEmote emote in thirdPartyEmotes)
                    {
                        JObject newEmote = new JObject();
                        newEmote["id"]         = emote.id;
                        newEmote["imageScale"] = emote.imageScale;
                        newEmote["data"]       = emote.imageData;
                        newEmote["name"]       = emote.name;
                        thirdParty.Add(newEmote);
                    }
                    foreach (KeyValuePair <string, SKBitmap> emote in firstPartyEmotes)
                    {
                        JObject newEmote = new JObject();
                        newEmote["id"]         = emote.Key;
                        newEmote["imageScale"] = 1;
                        newEmote["data"]       = SKImage.FromBitmap(emote.Value).Encode(SKEncodedImageFormat.Png, 100).ToArray();
                        firstParty.Add(newEmote);
                    }

                    result["emotes"]["thirdParty"] = thirdParty;
                    result["emotes"]["firstParty"] = firstParty;
                }

                using (StreamWriter sw = new StreamWriter(downloadOptions.Filename))
                {
                    if (downloadOptions.IsJson)
                    {
                        sw.Write(result.ToString(Formatting.None));
                    }
                    else
                    {
                        foreach (var comment in result["comments"])
                        {
                            string username = comment["commenter"]["display_name"].ToString();
                            string message  = comment["message"]["body"].ToString();
                            if (downloadOptions.Timestamp)
                            {
                                string timestamp = comment["created_at"].ToObject <DateTime>().ToString("u").Replace("Z", " UTC");
                                sw.WriteLine(String.Format("[{0}] {1}: {2}", timestamp, username, message));
                            }
                            else
                            {
                                sw.WriteLine(String.Format("{0}: {1}", username, message));
                            }
                        }
                    }

                    sw.Flush();
                    sw.Close();
                    result = null;
                }
            }
        }
コード例 #3
0
        public async Task DownloadAsync(IProgress <ProgressReport> progress, CancellationToken cancellationToken)
        {
            using (WebClient client = new WebClient())
            {
                client.Encoding = Encoding.UTF8;
                client.Headers.Add("Accept", "application/vnd.twitchtv.v5+json; charset=UTF-8");
                client.Headers.Add("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko");

                DownloadType downloadType = downloadOptions.Id.All(x => Char.IsDigit(x)) ? DownloadType.Video : DownloadType.Clip;
                string       videoId      = "";

                List <Comment> comments = new List <Comment>();
                ChatRoot       chatRoot = new ChatRoot()
                {
                    streamer = new Streamer(), video = new VideoTime(), comments = comments
                };

                double videoStart    = 0.0;
                double videoEnd      = 0.0;
                double videoDuration = 0.0;

                if (downloadType == DownloadType.Video)
                {
                    videoId = downloadOptions.Id;
                    JObject taskInfo = await TwitchHelper.GetVideoInfo(Int32.Parse(videoId));

                    chatRoot.streamer.name = taskInfo["channel"]["display_name"].ToString();
                    chatRoot.streamer.id   = taskInfo["channel"]["_id"].ToObject <int>();
                    videoStart             = downloadOptions.CropBeginning ? downloadOptions.CropBeginningTime : 0.0;
                    videoEnd = downloadOptions.CropEnding ? downloadOptions.CropEndingTime : taskInfo["length"].ToObject <double>();
                }
                else
                {
                    JObject taskInfo = await TwitchHelper.GetClipInfo(downloadOptions.Id);

                    videoId = taskInfo["vod"]["id"].ToString();
                    downloadOptions.CropBeginning     = true;
                    downloadOptions.CropBeginningTime = taskInfo["vod"]["offset"].ToObject <int>();
                    downloadOptions.CropEnding        = true;
                    downloadOptions.CropEndingTime    = downloadOptions.CropBeginningTime + taskInfo["duration"].ToObject <double>();
                    chatRoot.streamer.name            = taskInfo["broadcaster"]["display_name"].ToString();
                    chatRoot.streamer.id = taskInfo["broadcaster"]["id"].ToObject <int>();
                    videoStart           = taskInfo["vod"]["offset"].ToObject <double>();
                    videoEnd             = taskInfo["vod"]["offset"].ToObject <double>() + taskInfo["duration"].ToObject <double>();
                }

                chatRoot.video.start = videoStart;
                chatRoot.video.end   = videoEnd;
                videoDuration        = videoEnd - videoStart;

                double latestMessage = videoStart - 1;
                bool   isFirst       = true;
                string cursor        = "";

                while (latestMessage < videoEnd)
                {
                    string response;
                    if (isFirst)
                    {
                        response = await client.DownloadStringTaskAsync(String.Format("https://api.twitch.tv/v5/videos/{0}/comments?content_offset_seconds={1}", videoId, videoStart));
                    }
                    else
                    {
                        response = await client.DownloadStringTaskAsync(String.Format("https://api.twitch.tv/v5/videos/{0}/comments?cursor={1}", videoId, cursor));
                    }

                    CommentResponse commentResponse = JsonConvert.DeserializeObject <CommentResponse>(response);

                    foreach (var comment in commentResponse.comments)
                    {
                        if (latestMessage < videoEnd && comment.content_offset_seconds > videoStart)
                        {
                            comments.Add(comment);
                        }

                        latestMessage = comment.content_offset_seconds;
                    }
                    if (commentResponse._next == null)
                    {
                        break;
                    }
                    else
                    {
                        cursor = commentResponse._next;
                    }

                    int percent = (int)Math.Floor((latestMessage - videoStart) / videoDuration * 100);
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Percent, data = percent
                    });
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.MessageInfo, data = $"Downloading {percent}%"
                    });

                    cancellationToken.ThrowIfCancellationRequested();

                    if (isFirst)
                    {
                        isFirst = false;
                    }
                }

                if (downloadOptions.EmbedEmotes && downloadOptions.IsJson)
                {
                    progress.Report(new ProgressReport()
                    {
                        reportType = ReportType.Message, data = "Downloading + Embedding Emotes"
                    });
                    chatRoot.emotes = new Emotes();
                    List <FirstPartyEmoteData> firstParty = new List <FirstPartyEmoteData>();
                    List <ThirdPartyEmoteData> thirdParty = new List <ThirdPartyEmoteData>();

                    string cacheFolder = Path.Combine(Path.GetTempPath(), "TwitchDownloader", "cache");
                    List <ThirdPartyEmote> thirdPartyEmotes = new List <ThirdPartyEmote>();
                    List <KeyValuePair <string, SKBitmap> > firstPartyEmotes = new List <KeyValuePair <string, SKBitmap> >();

                    await Task.Run(() => {
                        thirdPartyEmotes = TwitchHelper.GetThirdPartyEmotes(chatRoot.streamer.id, cacheFolder);
                        firstPartyEmotes = TwitchHelper.GetEmotes(comments, cacheFolder).ToList();
                    });

                    foreach (ThirdPartyEmote emote in thirdPartyEmotes)
                    {
                        ThirdPartyEmoteData newEmote = new ThirdPartyEmoteData();
                        newEmote.id         = emote.id;
                        newEmote.imageScale = emote.imageScale;
                        newEmote.data       = emote.imageData;
                        newEmote.name       = emote.name;
                        thirdParty.Add(newEmote);
                    }
                    foreach (KeyValuePair <string, SKBitmap> emote in firstPartyEmotes)
                    {
                        FirstPartyEmoteData newEmote = new FirstPartyEmoteData();
                        newEmote.id         = emote.Key;
                        newEmote.imageScale = 1;
                        newEmote.data       = SKImage.FromBitmap(emote.Value).Encode(SKEncodedImageFormat.Png, 100).ToArray();
                        firstParty.Add(newEmote);
                    }

                    chatRoot.emotes.thirdParty = thirdParty;
                    chatRoot.emotes.firstParty = firstParty;
                }

                if (downloadOptions.IsJson)
                {
                    using (TextWriter writer = File.CreateText(downloadOptions.Filename))
                    {
                        var serializer = new JsonSerializer();
                        serializer.Serialize(writer, chatRoot);
                    }
                }
                else
                {
                    using (StreamWriter sw = new StreamWriter(downloadOptions.Filename))
                    {
                        foreach (var comment in chatRoot.comments)
                        {
                            string username = comment.commenter.display_name;
                            string message  = comment.message.body;
                            if (downloadOptions.Timestamp)
                            {
                                string timestamp = comment.created_at.ToString("u").Replace("Z", " UTC");
                                sw.WriteLine(String.Format("[{0}] {1}: {2}", timestamp, username, message));
                            }
                            else
                            {
                                sw.WriteLine(String.Format("{0}: {1}", username, message));
                            }
                        }

                        sw.Flush();
                        sw.Close();
                    }
                }

                chatRoot = null;
                GC.Collect();
            }
        }