Пример #1
0
        public static List <TwitchEmote> GetThirdPartyEmotes(int streamerId, string cacheFolder, Emotes embededEmotes = null, bool bttv = true, bool ffz = true, bool stv = true)
        {
            List <TwitchEmote> returnList   = new List <TwitchEmote>();
            List <string>      alreadyAdded = new List <string>();

            string bttvFolder = Path.Combine(cacheFolder, "bttv");
            string ffzFolder  = Path.Combine(cacheFolder, "ffz");
            string stvFolder  = Path.Combine(cacheFolder, "stv");

            if (embededEmotes != null)
            {
                foreach (ThirdPartyEmoteData emoteData in embededEmotes.thirdParty)
                {
                    try
                    {
                        MemoryStream ms       = new MemoryStream(emoteData.data);
                        SKCodec      codec    = SKCodec.Create(ms);
                        TwitchEmote  newEmote = new TwitchEmote(new List <SKBitmap>()
                        {
                            SKBitmap.Decode(emoteData.data)
                        }, codec, emoteData.name, codec.FrameCount == 0 ? "png" : "gif", "", emoteData.imageScale, emoteData.data);
                        returnList.Add(newEmote);
                        alreadyAdded.Add(emoteData.name);
                    }
                    catch { }
                }
            }

            using (WebClient client = new WebClient())
            {
                if (bttv)
                {
                    if (!Directory.Exists(bttvFolder))
                    {
                        TwitchHelper.CreateDirectory(bttvFolder);
                    }

                    //Global BTTV Emotes
                    JArray BBTV = JArray.Parse(client.DownloadString("https://api.betterttv.net/3/cached/emotes/global"));
                    foreach (var emote in BBTV)
                    {
                        string id   = emote["id"].ToString();
                        string name = emote["code"].ToString();
                        if (alreadyAdded.Contains(name))
                        {
                            continue;
                        }
                        string fileName = Path.Combine(bttvFolder, id + "_2x.png");
                        string url      = String.Format("https://cdn.betterttv.net/emote/{0}/2x", id);

                        TwitchEmote newEmote = GetTwitchEmote(fileName, url, name, emote["imageType"].ToString(), id, 2);
                        if (newEmote != null)
                        {
                            returnList.Add(newEmote);
                            alreadyAdded.Add(name);
                        }
                    }

                    //Channel specific BTTV emotes
                    try
                    {
                        JObject BBTV_channel = JObject.Parse(client.DownloadString("https://api.betterttv.net/3/cached/users/twitch/" + streamerId));
                        foreach (var emote in BBTV_channel["sharedEmotes"])
                        {
                            string id   = emote["id"].ToString();
                            string name = emote["code"].ToString();
                            string mime = emote["imageType"].ToString();
                            if (alreadyAdded.Contains(name))
                            {
                                continue;
                            }
                            string      fileName = Path.Combine(bttvFolder, id + "_2x." + mime);
                            string      url      = String.Format("https://cdn.betterttv.net/emote/{0}/2x", id);
                            TwitchEmote newEmote = GetTwitchEmote(fileName, url, name, mime, id, 2);
                            if (newEmote != null)
                            {
                                returnList.Add(newEmote);
                                alreadyAdded.Add(name);
                            }
                        }
                        foreach (var emote in BBTV_channel["channelEmotes"])
                        {
                            string id   = emote["id"].ToString();
                            string name = emote["code"].ToString();
                            string mime = emote["imageType"].ToString();
                            if (alreadyAdded.Contains(name))
                            {
                                continue;
                            }
                            string      fileName = Path.Combine(bttvFolder, id + "_2x." + mime);
                            string      url      = String.Format("https://cdn.betterttv.net/emote/{0}/2x", id);
                            TwitchEmote newEmote = GetTwitchEmote(fileName, url, name, mime, id, 2);
                            if (newEmote != null)
                            {
                                returnList.Add(newEmote);
                                alreadyAdded.Add(name);
                            }
                        }
                    }
                    catch { }
                }

                if (ffz)
                {
                    if (!Directory.Exists(ffzFolder))
                    {
                        TwitchHelper.CreateDirectory(ffzFolder);
                    }

                    //Global FFZ emotes
                    JArray FFZ = JArray.Parse(client.DownloadString("https://api.betterttv.net/3/cached/frankerfacez/emotes/global"));
                    foreach (var emote in FFZ)
                    {
                        string id   = emote["id"].ToString();
                        string name = emote["code"].ToString();
                        string mime = emote["imageType"].ToString();
                        if (alreadyAdded.Contains(name))
                        {
                            continue;
                        }
                        string      fileName = Path.Combine(ffzFolder, id + "_1x." + mime);
                        string      url      = String.Format("https://cdn.betterttv.net/frankerfacez_emote/{0}/1", id);
                        TwitchEmote newEmote = GetTwitchEmote(fileName, url, name, mime, id, 2);
                        if (newEmote != null)
                        {
                            returnList.Add(newEmote);
                            alreadyAdded.Add(name);
                        }
                    }

                    //Channel specific FFZ emotes
                    try
                    {
                        JArray FFZ_channel = JArray.Parse(client.DownloadString("https://api.betterttv.net/3/cached/frankerfacez/users/twitch/" + streamerId));
                        foreach (var emote in FFZ_channel)
                        {
                            string id   = emote["id"].ToString();
                            string name = emote["code"].ToString();
                            string mime = emote["imageType"].ToString();
                            if (alreadyAdded.Contains(name))
                            {
                                continue;
                            }
                            string      fileName    = Path.Combine(ffzFolder, id + "_2x." + mime);
                            string      fileNameLow = Path.Combine(ffzFolder, id + "_1x" + mime);
                            TwitchEmote newEmote    = null;
                            if (File.Exists(fileNameLow))
                            {
                                newEmote = GetTwitchEmote(fileName, String.Format("https://cdn.betterttv.net/frankerfacez_emote/{0}/1", id), name, mime, id, 1);
                            }
                            if (newEmote == null)
                            {
                                newEmote = GetTwitchEmote(fileName, String.Format("https://cdn.betterttv.net/frankerfacez_emote/{0}/2", id), name, mime, id, 2);
                                if (newEmote == null)
                                {
                                    newEmote = GetTwitchEmote(fileName, String.Format("https://cdn.betterttv.net/frankerfacez_emote/{0}/1", id), name, mime, id, 1);
                                }
                            }
                            if (newEmote != null)
                            {
                                returnList.Add(newEmote);
                                alreadyAdded.Add(name);
                            }
                        }
                    }
                    catch { }
                }

                if (stv)
                {
                    if (!Directory.Exists(stvFolder))
                    {
                        TwitchHelper.CreateDirectory(stvFolder);
                    }

                    //Global 7tv Emotes
                    JArray STV = JArray.Parse(client.DownloadString("https://api.7tv.app/v2/emotes/global"));
                    foreach (var emote in STV)
                    {
                        string id    = emote["id"].ToString();
                        string name  = emote["name"].ToString();
                        string mime  = emote["mime"].ToString().Split('/')[1];
                        string url2x = emote["urls"][1][1].ToString(); // 2x
                        if (alreadyAdded.Contains(name))
                        {
                            continue;
                        }
                        byte[] bytes;
                        string fileName = Path.Combine(stvFolder, id + "_2x." + mime);
                        if (File.Exists(fileName))
                        {
                            bytes = File.ReadAllBytes(fileName);
                        }
                        else
                        {
                            bytes = client.DownloadData(url2x);
                            File.WriteAllBytes(fileName, bytes);
                        }
                        MemoryStream ms = new MemoryStream(bytes);
                        returnList.Add(new TwitchEmote(new List <SKBitmap>()
                        {
                            SKBitmap.Decode(bytes)
                        }, SKCodec.Create(ms), name, mime, id, 2, bytes));
                        alreadyAdded.Add(name);
                    }

                    //Channel specific 7tv emotes
                    try
                    {
                        JArray STV_channel = JArray.Parse(client.DownloadString(String.Format("https://api.7tv.app/v2/users/{0}/emotes", streamerId)));
                        foreach (var emote in STV_channel)
                        {
                            string id    = emote["id"].ToString();
                            string name  = emote["name"].ToString();
                            string mime  = emote["mime"].ToString().Split('/')[1];
                            string url2x = emote["urls"][1][1].ToString(); // 2x
                            if (alreadyAdded.Contains(name))
                            {
                                continue;
                            }
                            byte[] bytes;
                            string fileName = Path.Combine(stvFolder, id + "_2x." + mime);
                            if (File.Exists(fileName))
                            {
                                bytes = File.ReadAllBytes(fileName);
                            }
                            else
                            {
                                bytes = client.DownloadData(url2x);
                                File.WriteAllBytes(fileName, bytes);
                            }
                            MemoryStream ms = new MemoryStream(bytes);
                            returnList.Add(new TwitchEmote(new List <SKBitmap>()
                            {
                                SKBitmap.Decode(bytes)
                            }, SKCodec.Create(ms), name, mime, id, 2, bytes));
                            alreadyAdded.Add(name);
                        }
                    }
                    catch { }
                }
            }

            return(returnList);
        }
