Quantcast
Channel: Active questions tagged youtube-api - Stack Overflow
Viewing all articles
Browse latest Browse all 3831

YouTube Data API v3 retrieval works fine in IDE, but no results on live server

$
0
0

This is my first time working with the YouTube Data API v3 and APIs in general.I have implemented the following requirements with the API in my existing web project:

  • Retrieve a flexible top X of comments on a video, measured by the number of likes
  • Retrieve all comments of a user on a video
  • Retrieval of all comments on a video with a number X of likes

The data retrieval works smoothly in my IDE - Visual Studio.After testing everything for full functionality, I published the website extension. Now when I want to run the functions on the website, the page takes a long time to load and no results are returned.

The method seems to work in principle, at the end I am redirected. However, without any listing of the requested data.

My key is without restrictions, I prevent misuse via website authentication. I have already checked this. The quota limit has also not been reached. Enclosed are the measured values from the Google Cloud Center. I published the website on 10.12.2024 at around 22:20. I use IONOS Webhosting Essential Windows for my hosting.

YouTubeServices.cs

public class YouTubeServices    {        private readonly ILogger<YouTubeServices> _logger;        public YouTubeServices(ILogger<YouTubeServices> logger)        {            _logger = logger;        }        private async Task<(string VideoTitle, int VideoViews)> GetVideoDetailsAsync(string videoId, string apiKey)        {            string videoInfoUrl = $"https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics&id={videoId}&key={apiKey}";            string videoTitle = null;            int videoViews = 0;            using (var client = new HttpClient())            {                try                {                    var videoInfoResponse = await client.GetAsync(videoInfoUrl);                    videoInfoResponse.EnsureSuccessStatusCode();                    var videoInfoJson = await videoInfoResponse.Content.ReadAsStringAsync();                    var videoInfoData = JObject.Parse(videoInfoJson);                    videoTitle = (string)videoInfoData["items"]?.FirstOrDefault()?["snippet"]?["title"];                    videoViews = (int?)videoInfoData["items"]?.FirstOrDefault()?["statistics"]?["viewCount"] ?? 0;                }                catch (Exception ex)                {                    _logger.LogError("Video info error: {0}", ex.Message);                    throw new Exception("Video details error");                }            }            return (videoTitle, videoViews);        }        private async Task<List<(string Author, string Comment, string CommentUrl, int Likes)>> GetCommentsAsync(string videoId, string apiKey, Func<JToken, bool> filter = null)        {            string apiUrl = $"https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId={videoId}&key={apiKey}";            List<(string Author, string Comment, string CommentUrl, int Likes)> comments = new();            string nextPageToken = null;            using (var client = new HttpClient())            {                try                {                    do                    {                        string url = apiUrl + (nextPageToken != null ? $"&pageToken={nextPageToken}" : "");                        var response = await client.GetAsync(url);                        response.EnsureSuccessStatusCode();                        var jsonString = await response.Content.ReadAsStringAsync();                        var jsonData = JObject.Parse(jsonString);                        var items = jsonData["items"];                        foreach (var item in items)                        {                            var topLevelComment = item["snippet"]["topLevelComment"]["snippet"];                            if (filter == null || filter(item))                            {                                comments.Add((                                    Author: (string)topLevelComment["authorDisplayName"],                                    Comment: RemoveHtmlTags((string)topLevelComment["textDisplay"]),                                    CommentUrl: $"https://www.youtube.com/watch?v={videoId}&lc={(string)item["id"]}",                                    Likes: (int)topLevelComment["likeCount"]                                ));                            }                        }                        nextPageToken = (string)jsonData["nextPageToken"];                    }                    while (nextPageToken != null);                }                catch (Exception ex)                {                    _logger.LogError("video comment error: {0}", ex.Message);                }            }            return comments;        }        public async Task<(string VideoTitle, int VideoViews, List<(string Author, string Comment, string CommentUrl, int Likes)> Comments)> GetTopCommentsAsync(string videoUrl, string apiKey, int maxComments)        {            string videoId = ExtractVideoId(videoUrl);            if (string.IsNullOrEmpty(videoId))                throw new ArgumentException("YouTube-URL not valid.");            var (videoTitle, videoViews) = await GetVideoDetailsAsync(videoId, apiKey);            var comments = await GetCommentsAsync(videoId, apiKey);            return (videoTitle, videoViews, comments.OrderByDescending(c => c.Likes).Take(maxComments).ToList());        }        public async Task<(string VideoTitle, int VideoViews, List<(string Author, string Comment, string CommentUrl, int Likes)> Comments)> GetCommentsByUserAsync(string videoUrl, string apiKey, string username)        {            string videoId = ExtractVideoId(videoUrl);            if (string.IsNullOrEmpty(videoId))                throw new ArgumentException("YouTube-URL not valid.");            var (videoTitle, videoViews) = await GetVideoDetailsAsync(videoId, apiKey);            var comments = await GetCommentsAsync(videoId, apiKey, item =>                ((string)item["snippet"]["topLevelComment"]["snippet"]["authorDisplayName"]).Equals(username, StringComparison.OrdinalIgnoreCase)            );            return (videoTitle, videoViews, comments);        }        public async Task<(string VideoTitle, int VideoViews, List<(string Author, string Comment, string CommentUrl, int Likes)> Comments)> GetCommentsByLikesAsync(string videoUrl, string apiKey, int exactLikes)        {            string videoId = ExtractVideoId(videoUrl);            if (string.IsNullOrEmpty(videoId))                throw new ArgumentException("YouTube-URL not valid.");            var (videoTitle, videoViews) = await GetVideoDetailsAsync(videoId, apiKey);            var comments = await GetCommentsAsync(videoId, apiKey, item =>                (int)item["snippet"]["topLevelComment"]["snippet"]["likeCount"] == exactLikes            );            return (videoTitle, videoViews, comments);        }        private static string ExtractVideoId(string videoUrl)        {            if (string.IsNullOrEmpty(videoUrl))                return null;            var match = Regex.Match(videoUrl, @"(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})");            return match.Success ? match.Groups[1].Value : null;        }        private static string RemoveHtmlTags(string input)        {            if (string.IsNullOrEmpty(input))                return input;            var allowedTags = new[] { "br", "b", "i", "u" };            return Regex.Replace(input, $@"</?(?!({string.Join("|", allowedTags)})\b)[^>]*>", string.Empty);        }    }

