| import pickle |
| import streamlit as st |
| import requests |
| from datetime import datetime |
|
|
| |
| st.set_page_config(page_title="🎬 Movie Recommender", page_icon="🎞️", layout="wide") |
|
|
| |
| if 'name' not in st.session_state: |
| st.session_state.name = None |
|
|
| |
| if st.session_state.name is None: |
| |
| st.title("🎬 Welcome to the Movie Recommender!") |
| |
| |
| hour = datetime.now().hour |
| greeting_time = "Good Morning ☀️" if hour < 12 else "Good Afternoon 🌤️" if hour < 18 else "Good Evening 🌙" |
| st.markdown(f"### {greeting_time}") |
|
|
| |
|
|
| name = st.text_input("Enter your name", "") |
| |
| if st.button("Submit"): |
| if name: |
| st.session_state.name = name |
| st.success(f"Hello, {name}! Welcome to the Movie Recommender 🎬") |
| |
| st.empty() |
| else: |
| st.error("Please enter a valid name.") |
|
|
|
|
| else: |
| |
| st.markdown(""" |
| <style> |
| .sidebar .sidebar-content { |
| background-color: #1c1c1c; /* خلفية داكنة جدًا */ |
| color: white; |
| padding: 15px; |
| border-radius: 10px; |
| } |
| .sidebar .sidebar-content h1, .sidebar .sidebar-content h2 { |
| font-size: 20px; |
| font-weight: bold; |
| color: #ecf0f1; /* لون النص */ |
| } |
| .sidebar .sidebar-content .stButton button { |
| background-color: #3498db; /* زر لون أزرق */ |
| color: white; |
| font-weight: bold; |
| border-radius: 5px; |
| width: 100%; |
| padding: 10px; |
| } |
| .sidebar .sidebar-content .stButton button:hover { |
| background-color: #2980b9; |
| } |
| </style> |
| """, unsafe_allow_html=True) |
|
|
| |
| try: |
| movies = pickle.load(open('movie_list.pkl', 'rb')) |
| similarity = pickle.load(open('similarity.pkl', 'rb')) |
| except FileNotFoundError: |
| st.error("❌ Required data files (movie_list.pkl and similarity.pkl) not found.") |
| st.stop() |
|
|
| |
| def fetch_poster(movie_id): |
| try: |
| url = f"https://api.themoviedb.org/3/movie/{movie_id}?api_key=8265bd1679663a7ea12ac168da84d2e8&language=en-US" |
| response = requests.get(url) |
| data = response.json() |
| poster_path = data.get('poster_path') |
| return f"https://image.tmdb.org/t/p/w500/{poster_path}" if poster_path else "https://via.placeholder.com/500x750?text=No+Image" |
| except: |
| return "https://via.placeholder.com/500x750?text=Error" |
|
|
| def fetch_movie_details(movie_id): |
| try: |
| url = f"https://api.themoviedb.org/3/movie/{movie_id}?api_key=8265bd1679663a7ea12ac168da84d2e8&language=en-US" |
| response = requests.get(url) |
| data = response.json() |
| overview = data.get('overview', 'No overview available.') |
| rating = data.get('vote_average', 'No rating') |
| release_date = data.get('release_date', 'No release date') |
| genres = ', '.join([genre['name'] for genre in data.get('genres', [])]) |
| return overview, rating, release_date, genres |
| except: |
| return "No details available.", "No rating", "No release date", "No genres" |
|
|
| def recommend(movie): |
| if movie not in movies['title'].values: |
| return [], [], [] |
| index = movies[movies['title'] == movie].index[0] |
| distances = sorted(list(enumerate(similarity[index])), reverse=True, key=lambda x: x[1]) |
| recommended_names = [] |
| recommended_posters = [] |
| recommended_ids = [] |
| for i in distances[1:6]: |
| movie_id = movies.iloc[i[0]].movie_id |
| recommended_names.append(movies.iloc[i[0]].title) |
| recommended_posters.append(fetch_poster(movie_id)) |
| recommended_ids.append(movie_id) |
| return recommended_names, recommended_posters, recommended_ids |
|
|
| def fetch_popular_movies(): |
| url = "https://api.themoviedb.org/3/movie/popular?api_key=8265bd1679663a7ea12ac168da84d2e8&language=en-US&page=1" |
| try: |
| response = requests.get(url) |
| data = response.json() |
| popular_movies = [] |
| for movie in data['results'][:60]: |
| title = movie['title'] |
| poster_path = movie.get('poster_path') |
| poster_url = f"https://image.tmdb.org/t/p/w500/{poster_path}" if poster_path else "https://via.placeholder.com/500x750?text=No+Image" |
| movie_id = movie['id'] |
| popular_movies.append((title, poster_url, movie_id)) |
| return popular_movies |
| except: |
| return [] |
|
|
| |
| st.sidebar.markdown(""" |
| <div style="text-align:center; color:white; font-size:30px; font-weight:bold;"> |
| 🎞️ Movie Recommender |
| </div> |
| <hr style="border-color: #ecf0f1;"> |
| """, unsafe_allow_html=True) |
|
|
| st.session_state.selected_section = st.sidebar.radio( |
| "Navigate", |
| ["Popular Movies", "Search & Recommend Movies", "Movie Details"] |
| ) |
|
|
| |
| st.markdown(f"### Hello, {st.session_state.get('name', 'Guest')} 👋", unsafe_allow_html=True) |
|
|
| if st.session_state.selected_section == "Popular Movies": |
| with st.expander("🔥 Popular Movies", expanded=True): |
| popular = fetch_popular_movies() |
| if popular: |
| cols = st.columns(5) |
| for i, (title, poster_url, movie_id) in enumerate(popular): |
| with cols[i % 5]: |
| st.image(poster_url, use_container_width=True) |
| st.markdown(f"<div class='movie-title'>{title}</div>", unsafe_allow_html=True) |
|
|
| |
| if f"show_details_{i}" not in st.session_state: |
| st.session_state[f"show_details_{i}"] = False |
|
|
| |
| if st.button("📄 Details", key=f"popular_details_{i}"): |
| |
| st.session_state[f"show_details_{i}"] = not st.session_state[f"show_details_{i}"] |
| |
| |
| if st.session_state[f"show_details_{i}"]: |
| overview, rating, release_date, genres = fetch_movie_details(movie_id) |
| st.markdown(f"**📅 Release Date:** {release_date}") |
| st.markdown(f"**⭐ Rating:** {rating}") |
| st.markdown(f"**🎭 Genres:** {genres}") |
| st.markdown(f"**📝 Overview:** {overview}") |
| else: |
| st.markdown("**Details Closed**") |
|
|
| else: |
| st.warning("Could not fetch popular movies.") |
|
|
| elif st.session_state.selected_section == "Search & Recommend Movies": |
| movie_list = movies['title'].values |
| selected_movie = st.selectbox("🎥 Select a Movie", movie_list) |
| rating = st.slider("⭐ Your Rating", 1, 10, 1) |
| st.write(f"✅ Your rating: {rating} stars") |
|
|
| if "show_recommendations" not in st.session_state: |
| st.session_state.show_recommendations = False |
|
|
| if st.button("🎯 Show Recommendations"): |
| st.session_state.show_recommendations = not st.session_state.show_recommendations |
|
|
| if st.session_state.show_recommendations: |
| with st.spinner("⏳ Fetching recommendations..."): |
| names, posters, ids = recommend(selected_movie) |
| if names: |
| st.markdown(f"### ✅ Recommended Movies Similar to {selected_movie}:") |
| cols = st.columns(5) |
| for i in range(len(names)): |
| with cols[i % 5]: |
| st.image(posters[i], use_container_width=True) |
| st.markdown(f"<div class='movie-title'>{names[i]}</div>", unsafe_allow_html=True) |
| if st.button("📄 Details", key=f"recommend_details_{i}"): |
| overview, rating, release_date, genres = fetch_movie_details(ids[i]) |
| st.markdown(f"**📅 Release Date:** {release_date}") |
| st.markdown(f"**⭐ Rating:** {rating}") |
| st.markdown(f"**🎭 Genres:** {genres}") |
| st.markdown(f"**📝 Overview:** {overview}") |
| else: |
| st.warning("No recommendations found.") |
|
|
| elif st.session_state.selected_section == "Movie Details": |
| if "show_details" not in st.session_state: |
| st.session_state.show_details = {} |
|
|
| movie_list = movies['title'].values |
| selected_movie = st.selectbox("🎥 Select a Movie to View Details", movie_list) |
| index = movies[movies['title'] == selected_movie].index[0] |
| movie_id = movies.iloc[index].movie_id |
| overview, rating, release_date, genres = fetch_movie_details(movie_id) |
|
|
| |
| if selected_movie not in st.session_state.show_details: |
| st.session_state.show_details[selected_movie] = True |
|
|
| if st.button(f"📄 Show/Hide Details for {selected_movie}"): |
| st.session_state.show_details[selected_movie] = not st.session_state.show_details[selected_movie] |
|
|
| |
| if st.session_state.show_details[selected_movie]: |
| st.image(fetch_poster(movie_id), use_container_width=True) |
| st.markdown(f"**📅 Release Date:** {release_date}") |
| st.markdown(f"**⭐ Rating:** {rating}") |
| st.markdown(f"**🎭 Genres:** {genres}") |
| st.markdown(f"**📝 Overview:** {overview}") |
| else: |
| st.markdown(f"Details for {selected_movie} are hidden. Click the button to view them.") |
|
|
| |
| st.markdown("<hr>", unsafe_allow_html=True) |
| st.markdown("<div class='footer'>© 2025 • by Youssef samy • Powered by TMDB API</div>", unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
|
|