🏗️ structured files for testing

Co-authored-by: Sindre Kjelsrud <kjelsrudsindre@gmail.com>
This commit is contained in:
haraldnilsen 2023-10-03 10:03:36 +02:00
parent 5cfc2653bb
commit d4b53e9912
15 changed files with 4 additions and 5 deletions

View file

@ -0,0 +1,11 @@
using backend;
using Microsoft.EntityFrameworkCore;
public class MovieDbContext: DbContext
{
public MovieDbContext(DbContextOptions<MovieDbContext> options) : base(options)
{
}
public DbSet<MovieDB> Movies { get; set; }
}

View file

@ -0,0 +1,164 @@
using System.Collections;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Writers;
namespace backend;
using static backend.QueryParameterValidators;
[ApiController]
[Route("[controller]")]
public class MovieController: ControllerBase
{
private readonly MovieDbContext _context;
private readonly ILogger<MovieController> _logger;
private static readonly string[] sortTypes = new[]
{
"titleasc", "titledesc", "yearasc", "yeardesc"
};
public MovieController(ILogger<MovieController> logger, MovieDbContext context)
{
_logger = logger;
_context = context;
}
[HttpGet(Name = "GetMovies")]
public ActionResult<IEnumerable<MovieDB>> Get(
[FromQuery] string? s,
[FromQuery] string? type,
[FromQuery] string? y,
[FromQuery] string? sort,
[FromQuery] int pageNumber = 1,
[FromQuery] int pageSize = 5
) {
try
{
var movies = _context.Movies.AsQueryable();
if (s != null) {
if (!IsValidS(s)) return StatusCode(400, "Bad Request: Invalid title");
movies = _context.Movies.Where(m => m.Title.ToLower().Contains(s.ToLower()));
}
if (type != null) {
if (!IsValidType(type)) return StatusCode(400, "Bad Request: Invalid type");
movies = movies.Where(m => m.Type == type);
}
if (y != null) {
if (!IsValidYear(y)) return StatusCode(400, "Bad Request: Invalid year");
movies = movies.Where(m => m.Year == y);
}
if (sort != null) {
if (!IsValidSort(sort)) return StatusCode(400, "Bad Request: Invalid sort-type");
if (sort == "titleasc") movies = movies.OrderBy(m => m.Title);
if (sort == "titledesc") movies = movies.OrderByDescending(m => m.Title);
if (sort == "yearasc") movies = movies.OrderBy(m => m.Year);
if (sort == "yeardesc") movies = movies.OrderByDescending(m => m.Year);
}
if (!IsValidPageNumber(pageNumber) || !IsValidPageSize(pageSize))
return StatusCode(400, "Bad Request: Invalid page-size or page-number");
var totalMovies = movies.Count();
var totalPages = Math.Ceiling((double)totalMovies / pageSize);
IEnumerable<MovieDB> resultSkip = movies.Skip(pageSize * (pageNumber - 1));
IEnumerable<MovieDB> resultTake = resultSkip.Take(pageSize);
if (resultTake.ToList().Count == 0) {
return StatusCode(204, "No Content");
}
MovieResponse Response = new MovieResponse("OK", resultTake.Count(), resultTake);
return Ok(Response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching movies");
return StatusCode(500, "Internal server error");
}
}
[HttpPost(Name = "PostMovie")]
public ActionResult Post(
[FromQuery] string s,
[FromQuery] string y,
[FromQuery] string imdbID,
[FromQuery] string type,
[FromQuery] string poster
) {
try
{
MovieDB newMovie = new(s, y, imdbID, type, poster);
var movies = _context.Movies.Where(m => m.imdbID.ToLower().Contains(imdbID.ToLower()));
if (movies.Count() == 0) {
_context.Add(newMovie);
_context.SaveChanges();
return Ok("Successfully added new movie");
} else {
return StatusCode(409, "Conflict, imdbID already exists");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error posting movie");
return StatusCode(500, "Internal server error");
}
}
[HttpDelete(Name = "DeleteMovie")]
public ActionResult Delete([FromQuery] string imdbID) {
try
{
var movie = _context.Movies.AsEnumerable()
.Where(m => m.imdbID.ToLower().Contains(imdbID.ToLower()))
.ElementAtOrDefault(0);
if (movie != null) {
_context.Remove(movie);
_context.SaveChanges();
return Ok("Successfully deleted movie");
} else {
return StatusCode(409, "Conflict, imdbID doesn't exists");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting movie");
return StatusCode(500, "Internal server error");
}
}
[HttpPut(Name = "PutMovie")]
public ActionResult Put(
[FromQuery] string? s,
[FromQuery] string? y,
[FromQuery] string imdbID,
[FromQuery] string? type,
[FromQuery] string? poster
) {
try
{
var movie = _context.Movies.AsEnumerable()
.Where(m => m.imdbID.ToLower().Contains(imdbID.ToLower()))
.ElementAtOrDefault(0);
if (movie != null) {
if (s != null) movie.Title = s;
if (y != null) movie.Year = y;
if (type != null) movie.Type = type;
if (poster != null) movie.Poster = poster;
_context.SaveChanges();
return Ok("Successfully edited movie");
} else {
return StatusCode(409, "Conflict, imdbID doesn't exists");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting movie");
return StatusCode(500, "Internal server error");
}
}
}

View file

@ -0,0 +1,50 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace backend.Migrations
{
[DbContext(typeof(MovieDbContext))]
[Migration("20230919073410_V1__init")]
partial class V1__init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("backend.MovieDB", b =>
{
b.Property<string>("imdbID")
.HasColumnType("text");
b.Property<string>("Poster")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("Type")
.HasColumnType("text");
b.Property<string>("Year")
.HasColumnType("text");
b.HasKey("imdbID");
b.ToTable("Movies");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace backend.Migrations
{
/// <inheritdoc />
public partial class V1__init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movies",
columns: table => new
{
imdbID = table.Column<string>(type: "text", nullable: false),
Title = table.Column<string>(type: "text", nullable: true),
Year = table.Column<string>(type: "text", nullable: true),
Type = table.Column<string>(type: "text", nullable: true),
Poster = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Movies", x => x.imdbID);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movies");
}
}
}

View file

@ -0,0 +1,47 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace backend.Migrations
{
[DbContext(typeof(MovieDbContext))]
partial class MovieDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("backend.MovieDB", b =>
{
b.Property<string>("imdbID")
.HasColumnType("text");
b.Property<string>("Poster")
.HasColumnType("text");
b.Property<string>("Title")
.HasColumnType("text");
b.Property<string>("Type")
.HasColumnType("text");
b.Property<string>("Year")
.HasColumnType("text");
b.HasKey("imdbID");
b.ToTable("Movies");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,16 @@
#nullable disable
namespace backend;
public class Movie
{
public string Title { get; set; }
public string Year { get; set; }
public string imdbID { get; set; }
public string Type { get; set; }
public string Poster { get; set; }
}

View file

@ -0,0 +1,19 @@
#nullable disable
namespace backend;
public class MovieResponse
{
public MovieResponse(string Response, int TotalResults, IEnumerable<MovieDB> Search) {
this.Response = Response;
this.TotalResults = TotalResults;
this.Search = Search;
}
public string Response { get; set; }
public int TotalResults { get; set; }
public IEnumerable<MovieDB> Search { get; set; }
}

View file

@ -0,0 +1,29 @@
#nullable disable
using Microsoft.EntityFrameworkCore;
using CsvHelper.Configuration;
using System.Globalization;
namespace backend;
[PrimaryKey(nameof(imdbID))]
public class MovieDB
{
public string Title { get; set; }
public string Year { get; set; }
public string imdbID { get; set; }
public string Type { get; set; }
public string Poster { get; set; }
public MovieDB(string Title, string Year, string imdbID, string Type, string Poster) {
this.Title = Title;
this.Year = Year;
this.imdbID = imdbID;
this.Type = Type;
this.Poster = Poster;
}
}

View file

@ -0,0 +1,75 @@
using Microsoft.EntityFrameworkCore;
using System.Globalization;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using CsvHelper;
using backend;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://localhost:5173");
});
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var configuration = builder.Configuration;
builder.Services.AddDbContext<MovieDbContext>(options =>
options.UseNpgsql(configuration.GetConnectionString("DefaultConnection")));
var services = builder.Services.BuildServiceProvider();
using (var scope = services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<MovieDbContext>();
context.Database.EnsureCreated();
// Check if movies are already inserted to avoid duplicate insertion
if (!context.Movies.Any())
{
using (context)
{
context.Database.Migrate();
}
using (var reader = new StreamReader("public/DbMockData.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
var records = csv.GetRecords<MovieDB>().ToList();
context.Movies.AddRange(records);
context.SaveChanges();
}
}
}
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();

View file

@ -0,0 +1,41 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:17138",
"sslPort": 44374
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5212",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7235;http://localhost:5212",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View file

@ -0,0 +1,56 @@
namespace backend;
public static class QueryParameterValidators
{
private static readonly string[] sortTypes = new[]
{
"titleasc", "titledesc", "yearasc", "yeardesc"
};
private static readonly string[] movieTypes = new[]
{
"movie", "series", "episode"
};
// Assuming `s` is a non-nullable parameter and can be any string
// If there are specific requirements for `s`, additional validation can be added
public static bool IsValidS(string s)
{
return !string.IsNullOrWhiteSpace(s);
}
// Assuming `type` can be any string but you might want to limit it to specific values
// If there are predefined types, you can replace the body with something like: return new List<string> { "type1", "type2" }.Contains(type);
public static bool IsValidType(string? type)
{
return string.IsNullOrWhiteSpace(type) || movieTypes.Contains(type.ToLower());
}
// For `year`, assuming it's a 4 digit representation of a year
public static bool IsValidYear(string? year)
{
if (string.IsNullOrWhiteSpace(year)) return true;
return int.TryParse(year, out int parsedYear) && parsedYear > 1900 && parsedYear <= DateTime.Now.Year;
}
// Assuming `sort` can be any string but you might want to limit it to specific values
// If there are predefined sorts, you can replace the body with something like: return new List<string> { "asc", "desc" }.Contains(sort);
public static bool IsValidSort(string? sort)
{
return string.IsNullOrWhiteSpace(sort) || sortTypes.Contains(sort.ToLower());
}
// Assuming `pageNumber` should be 1 or more
public static bool IsValidPageNumber(int pageNumber)
{
return pageNumber > 0;
}
// Assuming `pageSize` should be between 1 to 100 (or any other limits you might want to set)
public static bool IsValidPageSize(int pageSize)
{
return pageSize > 0 && pageSize <= 100; // you can adjust the upper limit as per requirements
}
}

View file

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View file

@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=movie-database;Port=5432;;Username=postgres;Password=moviedatabase"
}
}

View file

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,62 @@
Title,Year,imdbID,Type,Poster
The Shawshank Redemption,1994,tt0111161,Movie,https://example.com/poster1.jpg
The Godfather,1972,tt0068646,Movie,https://example.com/poster2.jpg
Pulp Fiction,1994,tt0110912,Movie,https://example.com/poster3.jpg
The Dark Knight,2008,tt0468569,Movie,https://example.com/poster4.jpg
Schindler's List,1993,tt0108052,Movie,https://example.com/poster5.jpg
Forrest Gump,1994,tt0109830,Movie,https://example.com/poster6.jpg
Inception,2010,tt1375666,Movie,https://example.com/poster7.jpg
The Matrix,1999,tt0133093,Movie,https://example.com/poster8.jpg
The Lord of the Rings: The Fellowship of the Ring,2001,tt0120737,Movie,https://example.com/poster9.jpg
The Silence of the Lambs,1991,tt0102926,Movie,https://example.com/poster10.jpg
Avatar,2009,tt0499549,Movie,https://example.com/poster11.jpg
Jurassic Park,1993,tt0107290,Movie,https://example.com/poster12.jpg
Titanic,1997,tt0120338,Movie,https://example.com/poster13.jpg
The Avengers,2012,tt0848228,Movie,https://example.com/poster14.jpg
E.T. the Extra-Terrestrial,1982,tt0083866,Movie,https://example.com/poster15.jpg
The Lion King,1994,tt0110357,Movie,https://example.com/poster16.jpg
Harry Potter and the Sorcerer's Stone,2001,tt0241527,Movie,https://example.com/poster17.jpg
Gladiator,2000,tt0172495,Movie,https://example.com/poster18.jpg
The Dark Knight Rises,2012,tt1345836,Movie,https://example.com/poster19.jpg
Saving Private Ryan,1998,tt0120815,Movie,https://example.com/poster20.jpg
Interstellar,2014,tt0816692,Movie,https://example.com/poster21.jpg
Forrest Gump 2: Gump's Odyssey,2023,tt9999999,Movie,https://example.com/poster22.jpg
The Green Mile,1999,tt0120689,Movie,https://example.com/poster23.jpg
The Revenant,2015,tt1663202,Movie,https://example.com/poster24.jpg
The Social Network,2010,tt1285016,Movie,https://example.com/poster25.jpg
The Great Gatsby,2013,tt1343092,Movie,https://example.com/poster26.jpg
The Grand Budapest Hotel,2014,tt2278388,Movie,https://example.com/poster27.jpg
The Shining,1980,tt0081505,Movie,https://example.com/poster28.jpg
The Martian,2015,tt3659388,Movie,https://example.com/poster29.jpg
The Shawshank Redemption 2: Redemption Day,2022,tt8888888,Movie,https://example.com/poster30.jpg
The Departed,2006,tt0407887,Movie,https://example.com/poster31.jpg
No Country for Old Men,2007,tt0477348,Movie,https://example.com/poster32.jpg
Forrest Gump 3: Gump's Legacy,2025,tt7777777,Movie,https://example.com/poster33.jpg
The Prestige,2006,tt0482571,Movie,https://example.com/poster34.jpg
Memento,2000,tt0209144,Movie,https://example.com/poster35.jpg
The Wolf of Wall Street,2013,tt0993846,Movie,https://example.com/poster36.jpg
La La Land,2016,tt3783958,Movie,https://example.com/poster37.jpg
Django Unchained,2012,tt1853728,Movie,https://example.com/poster38.jpg
The Incredibles,2004,tt0317705,Movie,https://example.com/poster39.jpg
Finding Nemo,2003,tt0266543,Movie,https://example.com/poster40.jpg
The Hateful Eight,2015,tt3460252,Movie,https://example.com/poster41.jpg
Whiplash,2014,tt2582802,Movie,https://example.com/poster42.jpg
Mad Max: Fury Road,2015,tt1392190,Movie,https://example.com/poster43.jpg
The King's Speech,2010,tt1504320,Movie,https://example.com/poster44.jpg
The Sixth Sense,1999,tt0167404,Movie,https://example.com/poster45.jpg
The Shawshank Redemption 3: Redemption Strikes Back,2027,tt6666666,Movie,https://example.com/poster46.jpg
Se7en,1995,tt0114369,Movie,https://example.com/poster47.jpg
The Truman Show,1998,tt0120382,Movie,https://example.com/poster48.jpg
The Imitation Game,2014,tt2084970,Movie,https://example.com/poster49.jpg
The Witcher: Nightmare of the Wolf,2021,tt10655758,Movie,https://example.com/poster50.jpg
The Matrix Reloaded,2003,tt0234215,Movie,https://example.com/poster51.jpg
Forrest Gump 4: Gump's Return,2030,tt5555555,Movie,https://example.com/poster52.jpg
Casablanca,1942,tt0034583,Movie,https://example.com/poster53.jpg
The Dark Knight Returns,2019,tt12043476,Movie,https://example.com/poster54.jpg
Schindler's List 2: Schindler's Revenge,2032,tt4444444,Movie,https://example.com/poster55.jpg
The Matrix Revolutions,2003,tt0242653,Movie,https://example.com/poster56.jpg
Braveheart,1995,tt0112573,Movie,https://example.com/poster57.jpg
The Departed 2: Departed Again,2035,tt3333333,Movie,https://example.com/poster58.jpg
The Godfather Part III,1990,tt0099674,Movie,https://example.com/poster59.jpg
Inception 2: The Dream Continues,2038,tt2222222,Movie,https://example.com/poster60.jpg
The Empire Strikes Back,1980,tt0080684,Movie,https://example.com/poster61
1 Title Year imdbID Type Poster
2 The Shawshank Redemption 1994 tt0111161 Movie https://example.com/poster1.jpg
3 The Godfather 1972 tt0068646 Movie https://example.com/poster2.jpg
4 Pulp Fiction 1994 tt0110912 Movie https://example.com/poster3.jpg
5 The Dark Knight 2008 tt0468569 Movie https://example.com/poster4.jpg
6 Schindler's List 1993 tt0108052 Movie https://example.com/poster5.jpg
7 Forrest Gump 1994 tt0109830 Movie https://example.com/poster6.jpg
8 Inception 2010 tt1375666 Movie https://example.com/poster7.jpg
9 The Matrix 1999 tt0133093 Movie https://example.com/poster8.jpg
10 The Lord of the Rings: The Fellowship of the Ring 2001 tt0120737 Movie https://example.com/poster9.jpg
11 The Silence of the Lambs 1991 tt0102926 Movie https://example.com/poster10.jpg
12 Avatar 2009 tt0499549 Movie https://example.com/poster11.jpg
13 Jurassic Park 1993 tt0107290 Movie https://example.com/poster12.jpg
14 Titanic 1997 tt0120338 Movie https://example.com/poster13.jpg
15 The Avengers 2012 tt0848228 Movie https://example.com/poster14.jpg
16 E.T. the Extra-Terrestrial 1982 tt0083866 Movie https://example.com/poster15.jpg
17 The Lion King 1994 tt0110357 Movie https://example.com/poster16.jpg
18 Harry Potter and the Sorcerer's Stone 2001 tt0241527 Movie https://example.com/poster17.jpg
19 Gladiator 2000 tt0172495 Movie https://example.com/poster18.jpg
20 The Dark Knight Rises 2012 tt1345836 Movie https://example.com/poster19.jpg
21 Saving Private Ryan 1998 tt0120815 Movie https://example.com/poster20.jpg
22 Interstellar 2014 tt0816692 Movie https://example.com/poster21.jpg
23 Forrest Gump 2: Gump's Odyssey 2023 tt9999999 Movie https://example.com/poster22.jpg
24 The Green Mile 1999 tt0120689 Movie https://example.com/poster23.jpg
25 The Revenant 2015 tt1663202 Movie https://example.com/poster24.jpg
26 The Social Network 2010 tt1285016 Movie https://example.com/poster25.jpg
27 The Great Gatsby 2013 tt1343092 Movie https://example.com/poster26.jpg
28 The Grand Budapest Hotel 2014 tt2278388 Movie https://example.com/poster27.jpg
29 The Shining 1980 tt0081505 Movie https://example.com/poster28.jpg
30 The Martian 2015 tt3659388 Movie https://example.com/poster29.jpg
31 The Shawshank Redemption 2: Redemption Day 2022 tt8888888 Movie https://example.com/poster30.jpg
32 The Departed 2006 tt0407887 Movie https://example.com/poster31.jpg
33 No Country for Old Men 2007 tt0477348 Movie https://example.com/poster32.jpg
34 Forrest Gump 3: Gump's Legacy 2025 tt7777777 Movie https://example.com/poster33.jpg
35 The Prestige 2006 tt0482571 Movie https://example.com/poster34.jpg
36 Memento 2000 tt0209144 Movie https://example.com/poster35.jpg
37 The Wolf of Wall Street 2013 tt0993846 Movie https://example.com/poster36.jpg
38 La La Land 2016 tt3783958 Movie https://example.com/poster37.jpg
39 Django Unchained 2012 tt1853728 Movie https://example.com/poster38.jpg
40 The Incredibles 2004 tt0317705 Movie https://example.com/poster39.jpg
41 Finding Nemo 2003 tt0266543 Movie https://example.com/poster40.jpg
42 The Hateful Eight 2015 tt3460252 Movie https://example.com/poster41.jpg
43 Whiplash 2014 tt2582802 Movie https://example.com/poster42.jpg
44 Mad Max: Fury Road 2015 tt1392190 Movie https://example.com/poster43.jpg
45 The King's Speech 2010 tt1504320 Movie https://example.com/poster44.jpg
46 The Sixth Sense 1999 tt0167404 Movie https://example.com/poster45.jpg
47 The Shawshank Redemption 3: Redemption Strikes Back 2027 tt6666666 Movie https://example.com/poster46.jpg
48 Se7en 1995 tt0114369 Movie https://example.com/poster47.jpg
49 The Truman Show 1998 tt0120382 Movie https://example.com/poster48.jpg
50 The Imitation Game 2014 tt2084970 Movie https://example.com/poster49.jpg
51 The Witcher: Nightmare of the Wolf 2021 tt10655758 Movie https://example.com/poster50.jpg
52 The Matrix Reloaded 2003 tt0234215 Movie https://example.com/poster51.jpg
53 Forrest Gump 4: Gump's Return 2030 tt5555555 Movie https://example.com/poster52.jpg
54 Casablanca 1942 tt0034583 Movie https://example.com/poster53.jpg
55 The Dark Knight Returns 2019 tt12043476 Movie https://example.com/poster54.jpg
56 Schindler's List 2: Schindler's Revenge 2032 tt4444444 Movie https://example.com/poster55.jpg
57 The Matrix Revolutions 2003 tt0242653 Movie https://example.com/poster56.jpg
58 Braveheart 1995 tt0112573 Movie https://example.com/poster57.jpg
59 The Departed 2: Departed Again 2035 tt3333333 Movie https://example.com/poster58.jpg
60 The Godfather Part III 1990 tt0099674 Movie https://example.com/poster59.jpg
61 Inception 2: The Dream Continues 2038 tt2222222 Movie https://example.com/poster60.jpg
62 The Empire Strikes Back 1980 tt0080684 Movie https://example.com/poster61