Exemple #1
0
        static void UploadThumbnail(VideoThumbnail videoThumbnail, string thumbnailIdentifier)
        {
            if (string.IsNullOrEmpty(LocalWebsiteDir))
            {
                FtpUpload("Originals", ".png");
                FtpUpload("Compressed", ".jpg");
                FtpUpload("Placeholders", ".jpg");
            }
            else
            {
                LocalUpload("Originals", ".png");
                LocalUpload("Compressed", ".jpg");
                LocalUpload("Placeholders", ".jpg");
            }

            void FtpUpload(string folder, string extension)
            {
                var ftpClient = (FtpWebRequest)WebRequest.Create($"{FtpUrl}/{Website}/wwwroot/{RemoteThumbnailsDir}/{folder}/{videoThumbnail.MediaId}_{thumbnailIdentifier}{extension}");

                ftpClient.Credentials = FtpCredentials;
                ftpClient.Method      = System.Net.WebRequestMethods.Ftp.UploadFile;
                ftpClient.UseBinary   = true;
                ftpClient.KeepAlive   = true;
                var fi = new FileInfo($"{RelativeLocalThumbnailsDir}\\{videoThumbnail.MediaId}\\AutoGen\\{folder}\\{videoThumbnail.MediaId}_{thumbnailIdentifier}{extension}");

                ftpClient.ContentLength = fi.Length;
                byte[] buffer      = new byte[4097];
                int    bytes       = 0;
                int    total_bytes = (int)fi.Length;

                try
                {
                    using (FileStream fs = fi.OpenRead())
                    {
                        using (Stream rs = ftpClient.GetRequestStream())
                        {
                            while (total_bytes > 0)
                            {
                                bytes = fs.Read(buffer, 0, buffer.Length);
                                rs.Write(buffer, 0, bytes);
                                total_bytes -= bytes;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            void LocalUpload(string folder, string extension)
            {
                File.Copy($"{RelativeLocalThumbnailsDir}\\{videoThumbnail.MediaId}\\AutoGen\\{folder}\\{videoThumbnail.MediaId}_{thumbnailIdentifier}{extension}", $"{LocalWebsiteDir}{RemoteThumbnailsDir}/{folder}/{videoThumbnail.MediaId}_{thumbnailIdentifier}{extension}");
            }
        }
Exemple #2
0
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        VideoThumbnail targetManager = (VideoThumbnail)target;

        if (GUILayout.Button("Set Video"))
        {
            targetManager.SetVideo();
        }
    }
 // create video thumbnail if 100% loaded
 void CreateThumbnail(CFile file)
 {
     Task.Run(() =>
     {
         string fileName = Path.ChangeExtension(file.Name, ".jpg");
         bool isOk       = VideoThumbnail.CreateThumbnail(
             Path.Combine(file.Path + file.Name),
             Path.Combine(file.Path, "Thumbnails", fileName));
     });
 }
Exemple #4
0
        private void CreateThumbnails(string tempVideoPath, string outputPath, int totalVideoSeconds, VideoThumbnail[] videoThumbnails)
        {
            Random rnd = new Random();

            for (int i = 0; i < videoThumbnails.Length; i++)
            {
                TimeSpan          randomSpan       = new TimeSpan(0, 0, 0, rnd.Next(totalVideoSeconds));
                var               outThumbnailPath = Path.Combine(outputPath, "thumbnail_" + i + FileExtensions.Png);
                IConversionResult result           = Conversion.Snapshot(tempVideoPath, outThumbnailPath, randomSpan).Start().Result;
                string            id = Path.GetFileName(outputPath);
                videoThumbnails[i] = new VideoThumbnail {
                    ThumbnailUrl = Path.Combine(_htmlRootVideoPath, id + "/thumbnail_" + i + FileExtensions.Png), Id = i
                };
            }
        }
Exemple #5
0
        protected void Page_Load(object sender, EventArgs e)
        {
            var tagParam     = Request.QueryString["tag"];
            var userTagParam = Request.QueryString["user"];
            var Search       = Request.QueryString["search"];

            Login();

            GetMedia(); //CheckPermissions() is dependent on this for CreatedByUserId

            NewMenu.LoggedInUser = myUser;
            NewMenu.HighlightButtonsForPage(PageIndex.Tag, "Edit");

            MediaTag OriginalTag = string.IsNullOrEmpty(tagParam) ? null : new MediaTag(Convert.ToInt32(tagParam));

            GetOriginalRedirect();

            CheckPermissions();

            string id = Request.QueryString["id"];

            if (!string.IsNullOrEmpty(id))
            {
                //REQUIRED TO VIEW POSTBACK
                form1.Action = Request.RawUrl;

                if (Request.QueryString["delete"] != null)
                {
                    DoDeleteMedia();

                    Response.Redirect(OriginalAlbumRedirect);
                }

                CheckForThumbnailUpload();

                PopulateTags();

                PopulateTagDropDowns();

                DisplayMediaAttributes();

                if (!IsPostBack)
                {
                    InputTitleTwo.Focus();
                }
            }
            else
            {
                Response.Redirect("home");
            }

            void Login()
            {
                myUser = Account.SecurePage(this, Data.DeviceType);

                NewMenu.SelectedPage = PageIndex.EditMedia;
                NewMenu.LoggedInUser = myUser;
                NewMenu.Share        = true;

                if (Request.QueryString["removetag"] == "true")
                {
                    MediaTagPair.Delete(new MediaId(Request.QueryString["id"]), Convert.ToInt32(Request.QueryString["tag"]));
                    if (Request.QueryString["tag"] == null)
                    {
                        Response.Redirect($"edit?id={Request.QueryString["id"]}");
                    }
                    else
                    {
                        Response.Redirect($"edit?id={Request.QueryString["id"]}&tag={Request.QueryString["tag"]}");
                    }
                }
                else if (Request.QueryString["removeusertag"] == "true")
                {
                    MediaUserPair.Delete(new MediaId(Request.QueryString["id"]), Convert.ToInt32(Request.QueryString["userid"]));
                    if (Request.QueryString["userid"] == null)
                    {
                        Response.Redirect($"edit?id={Request.QueryString["id"]}");
                    }
                    else
                    {
                        Response.Redirect($"edit?id={Request.QueryString["id"]}&userid={Request.QueryString["userid"]}");
                    }
                }
            }

            void GetMedia()
            {
                if (!string.IsNullOrWhiteSpace(Request.QueryString["id"]))
                {
                    MyYoutubeVideo = ParsnipData.Media.Youtube.Select(new MediaId(Request.QueryString["id"]), myUser.Id);
                    if (MyYoutubeVideo == null)
                    {
                        MyVideo = ParsnipData.Media.Video.Select(new MediaId(Request.QueryString["id"]), myUser.Id);
                    }

                    if (MyYoutubeVideo == null && MyVideo == null)
                    {
                        MyImage = ParsnipData.Media.Image.Select(new MediaId(Request.QueryString["id"]), myUser.Id);
                    }
                }

                if (MyYoutubeVideo != null)
                {
                    MyYoutubeVideo = Youtube.Select(new MediaId(Request.QueryString["id"]), myUser.Id);
                    MediaShare myMediaShare = MyYoutubeVideo.MyMediaShare;
                    if (myMediaShare == null)
                    {
                        myMediaShare = new MediaShare(MyYoutubeVideo.Id, myUser.Id);
                        myMediaShare.Insert();
                    }
                    ShareLink.Value = Request.Url.GetLeftPart(UriPartial.Authority) + "/view?share=" +
                                      myMediaShare.Id;
                    thumbnail.Src = MyYoutubeVideo.Compressed;
                    input_date_media_captured.Value = MyYoutubeVideo.DateTimeCaptured.ToString();
                    a_play_video.HRef    = string.Format("../../view?id={0}", MyYoutubeVideo.Id);
                    a_play_video.Visible = true;
                    Page.Title           = "Edit Youtube Video";
                }
                else if (MyVideo != null)
                {
                    MyVideo = Video.Select(new MediaId(Request.QueryString["id"]), myUser.Id);
                    MediaShare myMediaShare = MyVideo.MyMediaShare;
                    if (myMediaShare == null)
                    {
                        myMediaShare = new MediaShare(MyVideo.Id, myUser.Id);
                        myMediaShare.Insert();
                    }
                    ShareLink.Value = Request.Url.GetLeftPart(UriPartial.Authority) + "/view?share=" +
                                      myMediaShare.Id;
                    thumbnail.Src = MyVideo.Compressed;
                    input_date_media_captured.Value = MyVideo.DateTimeCaptured.ToString();
                    a_play_video.HRef    = string.Format("../../view?id={0}", MyVideo.Id);
                    a_play_video.Visible = true;
                    Page.Title           = "Edit Video";
                    if (MyVideo.Thumbnails.Count() > 0)
                    {
                        ThumbnailSelectorContainer.Visible = true;
                        foreach (var control in VideoThumbnailControl.GetVideoAsVideoThumbnailControls(MyVideo))
                        {
                            control.VideoThumbnailClick += new EventHandler(VideoThumbnail_ButtonClick);
                            ThumbnailSelector.Controls.Add(control);
                        }
                    }
                }
                else if (MyImage != null)
                {
                    myMediaShare = MyImage.MyMediaShare;
                    if (myMediaShare == null)
                    {
                        myMediaShare = new MediaShare(MyImage.Id, myUser.Id);
                        myMediaShare.Insert();
                    }
                    ShareLink.Value = Request.Url.GetLeftPart(UriPartial.Authority) + "/view?share=" +
                                      myMediaShare.Id;
                    ImagePreview.ImageUrl           = MyImage.Compressed;
                    input_date_media_captured.Value = MyImage.DateTimeCaptured.ToString();
                    ImagePreviewContainer.HRef      = string.Format("../../view?id={0}", MyImage.Id);
                    ImagePreviewContainer.Visible   = true;
                    Page.Title = "Edit Image";
                }
                else
                {
                    Response.Redirect("myuploads");
                }
            }

            void PopulateTags()
            {
                Page httpHandler = (Page)HttpContext.Current.Handler;

                foreach (MediaTagPair mediaTagPair in MyMedia.MediaTagPairs)
                {
                    MediaTagPairControl mediaTagPairControl = (MediaTagPairControl)httpHandler.LoadControl("~/Custom_Controls/Media/MediaTagPairControl.ascx");
                    mediaTagPairControl.MyMedia = MyMedia;
                    mediaTagPairControl.MyPair  = mediaTagPair;
                    MediaTagContainer.Controls.Add(mediaTagPairControl);
                }
                foreach (MediaUserPair mediaUserPair in MyMedia.MediaUserPairs)
                {
                    MediaUserPairControl mediaUserPairControl = (MediaUserPairControl)httpHandler.LoadControl("~/Custom_Controls/Media/MediaUserPairControl.ascx");
                    mediaUserPairControl.MyMedia = MyMedia;
                    mediaUserPairControl.MyPair  = mediaUserPair;
                    UserTagContainer.Controls.Add(mediaUserPairControl);
                }
            }

            void GetOriginalRedirect()
            {
                if (OriginalTag == null && tagParam == null && userTagParam == null && MyMedia.AlbumId == default && MyMedia.MediaTagPairs.Count == default && !string.IsNullOrEmpty(OriginalAlbumRedirect))
                {
                    OriginalAlbumRedirect = "myuploads?focus=" + MyMedia.Id.ToString();
                }
                else if (!string.IsNullOrEmpty(Search))
                {
                    OriginalAlbumRedirect = $"search?text={Search}&focus={MyMedia.Id}";
                }
                else if (OriginalTag != null)
                {
                    switch (OriginalTag.Id)
                    {
                    case (int)Data.MediaTagIds.Photos:
                        OriginalAlbumRedirect = "photos?focus=" + MyMedia.Id.ToString();
                        break;

                    case (int)Data.MediaTagIds.Memes:
                        OriginalAlbumRedirect = "memes?focus=" + MyMedia.Id.ToString();
                        break;

                    case (int)Data.MediaTagIds.Krakow:
                        OriginalAlbumRedirect = "krakow?focus=" + MyMedia.Id.ToString();
                        break;

                    case (int)Data.MediaTagIds.Videos:
                        OriginalAlbumRedirect = "videos?focus=" + MyMedia.Id.ToString();
                        break;

                    case (int)Data.MediaTagIds.Portugal:
                        OriginalAlbumRedirect = "portugal?focus=" + MyMedia.Id.ToString();
                        break;

                    case (int)Data.MediaTagIds.Amsterdam:
                        OriginalAlbumRedirect = "amsterdam?focus=" + MyMedia.Id.ToString();
                        break;

                    case default(int):
                        Debug.WriteLine(string.Format("The album id {0} was not recognised!",
                                                      MyMedia.AlbumId));
                        OriginalAlbumRedirect = "home?error=nomediaalbum4";
                        break;

                    default:
                        OriginalAlbumRedirect = $"tag?id={OriginalTag.Id}&focus={MyMedia.Id}";
                        break;
                    }
                }
                else
                {
                    if (userTagParam != null)
                    {
                        OriginalAlbumRedirect = $"tag?user={userTagParam}&focus={MyMedia.Id}";
                    }
                    else if (tagParam != null)
                    {
                        OriginalAlbumRedirect = $"tag?id={tagParam}&focus={MyMedia.Id}";
                    }
                    else
                    {
                        OriginalAlbumRedirect = $"myuploads?focus={MyMedia.Id}";
                    }
                    //else if (MyMedia.MediaTagPairs.Count != default)
                    //    OriginalAlbumRedirect = $"tag?id={MyMedia.MediaTagPairs[0].MediaTag.Id}&focus={MyMedia.Id}";
                }
            }

            void PopulateTagDropDowns()
            {
                NewAlbumsDropDown.Items.Clear();
                NewAlbumsDropDown.Items.Add(new ListItem()
                {
                    Value = "0", Text = "(No tag selected)"
                });
                foreach (MediaTag tempMediaTag in MediaTag.GetAllTags())
                {
                    NewAlbumsDropDown.Items.Add(new ListItem()
                    {
                        Value = Convert.ToString(tempMediaTag.Id),
                        Text  = tempMediaTag.Name
                    });
                }

                DropDown_SelectUser.Items.Clear();
                foreach (User user in ParsnipData.Accounts.User.GetAllUsers())
                {
                    DropDown_SelectUser.Items.Add(new ListItem()
                    {
                        Value = Convert.ToString(user.Id),
                        Text  = user.FullName
                    });
                }
            }

            void DoDeleteMedia()
            {
                bool deleteSuccess;

                if (myUser.AccountType == "admin")
                {
                    MyMedia.Delete();
                    deleteSuccess = true;
                }
                else
                {
                    new LogEntry(Log.General)
                    {
                        Text = string.Format("{0} tried to delete media called \"{1}\", but {2} was not allowed " +
                                             "because {2} is not an admin", myUser.FullName, MyMedia.Title,
                                             myUser.SubjectiveGenderPronoun)
                    };
                    deleteSuccess = false;
                }
            }

            void CheckPermissions()
            {
                if (MyMedia.CreatedById.ToString() != myUser.Id.ToString())
                {
                    if (myUser.AccountType == "admin" || myUser.AccountType == "media")
                    {
                        string accountType = myUser.AccountType == "admin" ? "admin" : "approved media editor";
                        new LogEntry(Log.General)
                        {
                            Text = string.Format("{0} started editing media called \"{1}\". {2} does not own the " +
                                                 "media but {3} is allowed since {3} is an {4}", myUser.FullName, MyMedia.Title,
                                                 myUser.SubjectiveGenderPronoun.First().ToString().ToUpper() +
                                                 myUser.SubjectiveGenderPronoun.Substring(1), myUser.SubjectiveGenderPronoun, accountType)
                        };
                    }
                    else
                    {
                        new LogEntry(Log.General)
                        {
                            Text = string.Format("{0} attempted to edit media called \"{1}\" which {2} " +
                                                 "did not own. Access was DENIED!", myUser.FullName, MyMedia.Title, myUser.SubjectiveGenderPronoun)
                        };

                        Response.Redirect($"{OriginalAlbumRedirect}&alert=P100");
                    }
                }
            }

            void DisplayMediaAttributes()
            {
                if (MyMedia.Title != null && !string.IsNullOrEmpty(MyMedia.Title) && !string.IsNullOrWhiteSpace(MyMedia.Title))
                {
                    InputTitleTwo.Text = MyMedia.Title;
                }

                if (myUser.AccountType == "admin")
                {
                    btn_AdminDelete.Visible = true;
                }

                if (MyMedia.SearchTerms != null && !string.IsNullOrEmpty(MyMedia.SearchTerms) && !string.IsNullOrWhiteSpace(MyMedia.SearchTerms))
                {
                    SearchTerms_Input.Text = MyMedia.SearchTerms;
                }
            }

            void CheckForThumbnailUpload()
            {
                if (MyVideo != null)
                {
                    if (ThumbnailUpload.PostedFile != null && ThumbnailUpload.PostedFile.ContentLength > 0)
                    {
                        var thumbnail = new VideoThumbnail(MyVideo, myUser, ThumbnailUpload.PostedFile);
                        thumbnail.Insert();
                        Response.Redirect(Page.Request.Url.ToString(), true);
                    }

                    if (MyVideo.Thumbnails.Count > 0 || !MyVideo.Status.Equals(MediaStatus.Complete))
                    {
                        ThumbnailUploadControl.Visible = true;

                        if (MyVideo.Thumbnails.Count == 0)
                        {
                            ThumbnailsAreProcessing.Visible = true;
                        }
                    }
                }
            }
        }
Exemple #6
0
        static void GenerateAndUploadThumbnails(Video video, bool UseCompressedVideo = false)
        {
            var originalsDir   = $"{RelativeLocalThumbnailsDir}\\{video.Id}\\AutoGen\\Originals";
            var compressedDir  = $"{RelativeLocalThumbnailsDir}\\{video.Id}\\AutoGen\\Compressed";
            var placeholderDir = $"{RelativeLocalThumbnailsDir}\\{video.Id}\\AutoGen\\Placeholders";
            var segment        = new TimeSpan(video.VideoData.Duration.Ticks / NumberOfGeneratedThumbnails);

            CreateLocalDirectories();
            GenerateAndUploadThumbnails();
            InsertThumbnailData();

            void CreateLocalDirectories()
            {
                if (Directory.Exists(originalsDir))
                {
                    Directory.Delete(originalsDir, true);
                }

                if (Directory.Exists(compressedDir))
                {
                    Directory.Delete(compressedDir, true);
                }

                if (Directory.Exists(placeholderDir))
                {
                    Directory.Delete(placeholderDir, true);
                }

                Directory.CreateDirectory(originalsDir);
                Directory.CreateDirectory(compressedDir);
                Directory.CreateDirectory(placeholderDir);
            }

            void GenerateAndUploadThumbnails()
            {
                for (int i = 0; i < NumberOfGeneratedThumbnails; i++)
                {
                    var    timeStamp                   = new TimeSpan(segment.Ticks * i);
                    string thumbnailIdentifier         = MediaId.NewMediaId().ToString();
                    var    videoThumbnail              = new VideoThumbnail();
                    System.Drawing.Image originalImage = null;

                    InitialiseThumbnail();
                    GenerateImages();
                    UploadThumbnail(videoThumbnail, thumbnailIdentifier);
                    video.Thumbnails.Add(videoThumbnail);

                    void GenerateImages()
                    {
                        originalImage = GenerateOriginal();
                        UpdateVideoThumbnailScale();
                        GenerateCompressed();
                        GeneratePlaceholder();

                        System.Drawing.Image GenerateOriginal()
                        {
                            var     thumbnailDir = $"{RelativeLocalThumbnailsDir}\\{videoThumbnail.MediaId}\\AutoGen\\Originals\\{videoThumbnail.MediaId}_{thumbnailIdentifier}.png";
                            var     videoDir     = UseCompressedVideo ? $"{RelativeLocalCompressedVideosDir}\\{video.Id}{video.VideoData.CompressedFileExtension}" : $"{RelativeLocalOriginalVideosDir}\\{video.Id}{video.VideoData.OriginalFileExtension}";
                            Process process      = new Process();

                            process.StartInfo.FileName    = "GenerateThumbnail.bat";
                            process.StartInfo.Arguments   = $"{thumbnailDir} {videoDir} {timeStamp}";
                            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                            process.Start();
                            process.WaitForExit();
                            int exitCode = process.ExitCode;

                            process.Close();
                            return(Bitmap.FromFile(thumbnailDir));
                        }

                        void UpdateVideoThumbnailScale()
                        {
                            int scale = Media.GetAspectScale(originalImage.Width, originalImage.Height);

                            videoThumbnail.XScale = Convert.ToInt16(originalImage.Width / scale);
                            videoThumbnail.YScale = Convert.ToInt16(originalImage.Height / scale);
                        }

                        void GenerateCompressed()
                        {
                            var    localDir = $"{RelativeLocalThumbnailsDir}\\{videoThumbnail.MediaId}\\AutoGen\\Compressed\\{videoThumbnail.MediaId}_{thumbnailIdentifier}.jpg";
                            Bitmap bitmap   = Media.GenerateBitmapOfSize(originalImage, 1280, 200);

                            Media.SaveBitmapWithCompression(bitmap, 85L, localDir);
                        }

                        void GeneratePlaceholder()
                        {
                            var    localDir = $"{RelativeLocalThumbnailsDir}\\{videoThumbnail.MediaId}\\AutoGen\\Placeholders\\{videoThumbnail.MediaId}_{thumbnailIdentifier}.jpg";
                            Bitmap bitmap   = Media.GenerateBitmapOfSize(originalImage, 250, 0);

                            Media.SaveBitmapWithCompression(bitmap, 15L, localDir);
                        }
                    }

                    void InitialiseThumbnail()
                    {
                        videoThumbnail.MediaId     = video.Id;
                        videoThumbnail.Placeholder = $"{RemoteThumbnailsDir}/Placeholders/{video.Id}_{thumbnailIdentifier}.jpg";
                        videoThumbnail.Compressed  = $"{RemoteThumbnailsDir}/Compressed/{video.Id}_{thumbnailIdentifier}.jpg";
                        videoThumbnail.Original    = $"{RemoteThumbnailsDir}/Originals/{video.Id}_{thumbnailIdentifier}.png";
                    }
                }
            }

            void InsertThumbnailData()
            {
                foreach (var videoThumbnail in video.Thumbnails)
                {
                    videoThumbnail.Insert();
                }
            }
        }
Exemple #7
0
        //ytInitialPlayerResponse.responseContext.serviceTrackingParams.filter(p => p.service == "CSI")[0].params
        public async Task <RecsAndExtra> GetRecsAndExtra(string videoId, ILogger log)
        {
            var watchPage = await GetVideoWatchPageHtmlAsync(videoId, log);

            var(html, raw, url) = watchPage;
            var infoDic = await GetVideoInfoDicAsync(videoId, log);

            var videoItem = GetVideo(videoId, infoDic, watchPage);

            var extra = new VideoExtraStored2 {
                VideoId      = videoId,
                Updated      = DateTime.UtcNow,
                ChannelId    = videoItem.ChannelId,
                ChannelTitle = videoItem.ChannelTitle,
                Description  = videoItem.Description,
                Duration     = videoItem.Duration,
                Keywords     = videoItem.Keywords,
                Title        = videoItem.Title,
                UploadDate   = videoItem.UploadDate.UtcDateTime,
                Statistics   = videoItem.Statistics,
                Source       = ScrapeSource.Web,
                Thumbnail    = VideoThumbnail.FromVideoId(videoId)
            };

            var restrictedMode = html.QueryElements("head > meta[property=\"og:restrictions:age\"]").FirstOrDefault()?.GetAttribute("content")?.Value == "18+";

            if (restrictedMode)
            {
                extra.Error    = RestrictedVideoError;
                extra.SubError = "Unable to find recommended video because it is age restricted and requires to log in";
            }
            else
            {
                extra.SubError = html.QueryElements("#unavailable-submessage").FirstOrDefault()?.GetInnerText();
                if (extra.SubError == "")
                {
                    extra.SubError = null;
                }
                if (extra.SubError.HasValue()) // all pages have the error, but not a sub-error
                {
                    extra.Error = html.QueryElements("#unavailable-message").FirstOrDefault()?.GetInnerText();
                }
            }
            if (extra.Error != null)
            {
                return(new RecsAndExtra(extra, new Rec[] { }));
            }


            var(recs, recEx) = Def.New(() => GetRecs2(html)).Try();
            if (recs?.Any() != true || recEx != null)
            {
                var uri    = new Uri(url);
                var path   = StringPath.Relative(DateTime.UtcNow.ToString("yyyy-MM-dd"), $"{uri.PathAndQuery}.html");
                var logUrl = LogStore.Url(path);
                await LogStore.Save(path, raw.AsStream(), log);

                log.Warning("WebScraper - Unable to find recs at ({Url}). error: {Error}", logUrl, recEx?.ToString());
            }

            var match = _ytAdRegex.Match(raw);

            extra.HasAd = match.Success && match.Groups[1].Value == "1";

            return(new RecsAndExtra(extra, recs));
        }