public async Task <IActionResult> MatchFiltredByTvgSitesAsync([FromRoute] string id, [FromQuery] bool onlyNotMatched = true,
                                                                      CancellationToken cancellationToken = default)
        {
            var idGuid = GetInternalPlaylistId(id);

            var playlistEntity = await _dbContext.Playlist.FirstOrDefaultAsync(x => x.UniqueId == idGuid, cancellationToken);

            if (playlistEntity == null)
            {
                return(NotFound(playlistEntity));
            }

            var list = playlistEntity.TvgMedias.Where(m => m.MediaType == MediaType.LiveTv).ToList();

            if (onlyNotMatched)
            {
                list = list.Where(x => x.Tvg == null || string.IsNullOrEmpty(x.Tvg.Id)).ToList();
            }

            //TODO : Match by culture and Country code

            list.AsParallel().ForAll(media =>
            {
                var matched = _sitePackService.MatchTermByDispaynamesAndFiltredBySiteNameAsync(media.DisplayName, media.Lang, playlistEntity.TvgSites, cancellationToken).GetAwaiter().GetResult();
                if (matched != null)
                {
                    media.MediaGroup = new MediaGroup(matched.Country);
                    if (media.Tvg == null)
                    {
                        media.Tvg = new Tvg {
                            Name = matched.Channel_name, TvgIdentify = matched.Id, TvgSiteSource = matched.Site, Id = matched.Xmltv_id
                        };
                    }
                    else
                    {
                        media.Tvg.Name          = matched.Channel_name;
                        media.Tvg.Id            = matched.Xmltv_id;
                        media.Tvg.TvgIdentify   = matched.Id;
                        media.Tvg.TvgSiteSource = matched.Site;
                        if (media.Tvg.TvgSource == null)
                        {
                            media.Tvg.TvgSource = new TvgSource();
                        }
                        media.Tvg.TvgSource.Site    = matched.Site;
                        media.Tvg.TvgSource.Country = matched.Country;
                        media.Tvg.TvgSource.Code    = matched.Site_id;
                    }
                }
            });

            return(Ok(PlaylistModel.ToModel(playlistEntity, Url)));
        }
        public async Task <IActionResult> MatchTvgAsync([FromRoute] string id, [FromQuery] bool onlyNotMatched = true,
                                                        CancellationToken cancellationToken = default)
        {
            var idGuid = GetInternalPlaylistId(id);

            var playlistEntity = await _dbContext.Playlist.FirstOrDefaultAsync(x => x.UniqueId == idGuid, cancellationToken);

            if (playlistEntity == null)
            {
                return(NotFound(playlistEntity));
            }

            playlistEntity.TvgMedias
            .Where(m => m.MediaType == MediaType.LiveTv && (!onlyNotMatched || m.Tvg == null || string.IsNullOrEmpty(m.Tvg.Id)))
            .AsParallel()
            .WithCancellation(cancellationToken)
            .ForAll(media =>
            {
                var matched = _sitePackService.MatchMediaNameAndBySiteAsync(media.DisplayName, media.Tvg?.TvgSource.Site, cancellationToken).GetAwaiter().GetResult();
                if (matched != null)
                {
                    media.Tvg.Id            = matched.Xmltv_id;
                    media.Tvg.Name          = matched.Channel_name;
                    media.Tvg.TvgIdentify   = matched.Id;
                    media.Tvg.TvgSiteSource = matched.Site;
                }
            });

            //Matching movies
            var list = playlistEntity.TvgMedias.Where(m => m.MediaType == MediaType.Video).ToList();

            if (onlyNotMatched)
            {
                list = list.Where(x => x.Tvg == null || string.IsNullOrEmpty(x.Tvg.Logo)).ToList();
            }

            list
            .Where(x => x.Tvg?.TvgSource != null)
            .AsParallel()
            .WithCancellation(cancellationToken)
            .ForAll(media =>
            {
                var matched = _mediaScraper.SearchAsync(media.DisplayName, _globalOptions.TmdbAPI, _globalOptions.TmdbPosterBaseUrl, cancellationToken).GetAwaiter().GetResult();
                if (matched != null)
                {
                    media.Tvg.Logo = matched.FirstOrDefault()?.PosterPath;
                }
            });

            return(Ok(PlaylistModel.ToModel(playlistEntity, Url)));
        }
        public async Task <IActionResult> GetAsync(string id, [FromQuery] bool light = true, CancellationToken cancellationToken = default)
        {
            var idGuid   = GetInternalPlaylistId(id);
            var playlist = await _dbContext.Playlist.FirstOrDefaultAsync(x => x.UniqueId == idGuid, cancellationToken);

            if (playlist == null)
            {
                return(NotFound(id));
            }

            //var tmp = playlist.TvgMedias.Where(x => x.Name.Contains("SPORTS MAX") && x.Group.Equals("beIN SPORTS"));

            //foreach (var item in tmp)
            //{
            //    if (item.Name.Contains('1'))
            //    {
            //        item.Tvg.Id = "max1";
            //        item.Tvg.Name = "max1";
            //        item.Tvg.TvgIdentify = "mena_sports/max1";
            //        item.Tvg.TvgSiteSource = "Bein.net";
            //    }
            //    else if (item.Name.Contains('2'))
            //    {
            //        item.Tvg.Id = "max2";
            //        item.Tvg.Name = "max2";
            //        item.Tvg.TvgIdentify = "mena_sports/max2";
            //        item.Tvg.TvgSiteSource = "Bein.net";
            //    }
            //    else if (item.Name.Contains('3'))
            //    {
            //        item.Tvg.Id = "max3";
            //        item.Tvg.Name = "max3";
            //        item.Tvg.TvgIdentify = "mena_sports/max3";
            //        item.Tvg.TvgSiteSource = "Bein.net";
            //    }
            //    else if (item.Name.Contains('4'))
            //    {
            //        item.Tvg.Id = "max4";
            //        item.Tvg.Name = "max4";
            //        item.Tvg.TvgIdentify = "mena_sports/max4";
            //        item.Tvg.TvgSiteSource = "Bein.net";
            //    }
            //}
            //await _dbContext.SaveChangesAsync(cancellationToken);

            var res = light ? Ok(PlaylistModel.ToLightModel(playlist, Url)) : Ok(PlaylistModel.ToModel(playlist, Url));

            return(res);
        }
        public async Task <IActionResult> MatchVideosByPlaylistAsync([FromRoute] string id, [FromQuery] bool onlyNotMatched = true,
                                                                     CancellationToken cancellationToken = default)
        {
            var idGuid = GetInternalPlaylistId(id);

            var playlistEntity = await _dbContext.Playlist.FirstOrDefaultAsync(x => x.UniqueId == idGuid, cancellationToken);

            if (playlistEntity == null)
            {
                return(NotFound(playlistEntity));
            }

            int limitRequest = 40;

            playlistEntity.TvgMedias
            .Where(m => m.MediaType == MediaType.Video)
            .AsParallel()
            .WithCancellation(cancellationToken)
            .ForAll(media =>
            {
                while (limitRequest <= 0)
                {
                    _logger.LogInformation($"Scrapper Media limit TMDB (40 request/10s) was reached {media.DisplayName}");
                    Thread.Sleep(10001);
                    if (limitRequest <= 0)
                    {
                        Interlocked.Add(ref limitRequest, 40);
                    }
                }

                Interlocked.Decrement(ref limitRequest);
                _logger.LogInformation($"Scrapping media {limitRequest}: {media.DisplayName}");

                var matched = _mediaScraper.SearchAsync(media.DisplayName, _globalOptions.TmdbAPI, _globalOptions.TmdbPosterBaseUrl, cancellationToken).GetAwaiter().GetResult();
                if (matched != null)
                {
                    media.Tvg.Logo = matched.FirstOrDefault()?.PosterPath;
                }
            });

            return(Ok(PlaylistModel.ToModel(playlistEntity, Url)));
        }
        public async Task <IActionResult> ListAsync([FromBody] QueryListBaseModel query, [FromQuery] bool light = true,
                                                    CancellationToken cancellationToken = default)
        {
            var user = await _dbContext.Users.FindAsync(new object[] { UserId }, cancellationToken);

            if (user == null)
            {
                _logger.LogError($"User {this.UserEmail} not founded");
                return(BadRequest($"User {this.UserEmail} not found"));
            }
            var plCacheKey = $"{UserCachePlaylistKey}_{query.GetHashCode()}_{light}";
            var playlists  = await _memoryCache.GetOrCreateAsync(plCacheKey, async entry =>
            {
                if (_memoryCache.TryGetValue(UserCachePlaylistKey, out List <string> list))
                {
                    list.Add(UserCachePlaylistKey);
                }
                else
                {
                    list = new List <string> {
                        plCacheKey
                    };
                }

                _memoryCache.Set(UserCachePlaylistKey, list);
                entry.SlidingExpiration = TimeSpan.FromHours(2);

                return(await Task.Run(() =>
                {
                    var response = _dbContext.Playlist
                                   .Where(x => x.UserId == user.Id)
                                   .OrderByDescending(x => x.Id)
                                   .Select(pl => light ? PlaylistModel.ToLightModel(pl, Url) : PlaylistModel.ToModel(pl, Url))
                                   .GetPaged(query.PageNumber, query.PageSize);
                    return response;
                }));
            });

            return(new OkObjectResult(playlists));
        }