reneboulard 34 Posted December 13, 2019 Posted December 13, 2019 I would like to have the ability to check if a movie is already in my library before scheduling a recording in the DVR. The only way to do it now is to make a search. This mean going from on screen to another. It is already possible to not record an episode of a serie that already exist in the library. A similar option should be available for movie, One suggestion is to have a seach display on screen when scheduling the recording of a movie, in order to inform if the movie is already in the library or not. Hope this help! 8 1
Luke 42135 Posted December 13, 2019 Posted December 13, 2019 Hi, yes it's good idea for the future. Thanks.
justinrh 261 Posted December 14, 2025 Posted December 14, 2025 Mine was marked as a generic 'duplicate' but is not linked to this post, so I'm mentioning here. And I do believe Emby does (or has in the past) remember meta data on deleted items because I've seen it happen more than once.
ebr 16296 Posted December 15, 2025 Posted December 15, 2025 We don't deliberately remember deleted items at this point. We just don't delete the user data right away because you may just be relocating an item which, to the system, is a delete and add operation and we don't want to lose your playstate and fav status, etc. when this happens. 1
Neminem 1579 Posted December 15, 2025 Posted December 15, 2025 (edited) 1 hour ago, ebr said: is a delete and add operation and we don't want to lose your playstate and fav status, etc. when this happens. Should this also be at play with playlists? When moving files around, they are being removed from playlist and manuel collections. Edited December 15, 2025 by Neminem
Luke 42135 Posted December 29, 2025 Posted December 29, 2025 I think on the program screen, being able to display if it's already in the library is a great idea. 1
justinrh 261 Posted December 29, 2025 Posted December 29, 2025 17 minutes ago, Luke said: I think on the program screen You mean Live TV > "Programs"? Seems to me the most useful place would be the Guide page. However, both places would be great
Luke 42135 Posted December 29, 2025 Posted December 29, 2025 Just now, justinrh said: You mean Live TV > "Programs"? Seems to me the most useful place would be the Guide page. However, both places would be great To me that would clutter the guide, but even as an option, it is currently not feasible. The recording process uses internet metadata lookups to help determine if it is already in the library. When you are working with a list of programs, it is not feasible to run that on every single one all at once. But when it's just a single program on the detail screen, then it's more doable there.
justinrh 261 Posted December 29, 2025 Posted December 29, 2025 Oh, maybe we are thinking the same thing. In the guide, you poke a program to get the detail window - that's where I'd expect to see it. In the guide itself would be nice also, but I understand the challenges there. 1
reneboulard 34 Posted 9 hours ago Author Posted 9 hours ago Proposed Solution: Visual EPG "In-Library" Indicators via Reverse Proxy Since this feature is still pending in the core Emby build, I’ve developed a workaround that identifies whether a movie in the EPG (Electronic Program Guide) is already in your library. It uses a combination of an external script and Nginx injection. The Implementation The solution consists of three main components: API Extraction Script: A custom script runs periodically to query the Emby API. It fetches a list of all movies currently in the EPG and compares them against your existing media library. It then generates a JSON file containing the "missing" status for these items. Nginx Reverse Proxy Injection: Using a reverse proxy (like Nginx), we inject a small JavaScript snippet and the generated JSON data into the Emby web interface as it is served to the client. UI Modification (CSS/JS Tagging): The injected script scans the web interface and looks for the movie IDs identified by our script. It then dynamically adds a visual tag (e.g., "Not in Library") directly on the movie details or guide screen. Why this works: No Core Modification: You don't need to wait for an official Emby update or modify the server's binary files. Reduced Friction: It eliminates the need to manually search for a movie before clicking "Record." Lightweight: The heavy lifting (comparing the library) is done by the script in the background, keeping the UI snappy.
reneboulard 34 Posted 7 hours ago Author Posted 7 hours ago Visual EPG "Not in Library" Indicators using Nginx and API Scripting This solution uses a small bash script and an Nginx reverse proxy to inject a visual "TO RECORD" tag directly into the Emby web interface for any movie found in the EPG that isn't already in your collection. How it works: Backend Script: Compares your library against the EPG via the Emby API. JSON Output: Saves a list of "missing" movies to a web-accessible folder. Nginx Injection: Automatically inserts a small JavaScript file into the Emby web app using sub_filter. UI Update: The script scans the page and adds a red badge to any matching movie titles. 1. The Automation Script (emby-absent.sh) This script generates the data. Place it in /usr/local/bin/ and ensure jq is installed. Update the EMBY_URL and API_KEY placeholders. #!/bin/bash # Configuration EMBY_URL="http://yourembyip:8096" API_KEY="YOUR_API_KEY_HERE" WEB_PATH="/var/www/report/absent_movies.json" # Function to clean up titles for better matching (removes punctuation/spaces) clean_title() { echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g' } # 1. Generate cleaned list of local movies LOCAL_CLEAN=$(curl -s "$EMBY_URL/emby/Items?IncludeItemTypes=Movie&Recursive=true&api_key=$API_KEY" \ | jq -r '.Items[].Name' | while read -r line; do clean_title "$line"; done | sort | uniq) # 2. Get list of movies currently in the EPG PROGRAMS=$(curl -s "$EMBY_URL/emby/LiveTv/Programs?IsMovie=true&api_key=$API_KEY" | jq -r '.Items[].Name' | sort | uniq) # 3. Compare and output JSON echo "$PROGRAMS" | while read -r title; do TITLE_CLEAN=$(clean_title "$title") if ! echo "$LOCAL_CLEAN" | grep -qxF "$TITLE_CLEAN"; then echo "$title" fi done | jq -R . | jq -s . > "$WEB_PATH" chmod 644 "$WEB_PATH" Set a cron job to run this every 4 hours: 0 */4 * * * /usr/local/bin/emby-absent.sh 2. Nginx Configuration Add these lines to your Emby location / block. This handles the injection and serves the custom files. location / { proxy_pass http://yourembyip:8096; # Disable compression so sub_filter can read the body proxy_set_header Accept-Encoding ""; # Inject the script before the closing body tag sub_filter '</body>' '<script src="/emby-mod.js"></script></body>'; sub_filter_once on; # Standard headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; } # Serve the injected files from your report directory location /emby-mod.js { root /var/www/report; } location /absent_movies.json { root /var/www/report; } 3. The Frontend Script (emby-mod.js) Save this in /var/www/report/emby-mod.js. It handles the visual tagging in the browser. (function() { async function markMovies() { try { const r = await fetch("/absent_movies.json?t=" + new Date().getTime()); const absentList = await r.json(); const absentListLower = absentList.map(t => t.toLowerCase().trim()); // Selector for movie titles in EPG and Library views const allTexts = document.querySelectorAll(".cardText, .itemName, .cardTitle"); allTexts.forEach(el => { const title = el.innerText.trim(); if (title && absentListLower.includes(title.toLowerCase())) { const card = el.closest(".card") || el.closest(".padded-card") || el.parentElement; const imageContainer = card.querySelector(".cardImageContainer") || card; if (card && !card.querySelector(".absent-tag")) { const tag = document.createElement("div"); tag.className = "absent-tag"; tag.innerText = "TO RECORD"; // Style the badge (Red, Bold, Floating) Object.assign(tag.style, { position: "absolute", top: "10px", left: "10px", backgroundColor: "#e74c3c", color: "white", padding: "4px 10px", fontWeight: "900", fontSize: "11px", borderRadius: "4px", zIndex: "999", boxShadow: "0 0 10px rgba(0,0,0,0.5)", border: "1px solid white", pointerEvents: "none" }); imageContainer.style.position = "relative"; imageContainer.appendChild(tag); } } }); } catch(e) { console.debug("EPG Check: Data not ready yet."); } } // Check for new cards every 2 seconds to handle scrolling setInterval(markMovies, 2000); })(); Credits: Special thanks to Gemini (Google AI) for the collaboration in refining this technical solution, writing the English documentation, and generating the architectural diagram.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now