Пример #2
0
        public static List <TwitchEmote> GetEmotes(List <Comment> comments, string cacheFolder, Emotes embededEmotes = null, bool deepSearch = false)
        {
            List <TwitchEmote> returnList   = new List <TwitchEmote>();
            List <string>      alreadyAdded = new List <string>();
            List <string>      failedEmotes = new List <string>();

            string emoteFolder = Path.Combine(cacheFolder, "emotes");

            if (!Directory.Exists(emoteFolder))
            {
                TwitchHelper.CreateDirectory(emoteFolder);
            }

            if (embededEmotes != null)
            {
                foreach (FirstPartyEmoteData emoteData in embededEmotes.firstParty)
                {
                    try
                    {
                        MemoryStream ms       = new MemoryStream(emoteData.data);
                        SKCodec      codec    = SKCodec.Create(ms);
                        TwitchEmote  newEmote = new TwitchEmote(new List <SKBitmap>()
                        {
                            SKBitmap.Decode(emoteData.data)
                        }, codec, emoteData.id, codec.FrameCount == 0 ? "png" : "gif", emoteData.id, emoteData.imageScale, emoteData.data);
                        returnList.Add(newEmote);
                        alreadyAdded.Add(emoteData.id);
                    }
                    catch { }
                }
            }

            using (WebClient client = new WebClient())
            {
                foreach (var comment in comments)
                {
                    if (comment.message.fragments == null)
                    {
                        continue;
                    }

                    foreach (var fragment in comment.message.fragments)
                    {
                        if (fragment.emoticon != null)
                        {
                            string id = fragment.emoticon.emoticon_id;
                            if (!alreadyAdded.Contains(id) && !failedEmotes.Contains(id))
                            {
                                try
                                {
                                    string filePath = "";
                                    if (File.Exists(Path.Combine(emoteFolder, id + "_1x.gif")))
                                    {
                                        filePath = Path.Combine(emoteFolder, id + "_1x.gif");
                                    }
                                    else if (File.Exists(Path.Combine(emoteFolder, id + "_1x.png")) && !id.Contains("emotesv2_"))
                                    {
                                        filePath = Path.Combine(emoteFolder, id + "_1x.png");
                                    }

                                    if (File.Exists(filePath))
                                    {
                                        SKBitmap emoteImage = SKBitmap.Decode(filePath);
                                        if (emoteImage == null)
                                        {
                                            try
                                            {
                                                File.Delete(filePath);
                                            }
                                            catch { }
                                        }
                                        else
                                        {
                                            try
                                            {
                                                byte[]       bytes = File.ReadAllBytes(filePath);
                                                MemoryStream ms    = new MemoryStream(bytes);
                                                SKCodec      codec = SKCodec.Create(ms);
                                                returnList.Add(new TwitchEmote(new List <SKBitmap>()
                                                {
                                                    SKBitmap.Decode(bytes)
                                                }, codec, id, codec.FrameCount == 0 ? "png" : "gif", id, 1, bytes));
                                                alreadyAdded.Add(id);
                                            }
                                            catch { }
                                        }
                                    }

                                    if (!alreadyAdded.Contains(id))
                                    {
                                        byte[] bytes = client.DownloadData(String.Format("https://static-cdn.jtvnw.net/emoticons/v2/{0}/default/dark/1.0", id));
                                        alreadyAdded.Add(id);
                                        MemoryStream ms       = new MemoryStream(bytes);
                                        SKCodec      codec    = SKCodec.Create(ms);
                                        TwitchEmote  newEmote = new TwitchEmote(new List <SKBitmap>()
                                        {
                                            SKBitmap.Decode(bytes)
                                        }, codec, id, codec.FrameCount == 0 ? "png" : "gif", id, 1, bytes);
                                        returnList.Add(newEmote);
                                        try
                                        {
                                            File.WriteAllBytes(Path.Combine(emoteFolder, newEmote.id + "_1x." + newEmote.imageType), bytes);
                                        }
                                        catch { }
                                    }
                                }
                                catch (WebException)
                                {
                                    failedEmotes.Add(id);
                                }
                            }
                        }
                    }
                }
            }

            return(returnList);
        }
Пример #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;
                int    errorCount    = 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;

                    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();
            }
        }