ControlCenterController.cs:

public class ControlCenterController : Controller    {        private readonly ILogger<ControlCenterController> _logger;        private readonly YouTubeServices _youTubeService;        private readonly string _apiKey;        public ControlCenterController(            ILogger<ControlCenterController> logger,            YouTubeServices youTubeService,            IOptions<YouTubeConfig> youTubeConfig)        {            _logger = logger;            _youTubeService = youTubeService;            _apiKey = youTubeConfig.Value.ApiKey;        }        [Authorize(Roles = "Administrator,Editor")]        [HttpGet]        public async Task<IActionResult> Index()        {            CombinedIndexViewModel viewModel = await GetDefaultViewModelAsync();            return View(viewModel);        }        [Authorize(Roles = "Administrator,Editor")]        [HttpPost]        public async Task<IActionResult> ListCommentsByCount(string videoUrl, int? commentCount)        {            CombinedIndexViewModel viewModel = await GetDefaultViewModelAsync();            if (string.IsNullOrEmpty(videoUrl))            {                ViewBag.ErrorMessage = "Enter a valid YouTube-URL.";                return View("Index", viewModel);            }            try            {                int count = commentCount.GetValueOrDefault(int.MaxValue);                var (videoTitle, videoViews, comments) = await _youTubeService.GetTopCommentsAsync(videoUrl, _apiKey, count);                viewModel.YouTubeComments = comments.Select(comment => (                    comment.Author,                    TransformLinks(comment.Comment),                    comment.CommentUrl,                    comment.Likes                )).ToList();                viewModel.VideoTitle = videoTitle;                viewModel.VideoViews = videoViews;                return View("Index", viewModel);            }            catch (ArgumentException ex)            {                ViewBag.ErrorMessage = ex.Message;            }            catch (Exception ex)            {                _logger.LogError("Video comment error: {0}", ex.Message);                ViewBag.ErrorMessage = "Video comment error.";            }            return View("Index", viewModel);        }        [Authorize(Roles = "Administrator,Editor")]        [HttpPost]        public async Task<IActionResult> ListCommentsByUser(string videoUrl, string username)        {            CombinedIndexViewModel viewModel = await GetDefaultViewModelAsync();            if (string.IsNullOrEmpty(videoUrl))            {                ViewBag.ErrorMessage = "Enter a valid YouTube-URL.";                return View("Index", viewModel);            }            if (string.IsNullOrEmpty(username))            {                ViewBag.ErrorMessage = "Enter a valid YouTube username starting with @.";                return View("Index", viewModel);            }            try            {                var (videoTitle, videoViews, comments) = await _youTubeService.GetCommentsByUserAsync(videoUrl, _apiKey, username);                viewModel.VideoTitle = videoTitle; // Videotitel einfügen                viewModel.VideoViews = videoViews; // Videoaufrufe einfügen                viewModel.YouTubeComments = comments                    .Select(comment => (                        comment.Author,                        TransformLinks(comment.Comment),                        comment.CommentUrl,                        comment.Likes                    )).ToList();            }            catch (ArgumentException ex)            {                ViewBag.ErrorMessage = ex.Message;            }            catch (Exception ex)            {                _logger.LogError("Video comment error: {0}", ex.Message);                ViewBag.ErrorMessage = "Video comment error";            }            return View("Index", viewModel);        }        [Authorize(Roles = "Administrator,Editor")]        [HttpPost]        public async Task<IActionResult> ListCommentsByLikes(string videoUrl, int minLikes)        {            CombinedIndexViewModel viewModel = await GetDefaultViewModelAsync();            if (string.IsNullOrEmpty(videoUrl))            {                ViewBag.ErrorMessage = "Enter a valid YouTube-URL.";                return View("Index", viewModel);            }            if (minLikes < 0)            {                ViewBag.ErrorMessage = "Enter a number <= 0.";                return View("Index", viewModel);            }            try            {                var (videoTitle, videoViews, comments) = await _youTubeService.GetCommentsByLikesAsync(videoUrl, _apiKey, minLikes);                viewModel.VideoTitle = videoTitle; // Videotitel hinzufügen                viewModel.VideoViews = videoViews; // Videoaufrufe hinzufügen                viewModel.YouTubeComments = comments.Select(comment => (                    comment.Author,                    TransformLinks(comment.Comment),                    comment.CommentUrl,                    comment.Likes                )).ToList();            }            catch (ArgumentException ex)            {                ViewBag.ErrorMessage = ex.Message;            }            catch (Exception ex)            {                _logger.LogError("Video comment error: {0}", ex.Message);                ViewBag.ErrorMessage = "Video comment error";            }            return View("Index", viewModel);        }        private async Task<CombinedIndexViewModel> GetDefaultViewModelAsync()        {            return new CombinedIndexViewModel            {                YouTubeComments = new List<(string Author, string Comment, string CommentUrl, int Likes)>()            };        }        // Methode zur Transformation von Links        private static string TransformLinks(string input)        {            if (string.IsNullOrEmpty(input))            {                return input;            }            // Präzisere Regex für URL-Erkennung mit verbatim string            var urlRegex = new Regex(@"(https?://[^\s<>\""]+)");            // Ersetze Links durch anklickbares Wort und füge Zeilenumbruch hinzu            string transformedText = urlRegex.Replace(input, match =>            {                var url = match.Value; // Gefundene URL                return $"<a href='{url}' target='_blank'>[Link]</a><br />";            });            // Ersetze Zeilenumbrüche mit <br />            return transformedText.Replace("\n", "").Replace("\r", "");        }    }

CombinedIndexViewModel.cs:

public List<(string Author, string Comment, string CommentUrl, int Likes)>? YouTubeComments { get; set; }public string? VideoTitle { get; set; }public int VideoViews { get; set; }

appsettings.json:

{"ConnectionStrings": {"DefaultConnection": "deleted"  },"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"    }  },"AllowedHosts": "*","YouTube": {"ApiKey": "deleted"  }}

YouTubeConfig.cs:

public class YouTubeConfig    {        public string ApiKey { get; set; } = string.Empty;    }

What are my next step to solve the issue or even just understand why it's not working.


Viewing all articles
Browse latest Browse all 3831

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>