public override async Task <ResultType> Run(CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ResultType.Cancelled);
            }

            JobStatus = VideoJobStatus.Running;
            Status    = "Retrieving video info...";
            var video_json = await TwitchYTDL.GetVideoJson(long.Parse(VideoInfo.VideoId));

            VideoInfo = new TwitchVideoInfo(TwitchYTDL.VideoFromJson(video_json), StreamService.TwitchChatReplay);
            if (!AssumeFinished && VideoInfo.VideoRecordingState == RecordingState.Live)
            {
                _UserInputRequest = new UserInputRequestStreamLive(this);
                return(ResultType.TemporarilyUnavailable);
            }

            string tempname       = Path.Combine(Util.TempFolderPath, GetTempFilenameWithoutExtension() + ".json.tmp");
            string finalintmpname = Path.Combine(Util.TempFolderPath, GetTempFilenameWithoutExtension() + ".json");
            string filename       = Path.Combine(Util.TargetFolderPath, GetTargetFilenameWithoutExtension() + ".json");
            Random rng            = new Random(int.Parse(VideoInfo.VideoId));

            if (!await Util.FileExists(filename))
            {
                if (!await Util.FileExists(finalintmpname))
                {
                    Status = "Downloading chat (Initial)...";
                    StringBuilder concatJson            = new StringBuilder();
                    string        url                   = GetStartUrl(VideoInfo);
                    int           attemptsLeft          = 5;
                    TimeSpan?     lastTimeSpan          = new TimeSpan(0);
                    int           nextDelayMilliseconds = 0;
                    while (true)
                    {
                        using (var client = new KeepAliveWebClient())
                            using (var cancellationCallback = cancellationToken.Register(client.CancelAsync)) {
                                try {
                                    try {
                                        if (nextDelayMilliseconds != 0)
                                        {
                                            await Task.Delay(nextDelayMilliseconds > 0?nextDelayMilliseconds : rng.Next(90000, 270000), cancellationToken);
                                        }
                                    } catch (TaskCanceledException) {
                                        return(ResultType.Cancelled);
                                    }

                                    string commentJson = await TwitchAPI.GetLegacy(url, Util.TwitchClientId);

                                    JObject responseObject = JObject.Parse(commentJson);
                                    if (responseObject["comments"] == null)
                                    {
                                        throw new Exception("Nonsense JSON returned, no comments.");
                                    }

                                    string offset = "Unknown";
                                    try {
                                        JToken   c   = ((JArray)responseObject["comments"]).Last;
                                        double   val = (double)c["content_offset_seconds"];
                                        TimeSpan ts  = TimeSpan.FromSeconds(val);
                                        if (lastTimeSpan != null)
                                        {
                                            TimeSpan diff  = ts - lastTimeSpan.Value;
                                            double   delay = diff.TotalMilliseconds;
                                            if (delay < 0.0)
                                            {
                                                nextDelayMilliseconds = -1;
                                            }
                                            else if (delay < 90000.0)
                                            {
                                                nextDelayMilliseconds = (int)delay;
                                            }
                                            else if (delay < 270000.0)
                                            {
                                                nextDelayMilliseconds = rng.Next(90000, (int)delay);
                                            }
                                            else
                                            {
                                                nextDelayMilliseconds = -1;
                                            }
                                        }
                                        else
                                        {
                                            nextDelayMilliseconds = -1;
                                        }
                                        lastTimeSpan = ts;
                                        offset       = ts.ToString();
                                    } catch (Exception) {
                                        lastTimeSpan          = null;
                                        nextDelayMilliseconds = -1;
                                    }

                                    concatJson.Append(commentJson);
                                    if (responseObject["_next"] != null)
                                    {
                                        string next = (string)responseObject["_next"];
                                        attemptsLeft = 5;
                                        Status       = "Downloading chat (Last offset: " + offset + "; next file: " + next + ")...";
                                        url          = GetNextUrl(VideoInfo, next);
                                    }
                                    else
                                    {
                                        // presumably done?
                                        break;
                                    }
                                } catch (System.Net.WebException ex) {
                                    Console.WriteLine(ex.ToString());
                                    --attemptsLeft;
                                    Status = "Downloading chat (Error; " + attemptsLeft + " attempts left)...";
                                    if (attemptsLeft <= 0)
                                    {
                                        throw;
                                    }
                                    continue;
                                }
                            }
                    }

                    await StallWrite(tempname, concatJson.Length * 4, cancellationToken);                       // size not accurate because encoding but whatever

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return(ResultType.Cancelled);
                    }
                    File.WriteAllText(tempname, concatJson.ToString());
                    File.Move(tempname, finalintmpname);
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    return(ResultType.Cancelled);
                }
                Status = "Moving to final location...";
                await StallWrite(filename, new FileInfo( finalintmpname ).Length, cancellationToken);

                if (cancellationToken.IsCancellationRequested)
                {
                    return(ResultType.Cancelled);
                }
                Util.MoveFileOverwrite(finalintmpname, filename);
            }

            Status    = "Done!";
            JobStatus = VideoJobStatus.Finished;
            return(ResultType.Success);
        }
Ejemplo n.º 2
0
        public override async Task <(ResultType result, List <DownloadInfo> downloadInfos)> GetFileUrlsOfVod(CancellationToken cancellationToken)
        {
            var video_json = await TwitchYTDL.GetVideoJson(long.Parse(VideoInfo.VideoId));

            VideoInfo = new TwitchVideoInfo(TwitchYTDL.VideoFromJson(video_json));

            string folderpath;
            List <DownloadInfo> downloadInfos;

            while (true)
            {
                try {
                    bool interactive = false;
                    if (interactive)
                    {
                        Status = "";
                        string tmp1         = Path.Combine(GetTempFolder(), GetTempFilenameWithoutExtension() + "_baseurl.txt");
                        string tmp2         = Path.Combine(GetTempFolder(), GetTempFilenameWithoutExtension() + "_tsnames.txt");
                        string linesbaseurl = TryGetUserCopyBaseurlM3U(tmp1);
                        string linestsnames = TryGetUserCopyTsnamesM3U(tmp2);
                        if (linesbaseurl == null)
                        {
                            File.WriteAllText(tmp1, "get baseurl for m3u8 from https://www.twitch.tv/videos/" + VideoInfo.VideoId);
                        }
                        if (linestsnames == null)
                        {
                            File.WriteAllText(tmp2, "get actual m3u file from https://www.twitch.tv/videos/" + VideoInfo.VideoId);
                        }

                        if (linesbaseurl == null || linestsnames == null)
                        {
                            await Task.Delay(200);

                            Process.Start(tmp1);
                            await Task.Delay(200);

                            Process.Start(tmp2);
                            await Task.Delay(200);

                            return(ResultType.UserInputRequired, null);
                        }

                        folderpath    = TsVideoJob.GetFolder(GetM3U8PathFromM3U(linesbaseurl, VideoQuality));
                        downloadInfos = TsVideoJob.GetFilenamesFromM3U8(folderpath, linestsnames);
                    }
                    else
                    {
                        string m3u8path = ExtractM3u8FromJson(video_json);
                        folderpath = TsVideoJob.GetFolder(m3u8path);
                        var client = new System.Net.Http.HttpClient();
                        var result = await client.GetAsync(m3u8path);

                        string m3u8 = await result.Content.ReadAsStringAsync();

                        downloadInfos = TsVideoJob.GetFilenamesFromM3U8(folderpath, m3u8);
                    }
                } catch (TwitchHttpException e) {
                    if (e.StatusCode == System.Net.HttpStatusCode.NotFound && VideoInfo.VideoRecordingState == RecordingState.Live)
                    {
                        // this can happen on streams that have just started, in this just wait a bit and retry
                        try {
                            await Task.Delay(20000, cancellationToken);
                        } catch (TaskCanceledException) {
                            return(ResultType.Cancelled, null);
                        }
                        video_json = await TwitchYTDL.GetVideoJson(long.Parse(VideoInfo.VideoId));

                        VideoInfo = new TwitchVideoInfo(TwitchYTDL.VideoFromJson(video_json));
                        continue;
                    }
                    else
                    {
                        throw;
                    }
                }
                break;
            }

            return(ResultType.Success, downloadInfos);
        }